Browse Source

Add Exr compressor factory

pull/3096/head
Brian Popow 2 months ago
parent
commit
137ebbba06
  1. 8
      src/ImageSharp/Formats/Exr/Compression/Compressors/NoCompressor.cs
  2. 47
      src/ImageSharp/Formats/Exr/Compression/Compressors/ZipCompressor.cs
  3. 4
      src/ImageSharp/Formats/Exr/Compression/Decompressors/B44Compression.cs
  4. 6
      src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs
  5. 6
      src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthCompression.cs
  6. 6
      src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs
  7. 23
      src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs
  8. 4
      src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs
  9. 26
      src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs
  10. 23
      src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs
  11. 7
      src/ImageSharp/Formats/Exr/Constants/ExrCompression.cs
  12. 43
      src/ImageSharp/Formats/Exr/ExrBaseCompressor.cs
  13. 26
      src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
  14. 5
      src/ImageSharp/Formats/Exr/ExrEncoder.cs
  15. 5
      src/ImageSharp/Formats/Exr/ExrEncoderCore.cs
  16. 5
      src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs
  17. 11
      src/ImageSharp/Formats/Exr/ExrThrowHelper.cs

8
src/ImageSharp/Formats/Exr/Compression/Compressors/NoCompressor.cs

@ -0,0 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
internal class NoCompressor
{
}

47
src/ImageSharp/Formats/Exr/Compression/Compressors/ZipCompressor.cs

@ -0,0 +1,47 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Exr.Constants;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
internal class ZipCompressor : ExrBaseCompressor
{
private readonly DeflateCompressionLevel compressionLevel;
private readonly MemoryStream memoryStream = new();
public ZipCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock, DeflateCompressionLevel compressionLevel)
: base(output, allocator, bytesPerBlock)
=> this.compressionLevel = compressionLevel;
/// <inheritdoc/>
public override ExrCompression Method => ExrCompression.Zip;
/// <inheritdoc/>
public override void Initialize(int rowsPerStrip)
{
}
/// <inheritdoc/>
public override void CompressStrip(Span<byte> rows, int height)
{
this.memoryStream.Seek(0, SeekOrigin.Begin);
using (ZlibDeflateStream stream = new(this.Allocator, this.memoryStream, this.compressionLevel))
{
stream.Write(rows);
stream.Flush();
}
int size = (int)this.memoryStream.Position;
byte[] buffer = this.memoryStream.GetBuffer();
this.Output.Write(buffer, 0, size);
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
}
}

4
src/ImageSharp/Formats/Exr/Compression/Decompressors/B44Compression.cs

@ -24,8 +24,8 @@ internal class B44Compression : ExrBaseDecompressor
private IMemoryOwner<ushort> tmpBuffer;
public B44Compression(MemoryAllocator allocator, uint uncompressedBytes, int width, int height, uint rowsPerBlock, int channelCount)
: base(allocator, uncompressedBytes)
public B44Compression(MemoryAllocator allocator, uint bytesPerBlock, int width, int height, uint rowsPerBlock, int channelCount)
: base(allocator, bytesPerBlock)
{
this.width = width;
this.height = height;

6
src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs

@ -8,13 +8,13 @@ namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
internal class NoneExrCompression : ExrBaseDecompressor
{
public NoneExrCompression(MemoryAllocator allocator, uint uncompressedBytes)
: base(allocator, uncompressedBytes)
public NoneExrCompression(MemoryAllocator allocator, uint bytesPerBlock)
: base(allocator, bytesPerBlock)
{
}
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer)
=> stream.Read(buffer, 0, Math.Min(buffer.Length, (int)this.UncompressedBytes));
=> stream.Read(buffer, 0, Math.Min(buffer.Length, (int)this.BytesPerBlock));
protected override void Dispose(bool disposing)
{

6
src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthCompression.cs

@ -19,7 +19,7 @@ internal class RunLengthCompression : ExrBaseDecompressor
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer)
{
Span<byte> uncompressed = this.tmpBuffer.GetSpan();
int maxLength = (int)this.UncompressedBytes;
int maxLength = (int)this.BytesPerBlock;
int offset = 0;
while (compressedBytes > 0)
{
@ -63,8 +63,8 @@ internal class RunLengthCompression : ExrBaseDecompressor
}
}
Reconstruct(uncompressed, this.UncompressedBytes);
Interleave(uncompressed, this.UncompressedBytes, buffer);
Reconstruct(uncompressed, this.BytesPerBlock);
Interleave(uncompressed, this.BytesPerBlock, buffer);
}
private static byte ReadNextByte(BufferedReadStream stream)

6
src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs

@ -13,8 +13,8 @@ internal class ZipExrCompression : ExrBaseDecompressor
{
private readonly IMemoryOwner<byte> tmpBuffer;
public ZipExrCompression(MemoryAllocator allocator, uint uncompressedBytes)
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes);
public ZipExrCompression(MemoryAllocator allocator, uint bytesPerBlock)
: base(allocator, bytesPerBlock) => this.tmpBuffer = allocator.Allocate<byte>((int)bytesPerBlock);
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer)
{
@ -28,7 +28,7 @@ internal class ZipExrCompression : ExrBaseDecompressor
int left = (int)(compressedBytes - (stream.Position - pos));
return left > 0 ? left : 0;
});
inflateStream.AllocateNewBytes((int)this.UncompressedBytes, true);
inflateStream.AllocateNewBytes((int)this.BytesPerBlock, true);
DeflateStream dataStream = inflateStream.CompressedStream!;
int totalRead = 0;

23
src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs

@ -9,10 +9,10 @@ internal abstract class ExrBaseCompression : IDisposable
{
private bool isDisposed;
protected ExrBaseCompression(MemoryAllocator allocator, uint bytePerRow)
protected ExrBaseCompression(MemoryAllocator allocator, uint bytesPerBlock)
{
this.Allocator = allocator;
this.UncompressedBytes = bytePerRow;
this.BytesPerBlock = bytesPerBlock;
}
/// <summary>
@ -21,9 +21,24 @@ internal abstract class ExrBaseCompression : IDisposable
protected MemoryAllocator Allocator { get; }
/// <summary>
/// Gets the uncompressed bytes.
/// Gets the bits per pixel.
/// </summary>
public uint UncompressedBytes { get; }
public int BitsPerPixel { get; }
/// <summary>
/// Gets the bytes per row.
/// </summary>
public int BytesPerRow { get; }
/// <summary>
/// Gets the uncompressed bytes per block.
/// </summary>
public uint BytesPerBlock { get; }
/// <summary>
/// Gets the image width.
/// </summary>
public int Width { get; }
/// <inheritdoc />
public void Dispose()

4
src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs

@ -8,8 +8,8 @@ namespace SixLabors.ImageSharp.Formats.Exr.Compression;
internal abstract class ExrBaseDecompressor : ExrBaseCompression
{
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytePerRow)
: base(allocator, bytePerRow)
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytesPerBlock)
: base(allocator, bytesPerBlock)
{
}

26
src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
using SixLabors.ImageSharp.Formats.Exr.Constants;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
internal static class ExrCompressorFactory
{
public static ExrBaseCompressor Create(
ExrCompression method,
Stream output,
MemoryAllocator allocator,
int width,
DeflateCompressionLevel compressionLevel)
{
switch (method)
{
default:
throw ExrThrowHelper.NotSupportedCompressor(method.ToString());
}
}
}

23
src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs

@ -2,26 +2,27 @@
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
using SixLabors.ImageSharp.Formats.Exr.Constants;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
internal static class ExrDecompressorFactory
{
public static ExrBaseDecompressor Create(ExrCompressionType method, MemoryAllocator memoryAllocator, uint uncompressedBytes, int width, int height, uint rowsPerBlock, int channelCount)
public static ExrBaseDecompressor Create(ExrCompression method, MemoryAllocator memoryAllocator, uint bytesPerBlock, int width, int height, uint rowsPerBlock, int channelCount)
{
switch (method)
{
case ExrCompressionType.None:
return new NoneExrCompression(memoryAllocator, uncompressedBytes);
case ExrCompressionType.Zips:
return new ZipExrCompression(memoryAllocator, uncompressedBytes);
case ExrCompressionType.Zip:
return new ZipExrCompression(memoryAllocator, uncompressedBytes);
case ExrCompressionType.RunLengthEncoded:
return new RunLengthCompression(memoryAllocator, uncompressedBytes);
case ExrCompressionType.B44:
return new B44Compression(memoryAllocator, uncompressedBytes, width, height, rowsPerBlock, channelCount);
case ExrCompression.None:
return new NoneExrCompression(memoryAllocator, bytesPerBlock);
case ExrCompression.Zips:
return new ZipExrCompression(memoryAllocator, bytesPerBlock);
case ExrCompression.Zip:
return new ZipExrCompression(memoryAllocator, bytesPerBlock);
case ExrCompression.RunLengthEncoded:
return new RunLengthCompression(memoryAllocator, bytesPerBlock);
case ExrCompression.B44:
return new B44Compression(memoryAllocator, bytesPerBlock, width, height, rowsPerBlock, channelCount);
default:
throw ExrThrowHelper.NotSupportedDecompressor(nameof(method));
}

7
src/ImageSharp/Formats/Exr/Compression/ExrCompressionType.cs → src/ImageSharp/Formats/Exr/Constants/ExrCompression.cs

@ -1,9 +1,12 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
namespace SixLabors.ImageSharp.Formats.Exr.Constants;
internal enum ExrCompressionType
/// <summary>
/// Enumeration representing the compression formats defined by the EXR file-format.
/// </summary>
public enum ExrCompression
{
/// <summary>
/// Pixel data is not compressed.

43
src/ImageSharp/Formats/Exr/ExrBaseCompressor.cs

@ -0,0 +1,43 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Exr.Constants;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
internal abstract class ExrBaseCompressor : ExrBaseCompression
{
/// <summary>
/// Initializes a new instance of the <see cref="ExrBaseCompressor"/> class.
/// </summary>
/// <param name="output">The output stream to write the compressed image to.</param>
/// <param name="allocator">The memory allocator.</param>
/// <param name="bytesPerBlock">Bytes per block.</param>
protected ExrBaseCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock)
: base(allocator, bytesPerBlock)
=> this.Output = output;
/// <summary>
/// Gets the compression method to use.
/// </summary>
public abstract ExrCompression Method { get; }
/// <summary>
/// Gets the output stream to write the compressed image to.
/// </summary>
public Stream Output { get; }
/// <summary>
/// Does any initialization required for the compression.
/// </summary>
/// <param name="rowsPerStrip">The number of rows per strip.</param>
public abstract void Initialize(int rowsPerStrip);
/// <summary>
/// Compresses a strip of the image.
/// </summary>
/// <param name="rows">Image rows to compress.</param>
/// <param name="height">Image height.</param>
public abstract void CompressStrip(Span<byte> rows, int height);
}

26
src/ImageSharp/Formats/Exr/ExrDecoderCore.cs

@ -79,7 +79,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <summary>
/// Gets or sets the compression method.
/// </summary>
private ExrCompressionType Compression { get; set; }
private ExrCompression Compression { get; set; }
/// <summary>
/// Gets or sets the image data type, either RGB, RGBA or gray.
@ -453,7 +453,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
IList<ExrChannelInfo> channels = null;
ExrBox2i? dataWindow = null;
ExrCompressionType? compression = null;
ExrCompression? compression = null;
ExrBox2i? displayWindow = null;
ExrLineOrder? lineOrder = null;
float? aspectRatio = null;
@ -471,7 +471,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
channels = this.ReadChannelList(stream, attribute.Length);
break;
case ExrConstants.AttributeNames.Compression:
compression = (ExrCompressionType)stream.ReadByte();
compression = (ExrCompression)stream.ReadByte();
break;
case ExrConstants.AttributeNames.DataWindow:
dataWindow = this.ReadBoxInteger(stream);
@ -648,11 +648,11 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
{
switch (this.Compression)
{
case ExrCompressionType.None:
case ExrCompressionType.Zip:
case ExrCompressionType.Zips:
case ExrCompressionType.RunLengthEncoded:
case ExrCompressionType.B44:
case ExrCompression.None:
case ExrCompression.Zip:
case ExrCompression.Zips:
case ExrCompression.RunLengthEncoded:
case ExrCompression.B44:
return true;
}
@ -757,12 +757,12 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
{
switch (this.Compression)
{
case ExrCompressionType.Zip:
case ExrCompressionType.Pxr24:
case ExrCompression.Zip:
case ExrCompression.Pxr24:
return 16;
case ExrCompressionType.B44:
case ExrCompressionType.B44A:
case ExrCompressionType.Piz:
case ExrCompression.B44:
case ExrCompression.B44A:
case ExrCompression.Piz:
return 32;
default:

5
src/ImageSharp/Formats/Exr/ExrEncoder.cs

@ -15,6 +15,11 @@ public sealed class ExrEncoder : ImageEncoder
/// </summary>
public ExrPixelType? PixelType { get; set; }
/// <summary>
/// Gets the compression type to use.
/// </summary>
public ExrCompression? Compression { get; init; }
/// <inheritdoc />
protected override void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{

5
src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

@ -6,7 +6,6 @@ using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Channels;
using SixLabors.ImageSharp.Formats.Exr.Compression;
using SixLabors.ImageSharp.Formats.Exr.Constants;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -77,7 +76,7 @@ internal sealed class ExrEncoderCore
this.pixelType ??= exrMetadata.PixelType;
int width = image.Width;
int height = image.Height;
ExrCompressionType compression = ExrCompressionType.None;
ExrCompression compression = ExrCompression.None;
float aspectRatio = 1.0f;
ExrBox2i dataWindow = new(0, 0, width - 1, height - 1);
ExrBox2i displayWindow = new(0, 0, width - 1, height - 1);
@ -311,7 +310,7 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0);
}
private void WriteCompression(Stream stream, ExrCompressionType compression)
private void WriteCompression(Stream stream, ExrCompression compression)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Compression, ExrConstants.AttibuteTypes.Compression, 1);
stream.WriteByte((byte)compression);

5
src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Exr.Compression;
using SixLabors.ImageSharp.Formats.Exr.Constants;
namespace SixLabors.ImageSharp.Formats.Exr;
@ -10,7 +9,7 @@ internal class ExrHeaderAttributes
{
public ExrHeaderAttributes(
IList<ExrChannelInfo> channels,
ExrCompressionType compression,
ExrCompression compression,
ExrBox2i dataWindow,
ExrBox2i displayWindow,
ExrLineOrder lineOrder,
@ -36,7 +35,7 @@ internal class ExrHeaderAttributes
public IList<ExrChannelInfo> Channels { get; set; }
public ExrCompressionType Compression { get; set; }
public ExrCompression Compression { get; set; }
public ExrBox2i DataWindow { get; set; }

11
src/ImageSharp/Formats/Exr/ExrThrowHelper.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
namespace SixLabors.ImageSharp.Formats.Exr;
/// <summary>
@ -8,15 +10,24 @@ namespace SixLabors.ImageSharp.Formats.Exr;
/// </summary>
internal static class ExrThrowHelper
{
[DoesNotReturn]
public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}");
[DoesNotReturn]
public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage);
[DoesNotReturn]
public static void ThrowNotSupportedVersion() => throw new NotSupportedException("Unsupported EXR version");
[DoesNotReturn]
public static void ThrowNotSupported(string msg) => throw new NotSupportedException(msg);
[DoesNotReturn]
public static void ThrowInvalidImageHeader() => throw new InvalidImageContentException("Invalid EXR image header");
[DoesNotReturn]
public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg);
[DoesNotReturn]
public static Exception NotSupportedCompressor(string compressionType) => throw new NotSupportedException($"Not supported encoder compression method: {compressionType}");
}

Loading…
Cancel
Save