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

我有一个 iOS 应用程序内的一系列用户定制的图像,这些图像都是以一种简单的、一帧一帧的翻页书风格制作的。

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

我知道怎么救一个。我找到了一种将动画记录为 QT 文件(http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/)的方法,但是我还没有找到一种方法只是踢出一个普通的老式动画 gif。我是不是错过了什么核心动画或其他地方?是否有任何方法、框架或资源可供推荐?如果这个问题太笼统,我很抱歉——很难找到一个起点。

39925 次浏览

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

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

用例子来解释是最容易的。我将向您展示我在 iPhone 5上创建这个 GIF 的代码:

animated GIF created by the code shown

首先,这里有一个 helper 函数,它接受一个大小和一个角度,并返回红色磁盘在该角度的 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 写入指定 URL 的 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的 iPhone5上测试过,但我相信这段代码可以追溯到 iOS 4.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 函数。

对于 Swift 3

import Foundation
import UIKit
import ImageIO
import MobileCoreServices


extension UIImage {
static func animatedGif(from images: [UIImage]) {
let fileProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]  as CFDictionary
let frameProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [(kCGImagePropertyGIFDelayTime as String): 1.0]] as CFDictionary


let documentsDirectoryURL: URL? = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL: URL? = documentsDirectoryURL?.appendingPathComponent("animated.gif")


if let url = fileURL as CFURL? {
if let destination = CGImageDestinationCreateWithURL(url, kUTTypeGIF, images.count, nil) {
CGImageDestinationSetProperties(destination, fileProperties)
for image in images {
if let cgImage = image.cgImage {
CGImageDestinationAddImage(destination, cgImage, frameProperties)
}
}
if !CGImageDestinationFinalize(destination) {
print("Failed to finalize the image destination")
}
print("Url = \(fileURL)")
}
}
}
}

我已经把它从 以上答案转换过来了。我希望它能有所帮助。

作为 大意可用。

欢迎编辑。