@@ -216,6 +216,7 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
216216 currentFrameControl = this . ReadFrameControlChunk ( chunk . Data . GetSpan ( ) ) ;
217217 break ;
218218 case PngChunkType . FrameData :
219+ {
219220 if ( frameCount >= this . maxFrames )
220221 {
221222 goto EOF ;
@@ -233,13 +234,19 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
233234
234235 this . InitializeFrame ( previousFrameControl , currentFrameControl . Value , image , previousFrame , out currentFrame ) ;
235236
237+ if ( this . Options . TryGetIccProfileForColorConversion ( metadata . IccProfile , out IccProfile ? iccProfile ) )
238+ {
239+ metadata . IccProfile = null ;
240+ }
241+
236242 this . currentStream . Position += 4 ;
237243 this . ReadScanlines (
238244 chunk . Length - 4 ,
239245 currentFrame ,
240246 pngMetadata ,
241247 this . ReadNextFrameDataChunk ,
242248 currentFrameControl . Value ,
249+ iccProfile ,
243250 cancellationToken ) ;
244251
245252 // if current frame dispose is restore to previous, then from future frame's perspective, it never happened
@@ -250,7 +257,10 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
250257 }
251258
252259 break ;
260+ }
261+
253262 case PngChunkType . Data :
263+ {
254264 pngMetadata . AnimateRootFrame = currentFrameControl != null ;
255265 currentFrameControl ??= new FrameControl ( ( uint ) this . header . Width , ( uint ) this . header . Height ) ;
256266 if ( image is null )
@@ -261,12 +271,18 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
261271 AssignColorPalette ( this . palette , this . paletteAlpha , pngMetadata ) ;
262272 }
263273
274+ if ( this . Options . TryGetIccProfileForColorConversion ( metadata . IccProfile , out IccProfile ? iccProfile ) )
275+ {
276+ metadata . IccProfile = null ;
277+ }
278+
264279 this . ReadScanlines (
265280 chunk . Length ,
266281 image . Frames . RootFrame ,
267282 pngMetadata ,
268283 this . ReadNextDataChunk ,
269284 currentFrameControl . Value ,
285+ iccProfile ,
270286 cancellationToken ) ;
271287 if ( pngMetadata . AnimateRootFrame )
272288 {
@@ -280,6 +296,8 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
280296 }
281297
282298 break ;
299+ }
300+
283301 case PngChunkType . Palette :
284302 this . palette = chunk . Data . GetSpan ( ) . ToArray ( ) ;
285303 break ;
@@ -327,9 +345,9 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
327345 PngThrowHelper . ThrowNoData ( ) ;
328346 }
329347
330- if ( this . Options . TryGetIccProfileForColorConversion ( metadata . IccProfile , out IccProfile ? iccProfile ) )
348+ if ( this . Options . TryGetIccProfileForColorConversion ( metadata . IccProfile , out IccProfile ? iccProfileToApply ) )
331349 {
332- ApplyRgbaCompatibleIccProfile ( image , iccProfile , CompactSrgbV4Profile . Profile ) ;
350+ ApplyRgbaCompatibleIccProfile ( image , iccProfileToApply , CompactSrgbV4Profile . Profile ) ;
333351 }
334352
335353 return image ;
@@ -752,13 +770,15 @@ private int CalculateScanlineLength(int width)
752770 /// <param name="pngMetadata">The png metadata</param>
753771 /// <param name="getData">A delegate to get more data from the inner stream for <see cref="ZlibInflateStream"/>.</param>
754772 /// <param name="frameControl">The frame control</param>
773+ /// <param name="iccProfile">Optional ICC profile for color conversion.</param>
755774 /// <param name="cancellationToken">The cancellation token.</param>
756775 private void ReadScanlines < TPixel > (
757776 int chunkLength ,
758777 ImageFrame < TPixel > image ,
759778 PngMetadata pngMetadata ,
760779 Func < int > getData ,
761780 in FrameControl frameControl ,
781+ IccProfile ? iccProfile ,
762782 CancellationToken cancellationToken )
763783 where TPixel : unmanaged, IPixel < TPixel >
764784 {
@@ -772,11 +792,11 @@ private void ReadScanlines<TPixel>(
772792
773793 if ( this . header . InterlaceMethod is PngInterlaceMode . Adam7 )
774794 {
775- this . DecodeInterlacedPixelData ( frameControl , dataStream , image , pngMetadata , cancellationToken ) ;
795+ this . DecodeInterlacedPixelData ( frameControl , dataStream , image , pngMetadata , iccProfile , cancellationToken ) ;
776796 }
777797 else
778798 {
779- this . DecodePixelData ( frameControl , dataStream , image , pngMetadata , cancellationToken ) ;
799+ this . DecodePixelData ( frameControl , dataStream , image , pngMetadata , iccProfile , cancellationToken ) ;
780800 }
781801 }
782802
@@ -788,12 +808,14 @@ private void ReadScanlines<TPixel>(
788808 /// <param name="compressedStream">The compressed pixel data stream.</param>
789809 /// <param name="imageFrame">The image frame to decode to.</param>
790810 /// <param name="pngMetadata">The png metadata</param>
811+ /// <param name="iccProfile">Optional ICC profile for color conversion.</param>
791812 /// <param name="cancellationToken">The CancellationToken</param>
792813 private void DecodePixelData < TPixel > (
793814 FrameControl frameControl ,
794815 DeflateStream compressedStream ,
795816 ImageFrame < TPixel > imageFrame ,
796817 PngMetadata pngMetadata ,
818+ IccProfile ? iccProfile ,
797819 CancellationToken cancellationToken )
798820 where TPixel : unmanaged, IPixel < TPixel >
799821 {
@@ -860,7 +882,7 @@ private void DecodePixelData<TPixel>(
860882 break ;
861883 }
862884
863- this . ProcessDefilteredScanline ( frameControl , currentRow , scanSpan , imageFrame , pngMetadata , blendRowBuffer ) ;
885+ this . ProcessDefilteredScanline ( frameControl , currentRow , scanSpan , imageFrame , pngMetadata , blendRowBuffer , iccProfile ) ;
864886 this . SwapScanlineBuffers ( ) ;
865887 currentRow ++ ;
866888 }
@@ -878,12 +900,14 @@ private void DecodePixelData<TPixel>(
878900 /// <param name="compressedStream">The compressed pixel data stream.</param>
879901 /// <param name="imageFrame">The current image frame.</param>
880902 /// <param name="pngMetadata">The png metadata.</param>
903+ /// <param name="iccProfile">Optional ICC profile for color conversion.</param>
881904 /// <param name="cancellationToken">The cancellation token.</param>
882905 private void DecodeInterlacedPixelData < TPixel > (
883906 in FrameControl frameControl ,
884907 DeflateStream compressedStream ,
885908 ImageFrame < TPixel > imageFrame ,
886909 PngMetadata pngMetadata ,
910+ IccProfile ? iccProfile ,
887911 CancellationToken cancellationToken )
888912 where TPixel : unmanaged, IPixel < TPixel >
889913 {
@@ -974,6 +998,7 @@ private void DecodeInterlacedPixelData<TPixel>(
974998 rowSpan ,
975999 pngMetadata ,
9761000 blendRowBuffer ,
1001+ iccProfile ,
9771002 pixelOffset : Adam7 . FirstColumn [ pass ] ,
9781003 increment : Adam7 . ColumnIncrement [ pass ] ) ;
9791004
@@ -1012,13 +1037,15 @@ private void DecodeInterlacedPixelData<TPixel>(
10121037 /// <param name="pixels">The image</param>
10131038 /// <param name="pngMetadata">The png metadata.</param>
10141039 /// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param>
1040+ /// <param name="iccProfile">Optional ICC profile for color conversion.</param>
10151041 private void ProcessDefilteredScanline < TPixel > (
10161042 in FrameControl frameControl ,
10171043 int currentRow ,
10181044 ReadOnlySpan < byte > scanline ,
10191045 ImageFrame < TPixel > pixels ,
10201046 PngMetadata pngMetadata ,
1021- Span < TPixel > blendRowBuffer )
1047+ Span < TPixel > blendRowBuffer ,
1048+ IccProfile ? iccProfile )
10221049 where TPixel : unmanaged, IPixel < TPixel >
10231050 {
10241051 Span < TPixel > destination = pixels . PixelBuffer . DangerousGetRowSpan ( currentRow ) ;
@@ -1052,7 +1079,8 @@ private void ProcessDefilteredScanline<TPixel>(
10521079 in frameControl ,
10531080 scanlineSpan ,
10541081 rowSpan ,
1055- pngMetadata . TransparentColor ) ;
1082+ pngMetadata . TransparentColor ,
1083+ iccProfile ) ;
10561084
10571085 break ;
10581086
@@ -1063,7 +1091,8 @@ private void ProcessDefilteredScanline<TPixel>(
10631091 scanlineSpan ,
10641092 rowSpan ,
10651093 ( uint ) this . bytesPerPixel ,
1066- ( uint ) this . bytesPerSample ) ;
1094+ ( uint ) this . bytesPerSample ,
1095+ iccProfile ) ;
10671096
10681097 break ;
10691098
@@ -1072,7 +1101,8 @@ private void ProcessDefilteredScanline<TPixel>(
10721101 in frameControl ,
10731102 scanlineSpan ,
10741103 rowSpan ,
1075- pngMetadata . ColorTable ) ;
1104+ pngMetadata . ColorTable ,
1105+ iccProfile ) ;
10761106
10771107 break ;
10781108
@@ -1085,7 +1115,8 @@ private void ProcessDefilteredScanline<TPixel>(
10851115 rowSpan ,
10861116 this . bytesPerPixel ,
10871117 this . bytesPerSample ,
1088- pngMetadata . TransparentColor ) ;
1118+ pngMetadata . TransparentColor ,
1119+ iccProfile ) ;
10891120
10901121 break ;
10911122
@@ -1097,7 +1128,8 @@ private void ProcessDefilteredScanline<TPixel>(
10971128 scanlineSpan ,
10981129 rowSpan ,
10991130 this . bytesPerPixel ,
1100- this . bytesPerSample ) ;
1131+ this . bytesPerSample ,
1132+ iccProfile ) ;
11011133
11021134 break ;
11031135 }
@@ -1124,6 +1156,7 @@ private void ProcessDefilteredScanline<TPixel>(
11241156 /// <param name="destination">The current image row.</param>
11251157 /// <param name="pngMetadata">The png metadata.</param>
11261158 /// <param name="blendRowBuffer">A span used to temporarily hold the decoded row pixel data for alpha blending.</param>
1159+ /// <param name="iccProfile">Optional ICC profile for color conversion.</param>
11271160 /// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
11281161 /// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
11291162 private void ProcessInterlacedDefilteredScanline < TPixel > (
@@ -1132,6 +1165,7 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
11321165 Span < TPixel > destination ,
11331166 PngMetadata pngMetadata ,
11341167 Span < TPixel > blendRowBuffer ,
1168+ IccProfile ? iccProfile ,
11351169 int pixelOffset = 0 ,
11361170 int increment = 1 )
11371171 where TPixel : unmanaged, IPixel < TPixel >
@@ -1166,7 +1200,8 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
11661200 rowSpan ,
11671201 ( uint ) pixelOffset ,
11681202 ( uint ) increment ,
1169- pngMetadata . TransparentColor ) ;
1203+ pngMetadata . TransparentColor ,
1204+ iccProfile ) ;
11701205
11711206 break ;
11721207
@@ -1179,7 +1214,8 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
11791214 ( uint ) pixelOffset ,
11801215 ( uint ) increment ,
11811216 ( uint ) this . bytesPerPixel ,
1182- ( uint ) this . bytesPerSample ) ;
1217+ ( uint ) this . bytesPerSample ,
1218+ iccProfile ) ;
11831219
11841220 break ;
11851221
@@ -1190,7 +1226,8 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
11901226 rowSpan ,
11911227 ( uint ) pixelOffset ,
11921228 ( uint ) increment ,
1193- pngMetadata . ColorTable ) ;
1229+ pngMetadata . ColorTable ,
1230+ iccProfile ) ;
11941231
11951232 break ;
11961233
@@ -1205,7 +1242,8 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
12051242 ( uint ) increment ,
12061243 this . bytesPerPixel ,
12071244 this . bytesPerSample ,
1208- pngMetadata . TransparentColor ) ;
1245+ pngMetadata . TransparentColor ,
1246+ iccProfile ) ;
12091247
12101248 break ;
12111249
@@ -1219,7 +1257,8 @@ private void ProcessInterlacedDefilteredScanline<TPixel>(
12191257 ( uint ) pixelOffset ,
12201258 ( uint ) increment ,
12211259 this . bytesPerPixel ,
1222- this . bytesPerSample ) ;
1260+ this . bytesPerSample ,
1261+ iccProfile ) ;
12231262
12241263 break ;
12251264 }
0 commit comments