iOSでアニメーションGIFを作成・書き出し?
質問
iOS アプリケーションで、ユーザーがカスタマイズした一連の画像を、シンプルなフレームごとのフリップブック スタイルでアニメーション化する必要があります。
私の質問は、ユーザーが自分のアニメーションをアニメーション GIF としてエクスポートできるようにする方法はあるかということです。 理想的には、電子メール、ソーシャル共有 (T/FB)、または (最悪の場合) iTunes を通じて取得できるようにドキュメント フォルダにアニメーション GIF を保存できるようにしたいのですが、いかがでしょうか。
私は .png をフォト ライブラリに保存する方法を知っていますし、アニメーションを QT ファイルとして記録する方法を見つけました ( http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/ ) としてアニメーションを記録する方法を見つけましたが、ただ単に古いアニメーション GIF を追い出す方法を見つけられませんでした。 私は、Core Animationかどこかで何かを見逃しているのでしょうか?誰かが推薦することができるアプローチ、フレームワーク、またはリソースがありますか? 質問があまりにも一般的であれば申し訳ありません - 出発点を見つけるのに苦労しています。
どのように解決するのですか?
Image I/O フレームワーク (iOS SDK の一部) を使用してアニメーション GIF を作成することができます。 また、このフレームワークには
MobileCoreServices
フレームワークも含める必要があります。これは GIF タイプ定数を定義しています。 これらのフレームワークをターゲットに追加し、アニメーション 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を作成することができます。 まず、フレーム数の定数を定義します。後で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
}
};
また、documents ディレクトリに GIF の URL を作成します。
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"];
これで
CGImageDestination
を作成し、指定された URL に GIF を書き込むことができます。
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 を実行している iPhone 5 でこれをテストしましたが、このコードは iOS 4.0 までさかのぼることができるはずです。
私はすべてのコードを この gist にまとめました。
関連
-
[解決済み] アニメーションGIFの表示
-
[解決済み] UITableViewの下にある余分なセパレータをなくす
-
[解決済み] UITextViewのプレースホルダー
-
[解決済み] フレームワークを使用したiOSアプリがデバイス上でクラッシュ、dyld: ライブラリがロードされない、Xcode 6 Beta
-
[解決済み] Swiftベースのアプリケーションは、OS X 10.9/iOS 7以下でも動作しますか?
-
[解決済み] Swift 3, 4, 5 で dispatch_after GCD を書くにはどうしたらいいですか?
-
[解決済み] iOSとWatchKitで画像のtintColorを変更する方法
-
[解決済み] コア・データ エンティティの全インスタンスを削除する最短の方法
-
[解決済み] ファイルはユニバーサル(3スライス)ですが、iOSの静的ライブラリのための(n)ARMv7-sスライスエラーが含まれていない、どうにかして回避するには?
-
[解決済み】PythonでビデオやアニメーションGIFをプログラム的に生成する?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
IOS8 Development Guide Error Thread 1: signal SIGABRT
-
[解決済み] Objective-Cでデリゲートを作成するにはどうしたらいいですか?
-
[解決済み] UITextFieldのテキスト変更イベント
-
[解決済み] Unwind segueは何に使うのか、どう使うのか?
-
[解決済み] IBOutletsはARCのもとで強くなるべきか、弱くなるべきか?
-
[解決済み] SwiftでUIAlertViewを作成するにはどうしたらいいですか?
-
[解決済み] iOSシミュレータでスクリーンショットを撮る
-
[解決済み] iOS - UITextFieldの外側をタッチするとキーボードが外れる。
-
[解決済み] 16進カラーバリューの使用方法
-
[解決済み] UITextBorderStyleNoneを使用してUITextFieldのパディングを設定する