diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a426208944..dce94b5cec 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -671,7 +671,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// A delegate to get more data from the inner stream for . /// The frame control /// The cancellation token. - private void ReadScanlines(int chunkLength, ImageFrame image, PngMetadata pngMetadata, Func getData, FrameControl frameControl, CancellationToken cancellationToken) + private void ReadScanlines(int chunkLength, ImageFrame image, PngMetadata pngMetadata, Func getData, in FrameControl frameControl, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { using ZlibInflateStream deframeStream = new(this.currentStream, getData); @@ -763,7 +763,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The current image. /// The png metadata. /// The cancellation token. - private void DecodeInterlacedPixelData(FrameControl frameControl, DeflateStream compressedStream, ImageFrame image, PngMetadata pngMetadata, CancellationToken cancellationToken) + private void DecodeInterlacedPixelData(in FrameControl frameControl, DeflateStream compressedStream, ImageFrame image, PngMetadata pngMetadata, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int currentRow = Adam7.FirstRow[0] + frameControl.YOffset; @@ -864,7 +864,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The de-filtered scanline /// The image /// The png metadata. - private void ProcessDefilteredScanline(FrameControl frameControl, int currentRow, ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetadata pngMetadata) + private void ProcessDefilteredScanline(in FrameControl frameControl, int currentRow, ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetadata pngMetadata) where TPixel : unmanaged, IPixel { Span rowSpan = pixels.PixelBuffer.DangerousGetRowSpan(currentRow); @@ -961,7 +961,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The png metadata. /// The column start index. Always 0 for none interlaced images. /// The column increment. Always 1 for none interlaced images. - private void ProcessInterlacedDefilteredScanline(FrameControl frameControl, ReadOnlySpan defilteredScanline, Span rowSpan, PngMetadata pngMetadata, int pixelOffset = 0, int increment = 1) + private void ProcessInterlacedDefilteredScanline(in FrameControl frameControl, ReadOnlySpan defilteredScanline, Span rowSpan, PngMetadata pngMetadata, int pixelOffset = 0, int increment = 1) where TPixel : unmanaged, IPixel { // Trim the first marker byte from the buffer diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 67a1f7c82d..85fc2b120e 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -17,7 +17,7 @@ internal static class PngScanlineProcessor { public static void ProcessGrayscaleScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, bool hasTrans, @@ -37,7 +37,7 @@ internal static class PngScanlineProcessor public static void ProcessInterlacedGrayscaleScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint pixelOffset, @@ -110,7 +110,7 @@ internal static class PngScanlineProcessor public static void ProcessGrayscaleWithAlphaScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint bytesPerPixel, @@ -128,7 +128,7 @@ internal static class PngScanlineProcessor public static void ProcessInterlacedGrayscaleWithAlphaScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint pixelOffset, @@ -172,7 +172,7 @@ internal static class PngScanlineProcessor } public static void ProcessPaletteScanline( - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, ReadOnlySpan palette, @@ -188,7 +188,7 @@ internal static class PngScanlineProcessor paletteAlpha); public static void ProcessInterlacedPaletteScanline( - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint pixelOffset, @@ -240,7 +240,7 @@ internal static class PngScanlineProcessor public static void ProcessRgbScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, int bytesPerPixel, @@ -248,84 +248,23 @@ internal static class PngScanlineProcessor bool hasTrans, Rgb48 rgb48Trans, Rgb24 rgb24Trans) - where TPixel : unmanaged, IPixel - { - uint offset = (uint)frameControl.XOffset; - TPixel pixel = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - - if (bitDepth == 16) - { - if (!hasTrans) - { - Rgb48 rgb48 = default; - int o = 0; - for (nuint x = offset; x < frameControl.XLimit; x++, o += bytesPerPixel) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - pixel.FromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgb48 rgb48 = default; - Rgba64 rgba64 = default; - int o = 0; - for (nuint x = offset; x < frameControl.XLimit; x++, o += bytesPerPixel) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - - return; - } - - if (hasTrans) - { - Rgba32 rgba32 = default; - ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); - ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); - for (nuint x = offset; x < frameControl.XLimit; x++) - { - ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); - rgba32.Rgb = rgb24; - rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; - - pixel.FromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - ReadOnlySpan source = MemoryMarshal.Cast(scanlineSpan)[..frameControl.Width]; - ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(rowSpan); - - for (nuint i = offset; i < frameControl.XLimit; i++) - { - ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgb24(sp); - } - } - } + where TPixel : unmanaged, IPixel => + ProcessInterlacedRgbScanline( + bitDepth, + frameControl, + scanlineSpan, + rowSpan, + 0, + 1, + bytesPerPixel, + bytesPerSample, + hasTrans, + rgb48Trans, + rgb24Trans); public static void ProcessInterlacedRgbScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint pixelOffset, @@ -413,51 +352,25 @@ internal static class PngScanlineProcessor public static void ProcessRgbaScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, int bytesPerPixel, int bytesPerSample) - where TPixel : unmanaged, IPixel - { - uint offset = (uint)frameControl.XOffset; - TPixel pixel = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - - if (bitDepth == 16) - { - Rgba64 rgba64 = default; - int o = 0; - for (nuint x = offset; x < frameControl.XLimit; x++, o += bytesPerPixel) - { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - ReadOnlySpan source = MemoryMarshal.Cast(scanlineSpan)[..frameControl.Width]; - ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(rowSpan); - - for (nuint i = offset; i < frameControl.XLimit; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgba32(sp); - } - } - } + where TPixel : unmanaged, IPixel => + ProcessInterlacedRgbaScanline( + bitDepth, + frameControl, + scanlineSpan, + rowSpan, + 0, + 1, + bytesPerPixel, + bytesPerSample); public static void ProcessInterlacedRgbaScanline( int bitDepth, - FrameControl frameControl, + in FrameControl frameControl, ReadOnlySpan scanlineSpan, Span rowSpan, uint pixelOffset, @@ -468,7 +381,6 @@ internal static class PngScanlineProcessor { uint offset = pixelOffset + (uint)frameControl.XOffset; TPixel pixel = default; - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (bitDepth == 16) @@ -488,6 +400,7 @@ internal static class PngScanlineProcessor } else { + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); Rgba32 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XLimit; x += increment, o += bytesPerPixel)