@@ -33,7 +33,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
3333
3434 Span < byte > flag = stackalloc byte [ PngConstants . HeaderBytes . Length ] ;
3535
36- List < ( Image < TPixel > Image , bool IsPng , int Index ) > decodedEntries = new ( this . Entries . Length ) ;
36+ List < ( Image < TPixel > Image , IconFrameCompression Compression , int Index ) > decodedEntries = new ( this . Entries . Length ) ;
3737
3838 for ( int i = 0 ; i < this . Entries . Length ; i ++ )
3939 {
@@ -58,18 +58,18 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
5858
5959 // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
6060 Image < TPixel > temp = this . GetDecoder ( isPng ) . Decode < TPixel > ( stream , cancellationToken ) ;
61- decodedEntries . Add ( ( temp , isPng , i ) ) ;
61+ decodedEntries . Add ( ( temp , isPng ? IconFrameCompression . Png : IconFrameCompression . Bmp , i ) ) ;
6262
6363 // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
6464 // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
6565 this . Dimensions = new ( Math . Max ( this . Dimensions . Width , temp . Size . Width ) , Math . Max ( this . Dimensions . Height , temp . Size . Height ) ) ;
6666 }
6767
6868 ImageMetadata metadata = new ( ) ;
69- BmpMetadata ? bmpMetadata = null ;
7069 PngMetadata ? pngMetadata = null ;
7170 Image < TPixel > result = new ( this . Options . Configuration , metadata , decodedEntries . Select ( x =>
7271 {
72+ BmpBitsPerPixel bitsPerPixel = default ;
7373 ImageFrame < TPixel > target = new ( this . Options . Configuration , this . Dimensions ) ;
7474 ImageFrame < TPixel > source = x . Image . Frames . RootFrameUnsafe ;
7575 for ( int y = 0 ; y < source . Height ; y ++ )
@@ -78,7 +78,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
7878 }
7979
8080 // Copy the format specific frame metadata to the image.
81- if ( x . IsPng )
81+ if ( x . Compression is IconFrameCompression . Png )
8282 {
8383 if ( x . Index == 0 )
8484 {
@@ -88,24 +88,19 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
8888 // Bmp does not contain frame specific metadata.
8989 target . Metadata . SetFormatMetadata ( PngFormat . Instance , target . Metadata . GetPngFrameMetadata ( ) ) ;
9090 }
91- else if ( x . Index == 0 )
91+ else
9292 {
93- bmpMetadata = x . Image . Metadata . GetBmpMetadata ( ) ;
93+ bitsPerPixel = x . Image . Metadata . GetBmpMetadata ( ) . BitsPerPixel ;
9494 }
9595
96- this . SetFrameMetadata ( target . Metadata , this . Entries [ x . Index ] ) ;
96+ this . SetFrameMetadata ( target . Metadata , this . Entries [ x . Index ] , x . Compression , bitsPerPixel ) ;
9797
9898 x . Image . Dispose ( ) ;
9999
100100 return target ;
101101 } ) . ToArray ( ) ) ;
102102
103103 // Copy the format specific metadata to the image.
104- if ( bmpMetadata != null )
105- {
106- result . Metadata . SetFormatMetadata ( BmpFormat . Instance , bmpMetadata ) ;
107- }
108-
109104 if ( pngMetadata != null )
110105 {
111106 result . Metadata . SetFormatMetadata ( PngFormat . Instance , pngMetadata ) ;
@@ -116,23 +111,56 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
116111
117112 public ImageInfo Identify ( BufferedReadStream stream , CancellationToken cancellationToken )
118113 {
114+ // Stream may not at 0.
115+ long basePosition = stream . Position ;
119116 this . ReadHeader ( stream ) ;
120117
118+ Span < byte > flag = stackalloc byte [ PngConstants . HeaderBytes . Length ] ;
119+
121120 ImageMetadata metadata = new ( ) ;
122121 ImageFrameMetadata [ ] frames = new ImageFrameMetadata [ this . FileHeader . Count ] ;
123122 for ( int i = 0 ; i < frames . Length ; i ++ )
124123 {
125- // TODO: Use the Identify methods in each decoder to return the
126- // format specific metadata for the image and frame.
124+ BmpBitsPerPixel bitsPerPixel = default ;
125+ ref IconDirEntry entry = ref this . Entries [ i ] ;
126+
127+ // If we hit the end of the stream we should break.
128+ if ( stream . Seek ( basePosition + entry . ImageOffset , SeekOrigin . Begin ) >= stream . Length )
129+ {
130+ break ;
131+ }
132+
133+ // There should always be enough bytes for this regardless of the entry type.
134+ if ( stream . Read ( flag ) != PngConstants . HeaderBytes . Length )
135+ {
136+ break ;
137+ }
138+
139+ // Reset the stream position.
140+ stream . Seek ( - PngConstants . HeaderBytes . Length , SeekOrigin . Current ) ;
141+
142+ bool isPng = flag . SequenceEqual ( PngConstants . HeaderBytes ) ;
143+
144+ // Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
145+ ImageInfo temp = this . GetDecoder ( isPng ) . Identify ( stream , cancellationToken ) ;
146+
127147 frames [ i ] = new ( ) ;
128- this . SetFrameMetadata ( frames [ i ] , this . Entries [ i ] ) ;
148+ if ( isPng )
149+ {
150+ bitsPerPixel = temp . Metadata . GetBmpMetadata ( ) . BitsPerPixel ;
151+ }
152+
153+ this . SetFrameMetadata ( frames [ i ] , this . Entries [ i ] , isPng ? IconFrameCompression . Png : IconFrameCompression . Bmp , bitsPerPixel ) ;
154+
155+ // Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
156+ // which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
157+ this . Dimensions = new ( Math . Max ( this . Dimensions . Width , temp . Size . Width ) , Math . Max ( this . Dimensions . Height , temp . Size . Height ) ) ;
129158 }
130159
131- // TODO: Use real values from the metadata.
132- return new ( new ( 32 ) , new ( 0 ) , metadata , frames ) ;
160+ return new ( new ( 32 ) , this . Dimensions , metadata , frames ) ;
133161 }
134162
135- protected abstract void SetFrameMetadata ( ImageFrameMetadata metadata , in IconDirEntry entry ) ;
163+ protected abstract void SetFrameMetadata ( ImageFrameMetadata metadata , in IconDirEntry entry , IconFrameCompression compression , BmpBitsPerPixel bitsPerPixel ) ;
136164
137165 protected void ReadHeader ( Stream stream )
138166 {
0 commit comments