web-dev-qa-db-ja.com

iOS経由でアニメーションGIFを作成してエクスポートしますか?

IOSアプリ内に、ユーザーがカスタマイズした一連の画像があり、シンプルなフレームごとのフリップブックスタイルでアニメーション化されています。

私の質問はこれです:ユーザーがアニメーションをアニメーションgifとしてエクスポートできるようにする方法はありますか?理想的には、メール、ソーシャル共有(T/FB)、または(最悪の場合)アニメートされたgifをドキュメントフォルダに保存して、iTunesで取得できるようにしたいと思います。

.pngを写真ライブラリに保存する方法を知っていて、アニメーションをQTファイルとして記録する方法を見つけました( http://www.cimgf.com/2009/02/03/record-your -core-animation-animation / )、しかし、私は単純な古いアニメーションGIFを追い出す方法を見つけていません。 Core Animationまたは他の場所に何か不足していますか?誰もが推奨できるアプローチ、フレームワーク、またはリソースはありますか?質問が一般的すぎる場合は申し訳ありません-出発点を見つけるのに苦労しています。

73
crgt

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

まず、サイズと角度を取り、その角度で赤いディスクの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を作成できます。最初にフレーム数の定数を定義します。これは後で2回必要になるためです。

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"];

これで、指定されたURLにGIFを書き込む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 Organizerウィンドウを使用して、デバイスからアプリサンドボックスをダウンロードし、画像を見ることができます。または、iExplorerなどのアプリを使用して、デバイスのファイルシステムを直接参照できます。 (これはジェイルブレイクを必要としません。)

IOS 6.1を実行しているiPhone 5でこれをテストしましたが、コードはiOS 4.0まで遡って動作するはずです。

簡単にコピーできるように、すべてのコードを this Gist に入れました。

160
rob mayoff

ForSwift 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)")
            }
        }
    }
}

上記の回答 から変換しました。役に立てば幸いです。

Gist として利用可能。

編集を歓迎します。

1
Nikhil Manapure

Swift 3ソリューションを探している場合は、 https://github.com/onmyway133/GifMagic をご覧ください。EncoderおよびDecoderは、gifファイルをアセンブルおよびディスアセンブルします。

基本的に、これらの関数でImage IOフレームワークを使用する必要がありますCGImageDestinationCreateWithURLCGImageDestinationSetPropertiesCGImageDestinationAddImageCGImageDestinationFinalize

またSwift https://developer.Apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html

注釈付きAPIから返されるCore Foundationオブジェクトは、Swiftで自動的にメモリ管理されます。CFRetain、CFRelease、またはCFAutorelease関数を自分で呼び出す必要はありません。

0
onmyway133