phpでアニメーションGIFを作りたいのですが、何を使っていますか?


目的はモバゲーのアバターのように、静止画像とアニメーションを組み合わせたようなものです。
静止画像はpngで用意して、それを重ね、レイヤーの一つとしてアニメーションgifも入れることができて、
最終的に出力されるgifもアニメーションgifに成っているようなイメージです。

また、imagegifを使って静止画像を作っていますが、画質が悪いです。合わせて解決できると嬉しいです

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2010/09/14 16:20:03
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答3件)

id:smallzhu No.1

回答回数107ベストアンサー獲得回数0

(はてなにより削除しました)
id:Numeric No.2

回答回数83ベストアンサー獲得回数18

ポイント80pt

①GIFアニメーションの作成

ImageMagickとPECL::ImagickでアニメーションGIFを合成する: Kwappa開発室

ここにちょうどいいサンプルコードがありましたので紹介します。


■GifCompositeクラス

<?php
class GifComposite
{
    // imagick objects
    private $imgs ;             // 合成対象(array)
    private $result ;           // 合成結果
    private $anim_delay ;       // アニメーションディレイ

    // 合成のベースとなる透明画像
    const TRANS_IMG = "img/blank.gif" ;

    /**
     *  コンストラクタ
     *      @param      array       &$img_files     画像ファイルのパス配列
     *      @param      integer     $anim_delay     1コマの時間(msec)
     */
    public function __construct(&$img_files, $anim_delay = 20)
    {
        foreach ($img_files as $img_file)
        {
            $this->imgs[] = new Imagick($img_file) ;
        }
        $this->result = new Imagick(self::TRANS_IMG) ;
        $this->anim_delay = $anim_delay ;
    }

    /**
     *  合成
     */
    public function composite()
    {
        //----------------------------------------------------------------------
        // 最大フレーム数を算出
        //----------------------------------------------------------------------
        $max_frames = 0 ;
        foreach ($this->imgs as &$img)
        {
            // 枚数をチェックして最大数を控える
            $num = $img->getNumberImages() ;
            if ($num > $max_frames) $max_frames = $num ;
            unset($img) ;
        }
        if ($max_frames <= 0) return false ;

        //----------------------------------------------------------------------
        // アニメーションアイテムを読み込んでいなければ単純に合成して終了
        //----------------------------------------------------------------------
        if ($max_frames == 1)
        {
            // 透明画像に全部かぶせて終了
            foreach ($this->imgs as $key => &$img)
            {
                $this->result->compositeImage($img, imagick::COMPOSITE_OVER, 0, 0) ;
            }

            $this->result->writeImages("result.gif", true) ;
            return true ;
        }

        //----------------------------------------------------------------------
        // アニメーションアイテムの合成
        //----------------------------------------------------------------------
        $comp_tmp = $this->result->clone() ; // 透明画像の控えを取っておく
        // アニメーションのコマ数ループ
        for ($i = 0 ; $i < $max_frames ; $i ++)
        {
            // 2コマ目以降:積み込み先画像は透明画像のコピー
            if ($i > 0)
            {
                $target = $comp_tmp->clone() ;
            }
            // 1コマ目:積み込み先画像は結果として使う予定の透明画像
            else
            {
                $target = &$this->result ; // 使用後かならずunsetしないと悲惨
            }
            // 読み込み済みファイルをループ
            foreach ($this->imgs as $key => &$img)
            {
                $count = $img->getNumberImages() ;  // 画像のコマ数
                // アニメーションアイテムならコマを指定
                if ($count > 1)
                {
                    $index = $i % $max_frames ;
                }
                // 通常アイテムは1コマ目
                else
                {
                    $index = 0 ;
                }
                // コマ数を指定して$this->resultにかぶせる
                $img->setImageIndex($index) ;
                $target->compositeImage($img, imagick::COMPOSITE_OVER, $offset_x, $offset_y) ;
            }
            $target->setImageDelay($this->anim_delay) ; // アニメーションディレイの設定
            // 最初のコマ
            if ($i == 0)
            {
                $target->setImageIterations($loop_count) ; // アニメーションループの設定
            }
            // それ以降
            else
            {
                $this->result->addImage($target) ; // 結果画像に積む
                $target->destroy() ; // 後片付け
            }
            unset($target) ;    // 変数の解放(参照入れてるので重要)
        }
        return true ;

    }

    /**
     *  合成結果を保存
     *      @param      string      $save_name      保存先のパス
     */
    public function save($save_name)
    {
        $frames = $this->result->getNumberImages() ;

        // アニメーションしなければ普通に書いて終了
        if ($frames == 1)
        {
            return $this->result->writeImage($save_name) ;
        }

        // アニメーションするなら最適化
        // 結果画像を書き出す
        $this->result->writeImages("{$save_name}.MIFF", true) ;
        // Quantizeが使えないので保存ファイルをconvert +mapに通す
        exec("convert {$save_name}.MIFF -layers OptimizeTransparency +map {$save_name}", $ret, $result) ;
        // エラーチェックは省略
        return true ;
    }
}
?>

■動作サンプル

<?php
// 合成画像の配列
$img_files = array(
    "img/sara_yamaguchi.gif",
    "img/devlish_heart.gif",
) ;

$gifComposite = new GifComposite($img_files) ;
$gifComposite->composite() ;
$gifComposite->save("result.gif") ;
?>

②静止画(GIF)の画質について

新規画像作成時に「imagecreate()」を使用していませんか?

「imagecreatetruecolor()」を使用することで画質は改善するはずです。

それでも画質が悪いと感じるなら、それはきっとGIFには向かない画像なのでしょう。

id:dingding

大変詳しいコードをいただいてとても参考になります。ありがとうございます。

imagecreatetruecolorを使っていますが、期待した画質ではないですね。

ImageMagickを試してみます。

2010/09/09 17:26:55
id:simoke123 No.3

回答回数220ベストアンサー獲得回数0

(はてなにより削除しました)
  • id:tasklight
    ImageMagickを使ったらどうでしょう。
  • id:dingding
    ImageMagickはメンド臭いというイメージが強かったんですが、見てみたら思ったより簡単そうですね。
  • id:Numeric
    書き忘れましたが、回答で示したコードの実行にはImageMagickが必要です。
    それと、回答後に気づいたのですが「何を使っていますか?」という質問には
    答えられていません。ご注意ください。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません