diff --git a/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs b/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs index 6773f3b631..44db67b618 100644 --- a/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs +++ b/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs @@ -132,8 +132,8 @@ internal sealed class ExrDecoderCore : ImageDecoderCore where TPixel : unmanaged, IPixel { bool hasAlpha = this.HasAlpha(); - uint bytesPerRow = this.CalculateBytesPerRow((uint)this.Width); - uint rowsPerBlock = this.RowsPerBlock(); + uint bytesPerRow = ExrUtils.CalculateBytesPerRow(this.Channels, (uint)this.Width); + uint rowsPerBlock = ExrUtils.RowsPerBlock(this.Compression); uint bytesPerBlock = bytesPerRow * rowsPerBlock; int width = this.Width; int height = this.Height; @@ -185,8 +185,8 @@ internal sealed class ExrDecoderCore : ImageDecoderCore where TPixel : unmanaged, IPixel { bool hasAlpha = this.HasAlpha(); - uint bytesPerRow = this.CalculateBytesPerRow((uint)this.Width); - uint rowsPerBlock = this.RowsPerBlock(); + uint bytesPerRow = ExrUtils.CalculateBytesPerRow(this.Channels, (uint)this.Width); + uint rowsPerBlock = ExrUtils.RowsPerBlock(this.Compression); uint bytesPerBlock = bytesPerRow * rowsPerBlock; int width = this.Width; int height = this.Height; @@ -728,48 +728,6 @@ internal sealed class ExrDecoderCore : ImageDecoderCore return false; } - private uint CalculateBytesPerRow(uint width) - { - uint bytesPerRow = 0; - foreach (ExrChannelInfo channelInfo in this.Channels) - { - if (channelInfo.ChannelName.Equals("A", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("R", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("G", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("B", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("Y", StringComparison.Ordinal)) - { - if (channelInfo.PixelType == ExrPixelType.Half) - { - bytesPerRow += 2 * width; - } - else - { - bytesPerRow += 4 * width; - } - } - } - - return bytesPerRow; - } - - private uint RowsPerBlock() - { - switch (this.Compression) - { - case ExrCompression.Zip: - case ExrCompression.Pxr24: - return 16; - case ExrCompression.B44: - case ExrCompression.B44A: - case ExrCompression.Piz: - return 32; - - default: - return 1; - } - } - private ulong ReadUnsignedLong(BufferedReadStream stream) { int bytesRead = stream.Read(this.buffer, 0, 8); diff --git a/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs b/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs index e393dcf686..2705a2057c 100644 --- a/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs +++ b/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs @@ -158,8 +158,8 @@ internal sealed class ExrEncoderCore ExrCompression compression) where TPixel : unmanaged, IPixel { - uint bytesPerRow = this.CalculateBytesPerRow(channels, (uint)width); - uint rowsPerBlock = this.RowsPerBlock(compression); + uint bytesPerRow = ExrUtils.CalculateBytesPerRow(channels, (uint)width); + uint rowsPerBlock = ExrUtils.RowsPerBlock(compression); uint bytesPerBlock = bytesPerRow * rowsPerBlock; int channelCount = channels.Count; @@ -234,8 +234,8 @@ internal sealed class ExrEncoderCore ExrCompression compression) where TPixel : unmanaged, IPixel { - uint bytesPerRow = this.CalculateBytesPerRow(channels, (uint)width); - uint rowsPerBlock = this.RowsPerBlock(compression); + uint bytesPerRow = ExrUtils.CalculateBytesPerRow(channels, (uint)width); + uint rowsPerBlock = ExrUtils.RowsPerBlock(compression); uint bytesPerBlock = bytesPerRow * rowsPerBlock; int channelCount = channels.Count; @@ -335,19 +335,19 @@ internal sealed class ExrEncoderCore int offset = 0; for (int x = 0; x < width; x++) { - this.WriteHalfSingle(buffer.Slice(offset), blueBuffer[x]); + WriteHalfSingle(buffer.Slice(offset), blueBuffer[x]); offset += 2; } for (int x = 0; x < width; x++) { - this.WriteHalfSingle(buffer.Slice(offset), greenBuffer[x]); + WriteHalfSingle(buffer.Slice(offset), greenBuffer[x]); offset += 2; } for (int x = 0; x < width; x++) { - this.WriteHalfSingle(buffer.Slice(offset), redBuffer[x]); + WriteHalfSingle(buffer.Slice(offset), redBuffer[x]); offset += 2; } } @@ -357,19 +357,19 @@ internal sealed class ExrEncoderCore int offset = 0; for (int x = 0; x < width; x++) { - this.WriteUnsignedInt(buffer.Slice(offset), blueBuffer[x]); + WriteUnsignedInt(buffer.Slice(offset), blueBuffer[x]); offset += 4; } for (int x = 0; x < width; x++) { - this.WriteUnsignedInt(buffer.Slice(offset), greenBuffer[x]); + WriteUnsignedInt(buffer.Slice(offset), greenBuffer[x]); offset += 4; } for (int x = 0; x < width; x++) { - this.WriteUnsignedInt(buffer.Slice(offset), redBuffer[x]); + WriteUnsignedInt(buffer.Slice(offset), redBuffer[x]); offset += 4; } } @@ -521,10 +521,10 @@ internal sealed class ExrEncoderCore private unsafe void WriteSingle(Span buffer, float value) => BinaryPrimitives.WriteInt32LittleEndian(buffer, *(int*)&value); [MethodImpl(InliningOptions.ShortMethod)] - private void WriteHalfSingle(Span buffer, float value) + private static void WriteHalfSingle(Span buffer, float value) { ushort valueAsShort = HalfTypeHelper.Pack(value); - BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, valueAsShort); + BinaryPrimitives.WriteUInt16LittleEndian(buffer, valueAsShort); } [MethodImpl(InliningOptions.ShortMethod)] @@ -535,49 +535,5 @@ internal sealed class ExrEncoderCore } [MethodImpl(InliningOptions.ShortMethod)] - private void WriteUnsignedInt(Span buffer, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(buffer, value); - - // TODO: avoid code duplication: This code is duplicate in the decoder. - private uint CalculateBytesPerRow(List channels, uint width) - { - uint bytesPerRow = 0; - foreach (ExrChannelInfo channelInfo in channels) - { - if (channelInfo.ChannelName.Equals("A", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("R", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("G", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("B", StringComparison.Ordinal) - || channelInfo.ChannelName.Equals("Y", StringComparison.Ordinal)) - { - if (channelInfo.PixelType == ExrPixelType.Half) - { - bytesPerRow += 2 * width; - } - else - { - bytesPerRow += 4 * width; - } - } - } - - return bytesPerRow; - } - - // TODO: avoid code duplication: This code is duplicate in the decoder. - private uint RowsPerBlock(ExrCompression compression) - { - switch (compression) - { - case ExrCompression.Zip: - case ExrCompression.Pxr24: - return 16; - case ExrCompression.B44: - case ExrCompression.B44A: - case ExrCompression.Piz: - return 32; - - default: - return 1; - } - } + private static void WriteUnsignedInt(Span buffer, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(buffer, value); } diff --git a/src/ImageSharp/Formats/Exr/ExrUtils.cs b/src/ImageSharp/Formats/Exr/ExrUtils.cs new file mode 100644 index 0000000000..4d172c6ef8 --- /dev/null +++ b/src/ImageSharp/Formats/Exr/ExrUtils.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Exr.Constants; + +namespace SixLabors.ImageSharp.Formats.Exr; + +internal static class ExrUtils +{ + public static uint CalculateBytesPerRow(IList channels, uint width) + { + uint bytesPerRow = 0; + foreach (ExrChannelInfo channelInfo in channels) + { + if (channelInfo.ChannelName.Equals("A", StringComparison.Ordinal) + || channelInfo.ChannelName.Equals("R", StringComparison.Ordinal) + || channelInfo.ChannelName.Equals("G", StringComparison.Ordinal) + || channelInfo.ChannelName.Equals("B", StringComparison.Ordinal) + || channelInfo.ChannelName.Equals("Y", StringComparison.Ordinal)) + { + if (channelInfo.PixelType == ExrPixelType.Half) + { + bytesPerRow += 2 * width; + } + else + { + bytesPerRow += 4 * width; + } + } + } + + return bytesPerRow; + } + + public static uint RowsPerBlock(ExrCompression compression) => compression switch + { + ExrCompression.Zip or ExrCompression.Pxr24 => 16, + ExrCompression.B44 or ExrCompression.B44A or ExrCompression.Piz => 32, + _ => 1, + }; +}