December 2, 2012

FuelPHPで画像をプログラムから出力する方法。切り取る方法。応用する方法。

2012/12/02 15:53追記
Input::extension()メソッドで、URLの拡張子を取得可能とご教示を頂きました。「1. 画像をプログラムから出力する方法」について、内容を修正しました。
--

FuelPHP Advent Calendar 2012 2日目です。@madmamor です。
昨日は @kenji_s さんの「FuelPHPのこの1年」でした。

本日は「FuelPHPで画像をプログラムから出力する方法。切り取る方法。応用する方法。」を紹介します。WEB開発でよくある、ユーザによる画像アップロード機能の実装に際して、参考になれば幸いです。尚、当記事の内容はFuelPHP 1.4で確認しています。

1. 画像をプログラムから出力する方法

以下のようなコントローラを用意します。
<?php

class Controller_Image extends Controller
{

    private static $exts = array(
        'gif' => 'image/gif',
        'jpg' => 'image/jpeg',
        'jpeg'=> 'image/jpeg',
        'png' => 'image/png',
    );

    public function get_image($file_name = null)
    {
        $ext = Input::extension();
        $file_path = APPPATH.'tmp'.DS.$file_name.'.'.$ext;

        if ( ! is_file($file_path))
        {
            throw new Exception('Invalid file name.');
        }

        return Response::forge(
            file_get_contents($file_path),
            200,
            array('Content-Type' => static::$exts[$ext])
        );
    }

}
get_image()は、URLのセグメントから画像ファイル名を受け取り、その画像を出力します。

使い方は簡単で、Viewファイルに、以下のようなimgタグを書くだけです。
<img src="<?php echo Uri::create('image/image/xxx.png'); ?>" alt="xxx" />

2. 画像を切り取る方法

以下の方法で、切り取りつつ保存出来ます。
Image::load($path1)->crop($x1, $y1, $x2, $y2)->save($path2);
$x1 と $y1 が始点座標、$x2 と $y2 が終点座標です。$path1 が元のファイル名で、$path2 が保存するファイル名です。

Imageクラス:


3. 応用する方法

以上の2つの機能を組み合わせて、最近よく見かける方式の画像アップロード機能が実装できます。

例えばSNSで、ユーザがプロフィール画像をアップロードする際、画像の 縦幅 / 横幅 / 比率 はバラバラなので、それらをサーバサイドで一定の基準に基づき処理する必要があります。また、プロフィール画像はデザインとの関係も強く、切り取りやリサイズ処理が入るケースも多いと思われます。

その際、その基準(比率を維持する??横幅がNピクセル以上ならリサイズする?? etc…)の決定が煩わしいのであれば、ユーザに任せてしまうのも、一つの方法です。

例えばJcropのようなjQueryライブラリと組み合わせることで、ユーザによる切り取り機能を実装できます。

Jcrop:


Jcropは、比率固定の切り取りや、サイズ固定の切り取りが可能です。切り取りのchangeイベントも、随時キャッチできます。Jcrop側で、比率と、ミニマムな幅を制御すれば、サーバサイドの処理も楽になりますね。

実装の基本的なステップは、以下の流れになります。

画面1(ファイルアップロード画面)

  • 通常の画像アップロード画面を用意、ユーザに画像をアップロードさせる。

画面2(リサイズ画面)

  • 画面1から送信された画像を非公開ディレクトリにテンポラリとして保存。
  • 「1. 画像をプログラムから出力する方法」でHTMLに出力。
  • Jcropで切り取り、始点座標と終点座標をhiddenで送信。
セッションを用いない場合は、併せて、テンポラリとして保存されているファイル名もhiddenで送信する必要があります。

画面3(完了画面)

  • 画面2から送信されたhidden値を使い、「2. 画像を切り取る方法」で切り取って、正式に保存。
  • 切り取った画像を表示。等。

絵的にも面白い(カッコいい)機能と思いますので、機会があれば是非、取り入れてみて下さい。

また、更なる応用で、ドラッグドロップに対応したシームレスなアップロードを目指す場合、以下が参考になりそうです。

jQuery File Upload Plugin:


明日は @mkkn_info さんの「Fuel PHP を使ったモジュール開発入門」です。お楽しみに!

1 comment:

  1. Controllerから画像をResponseするには、

    $image = Image::forge();
    $image->load($file_path)->output($ext);
    exit;

    みたいな書き方もありますね。これだとMimeTypeを用意しなくていいので少しだけ楽ちんです。

    ReplyDelete