Browse Source

Remove per-pixel transform

pull/3028/head
James Jackson-South 9 months ago
parent
commit
bb93350bb5
  1. 4
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsPixelCompatible.cs
  2. 65
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  3. 162
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

4
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsPixelCompatible.cs

@ -47,7 +47,7 @@ internal static class ColorProfileConverterExtensionsPixelCompatible
throw new InvalidOperationException("Target ICC profile is missing."); throw new InvalidOperationException("Target ICC profile is missing.");
} }
// Process the rows in parallel chnks, the converter itself is thread safe. // Process the rows in parallel chunks, the converter itself is thread safe.
source.Mutate(o => o.ProcessPixelRowsAsVector4( source.Mutate(o => o.ProcessPixelRowsAsVector4(
row => row =>
{ {
@ -64,7 +64,7 @@ internal static class ColorProfileConverterExtensionsPixelCompatible
for (int i = 0; i < rgbSpan.Length; i++) for (int i = 0; i < rgbSpan.Length; i++)
{ {
Vector3 rgb = rgbSpan[i].AsVector3Unsafe(); Vector3 rgb = rgbSpan[i].AsVector3Unsafe();
Unsafe.As<Vector4, Vector3>(ref Unsafe.Add(ref rowRef, i)) = rgb; Unsafe.As<Vector4, Vector3>(ref Unsafe.Add(ref rowRef, (uint)i)) = rgb;
} }
}, },
PixelConversionModifiers.Scale)); PixelConversionModifiers.Scale));

65
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -230,12 +230,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
this.InitializeFrame(previousFrameControl, currentFrameControl.Value, image, previousFrame, out currentFrame); this.InitializeFrame(previousFrameControl, currentFrameControl.Value, image, previousFrame, out currentFrame);
if (!this.Options.TryGetIccProfileForColorConversion(metadata.IccProfile, out IccProfile? iccProfile))
{
// TODO: Rework this. We need to preserve metadata
// metadata.IccProfile = null;
}
this.currentStream.Position += 4; this.currentStream.Position += 4;
this.ReadScanlines( this.ReadScanlines(
chunk.Length - 4, chunk.Length - 4,
@ -243,7 +237,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
pngMetadata, pngMetadata,
this.ReadNextFrameDataChunk, this.ReadNextFrameDataChunk,
currentFrameControl.Value, currentFrameControl.Value,
iccProfile,
cancellationToken); cancellationToken);
// if current frame dispose is restore to previous, then from future frame's perspective, it never happened // if current frame dispose is restore to previous, then from future frame's perspective, it never happened
@ -268,19 +261,12 @@ internal sealed class PngDecoderCore : ImageDecoderCore
AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata);
} }
if (!this.Options.TryGetIccProfileForColorConversion(metadata.IccProfile, out IccProfile? iccProfile))
{
// TODO: Rework this. We need to preserve metadata
// metadata.IccProfile = null;
}
this.ReadScanlines( this.ReadScanlines(
chunk.Length, chunk.Length,
image.Frames.RootFrame, image.Frames.RootFrame,
pngMetadata, pngMetadata,
this.ReadNextDataChunk, this.ReadNextDataChunk,
currentFrameControl.Value, currentFrameControl.Value,
iccProfile,
cancellationToken); cancellationToken);
if (pngMetadata.AnimateRootFrame) if (pngMetadata.AnimateRootFrame)
{ {
@ -764,7 +750,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
/// <param name="pngMetadata">The png metadata</param> /// <param name="pngMetadata">The png metadata</param>
/// <param name="getData">A delegate to get more data from the inner stream for <see cref="ZlibInflateStream"/>.</param> /// <param name="getData">A delegate to get more data from the inner stream for <see cref="ZlibInflateStream"/>.</param>
/// <param name="frameControl">The frame control</param> /// <param name="frameControl">The frame control</param>
/// <param name="iccProfile">Optional ICC profile for color conversion.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
private void ReadScanlines<TPixel>( private void ReadScanlines<TPixel>(
int chunkLength, int chunkLength,
@ -772,7 +757,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
PngMetadata pngMetadata, PngMetadata pngMetadata,
Func<int> getData, Func<int> getData,
in FrameControl frameControl, in FrameControl frameControl,
IccProfile? iccProfile,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -786,11 +770,11 @@ internal sealed class PngDecoderCore : ImageDecoderCore
if (this.header.InterlaceMethod is PngInterlaceMode.Adam7) if (this.header.InterlaceMethod is PngInterlaceMode.Adam7)
{ {
this.DecodeInterlacedPixelData(frameControl, dataStream, image, pngMetadata, iccProfile, cancellationToken); this.DecodeInterlacedPixelData(frameControl, dataStream, image, pngMetadata, cancellationToken);
} }
else else
{ {
this.DecodePixelData(frameControl, dataStream, image, pngMetadata, iccProfile, cancellationToken); this.DecodePixelData(frameControl, dataStream, image, pngMetadata, cancellationToken);
} }
} }
@ -802,14 +786,12 @@ internal sealed class PngDecoderCore : ImageDecoderCore
/// <param name="compressedStream">The compressed pixel data stream.</param> /// <param name="compressedStream">The compressed pixel data stream.</param>
/// <param name="imageFrame">The image frame to decode to.</param> /// <param name="imageFrame">The image frame to decode to.</param>
/// <param name="pngMetadata">The png metadata</param> /// <param name="pngMetadata">The png metadata</param>
/// <param name="iccProfile">Optional ICC profile for color conversion.</param>
/// <param name="cancellationToken">The CancellationToken</param> /// <param name="cancellationToken">The CancellationToken</param>
private void DecodePixelData<TPixel>( private void DecodePixelData<TPixel>(
FrameControl frameControl, FrameControl frameControl,
DeflateStream compressedStream, DeflateStream compressedStream,
ImageFrame<TPixel> imageFrame, ImageFrame<TPixel> imageFrame,
PngMetadata pngMetadata, PngMetadata pngMetadata,
IccProfile? iccProfile,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -876,7 +858,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
break; break;
} }
this.ProcessDefilteredScanline(frameControl, currentRow, scanSpan, imageFrame, pngMetadata, blendRowBuffer, iccProfile); this.ProcessDefilteredScanline(frameControl, currentRow, scanSpan, imageFrame, pngMetadata, blendRowBuffer);
this.SwapScanlineBuffers(); this.SwapScanlineBuffers();
currentRow++; currentRow++;
} }
@ -894,14 +876,12 @@ internal sealed class PngDecoderCore : ImageDecoderCore
/// <param name="compressedStream">The compressed pixel data stream.</param> /// <param name="compressedStream">The compressed pixel data stream.</param>
/// <param name="imageFrame">The current image frame.</param> /// <param name="imageFrame">The current image frame.</param>
/// <param name="pngMetadata">The png metadata.</param> /// <param name="pngMetadata">The png metadata.</param>
/// <param name="iccProfile">Optional ICC profile for color conversion.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
private void DecodeInterlacedPixelData<TPixel>( private void DecodeInterlacedPixelData<TPixel>(
in FrameControl frameControl, in FrameControl frameControl,
DeflateStream compressedStream, DeflateStream compressedStream,
ImageFrame<TPixel> imageFrame, ImageFrame<TPixel> imageFrame,
PngMetadata pngMetadata, PngMetadata pngMetadata,
IccProfile? iccProfile,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -992,7 +972,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
rowSpan, rowSpan,
pngMetadata, pngMetadata,
blendRowBuffer, blendRowBuffer,
iccProfile,
pixelOffset: Adam7.FirstColumn[pass], pixelOffset: Adam7.FirstColumn[pass],
increment: Adam7.ColumnIncrement[pass]); increment: Adam7.ColumnIncrement[pass]);
@ -1031,15 +1010,13 @@ internal sealed class PngDecoderCore : ImageDecoderCore
/// <param name="pixels">The image</param> /// <param name="pixels">The image</param>
/// <param name="pngMetadata">The png metadata.</param> /// <param name="pngMetadata">The png metadata.</param>
/// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param> /// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param>
/// <param name="iccProfile">Optional ICC profile for color conversion.</param>
private void ProcessDefilteredScanline<TPixel>( private void ProcessDefilteredScanline<TPixel>(
in FrameControl frameControl, in FrameControl frameControl,
int currentRow, int currentRow,
ReadOnlySpan<byte> scanline, ReadOnlySpan<byte> scanline,
ImageFrame<TPixel> pixels, ImageFrame<TPixel> pixels,
PngMetadata pngMetadata, PngMetadata pngMetadata,
Span<TPixel> blendRowBuffer, Span<TPixel> blendRowBuffer)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
Span<TPixel> destination = pixels.PixelBuffer.DangerousGetRowSpan(currentRow); Span<TPixel> destination = pixels.PixelBuffer.DangerousGetRowSpan(currentRow);
@ -1073,8 +1050,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
in frameControl, in frameControl,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pngMetadata.TransparentColor, pngMetadata.TransparentColor);
iccProfile);
break; break;
@ -1085,8 +1061,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
(uint)this.bytesPerPixel, (uint)this.bytesPerPixel,
(uint)this.bytesPerSample, (uint)this.bytesPerSample);
iccProfile);
break; break;
@ -1095,8 +1070,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
in frameControl, in frameControl,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pngMetadata.ColorTable, pngMetadata.ColorTable);
iccProfile);
break; break;
@ -1109,8 +1083,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
rowSpan, rowSpan,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample, this.bytesPerSample,
pngMetadata.TransparentColor, pngMetadata.TransparentColor);
iccProfile);
break; break;
@ -1122,8 +1095,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample, this.bytesPerSample);
iccProfile);
break; break;
} }
@ -1134,8 +1106,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
PixelOperations<TPixel>.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); PixelOperations<TPixel>.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver);
blender.Blend<TPixel>(this.configuration, destination, destination, rowSpan, 1F); blender.Blend<TPixel>(this.configuration, destination, destination, rowSpan, 1F);
} }
// TODO: Here is where we would perform ICC color conversion if needed over the 'destination' span.
} }
finally finally
{ {
@ -1152,7 +1122,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
/// <param name="destination">The current image row.</param> /// <param name="destination">The current image row.</param>
/// <param name="pngMetadata">The png metadata.</param> /// <param name="pngMetadata">The png metadata.</param>
/// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param> /// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param>
/// <param name="iccProfile">Optional ICC profile for color conversion.</param>
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param> /// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
/// <param name="increment">The column increment. Always 1 for none interlaced images.</param> /// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
private void ProcessInterlacedDefilteredScanline<TPixel>( private void ProcessInterlacedDefilteredScanline<TPixel>(
@ -1161,7 +1130,6 @@ internal sealed class PngDecoderCore : ImageDecoderCore
Span<TPixel> destination, Span<TPixel> destination,
PngMetadata pngMetadata, PngMetadata pngMetadata,
Span<TPixel> blendRowBuffer, Span<TPixel> blendRowBuffer,
IccProfile? iccProfile,
int pixelOffset = 0, int pixelOffset = 0,
int increment = 1) int increment = 1)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -1196,8 +1164,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
rowSpan, rowSpan,
(uint)pixelOffset, (uint)pixelOffset,
(uint)increment, (uint)increment,
pngMetadata.TransparentColor, pngMetadata.TransparentColor);
iccProfile);
break; break;
@ -1210,8 +1177,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
(uint)pixelOffset, (uint)pixelOffset,
(uint)increment, (uint)increment,
(uint)this.bytesPerPixel, (uint)this.bytesPerPixel,
(uint)this.bytesPerSample, (uint)this.bytesPerSample);
iccProfile);
break; break;
@ -1222,8 +1188,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
rowSpan, rowSpan,
(uint)pixelOffset, (uint)pixelOffset,
(uint)increment, (uint)increment,
pngMetadata.ColorTable, pngMetadata.ColorTable);
iccProfile);
break; break;
@ -1238,8 +1203,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
(uint)increment, (uint)increment,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample, this.bytesPerSample,
pngMetadata.TransparentColor, pngMetadata.TransparentColor);
iccProfile);
break; break;
@ -1253,8 +1217,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore
(uint)pixelOffset, (uint)pixelOffset,
(uint)increment, (uint)increment,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample, this.bytesPerSample);
iccProfile);
break; break;
} }

162
src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

@ -1,15 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorProfiles;
using SixLabors.ImageSharp.ColorProfiles.Icc;
using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Png; namespace SixLabors.ImageSharp.Formats.Png;
@ -25,8 +20,7 @@ internal static class PngScanlineProcessor
in FrameControl frameControl, in FrameControl frameControl,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
Color? transparentColor, Color? transparentColor)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedGrayscaleScanline( ProcessInterlacedGrayscaleScanline(
bitDepth, bitDepth,
@ -35,8 +29,7 @@ internal static class PngScanlineProcessor
rowSpan, rowSpan,
0, 0,
1, 1,
transparentColor, transparentColor);
iccProfile);
public static void ProcessInterlacedGrayscaleScanline<TPixel>( public static void ProcessInterlacedGrayscaleScanline<TPixel>(
int bitDepth, int bitDepth,
@ -45,11 +38,9 @@ internal static class PngScanlineProcessor
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
uint pixelOffset, uint pixelOffset,
uint increment, uint increment,
Color? transparentColor, Color? transparentColor)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// FIXME-icc
uint offset = pixelOffset + frameControl.XOffset; uint offset = pixelOffset + frameControl.XOffset;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
@ -107,8 +98,7 @@ internal static class PngScanlineProcessor
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
uint bytesPerPixel, uint bytesPerPixel,
uint bytesPerSample, uint bytesPerSample)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedGrayscaleWithAlphaScanline( ProcessInterlacedGrayscaleWithAlphaScanline(
bitDepth, bitDepth,
@ -118,8 +108,7 @@ internal static class PngScanlineProcessor
0, 0,
1, 1,
bytesPerPixel, bytesPerPixel,
bytesPerSample, bytesPerSample);
iccProfile);
public static void ProcessInterlacedGrayscaleWithAlphaScanline<TPixel>( public static void ProcessInterlacedGrayscaleWithAlphaScanline<TPixel>(
int bitDepth, int bitDepth,
@ -129,11 +118,9 @@ internal static class PngScanlineProcessor
uint pixelOffset, uint pixelOffset,
uint increment, uint increment,
uint bytesPerPixel, uint bytesPerPixel,
uint bytesPerSample, uint bytesPerSample)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// FIXME-icc
uint offset = pixelOffset + frameControl.XOffset; uint offset = pixelOffset + frameControl.XOffset;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
@ -166,8 +153,7 @@ internal static class PngScanlineProcessor
in FrameControl frameControl, in FrameControl frameControl,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
ReadOnlyMemory<Color>? palette, ReadOnlyMemory<Color>? palette)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedPaletteScanline( ProcessInterlacedPaletteScanline(
frameControl, frameControl,
@ -175,8 +161,7 @@ internal static class PngScanlineProcessor
rowSpan, rowSpan,
0, 0,
1, 1,
palette, palette);
iccProfile);
public static void ProcessInterlacedPaletteScanline<TPixel>( public static void ProcessInterlacedPaletteScanline<TPixel>(
in FrameControl frameControl, in FrameControl frameControl,
@ -184,11 +169,9 @@ internal static class PngScanlineProcessor
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
uint pixelOffset, uint pixelOffset,
uint increment, uint increment,
ReadOnlyMemory<Color>? palette, ReadOnlyMemory<Color>? palette)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// FIXME-icc
if (palette is null) if (palette is null)
{ {
PngThrowHelper.ThrowMissingPalette(); PngThrowHelper.ThrowMissingPalette();
@ -215,8 +198,7 @@ internal static class PngScanlineProcessor
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample, int bytesPerSample,
Color? transparentColor, Color? transparentColor)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbScanline( ProcessInterlacedRgbScanline(
configuration, configuration,
@ -228,8 +210,7 @@ internal static class PngScanlineProcessor
1, 1,
bytesPerPixel, bytesPerPixel,
bytesPerSample, bytesPerSample,
transparentColor, transparentColor);
iccProfile);
public static void ProcessInterlacedRgbScanline<TPixel>( public static void ProcessInterlacedRgbScanline<TPixel>(
Configuration configuration, Configuration configuration,
@ -241,11 +222,9 @@ internal static class PngScanlineProcessor
uint increment, uint increment,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample, int bytesPerSample,
Color? transparentColor, Color? transparentColor)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// FIXME-icc
uint offset = pixelOffset + frameControl.XOffset; uint offset = pixelOffset + frameControl.XOffset;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
@ -323,8 +302,7 @@ internal static class PngScanlineProcessor
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample, int bytesPerSample)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> => where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbaScanline( ProcessInterlacedRgbaScanline(
configuration, configuration,
@ -335,8 +313,7 @@ internal static class PngScanlineProcessor
0, 0,
1, 1,
bytesPerPixel, bytesPerPixel,
bytesPerSample, bytesPerSample);
iccProfile);
public static void ProcessInterlacedRgbaScanline<TPixel>( public static void ProcessInterlacedRgbaScanline<TPixel>(
Configuration configuration, Configuration configuration,
@ -347,104 +324,43 @@ internal static class PngScanlineProcessor
uint pixelOffset, uint pixelOffset,
uint increment, uint increment,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample, int bytesPerSample)
IccProfile? iccProfile)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
uint offset = pixelOffset + frameControl.XOffset; uint offset = pixelOffset + frameControl.XOffset;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
if (iccProfile != null) if (bitDepth == 16)
{ {
ColorConversionOptions options = new() int o = 0;
{ for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
SourceIccProfile = iccProfile,
TargetIccProfile = CompactSrgbV4Profile.Profile,
MemoryAllocator = configuration.MemoryAllocator,
};
ColorProfileConverter converter = new(options);
using IMemoryOwner<Rgb> rgbBuffer = configuration.MemoryAllocator.Allocate<Rgb>((int)(frameControl.XMax - offset));
Span<Rgb> rgbPacked = rgbBuffer.Memory.Span;
ref Rgb rgbPackedRef = ref MemoryMarshal.GetReference(rgbPacked);
using IMemoryOwner<float> alphaBuffer = configuration.MemoryAllocator.Allocate<float>((int)(frameControl.XMax - offset));
Span<float> alphaPacked = alphaBuffer.Memory.Span;
ref float alphaPackedRef = ref MemoryMarshal.GetReference(alphaPacked);
if (bitDepth == 16)
{
int o = 0;
for (int i = 0; i < rgbPacked.Length; o += bytesPerPixel, i++)
{
ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample));
Unsafe.Add(ref rgbPackedRef, i) = new Rgb(r / (float)ushort.MaxValue, g / (float)ushort.MaxValue, b / (float)ushort.MaxValue);
Unsafe.Add(ref alphaPackedRef, i) = a / (float)ushort.MaxValue;
}
}
else
{
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
int o = 0;
for (int i = 0; i < rgbPacked.Length; o += bytesPerPixel, i++)
{
byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o);
byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
Unsafe.Add(ref rgbPackedRef, i) = new Rgb(r / (float)byte.MaxValue, g / (float)byte.MaxValue, b / (float)byte.MaxValue);
Unsafe.Add(ref alphaPackedRef, i) = a / (float)byte.MaxValue;
}
}
converter.Convert<Rgb, Rgb>(rgbPacked, rgbPacked);
int idx = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, idx++)
{ {
Rgb rgb = Unsafe.Add(ref rgbPackedRef, idx); ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
Vector4 rgba = rgb.ToScaledVector4(Unsafe.Add(ref alphaPackedRef, idx)); ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromScaledVector4(rgba); ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(new Rgba64(r, g, b, a));
} }
} }
else if (pixelOffset == 0 && increment == 1)
{
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
configuration,
scanlineSpan[..(int)(frameControl.Width * bytesPerPixel)],
rowSpan.Slice((int)frameControl.XOffset, (int)frameControl.Width),
(int)frameControl.Width);
}
else else
{ {
if (bitDepth == 16) ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
{ int o = 0;
int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(new Rgba64(r, g, b, a));
}
}
else if (pixelOffset == 0 && increment == 1)
{
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
configuration,
scanlineSpan[..(int)(frameControl.Width * bytesPerPixel)],
rowSpan.Slice((int)frameControl.XOffset, (int)frameControl.Width),
(int)frameControl.Width);
}
else
{ {
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o);
int o = 0; byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
{ byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o); Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(new Rgba32(r, g, b, a));
byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(new Rgba32(r, g, b, a));
}
} }
} }
} }

Loading…
Cancel
Save