@@ -31,10 +31,16 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
3131
3232 Span < byte > flag = stackalloc byte [ PngConstants . HeaderBytes . Length ] ;
3333
34- List < ( Image < TPixel > Image , IconFrameCompression Compression , int Index ) > decodedEntries = new ( this . entries . Length ) ;
34+ List < ( Image < TPixel > Image , IconFrameCompression Compression , int Index ) > decodedEntries
35+ = new ( ( int ) Math . Min ( this . entries . Length , this . Options . MaxFrames ) ) ;
3536
3637 for ( int i = 0 ; i < this . entries . Length ; i ++ )
3738 {
39+ if ( i == this . Options . MaxFrames )
40+ {
41+ break ;
42+ }
43+
3844 ref IconDirEntry entry = ref this . entries [ i ] ;
3945
4046 // If we hit the end of the stream we should break.
@@ -69,6 +75,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
6975 Image < TPixel > result = new ( this . Options . Configuration , metadata , decodedEntries . Select ( x =>
7076 {
7177 BmpBitsPerPixel bitsPerPixel = BmpBitsPerPixel . Pixel32 ;
78+ ReadOnlyMemory < Color > ? colorTable = null ;
7279 ImageFrame < TPixel > target = new ( this . Options . Configuration , this . Dimensions ) ;
7380 ImageFrame < TPixel > source = x . Image . Frames . RootFrameUnsafe ;
7481 for ( int y = 0 ; y < source . Height ; y ++ )
@@ -88,11 +95,22 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
8895 }
8996 else
9097 {
91- bmpMetadata = x . Image . Metadata . GetBmpMetadata ( ) ;
92- bitsPerPixel = bmpMetadata . BitsPerPixel ;
98+ BmpMetadata meta = x . Image . Metadata . GetBmpMetadata ( ) ;
99+ bitsPerPixel = meta . BitsPerPixel ;
100+ colorTable = meta . ColorTable ;
101+
102+ if ( x . Index == 0 )
103+ {
104+ bmpMetadata = meta ;
105+ }
93106 }
94107
95- this . SetFrameMetadata ( target . Metadata , this . entries [ x . Index ] , x . Compression , bitsPerPixel ) ;
108+ this . SetFrameMetadata (
109+ target . Metadata ,
110+ this . entries [ x . Index ] ,
111+ x . Compression ,
112+ bitsPerPixel ,
113+ colorTable ) ;
96114
97115 x . Image . Dispose ( ) ;
98116
@@ -122,11 +140,14 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
122140 Span < byte > flag = stackalloc byte [ PngConstants . HeaderBytes . Length ] ;
123141
124142 ImageMetadata metadata = new ( ) ;
125- ImageFrameMetadata [ ] frames = new ImageFrameMetadata [ this . fileHeader . Count ] ;
143+ BmpMetadata ? bmpMetadata = null ;
144+ PngMetadata ? pngMetadata = null ;
145+ ImageFrameMetadata [ ] frames = new ImageFrameMetadata [ Math . Min ( this . fileHeader . Count , this . Options . MaxFrames ) ] ;
126146 int bpp = 0 ;
127147 for ( int i = 0 ; i < frames . Length ; i ++ )
128148 {
129149 BmpBitsPerPixel bitsPerPixel = BmpBitsPerPixel . Pixel32 ;
150+ ReadOnlyMemory < Color > ? colorTable = null ;
130151 ref IconDirEntry entry = ref this . entries [ i ] ;
131152
132153 // If we hit the end of the stream we should break.
@@ -149,25 +170,65 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
149170 // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
150171 ImageInfo temp = this . GetDecoder ( isPng ) . Identify ( stream , cancellationToken ) ;
151172
152- frames [ i ] = new ( ) ;
153- if ( ! isPng )
173+ ImageFrameMetadata frameMetadata = new ( ) ;
174+
175+ if ( isPng )
176+ {
177+ if ( i == 0 )
178+ {
179+ pngMetadata = temp . Metadata . GetPngMetadata ( ) ;
180+ }
181+
182+ frameMetadata . SetFormatMetadata ( PngFormat . Instance , temp . FrameMetadataCollection [ 0 ] . GetPngMetadata ( ) ) ;
183+ }
184+ else
154185 {
155- bitsPerPixel = temp . Metadata . GetBmpMetadata ( ) . BitsPerPixel ;
186+ BmpMetadata meta = temp . Metadata . GetBmpMetadata ( ) ;
187+ bitsPerPixel = meta . BitsPerPixel ;
188+ colorTable = meta . ColorTable ;
189+
190+ if ( i == 0 )
191+ {
192+ bmpMetadata = meta ;
193+ }
156194 }
157195
158196 bpp = Math . Max ( bpp , ( int ) bitsPerPixel ) ;
159197
160- this . SetFrameMetadata ( frames [ i ] , this . entries [ i ] , isPng ? IconFrameCompression . Png : IconFrameCompression . Bmp , bitsPerPixel ) ;
198+ frames [ i ] = frameMetadata ;
199+
200+ this . SetFrameMetadata (
201+ frames [ i ] ,
202+ this . entries [ i ] ,
203+ isPng ? IconFrameCompression . Png : IconFrameCompression . Bmp ,
204+ bitsPerPixel ,
205+ colorTable ) ;
161206
162207 // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
163208 // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
164209 this . Dimensions = new ( Math . Max ( this . Dimensions . Width , temp . Size . Width ) , Math . Max ( this . Dimensions . Height , temp . Size . Height ) ) ;
165210 }
166211
212+ // Copy the format specific metadata to the image.
213+ if ( bmpMetadata != null )
214+ {
215+ metadata . SetFormatMetadata ( BmpFormat . Instance , bmpMetadata ) ;
216+ }
217+
218+ if ( pngMetadata != null )
219+ {
220+ metadata . SetFormatMetadata ( PngFormat . Instance , pngMetadata ) ;
221+ }
222+
167223 return new ( new ( bpp ) , this . Dimensions , metadata , frames ) ;
168224 }
169225
170- protected abstract void SetFrameMetadata ( ImageFrameMetadata metadata , in IconDirEntry entry , IconFrameCompression compression , BmpBitsPerPixel bitsPerPixel ) ;
226+ protected abstract void SetFrameMetadata (
227+ ImageFrameMetadata metadata ,
228+ in IconDirEntry entry ,
229+ IconFrameCompression compression ,
230+ BmpBitsPerPixel bitsPerPixel ,
231+ ReadOnlyMemory < Color > ? colorTable ) ;
171232
172233 [ MemberNotNull ( nameof ( entries ) ) ]
173234 protected void ReadHeader ( Stream stream )
0 commit comments