通过iOS创建和导出动画gif?

时间:2013-02-16 21:09:32

标签: ios objective-c swift core-graphics animated-gif

我在iOS应用程序中有一系列用户自定义图像,这些图像以简单的逐帧翻书风格进行动画制作。

我的问题是:有没有办法允许用户将动画导出为GIF动画?理想情况下,我想让他们通过电子邮件,社交分享(T / FB)或(最糟糕的情况......)将动画gif保存到他们的文档文件夹中,以便通过iTunes进行检索。

我知道如何将.png保存到照片库,我找到了一种将动画录制为QT文件(http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/)的方法,但我还没有找到一种方法来启动它普通的老动画GIF。我在Core Animation或其他地方遗漏了什么吗?是否有任何人可以推荐的方法,框架或资源?对不起,如果问题太笼统 - 努力找到一个起点。

3 个答案:

答案 0 :(得分:160)

您可以使用Image I / O框架(iOS SDK的一部分)创建动画GIF。您还需要包含MobileCoreServices框架,该框架定义了GIF类型常量。您需要将这些框架添加到目标中,并将其标题导入要创建动画GIF的文件中,如下所示:

#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

通过示例解释最容易。我将向您展示我用于在iPhone 5上制作此GIF的代码:

animated GIF created by the code shown

首先,这是一个辅助函数,它采用一个大小和一个角度,并以该角度返回红色磁盘的UIImage

static UIImage *frameImage(CGSize size, CGFloat radians) {
    UIGraphicsBeginImageContextWithOptions(size, YES, 1); {
        [[UIColor whiteColor] setFill];
        UIRectFill(CGRectInfinite);
        CGContextRef gc = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(gc, size.width / 2, size.height / 2);
        CGContextRotateCTM(gc, radians);
        CGContextTranslateCTM(gc, size.width / 4, 0);
        [[UIColor redColor] setFill];
        CGFloat w = size.width / 10;
        CGContextFillEllipseInRect(gc, CGRectMake(-w / 2, -w / 2, w, w));
    }
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

现在我们可以创建GIF了。首先,我们将为帧数定义一个常量,因为我们需要它两次:

static void makeAnimatedGif(void) {
    static NSUInteger const kFrameCount = 16;

我们需要一个属性字典来指定动画重复的次数:

    NSDictionary *fileProperties = @{
        (__bridge id)kCGImagePropertyGIFDictionary: @{
            (__bridge id)kCGImagePropertyGIFLoopCount: @0, // 0 means loop forever
        }
    };

我们需要另一个属性字典,我们将附加到每个框架,指定该框架应显示多长时间:

    NSDictionary *frameProperties = @{
        (__bridge id)kCGImagePropertyGIFDictionary: @{
            (__bridge id)kCGImagePropertyGIFDelayTime: @0.02f, // a float (not double!) in seconds, rounded to centiseconds in the GIF data
        }
    };

我们还将在文档目录中为GIF创建一个URL:

    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
    NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"];

现在我们可以创建一个将GIF写入指定网址的CGImageDestination

    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, kFrameCount, NULL);
    CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);

我发现将fileProperties作为CGImageDestinationCreateWithURL的最后一个参数传递。您必须使用CGImageDestinationSetProperties

现在我们可以创建和编写我们的框架:

    for (NSUInteger i = 0; i < kFrameCount; i++) {
        @autoreleasepool {
            UIImage *image = frameImage(CGSizeMake(300, 300), M_PI * 2 * i / kFrameCount);
            CGImageDestinationAddImage(destination, image.CGImage, (__bridge CFDictionaryRef)frameProperties);
        }
    }

请注意,我们将帧属性字典与每个帧图像一起传递。

在我们准确添加了指定数量的帧后,我们最终确定了目标并将其释放:

    if (!CGImageDestinationFinalize(destination)) {
        NSLog(@"failed to finalize image destination");
    }
    CFRelease(destination);

    NSLog(@"url=%@", fileURL);
}

如果您在模拟器上运行此操作,则可以从调试控制台复制URL并将其粘贴到浏览器中以查看图像。如果您在设备上运行它,则可以使用Xcode Organizer窗口从设备下载应用程序沙箱并查看图像。或者您可以使用iExplorer这样的应用程序,让您直接浏览设备的文件系统。 (这不需要越狱。)

我在运行iOS 6.1的iPhone 5上测试了这个,但我相信代码应该可以像iOS 4.0一样工作。

我已将所有代码放在this gist中以便于复制。

答案 1 :(得分:0)

如果您正在寻找Swift 3解决方案,可以查看https://github.com/onmyway133/GifMagic。它有EncoderDecoder汇编和反汇编gif文件。

基本上,您应该将Image IO框架用于CGImageDestinationCreateWithURLCGImageDestinationSetPropertiesCGImageDestinationAddImageCGImageDestinationFinalize

这些功能

还有Swift https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html

  

从带注释的API返回的Core Foundation对象在Swift中自动进行内存管理 - 您不需要自己调用CFRetain,CFRelease或CFAutorelease函数。

答案 2 :(得分:0)

Swift 3

<header class="bg-ratio">
  <div>content in here</div>
</header>
<main>play full page and resize window's width</main>

我已将其从above answer转换而来。我希望它有所帮助。

gist提供。

欢迎编辑。