通过 iOS 创建和导出动画 gif?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14915138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create and export an animated gif via iOS?
提问by crgt
I have a series of user-customized images within an iOS app that are being animated in a simple, frame-by-frame flip book style.
我在 iOS 应用程序中有一系列用户自定义的图像,这些图像以简单的、逐帧的翻书风格进行动画处理。
My question is this: is there a way to allow users to export their animation as an animated gif? Ideally, I'd like to enable them to email, social share (T/FB) or (worst case..) save an animated gif to their documents folder for retrieval via iTunes.
我的问题是:有没有办法允许用户将他们的动画导出为动画 gif?理想情况下,我希望他们能够通过电子邮件、社交分享 (T/FB) 或(最坏的情况..)将动画 gif 保存到他们的文档文件夹中,以便通过 iTunes 进行检索。
I know how to save a .png to the photo library, and I found a way to record an animation as a QT file (http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/), but I haven't found a way to just kick out a plain old animated gif. Am I missing something in Core Animation or somewhere else? Are there any approaches, frameworks, or resources that anyone can recommend? Sorry if the question is too general - struggling to find a starting point.
我知道如何将 .png 保存到照片库,并且我找到了一种将动画录制为 QT 文件的方法(http://www.cimgf.com/2009/02/03/record-your-core-animation -animation/),但我还没有找到一种方法来踢出一个普通的旧动画 gif。我在 Core Animation 或其他地方遗漏了什么吗?是否有任何人可以推荐的方法、框架或资源?对不起,如果问题太笼统 - 努力寻找起点。
回答by rob mayoff
You can create an animated GIF using the Image I/O framework (which is part of the iOS SDK). You will also want to include the MobileCoreServices
framework, which defines the GIF type constant. You need to add these frameworks to your target, and import their headers in the file where you want to create the animated GIF, like this:
您可以使用 Image I/O 框架(它是 iOS SDK 的一部分)创建动画 GIF。您还需要包含MobileCoreServices
定义 GIF 类型常量的框架。您需要将这些框架添加到您的目标中,并将它们的标题导入到您要创建动画 GIF 的文件中,如下所示:
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
It's easiest to explain by example. I'll show you the code I used to make this GIF on my iPhone 5:
用例子来解释最简单。我将向您展示我用来在 iPhone 5 上制作此 GIF 的代码:
First, here's a helper function that takes a size and an angle and returns a UIImage
of the red disk at that angle:
首先,这是一个辅助函数,它接受一个大小和一个角度,并返回UIImage
那个角度的红色圆盘的a :
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;
}
Now we can create the GIF. First we'll define a constant for the number of frames, because we need it twice later:
现在我们可以创建 GIF。首先我们将为帧数定义一个常量,因为我们稍后需要它两次:
static void makeAnimatedGif(void) {
static NSUInteger const kFrameCount = 16;
We'll need a property dictionary to specify the number of times the animation should repeat:
我们需要一个属性字典来指定动画应该重复的次数:
NSDictionary *fileProperties = @{
(__bridge id)kCGImagePropertyGIFDictionary: @{
(__bridge id)kCGImagePropertyGIFLoopCount: @0, // 0 means loop forever
}
};
And we'll need another property dictionary, which we'll attach to each frame, specifying how long that frame should be displayed:
我们需要另一个属性字典,我们将附加到每个框架,指定该框架应显示多长时间:
NSDictionary *frameProperties = @{
(__bridge id)kCGImagePropertyGIFDictionary: @{
(__bridge id)kCGImagePropertyGIFDelayTime: @0.02f, // a float (not double!) in seconds, rounded to centiseconds in the GIF data
}
};
We'll also create a URL for the GIF in our documents directory:
我们还将在我们的文档目录中为 GIF 创建一个 URL:
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"];
Now we can create a CGImageDestination
that writes a GIF to the specified URL:
现在我们可以创建一个CGImageDestination
将 GIF 写入指定 URL 的文件:
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, kFrameCount, NULL);
CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);
I discovered that passing fileProperties
as the last argument of CGImageDestinationCreateWithURL
does notwork. You have to use CGImageDestinationSetProperties
.
我发现,通过fileProperties
作为最后一个参数CGImageDestinationCreateWithURL
确实没有工作。你必须使用CGImageDestinationSetProperties
.
Now we can create and write our frames:
现在我们可以创建和编写我们的框架:
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);
}
}
Note that we pass the frame properties dictionary along with each frame image.
请注意,我们将帧属性字典与每个帧图像一起传递。
After we've added exactly the specified number of frames, we finalize the destination and release it:
在我们准确添加了指定数量的帧后,我们最终确定目标并释放它:
if (!CGImageDestinationFinalize(destination)) {
NSLog(@"failed to finalize image destination");
}
CFRelease(destination);
NSLog(@"url=%@", fileURL);
}
If you run this on the simulator, you can copy the URL from the debug console and paste it into your browser to see the image. If you run it on the device, you can use the Xcode Organizer window to download the app sandbox from the device and look at the image. Or you can use an app like iExplorer
that lets you browse your device's filesystem directly. (This doesn't require jailbreaking.)
如果您在模拟器上运行它,您可以从调试控制台复制 URL 并将其粘贴到浏览器中以查看图像。如果您在设备上运行它,您可以使用 Xcode Organizer 窗口从设备下载应用程序沙箱并查看图像。或者您可以使用类似的应用程序iExplorer
,让您直接浏览设备的文件系统。(这不需要越狱。)
I tested this on my iPhone 5 running iOS 6.1, but I believe the code should work as far back as iOS 4.0.
我在运行 iOS 6.1 的 iPhone 5 上对此进行了测试,但我相信代码应该可以追溯到 iOS 4.0。
I've put all the code in this gistfor easy copying.
为了便于复制,我已将所有代码放在此要点中。
回答by Nikhil Manapure
For Swift 3
对于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)")
}
}
}
}
I have converted it from the above answer. I hope it helps.
我已经从上面的答案转换了它。我希望它有帮助。
Available as a gist.
可作为要点。
Edits are welcomed.
欢迎编辑。
回答by onmyway133
If you're looking for Swift 3 solution, you can take a look at https://github.com/onmyway133/GifMagic. It has Encoder
and Decoder
which assembles and disassembles gif file.
如果您正在寻找 Swift 3 解决方案,您可以查看https://github.com/onmyway133/GifMagic。它有Encoder
和Decoder
哪个汇编和反汇编gif文件。
Basically, you should use Image IO
framework with these functions CGImageDestinationCreateWithURL
, CGImageDestinationSetProperties
, CGImageDestinationAddImage
, CGImageDestinationFinalize
基本上,你应该使用Image IO
框架具有这些功能CGImageDestinationCreateWithURL
,CGImageDestinationSetProperties
,CGImageDestinationAddImage
,CGImageDestinationFinalize
Also with Swift https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html
Core Foundation objects returned from annotated APIs are automatically memory managed in Swift—you do not need to invoke the CFRetain, CFRelease, or CFAutorelease functions yourself.
从带注释的 API 返回的 Core Foundation 对象在 Swift 中自动进行内存管理——您不需要自己调用 CFRetain、CFRelease 或 CFAutorelease 函数。