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

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

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

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

最佳答案

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

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

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

首先,这是一个辅助函数,它接受一个大小和一个角度,并返回该角度的红色圆盘的 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"];

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

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

我发现将 fileProperties 作为 CGImageDestinationCreateWithURL 的最后一个参数传递 not 工作。您必须使用 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便于复制。

https://stackoverflow.com/questions/14915138/

相关文章:

iphone - 实现 copyWithZone : 时的最佳实践

ios - 是否可以调试 "Terminated due to memory error"?

objective-c - 在 Objective-C 中从字符串中删除空格

ios - 如何为 NSDate 添加一个月?

objective-c - 整数总是初始化为0吗?

ios - 如何关闭 Storyboard 弹出框

ios - 在主线程上调用方法?

iphone - iOS 7 UIRefreshControl tintColor 不适用于 beg

iphone - 你需要在 GCD 的一个 block 中创建一个 NSAutoreleasePoo

objective-c - @interface 和 @protocol 解释?