目的はモバゲーのアバターのように、静止画像とアニメーションを組み合わせたようなものです。
静止画像はpngで用意して、それを重ね、レイヤーの一つとしてアニメーションgifも入れることができて、
最終的に出力されるgifもアニメーションgifに成っているようなイメージです。
また、imagegifを使って静止画像を作っていますが、画質が悪いです。合わせて解決できると嬉しいです
①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には向かない画像なのでしょう。
大変詳しいコードをいただいてとても参考になります。ありがとうございます。
imagecreatetruecolorを使っていますが、期待した画質ではないですね。
ImageMagickを試してみます。