@@ -172,6 +172,9 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
172172 /// <inheritdoc />
173173 public ImageInfo Identify ( BufferedReadStream stream , CancellationToken cancellationToken )
174174 {
175+ uint frameCount = 0 ;
176+ ImageFrameMetadata ? previousFrame = null ;
177+ List < ImageFrameMetadata > framesMetadata = new ( ) ;
175178 try
176179 {
177180 this . ReadLogicalScreenDescriptorAndGlobalColorTable ( stream ) ;
@@ -182,14 +185,23 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
182185 {
183186 if ( nextFlag == GifConstants . ImageLabel )
184187 {
185- this . ReadImageDescriptor ( stream ) ;
188+ if ( previousFrame != null && ++ frameCount == this . maxFrames )
189+ {
190+ break ;
191+ }
192+
193+ this . ReadFrameMetadata ( stream , framesMetadata , ref previousFrame ) ;
194+
195+ // Reset per-frame state.
196+ this . imageDescriptor = default ;
197+ this . graphicsControlExtension = default ;
186198 }
187199 else if ( nextFlag == GifConstants . ExtensionIntroducer )
188200 {
189201 switch ( stream . ReadByte ( ) )
190202 {
191203 case GifConstants . GraphicControlLabel :
192- SkipBlock ( stream ) ; // Skip graphic control extension block
204+ this . ReadGraphicalControlExtension ( stream ) ;
193205 break ;
194206 case GifConstants . CommentLabel :
195207 this . ReadComments ( stream ) ;
@@ -226,9 +238,9 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
226238
227239 return new ImageInfo (
228240 new PixelTypeInfo ( this . logicalScreenDescriptor . BitsPerPixel ) ,
229- this . logicalScreenDescriptor . Width ,
230- this . logicalScreenDescriptor . Height ,
231- this . metadata ) ;
241+ new ( this . logicalScreenDescriptor . Width , this . logicalScreenDescriptor . Height ) ,
242+ this . metadata ,
243+ framesMetadata ) ;
232244 }
233245
234246 /// <summary>
@@ -486,7 +498,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel>? image, ref ImageFrame<TP
486498 image = new Image < TPixel > ( this . configuration , imageWidth , imageHeight , this . metadata ) ;
487499 }
488500
489- this . SetFrameMetadata ( image . Frames . RootFrame . Metadata , true ) ;
501+ this . SetFrameMetadata ( image . Frames . RootFrame . Metadata ) ;
490502
491503 imageFrame = image . Frames . RootFrame ;
492504 }
@@ -499,7 +511,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel>? image, ref ImageFrame<TP
499511
500512 currentFrame = image ! . Frames . CreateFrame ( ) ;
501513
502- this . SetFrameMetadata ( currentFrame . Metadata , false ) ;
514+ this . SetFrameMetadata ( currentFrame . Metadata ) ;
503515
504516 imageFrame = currentFrame ;
505517
@@ -606,6 +618,37 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel>? image, ref ImageFrame<TP
606618 }
607619 }
608620
621+ /// <summary>
622+ /// Reads the frames metadata.
623+ /// </summary>
624+ /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
625+ /// <param name="frameMetadata">The collection of frame metadata.</param>
626+ /// <param name="previousFrame">The previous frame metadata.</param>
627+ private void ReadFrameMetadata ( BufferedReadStream stream , List < ImageFrameMetadata > frameMetadata , ref ImageFrameMetadata ? previousFrame )
628+ {
629+ this . ReadImageDescriptor ( stream ) ;
630+
631+ // Skip the color table for this frame if local.
632+ if ( this . imageDescriptor . LocalColorTableFlag )
633+ {
634+ stream . Skip ( this . imageDescriptor . LocalColorTableSize * 3 ) ;
635+ }
636+
637+ // Skip the frame indices. Pixels length + mincode size.
638+ // The gif format does not tell us the length of the compressed data beforehand.
639+ int minCodeSize = stream . ReadByte ( ) ;
640+ using LzwDecoder lzwDecoder = new ( this . configuration . MemoryAllocator , stream ) ;
641+ lzwDecoder . SkipIndices ( minCodeSize , this . imageDescriptor . Width * this . imageDescriptor . Height ) ;
642+
643+ ImageFrameMetadata currentFrame = new ( ) ;
644+ frameMetadata . Add ( currentFrame ) ;
645+ this . SetFrameMetadata ( currentFrame ) ;
646+ previousFrame = currentFrame ;
647+
648+ // Skip any remaining blocks
649+ SkipBlock ( stream ) ;
650+ }
651+
609652 /// <summary>
610653 /// Restores the current frame area to the background.
611654 /// </summary>
@@ -627,34 +670,33 @@ private void RestoreToBackground<TPixel>(ImageFrame<TPixel> frame)
627670 }
628671
629672 /// <summary>
630- /// Sets the frames metadata.
673+ /// Sets the metadata for the image frame .
631674 /// </summary>
632- /// <param name="meta">The metadata.</param>
633- /// <param name="isRoot">Whether the metadata represents the root frame.</param>
675+ /// <param name="metadata">The metadata.</param>
634676 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
635- private void SetFrameMetadata ( ImageFrameMetadata meta , bool isRoot )
677+ private void SetFrameMetadata ( ImageFrameMetadata metadata )
636678 {
637679 // Frames can either use the global table or their own local table.
638- if ( isRoot && this . logicalScreenDescriptor . GlobalColorTableFlag
680+ if ( this . logicalScreenDescriptor . GlobalColorTableFlag
639681 && this . logicalScreenDescriptor . GlobalColorTableSize > 0 )
640682 {
641- GifFrameMetadata gifMeta = meta . GetGifMetadata ( ) ;
683+ GifFrameMetadata gifMeta = metadata . GetGifMetadata ( ) ;
642684 gifMeta . ColorTableMode = GifColorTableMode . Global ;
643685 gifMeta . ColorTableLength = this . logicalScreenDescriptor . GlobalColorTableSize ;
644686 }
645687
646688 if ( this . imageDescriptor . LocalColorTableFlag
647689 && this . imageDescriptor . LocalColorTableSize > 0 )
648690 {
649- GifFrameMetadata gifMeta = meta . GetGifMetadata ( ) ;
691+ GifFrameMetadata gifMeta = metadata . GetGifMetadata ( ) ;
650692 gifMeta . ColorTableMode = GifColorTableMode . Local ;
651693 gifMeta . ColorTableLength = this . imageDescriptor . LocalColorTableSize ;
652694 }
653695
654696 // Graphics control extensions is optional.
655697 if ( this . graphicsControlExtension != default )
656698 {
657- GifFrameMetadata gifMeta = meta . GetGifMetadata ( ) ;
699+ GifFrameMetadata gifMeta = metadata . GetGifMetadata ( ) ;
658700 gifMeta . FrameDelay = this . graphicsControlExtension . DelayTime ;
659701 gifMeta . DisposalMethod = this . graphicsControlExtension . DisposalMethod ;
660702 }
0 commit comments