user339946
user339946

Reputation: 6119

How to access animated GIF's frames

I have an animated GIF successfully loaded into an NSData or NSBitmapImageRep object. Reference for NSBitmapImageRep

I've figured how to return data like the number of frames in that gif using:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

However, I'm a bit confused as to how I can actually access that frame as its own object.

I think one of these two methods will help, but I'm not actually sure how they'll get the individual frame for me.

+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:

Any help appreciated. Thanks

Upvotes: 4

Views: 2671

Answers (3)

Heinrich Giesen
Heinrich Giesen

Reputation: 1835

I've figured how to return data like the number of frames in that gif using:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

However, I'm a bit confused as to how I can actually access that frame as its own object.

To have access to a special frame indexOfFrame ( 0 <= indexOfFrame < [frames intValue] ) you only need to set the NSImageCurrentFrame and you are done. There is no need to use CG-functions or make copies of frames. You can stay in the object oriented Cocoa world. A small example shows the duration of all GIF frames:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];
if( frames!=nil ){   // bitmapRep is a Gif imageRep
   for( NSUInteger i=0; i<[frames intValue]; i++ ){
      [bitmapRep setProperty:NSImageCurrentFrame
                   withValue:[NSNumber numberWithUnsignedInt:i] ];
       NSLog(@"%2d duration=%@",
                 i, [bitmapRep valueForProperty:NSImageCurrentFrameDuration] );
   }
}

Another example: write all frames of a GIF image as PNG files to the filesystem:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];
if( frames!=nil ){   // bitmapRep is a Gif imageRep
   for( NSUInteger i=0; i<[frames intValue]; i++ ){
      [bitmapRep setProperty:NSImageCurrentFrame
                   withValue:[NSNumber numberWithUnsignedInt:i] ];
       NSData *repData = [bitmapRep representationUsingType:NSPNGFileType
                                                 properties:nil];
       [repData writeToFile:
            [NSString stringWithFormat:@"/tmp/gif_%02d.png", i ] atomically:YES];
    }
}

Upvotes: 8

MoDJ
MoDJ

Reputation: 4425

If you want to have a look at some working source code for a GIF decoder for iOS (works for MacOSX too) then you can find it AVGIF89A2MvidResourceLoader.m at github. The approach is to use the ImageIO framework and call CGImageSourceCreateWithData() along with CGImageSourceCreateImageAtIndex() to get access to the Nth gif image in the file. But, there are some tricky details related to detecting if a transparent pixel appears in the GIF and how to write the results to a file to avoid running out of memory if the GIF is really long that might not be obvious.

Upvotes: 1

Peter Hosey
Peter Hosey

Reputation: 96333

I've figured how to return data like the number of frames in that gif using:

NSNumber *frames = [bitmapRep valueForProperty:@"NSImageFrameCount"];

However, I'm a bit confused as to how I can actually access that frame as its own object.

As far as I know, you can't—not from an NSBitmapImageRep.

Instead, create a CGImageSource from the GIF data, and use CGImageSourceCreateImageAtIndex to extract each frame (preferably as you need it).

Alternatively, you might try setting the NSImageCurrentFrame property. If you need a rep for each frame, make as many copies as there are frames (minus one, since you have the original), and set each rep's current frame to a different number. But I haven't tried that, so I'm not sure it will actually work.

Basically, NSBitmapImageRep's GIF support is weird, so you should just use CGImageSource.

I think one of these two methods will help, but I'm not actually sure how they'll get the individual frame for me.

+ representationOfImageRepsInArray:usingType:properties:
– representationUsingType:properties:

No, those methods are for serializing an image (or image rep). They're for writing data out, not reading it in. (Notice what constants those methods expect in their type parameters.)

Upvotes: 2

Related Questions