@@ -32,7 +32,8 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
3232 this . ReadHeader ( stream ) ;
3333
3434 Span < byte > flag = stackalloc byte [ PngConstants . HeaderBytes . Length ] ;
35- Image < TPixel > result = new ( this . Dimensions . Width , this . Dimensions . Height ) ;
35+
36+ List < ( Image < TPixel > Image , bool IsPng , int Index ) > decodedEntries = new ( this . Entries . Length ) ;
3637
3738 for ( int i = 0 ; i < this . Entries . Length ; i ++ )
3839 {
@@ -54,37 +55,62 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
5455 stream . Seek ( - PngConstants . HeaderBytes . Length , SeekOrigin . Current ) ;
5556
5657 bool isPng = flag . SequenceEqual ( PngConstants . HeaderBytes ) ;
57- using Image < TPixel > temp = this . GetDecoder ( isPng ) . Decode < TPixel > ( stream , cancellationToken ) ;
5858
59- ImageFrame < TPixel > source = temp . Frames . RootFrameUnsafe ;
60- ImageFrame < TPixel > target = i == 0 ? result . Frames . RootFrameUnsafe : result . Frames . CreateFrame ( ) ;
59+ // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
60+ Image < TPixel > temp = this . GetDecoder ( isPng ) . Decode < TPixel > ( stream , cancellationToken ) ;
61+ decodedEntries . Add ( ( temp , isPng , i ) ) ;
62+
63+ // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
64+ // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
65+ this . Dimensions = new ( Math . Max ( this . Dimensions . Width , temp . Size . Width ) , Math . Max ( this . Dimensions . Height , temp . Size . Height ) ) ;
66+ }
6167
62- // Draw the new frame at position 0,0. We capture the dimensions for cropping during encoding
63- // via the icon entry.
64- for ( int h = 0 ; h < source . Height ; h ++ )
68+ ImageMetadata metadata = new ( ) ;
69+ BmpMetadata ? bmpMetadata = null ;
70+ PngMetadata ? pngMetadata = null ;
71+ Image < TPixel > result = new ( this . Options . Configuration , metadata , decodedEntries . Select ( x =>
72+ {
73+ ImageFrame < TPixel > target = new ( this . Options . Configuration , this . Dimensions ) ;
74+ ImageFrame < TPixel > source = x . Image . Frames . RootFrameUnsafe ;
75+ for ( int y = 0 ; y < source . Height ; y ++ )
6576 {
66- source . PixelBuffer . DangerousGetRowSpan ( h ) . CopyTo ( target . PixelBuffer . DangerousGetRowSpan ( h ) ) ;
77+ source . PixelBuffer . DangerousGetRowSpan ( y ) . CopyTo ( target . PixelBuffer . DangerousGetRowSpan ( y ) ) ;
6778 }
6879
69- // Copy the format specific metadata to the image.
70- if ( isPng )
80+ // Copy the format specific frame metadata to the image.
81+ if ( x . IsPng )
7182 {
72- if ( i == 0 )
83+ if ( x . Index == 0 )
7384 {
74- result . Metadata . SetFormatMetadata ( PngFormat . Instance , temp . Metadata . GetPngMetadata ( ) ) ;
85+ pngMetadata = x . Image . Metadata . GetPngMetadata ( ) ;
7586 }
7687
88+ // Bmp does not contain frame specific metadata.
7789 target . Metadata . SetFormatMetadata ( PngFormat . Instance , target . Metadata . GetPngFrameMetadata ( ) ) ;
7890 }
79- else if ( i == 0 )
91+ else if ( x . Index == 0 )
8092 {
81- // Bmp does not contain frame specific metadata.
82- result . Metadata . SetFormatMetadata ( BmpFormat . Instance , temp . Metadata . GetBmpMetadata ( ) ) ;
93+ bmpMetadata = x . Image . Metadata . GetBmpMetadata ( ) ;
8394 }
8495
8596 // TODO: The inheriting decoder should be responsible for setting the actual data (FromIconDirEntry)
8697 // so we can avoid the protected Field1 and Field2 properties and use strong typing.
87- this . GetFrameMetadata ( target . Metadata ) . FromIconDirEntry ( entry ) ;
98+ this . GetFrameMetadata ( target . Metadata ) . FromIconDirEntry ( this . Entries [ x . Index ] ) ;
99+
100+ x . Image . Dispose ( ) ;
101+
102+ return target ;
103+ } ) . ToArray ( ) ) ;
104+
105+ // Copy the format specific metadata to the image.
106+ if ( bmpMetadata != null )
107+ {
108+ result . Metadata . SetFormatMetadata ( BmpFormat . Instance , bmpMetadata ) ;
109+ }
110+
111+ if ( pngMetadata != null )
112+ {
113+ result . Metadata . SetFormatMetadata ( PngFormat . Instance , pngMetadata ) ;
88114 }
89115
90116 return result ;
@@ -125,6 +151,8 @@ protected void ReadHeader(Stream stream)
125151 int height = 0 ;
126152 foreach ( IconDirEntry entry in this . Entries )
127153 {
154+ // Since Windows 95 size of an image in the ICONDIRENTRY structure might
155+ // be set to zero, which means 256 pixels.
128156 if ( entry . Width == 0 )
129157 {
130158 width = 256 ;
0 commit comments