強火で進め

このブログではプログラム関連の記事を中心に書いてます。こちらで( http://blog.livedoor.jp/tsuyobi-outdoor/ ) アウトドア関連の記事も書いてます。

iPhoneアプリ内でアニメーションGIF(Animated GIF)を作成するサンプル



(2010/09/22 追記)
こちらの方法ではiOS 4.0以降ではビルドに失敗する様です。4.0以降の場合は以下のImageMagick を使った方法を試して下さい。

ImageMagick(MagickWand)でアニメーションGIF(Animated GIF)を作成するサンプル - 強火で進め
http://d.hatena.ne.jp/nakamura001/20100921/1285087936



やってることは画像処理のライブラリで有るGDをiPhone向けにビルドし、GDに有るアニメーションGIF(Animated GIF)の作成をする関数を呼んでいるだけです。

サンプルコードはこちらになります。

使用ライブラリ

今回のサンプルで使用したiPhone SDK以外に必要なライブラリ。
・GDライブラリ

Main Page - LibGD
http://www.libgd.org/Main_Page

・libpng
・libjpeg

GDをiPhoneで使用するためにした作業

1. GDファイルのソースを解凍後、 .h と .c ファイルのみを抽出し、 フォルダ(名称「gd」 )にコピー。Windows向けやテスト用と思われるファイルを削除。
2. ファイルをコピーしたフォルダをプロジェクトに追加。
3. GD_GIfAppDelegate.m ファイルの先頭に #include "gd.h" を追加。
4. gdフォルダ内の gd.h に以下の定義を追加。

#define HAVE_LIBPNG 1
#define HAVE_LIBJPEG 1

※この記述によりPNGJPEGファイルの読み書きを行う関数が使用出来る様になります。
5. ライブラリのリンク。 libpng.dylib と libjpeg.dylib
自分はMac Portsでインストールしたものを使ったので以下のパスのものを使用。別の方法でインストールしている人はパスが異なる可能性があります。

/opt/local/lib/libpng.dylib
/opt/local/lib/libjpeg.dylib

6. includeの記述を変更。
libepng関連。

#include "png.h" /* includes zlib.h and setjmp.h */

#include "/opt/local/include/libpng12/png.h"
//#include "png.h" /* includes zlib.h and setjmp.h */

libjpeg関連。

#include "jpeglib.h"
#include "jerror.h"

#include "/opt/local/include/jpeglib.h"
#include "/opt/local/include/jerror.h"
//#include "jpeglib.h"
//#include "jerror.h"

アニメーションGIFの作成処理

GDの準備が完了したら後はPNGファイル、またはJPEGファイルを元にアニメーションGIFを作成する関数を呼ぶだけです。

該当部分のソースはこの様になっています。デフォルトではPNGファイルから作成するようになっています。

- (void)createAnimatedGif {
    FILE *in1Fp;
    FILE *in2Fp;
    FILE *in3Fp;
    FILE *outFp;
    
    // アニメGifにする画像ファイル
    NSString *in1FilePath = [[NSString alloc] initWithFormat:@"%@/img01.png", [[NSBundle mainBundle] resourcePath]];
    NSString *in2FilePath = [[NSString alloc] initWithFormat:@"%@/img02.png", [[NSBundle mainBundle] resourcePath]];
    NSString *in3FilePath = [[NSString alloc] initWithFormat:@"%@/img03.png", [[NSBundle mainBundle] resourcePath]];
    /*
     NSString *in1FilePath = [[NSString alloc] initWithFormat:@"%@/img01.jpg", [[NSBundle mainBundle] resourcePath]];
     NSString *in2FilePath = [[NSString alloc] initWithFormat:@"%@/img02.jpg", [[NSBundle mainBundle] resourcePath]];
     NSString *in3FilePath = [[NSString alloc] initWithFormat:@"%@/img03.jpg", [[NSBundle mainBundle] resourcePath]];
     */
    // 出力先(シミュレータで確認しやすい位置に設定してあります。実際に使用するときは適切な位置に出力(保存)して下さい)
    NSString *outFilePath = [[NSString alloc] initWithFormat:@"%@/../../img01.gif", [[NSBundle mainBundle] resourcePath]];
    NSLog(@"[output] %@", outFilePath);
    
    in1Fp = fopen([in1FilePath UTF8String], "rb");
    in2Fp = fopen([in2FilePath UTF8String], "rb");
    in3Fp = fopen([in3FilePath UTF8String], "rb");
    outFp = fopen([outFilePath UTF8String], "wb");
    if (in1Fp && in2Fp && in3Fp && outFp) {
        //
        // 参照サイト
        // [GD] GIFアニメーションの作成 | idocsq.net
        // http://idocsq.net/page/162
        //
        // The Joel on Software Discussion Group - Help with GD.
        // http://discuss.joelonsoftware.com/default.asp?joel.3.55828.1
        //
        // http://bugs.libgd.org/?getfile=176
        //
        gdImagePtr gdImg1Ptr = gdImageCreateFromPng(in1Fp);
        gdImagePtr gdImg2Ptr = gdImageCreateFromPng(in2Fp);
        gdImagePtr gdImg3Ptr = gdImageCreateFromPng(in3Fp);
        /*
         // JPEGファイルのとき
         gdImagePtr gdImg1Ptr = gdImageCreateFromJpeg(in1Fp);
         gdImagePtr gdImg2Ptr = gdImageCreateFromJpeg(in2Fp);
         gdImagePtr gdImg3Ptr = gdImageCreateFromJpeg(in3Fp);
         */
        gdImageTrueColorToPalette(gdImg1Ptr, TRUE, gdMaxColors);
        gdImageTrueColorToPalette(gdImg2Ptr, TRUE, gdMaxColors);
        gdImageTrueColorToPalette(gdImg3Ptr, TRUE, gdMaxColors);
        // 全てのイメージのパレットを共通化する
        gdImagePaletteCopy(gdImg2Ptr, gdImg1Ptr);
        gdImagePaletteCopy(gdImg3Ptr, gdImg1Ptr);
        /*** アニメーション作成とファイル出力の開始 ***/
        /*** (ファイルは事前にオープンしておく) ***/
        gdImageGifAnimBegin(gdImg1Ptr, outFp, 1, 0);
        /*** アニメーションを構成する画像(コマ)の追加 ***/
        gdImageGifAnimAdd(gdImg1Ptr, outFp, 0,
                          0, 0, 200, gdDisposalNone, NULL);
        gdImageGifAnimAdd(gdImg2Ptr, outFp, 0,
                          0, 0, 200, 1, gdImg1Ptr);
        gdImageGifAnimAdd(gdImg3Ptr, outFp, 0,
                          0, 0, 200, 1, gdImg2Ptr);
        
        /*** アニメーション作成とファイル出力の終了 ***/
        /*** (ファイルはこのあとにクローズする) ***/
        gdImageGifAnimEnd(outFp);
        
        gdImageDestroy(gdImg1Ptr);
        gdImageDestroy(gdImg2Ptr);
        gdImageDestroy(gdImg3Ptr);
    }
    if (in1Fp) fclose(in1Fp);
    if (in2Fp) fclose(in2Fp);
    if (in3Fp) fclose(in3Fp);
    if (outFp) fclose(outFp);
}

JPEGからの作成はコメントアウトして有るのでそちらを試したいときはPNG向けのものと置き換えて下さい。

作成されたアニメーションGIFはコンソールに [output] 文字の後にフルパスで表示されます。
こちらのファイルをブラウザにドラッグして正しく生成されているか確認して下さい。

むむむっ

プロジェクトファイル名、「GD_Gif」って付けたつもりが「GD_GIf」ってなってた。まぁ、サンプルなので細かい事は気にしない方向で…

こちらのサンプルの使用にして

やってることはGDライブラリの関数呼んでるだけのサンプルなので自由に使って貰って良いです。
一応、GDのライセンスと同一としておきます。GDのライセンスはサイトには明確な記載が見当たらなかったのですがソースファイルに同梱されている「COPYING」というファイルがそれっぽいです。こちらのファイルをコピーしたものを「GDライブラリのCOPYING.txt」というファイル名で同梱しています。

GDライセンス(※AS ISっぽいですけど、英語は苦手なのでご利用される方はしっかりご確認下さい)の範囲で御自由に自身のアプリに活用しちゃって下さい。

関連情報

・日本語のサイト。GDの使い方からアニメーションGIFの作成方法まで扱っているサイト。GDの使い方

[GD] GIFアニメーションの作成 | idocsq.net
http://idocsq.net/page/162

PHPのGDについてのマニュアル。基本使い方が同じなのでPHP向けの解説でも問題ないです。これだと日本語のものがたくさん有ります。
関数名の頭に gd を加えたものが実際にiPhoneで使うときの関数名となります。

PHP: GD および Image 関数 - Manual
http://www.php.net/manual/ja/ref.image.php

GIFアニメーションの作成方法の解説をしているサイト。こちらは画像ファイルを読み込んで使うのではなく、プログラム内で描画したものをGIFとして作成しているので参考にしたのは一部。そういう用途の人には良いサイトだと思います。

The Joel on Software Discussion Group - Help with GD.
http://discuss.joelonsoftware.com/default.asp?joel.3.55828.1

・バグ検証用のファイル?このファイルのおかげでパレット情報のコピーの方法が分かりました。

http://bugs.libgd.org/?getfile=176