6

This is an ObjectiveC method that generates GIF image:

@implementation NSArray (GIFImage)

- (NSString*)GIFImageWithImageDuration:(CGFloat)GIFImageDuration
{
    NSArray *images = self;

    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"animated.gif"];
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path],
                                                                        kUTTypeGIF,
                                                                        images.count,
                                                                        NULL);

    NSDictionary *frameProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:GIFImageDuration]
                                                                                                   forKey:(NSString *)kCGImagePropertyGIFDelayTime]
                                                                forKey:(NSString *)kCGImagePropertyGIFDictionary];


    NSDictionary *gifProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCGImagePropertyGIFLoopCount]
                                                              forKey:(NSString *)kCGImagePropertyGIFDictionary];

    for ( NSInteger index = 0; index < images.count; index++ )
    {
        UIImage *image = (UIImage *)[images objectAtIndex:index];
        CGImageDestinationAddImage(destination, image.CGImage, (CFDictionaryRef)frameProperties);
    }

    CGImageDestinationSetProperties(destination, (CFDictionaryRef)gifProperties);
    CGImageDestinationFinalize(destination);
    CFRelease(destination);
    NSLog(@"animated GIF file created at %@", path);
    return path;
}

@end

Running this method on iOS9 works fine, GIF generated loops forever on browsers:

enter image description here

Running the same method on iOS10 fails, GIF generated no longer loops forever on browsers, it only play once:

enter image description here

Besides, inspired by this answer: https://stackoverflow.com/a/38082881/448662, I did a hex comparison of the two GIFs generated in both iOS9 and iOS10, it appears that a segment (Netscape application extension) is missing in the iOS10 generated GIF, this could be the reason why it doesn't loop, but I can't be sure.

In short, how can we generate GIF image (using ObjectiveC) that loops forever on browser?

enter image description here

Community
  • 1
  • 1
mkto
  • 4,584
  • 5
  • 41
  • 65
  • As far as I know it all depends on the imageview animationRepeat attribute. – Teja Nandamuri Oct 28 '16 at 17:53
  • I need the generated GIF to loop correctly on browser (image generated on iOS will be uploaded to server and then rendered on website). Edited my question to clarify this. – mkto Oct 28 '16 at 18:02
  • @mkto Missing the `NETSCAPE` extension command is the problem. If you can add an **application extension** chunk before first frame with your API (sorry do not code on IOS so I do not know if possible) then just do it. If not either use another encoder lib or inject the chunk on yourself (preferably in memory) all the stuff you need to code it you got in my answer that you linked (in the sub-links is also the C++ code to find the correct place for it). – Spektre Sep 13 '17 at 10:34

1 Answers1

4

I found the solution on a recent commit on this GitHub repo: https://github.com/NSRare/NSGIF/pull/23/files?diff=split

Basically, calling CGImageDestinationSetProperties before CGImageDestinationAddImage solves the problem on iOS10.

This is the working code:

@implementation NSArray (GIFImage)
- (NSString*)GIFImageWithImageDuration:(CGFloat)GIFImageDuration
{
    NSArray *images = self;

    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"animated.gif"];
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path],
                                                                        kUTTypeGIF,
                                                                        images.count,
                                                                        NULL);

    NSDictionary *frameProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:GIFImageDuration]
                                                                                                   forKey:(NSString *)kCGImagePropertyGIFDelayTime]
                                                                forKey:(NSString *)kCGImagePropertyGIFDictionary];


    NSDictionary *gifProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCGImagePropertyGIFLoopCount]
                                                              forKey:(NSString *)kCGImagePropertyGIFDictionary];

    CGImageDestinationSetProperties(destination, (CFDictionaryRef)gifProperties);

    for ( NSInteger index = 0; index < images.count; index++ )
    {
        UIImage *image = (UIImage *)[images objectAtIndex:index];
        CGImageDestinationAddImage(destination, image.CGImage, (CFDictionaryRef)frameProperties);
    }

    CGImageDestinationFinalize(destination);
    CFRelease(destination);
    NSLog(@"animated GIF file created at %@", path);
    return path;
}
mkto
  • 4,584
  • 5
  • 41
  • 65