|
|
@ -216,6 +216,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
currentFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); |
|
|
currentFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); |
|
|
break; |
|
|
break; |
|
|
case PngChunkType.FrameData: |
|
|
case PngChunkType.FrameData: |
|
|
|
|
|
{ |
|
|
if (frameCount >= this.maxFrames) |
|
|
if (frameCount >= this.maxFrames) |
|
|
{ |
|
|
{ |
|
|
goto EOF; |
|
|
goto EOF; |
|
|
@ -233,6 +234,11 @@ 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)) |
|
|
|
|
|
{ |
|
|
|
|
|
metadata.IccProfile = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.currentStream.Position += 4; |
|
|
this.currentStream.Position += 4; |
|
|
this.ReadScanlines( |
|
|
this.ReadScanlines( |
|
|
chunk.Length - 4, |
|
|
chunk.Length - 4, |
|
|
@ -240,6 +246,7 @@ 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
|
|
|
@ -250,7 +257,10 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case PngChunkType.Data: |
|
|
case PngChunkType.Data: |
|
|
|
|
|
{ |
|
|
pngMetadata.AnimateRootFrame = currentFrameControl != null; |
|
|
pngMetadata.AnimateRootFrame = currentFrameControl != null; |
|
|
currentFrameControl ??= new FrameControl((uint)this.header.Width, (uint)this.header.Height); |
|
|
currentFrameControl ??= new FrameControl((uint)this.header.Width, (uint)this.header.Height); |
|
|
if (image is null) |
|
|
if (image is null) |
|
|
@ -261,12 +271,18 @@ 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)) |
|
|
|
|
|
{ |
|
|
|
|
|
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) |
|
|
{ |
|
|
{ |
|
|
@ -280,6 +296,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case PngChunkType.Palette: |
|
|
case PngChunkType.Palette: |
|
|
this.palette = chunk.Data.GetSpan().ToArray(); |
|
|
this.palette = chunk.Data.GetSpan().ToArray(); |
|
|
break; |
|
|
break; |
|
|
@ -327,9 +345,9 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
PngThrowHelper.ThrowNoData(); |
|
|
PngThrowHelper.ThrowNoData(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (this.Options.TryGetIccProfileForColorConversion(metadata.IccProfile, out IccProfile? iccProfile)) |
|
|
if (this.Options.TryGetIccProfileForColorConversion(metadata.IccProfile, out IccProfile? iccProfileToApply)) |
|
|
{ |
|
|
{ |
|
|
ApplyRgbaCompatibleIccProfile(image, iccProfile, CompactSrgbV4Profile.Profile); |
|
|
ApplyRgbaCompatibleIccProfile(image, iccProfileToApply, CompactSrgbV4Profile.Profile); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return image; |
|
|
return image; |
|
|
@ -752,6 +770,7 @@ 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, |
|
|
@ -759,6 +778,7 @@ 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> |
|
|
{ |
|
|
{ |
|
|
@ -772,11 +792,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, cancellationToken); |
|
|
this.DecodeInterlacedPixelData(frameControl, dataStream, image, pngMetadata, iccProfile, cancellationToken); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
this.DecodePixelData(frameControl, dataStream, image, pngMetadata, cancellationToken); |
|
|
this.DecodePixelData(frameControl, dataStream, image, pngMetadata, iccProfile, cancellationToken); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -788,12 +808,14 @@ 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> |
|
|
{ |
|
|
{ |
|
|
@ -860,7 +882,7 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.ProcessDefilteredScanline(frameControl, currentRow, scanSpan, imageFrame, pngMetadata, blendRowBuffer); |
|
|
this.ProcessDefilteredScanline(frameControl, currentRow, scanSpan, imageFrame, pngMetadata, blendRowBuffer, iccProfile); |
|
|
this.SwapScanlineBuffers(); |
|
|
this.SwapScanlineBuffers(); |
|
|
currentRow++; |
|
|
currentRow++; |
|
|
} |
|
|
} |
|
|
@ -878,12 +900,14 @@ 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> |
|
|
{ |
|
|
{ |
|
|
@ -974,6 +998,7 @@ 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]); |
|
|
|
|
|
|
|
|
@ -1012,13 +1037,15 @@ 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); |
|
|
@ -1052,7 +1079,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
in frameControl, |
|
|
in frameControl, |
|
|
scanlineSpan, |
|
|
scanlineSpan, |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
pngMetadata.TransparentColor); |
|
|
pngMetadata.TransparentColor, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1063,7 +1091,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
scanlineSpan, |
|
|
scanlineSpan, |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
(uint)this.bytesPerPixel, |
|
|
(uint)this.bytesPerPixel, |
|
|
(uint)this.bytesPerSample); |
|
|
(uint)this.bytesPerSample, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1072,7 +1101,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
in frameControl, |
|
|
in frameControl, |
|
|
scanlineSpan, |
|
|
scanlineSpan, |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
pngMetadata.ColorTable); |
|
|
pngMetadata.ColorTable, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1085,7 +1115,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerSample, |
|
|
this.bytesPerSample, |
|
|
pngMetadata.TransparentColor); |
|
|
pngMetadata.TransparentColor, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1097,7 +1128,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
scanlineSpan, |
|
|
scanlineSpan, |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerSample); |
|
|
this.bytesPerSample, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
@ -1124,6 +1156,7 @@ 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>( |
|
|
@ -1132,6 +1165,7 @@ 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> |
|
|
@ -1166,7 +1200,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
(uint)pixelOffset, |
|
|
(uint)pixelOffset, |
|
|
(uint)increment, |
|
|
(uint)increment, |
|
|
pngMetadata.TransparentColor); |
|
|
pngMetadata.TransparentColor, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1179,7 +1214,8 @@ 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; |
|
|
|
|
|
|
|
|
@ -1190,7 +1226,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
rowSpan, |
|
|
rowSpan, |
|
|
(uint)pixelOffset, |
|
|
(uint)pixelOffset, |
|
|
(uint)increment, |
|
|
(uint)increment, |
|
|
pngMetadata.ColorTable); |
|
|
pngMetadata.ColorTable, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1205,7 +1242,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
(uint)increment, |
|
|
(uint)increment, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerSample, |
|
|
this.bytesPerSample, |
|
|
pngMetadata.TransparentColor); |
|
|
pngMetadata.TransparentColor, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@ -1219,7 +1257,8 @@ internal sealed class PngDecoderCore : ImageDecoderCore |
|
|
(uint)pixelOffset, |
|
|
(uint)pixelOffset, |
|
|
(uint)increment, |
|
|
(uint)increment, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerPixel, |
|
|
this.bytesPerSample); |
|
|
this.bytesPerSample, |
|
|
|
|
|
iccProfile); |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|