我在一个iOS应用程序中有一系列用户定制的图像,它们正在以简单的逐帧活页书式进行动画制作.

我的问题是:有没有办法允许用户将他们的动画导出为动画gif?理想情况下,我希望使他们能够发送邮箱、社交共享(T/FB)或(最糟糕的情况..)将动画gif保存到他们的Documents文件夹,以便通过iTunes检索.

我知道如何拯救一个子元素.png的图片库,我找到了一种方法来记录一个动画作为QT文件(http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/),但我还没有找到一种方法,只是踢出一个普通的旧动画gif.我是不是在核心动画或其他地方遗漏了什么?有没有任何人可以推荐的方法、框架或资源?抱歉,如果问题太笼统了——很难找到起点.

推荐答案

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

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

用例子来解释是最容易的.我会给你看我用来在我的iPhone5上制作这个GIF的代码:

首先,下面是一个辅助函数,它接受一个大小和一个Angular ,并在该Angular 返回红盘的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的最后一个参数可以做到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管理器窗口从设备下载应用程序沙箱并查看图像.或者你可以使用像iExplorer这样的应用程序,让你直接浏览设备的文件系统.(这不需要越狱.)

我在运行iOS 6.1的iPhone 5上测试了这一点,但我相信代码应该可以追溯到iOS 4.0.

为了便于复制,我把所有代码都写进了this gist.

Ios相关问答推荐

Xcode 15中的版本控制发生了什么?

为什么下面的代码没有在主线程上运行?

当目标位于菜单标签内时,matchedGeometryEffect 的行为很奇怪

使用异步重载实现Swift协议一致性

iOS 16.4 更新后 Xcode 14.3 构建错误:找不到 libarclite_iphoneos.a,链接器命令失败

AppCenter 错误:/usr/bin/xcodebuild 失败,返回码:65

弹出视图后使所有背景 UI 模糊

将角半径仅应用于 Swiftui 中按钮的两个角

一个 SwiftUI 视图中的多个垂直滚动视图

UIViewControllerRepresentable 在 Xcode 14 iOS 16 上崩溃

UITableView 页脚,停止浮动内容

Xcode 缺少支持文件 iOS 12.2 (16E227)

Xcode 4.1 致命错误:自构建预编译头文件后修改了 stdlib

是否可以在 iOS 9 上让您的 iPad 应用退出多任务处理?

try 在 iOS 中处理后退导航按钮操作

aps-environment 始终在发展

'无效更新:第 0 节中的无效行数

检测应用程序何时进入我的视图背景的最佳方法是什么?

将视图控制器从一个情节提要移动或复制到另一个情节提要

在自动布局中居中子视图的 X 会引发未准备好约束