LoginSignup
0
0

More than 5 years have passed since last update.

a-blog cmsでPDFファイルのサムネイル画像を生成してみる【MAMP編】

Last updated at Posted at 2016-04-03

ImageMagickGhostscript を使って、a-blog cmsでPDFファイルをアップロードするときに、サムネイル画像を生成する方法を実装してみました。

お手本)【a-blog cms】アップロードしたPDFのサムネイルを作成する

基本はお手本サイト通りなのですが、環境設定に苦労しました。黒い画面が苦手なデザイナーが試した長い道のりの備忘録です。

まずはMacのMAMPでテスト。
環境は OS X 10.9.5 (Mavericks) / MAMP 2.2 (PHP 5.4.19) / a-blog cms 2.6.0.1 です。

【Mac OS / MAMP のバージョンアップについて】
MAMP 4.0.2(おそらく 3.0 以降?)では、php.iniにエクステンションを追記する(コメントアウトされているのでコメントを外す)ところからで Imagick を有効にできました。それでもエラーが出る場合は、XQuartz のインストールが必要かもしれません。

設定の流れ

  1. 作業準備
  2. 必要なツール等のインストール
  3. a-blog cmsのカスタマイズ
  4. アップロード!

Step1: 作業準備

まずは、 作業をしやすくするためにパッケージマネージャー Homebrew をインストールします。
ターミナルを起動し、公式サイトのコマンドを実行します。

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールできたか確認してみます。

$ brew doctor

Warningが出たら書いてある通りに解決してゆきます。
(わたしの場合はXcodeのアップデートが必要でした)

Your system is ready to brew.

と表示されれば準備完了です。

Step2: 必要なツール等のインストール

サーバ側に以下の3つを準備します。

  • ImageMagick
  • Ghostscript - PostScriptやPDFなどのページ記述言語用インタプリタ(Adobe製)
  • Imagick - ImageMagickを操作するためのPHP拡張モジュール

Homebrewでパッケージをインストールしてゆきます。

1. Ghostscript

$ brew install ghostscript

2. ImageMagick

オプションにGhostscriptを指定。

$ brew install imagemagick --with-ghostscript

インストールのオプションを調べるコマンドはこちら。

$ brew options imagemagick

3. Imagick(PHP拡張モジュール)

peclコマンドを使います。

$ pecl install imagick

わたしの場合、「 -bash: pecl: command not found 」と怒られたので、PEARをインストールしました。

$ cd /tmp && mkdir pear && cd pear
$ curl -O http://pear.php.net/go-pear.phar
$ sudo php -d detect_unicode=0 go-pear.phar

PEAEのインストール先はこんな感じ(わたしは1と4を変更しました)。

 1. Installation base ($prefix)                   : /usr/local/pear
 2. Temporary directory for processing            : /tmp/pear/install
 3. Temporary directory for downloads             : /tmp/pear/install
 4. Binaries directory                            : /usr/local/bin
 5. PHP code directory ($php_dir)                 : /usr/local/pear/share/pear
 6. Documentation directory                       : /usr/local/pear/docs
 7. Data directory                                : /usr/local/pear/data
 8. User-modifiable configuration files directory : /usr/local/pear/cfg
 9. Public Web Files directory                    : /usr/local/pear/www
10. System manual pages directory                 : /usr/local/pear/man
11. Tests directory                               : /usr/local/pear/tests
12. Name of configuration file                    : /private/etc/pear.conf

php.ini ファイルを作成。

$ sudo cp /etc/php.ini.default /etc/php.ini

php.ini ファイルを開き、インクルードパスを追加。
( PEARインストール時の 5. PHP code directory ($php_dir) のパスを追加します)

include_path = ".:/php/includes:/usr/local/pear/share/pear"

autoconf がないと怒られたのでインストール。

$ brew install autoconf

さらにエラーが…(心折れそう

1 error generated.
make: *** [imagick.lo] Error 1
ERROR: `make' failed

わたしの環境では php54-imagick を使わなきゃいけないみたいなので、以下のコマンドを順に実行。

$ brew remove imagemagick
$ brew update && brew upgrade
$ brew install homebrew/php/php54-imagick

ここまででインストール作業は完了。のはず。

4. MAMPのphp.iniにエクステンションを追記

/Applications/MAMP/bin/php/php5.4.19/conf/php.ini に以下の記述を追加しました。

extension=imagick.so

imagick.soファイルをMAMPのextensionsディレクトリにコピーするのも忘れずに。
(コピー元: /usr/local/Cellar/php54-imagick/3.3.0_1/imagick.so もしくは /usr/local/Cellar/php54/5.4.45_3/lib/php/extensions/no-debug-non-zts-20100525/imagick.so

ここで phpInfo を確認してみると imagick がありません。
ライブラリのパスが通っていないことが原因らしい。

Comment out the 2 lines in the file /Applications/MAMP/Library/bin/envvars:

DYLD_LIBRARY_PATH="/Applications/MAMP/Library/lib:$DYLD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH

/Applications/MAMP/Library/bin/envvars ファイルを開いて上記2行をコメントアウトすると書いてありました。

わたしの場合、6行くらいあったのですべてコメントアウト。さらに1行追加しました。
最後の1行が抜けていると画像生成できません。

# if test "x$DYLD_LIBRARY_PATH" != "x" ; then
#   DYLD_LIBRARY_PATH="/Applications/MAMP/Library/lib:$DYLD_LIBRARY_PATH"
# else
#   DYLD_LIBRARY_PATH="/Applications/MAMP/Library/lib"
# fi
# export DYLD_LIBRARY_PATH
#
export PATH="$PATH:/usr/local/bin"

もう一度 phpInfo を見てみると……はい!

imagick_3.3.0.png

これでようやく環境が整いました。
(MAMP PRO 3.0 では ImageMagick が使えるようになっているとか…?)

Step3: a-blog cmsのカスタマイズ

1. カスタムフィールドを作成

/admin/entry/field.html にPDFファイルをアップロードするカスタムフィールドを記述します(お好みでincludeファイルに)。

カスタムフィールドメーカー でファイルのカスタムフィールドを作成し、画像ファイルのパス ( /images/fileicon/pdf.gif ) を変数 ( %{ARCHIVES_DIR}{pdfThumbnail} ) 変更します。

<table class="entryFormTable acms-admin-table-entry">
    <tr>
        <th>PDFファイル</th>
        <td>
            <!-- BEGIN pdfFile@path:veil -->
            <input type="hidden" name="pdfFile@old" value="{pdfFile@path}" />
            <input type="hidden" name="pdfFile@secret" value="{pdfFile@secret}" />
            <input type="hidden" name="pdfFile@fileSize" value="{pdfFile@fileSize}" />
            <label for="input-checkbox-pdfFile@edit" class="acms-admin-form-checkbox">
                <input type="checkbox" name="pdfFile@edit" value="delete" id="input-checkbox-pdfFile@edit" />
                <i class="acms-admin-ico-checkbox"></i> 削除
            </label>
            <a href="%{ARCHIVES_DIR}{pdfFile@path}"><img src="%{ARCHIVES_DIR}{pdfThumbnail}" width="120" alt="" /></a>
            <!-- END pdfFile@path:veil -->
            <input type="file" name="pdfFile" />
            <input type="hidden" name="field[]" value="pdfFile" />
            <input type="hidden" name="pdfFile@baseName" value="{pdfFile@baseName}" />
            <input type="hidden" name="pdfFile:extension" value="file" />
            <input type="hidden" name="pdfFile@extension" value="pdf" />
        </td>
    </tr>
</table>

2. Hookを有効に設定

config.server.php でフック拡張を有効(0→1)に変更。

define('HOOK_ENABLE', 1);

3. 独自処理の追加

/php/ACMS/User/Hook.phpbeforePostFire function内に以下のコードを追加(お手本サイトよりコピペ)。

public function beforePostFire($thisModule)
{
    if ( !sessionWithContribution() ) return false;  // 権限チェック

    $class      = get_class($thisModule);  // モジュールのクラス名取得
    $destDir    = 'thumbnail/';            // サムネイルを保存するディレクトリ名
    $fieldName  = 'pdfFile';               // アップロードするPDFのフィールド名
    $thumbnailFieldName = 'pdfThumbnail';  // サムネイル画像の変数名

    // エントリーの作成or更新のみ
    if ( !in_array($class, array(
        'ACMS_POST_Entry_Insert',
        'ACMS_POST_Entry_Update'
    )) ) {
        return false;
    }

    $Post   =& $thisModule->Post;  // POSTデータを取得
    $bid    = $Post->get('bid');
    $cid    = $Post->get('cid');

    if ( !isset($_FILES[$fieldName]['tmp_name']) ) return false;

    $source = $_FILES[$fieldName]['tmp_name'];
    if ( !is_readable($source) ) return false;

    $myurl  = $source.'[0]';  // PDFの1ページを指定

    try {
        $image  = new Imagick();
        $image->setResolution(140, 140);  // 解像度を指定
        $image->readimage($myurl);        // PDFの読み込み
        $image->setImageFormat('png');

        ACMS_POST::setupDir(ARCHIVES_DIR.$destDir, intval(config('permission_dir')));  // 保存先ディレクトリの作成
        $file   = uniqueString().'.png';        // 保存ファイル名
        $dest   = ARCHIVES_DIR.$destDir.$file;  // 保存先

        $image->writeImage($dest);
        $image->destroy();

        // カスタムフィールドに登録する為、POSTデータにサムネイル画像のパスを登録
        $Post->add('field', $thumbnailFieldName);
        $Post->add($thumbnailFieldName, $destDir.$file);
    } catch(Exception $e) {
        echo $e->getMessage();
    }
}

【教訓】「 Parse error: syntax error, unexpected T_VARIABLE 」と怒られたら、当該lineの上にセミコロンが抜けていたり全角スペースがある可能性があります。

Step4: アップロード!

カスタムフィールドでPDFファイルをアップロードしてみます。
作成したエントリーを確認してみると

customfield.png

画像が生成されていました!

表示用のテンプレートにも以下のコードを追加してみます。

<!-- BEGIN pdfFile@path:veil -->
<a href="%{ARCHIVES_DIR}{pdfFile@path}" target="_blank"><img src="%{ARCHIVES_DIR}{pdfThumbnail}" width="120" alt="" /></a>
<!-- END pdfFile@path:veil -->

entry.png

表示されました!

サムネイル画像は /archives/thumbnail の中に保存されます(Hook.phpで設定)。

おわりに

現状、問題点がいくつかあります。

  • エントリーを編集すると画像が消えてしまう → 解決案:追記2へ
  • PDFのファイル名と生成したサムネイルのファイル名が連動していない → 解決案:追記へ
  • PDFファイルを差替えても元のサムネイル画像は削除されずに残る

便利に運用するにはもう少しカスタマイズが必要かもしれません。

〈追記〉問題点の解決案

PDFのファイル名を元のファイル名でアップロードする方法を見つけたので少しカスタマイズしてみました。

1. PDFファイルを元のファイル名でアップロード

/php/ACMS/User/Hook.php に次のコードを追加します(自己責任)。

switch($class) {
    case 'ACMS_POST_Entry_Insert':
    case 'ACMS_POST_Entry_Update':

    $thisModule->Post->_aryField['pdfFile@filename'][0] = 'pdf/'.$_FILES['pdfFile']['name'];

    break;
}

参考)カスタムフィールドでアップするファイル名をアップ元のファイル名にする - 気づいたら、ここだった

ファイル名が元のファイル名になっているのを確認しました。

2. サムネイル画像をPDFファイル名と連動

ランダムな文字列だった画像のファイル名を 元のファイル名.png にします。

$file   = $_FILES['pdfFile']['name'].'.png';

元のファイル名には拡張子が含まれるため filename.pdf.png のような名前になります。
画像のファイル名が固定されたので、アップし直しても画像が増えていくことはなくなりました。

3. サムネイル画像の保存先を変更

サムネイル画像が /archives の直下にあるのが気になったので、PDFファイルと同じ階層に変更します。

$destDir    = sprintf('%03d', BID).'/thumbnail/';

もとのディレクトリに合わせて数字3桁になるように0で埋めます。
これで、ブログIDが1のときは /archives/001/thumbnail にサムネイル画像が保存できるようになりました。

最終的なコードはこんな感じに。

public function beforePostFire($thisModule)
{
    if ( !sessionWithContribution() ) return false;  // 権限チェック

    $class      = get_class($thisModule);              // モジュールのクラス名取得
    $destDir    = sprintf('%03d', BID).'/thumbnail/';  // サムネイルを保存するディレクトリ名
    $fieldName  = 'pdfFile';                           // アップロードするPDFのフィールド名
    $thumbnailFieldName = 'pdfThumbnail';              // サムネイル画像の変数名

    // PDFファイルを元のファイル名に
    switch($class) {
        case 'ACMS_POST_Entry_Insert':
        case 'ACMS_POST_Entry_Update':

        $thisModule->Post->_aryField['pdfFile@filename'][0] = 'pdf/'.$_FILES['pdfFile']['name'];

        break;
    }

    // エントリーの作成or更新のみ
    if ( !in_array($class, array(
        'ACMS_POST_Entry_Insert',
        'ACMS_POST_Entry_Update'
    )) ) {
        return false;
    }

    $Post   =& $thisModule->Post;  // POSTデータを取得
    $bid    = $Post->get('bid');
    $cid    = $Post->get('cid');

    if ( !isset($_FILES[$fieldName]['tmp_name']) ) return false;

    $source = $_FILES[$fieldName]['tmp_name'];
    if ( !is_readable($source) ) return false;

    $myurl  = $source.'[0]';  // PDFの1ページを指定

    try {
        $image  = new Imagick();
        $image->setResolution(140, 140);  // 解像度を指定
        $image->readimage($myurl);        // PDFの読み込み
        $image->setImageFormat('png');

        ACMS_POST::setupDir(ARCHIVES_DIR.$destDir, intval(config('permission_dir')));  // 保存先ディレクトリの作成
        $file   = $_FILES['pdfFile']['name'].'.png';  // 保存ファイル名 (元のファイル名.png)
        $dest   = ARCHIVES_DIR.$destDir.$file;        // 保存先

        $image->writeImage($dest);
        $image->destroy();

        // カスタムフィールドに登録する為、POSTデータにサムネイル画像のパスを登録
        $Post->add('field', $thumbnailFieldName);
        $Post->add($thumbnailFieldName, $destDir.$file);
    } catch(Exception $e) {
        echo $e->getMessage();
    }
}

あとは、エントリーを編集すると画像が消えるのを解決できるかどうか。
でも、ここまででわりと満足しました笑

〈追記2〉エントリー編集後も画像を保持する

エントリーを編集すると画像が消える問題について、以下の2行をカスタムフィールドに追加するとよいのでは?というアドバイスをいただいたのですが、

<input type="hidden" name="pdfThumbnail" value="{pdfThumbnail}" />
<input type="hidden" name="field[]" value="pdfThumbnail" />

わたしがやってもうまくいきませんでした…(未だに変数をカスタムフィールドに格納するのできない)
ただ、生成した画像は残っているので、画像のパスの書き方を変えることで解決したいと思います!

ファイル名とパスを見てみる

サムネイル画像をPDFファイル名と連動したことで、それぞれのパスは以下のようになります(ブログIDが1のとき)。

PDFファイル: /archives/001/pdf/filename.pdf
サムネイル画像: /archives/001/thumbnail/filename.pdf.png

PDFファイルのパス ( 001/pdf/filename.pdf ) はカスタムフィールドの値 {pdfFile@path} なので、これに画像の拡張子を追加する ( {pdfFile@path}.png ) と画像のファイル名は取得できますね。

生成したサムネイル画像の保存先がPDFファイルと同じ場所 ( /archives/001/pdf ) ならこのままでOKでした。でもわたしはサムネイル画像は個別に管理したいのです。画像のパスを pdf ディレクトリから thumbnail に変更する必要があります。

そこで登場するのが 校正オプションの拡張 です!

校正オプションの拡張

まずはファイルを準備します。

ダウンロードパッケージのomakeフォルダに含まれるファイルを、設置先にコピーします。

コピー元
(ダウンロードパッケージの展開先)/omake/php/ACMS/User/Corrector.php
コピー先
(a-blog cms設置先)/php/ACMS/User/Corrector.php

所定の位置にファイルがコピーされていれば、自動で校正オプションが拡張されるようになります。

参考)校正オプションの拡張について

Corrector.php に以下のコードを追加します。

function pdf2thumb($txt, $args = array())
{
    if ( mb_strpos($txt, '/pdf/') ) {
        $txt = str_replace( '/pdf/', '/thumbnail/', $txt );
    }
    return $txt;
}

表示側の画像のパスを {pdfThumbnail} から {pdfFile@path}.png に変更し、作成した校正オプションを追加します。

<!-- BEGIN pdfFile@path:veil -->
<a href="%{ARCHIVES_DIR}{pdfFile@path}" target="_blank"><img src="%{ARCHIVES_DIR}{pdfFile@path}[pdf2thumb].png" width="120" alt="" /></a>
<!-- END pdfFile@path:veil -->

{pdfFile@path}[pdf2thumb].png のように校正オプションを追加することで 001/pdf/filename.pdf.png が 001/thumbnail/filename.pdf.png になります。

カスタムフィールドの画像のパスも変更しておきましょう。

<table class="entryFormTable acms-admin-table-entry">
    <tr>
        <th>PDFファイル</th>
        <td>
            <!-- BEGIN pdfFile@path:veil -->
            <input type="hidden" name="pdfFile@old" value="{pdfFile@path}" />
            <input type="hidden" name="pdfFile@secret" value="{pdfFile@secret}" />
            <input type="hidden" name="pdfFile@fileSize" value="{pdfFile@fileSize}" />
            <label for="input-checkbox-pdfFile@edit" class="acms-admin-form-checkbox">
                <input type="checkbox" name="pdfFile@edit" value="delete" id="input-checkbox-pdfFile@edit" />
                <i class="acms-admin-ico-checkbox"></i> 削除
            </label>
            <a href="%{ARCHIVES_DIR}{pdfFile@path}"><img src="%{ARCHIVES_DIR}{pdfFile@path}[pdf2thumb].png" width="120" alt="" /></a>
            <!-- END pdfFile@path:veil -->
            <input type="file" name="pdfFile" />
            <input type="hidden" name="field[]" value="pdfFile" />
            <input type="hidden" name="pdfFile@baseName" value="{pdfFile@baseName}" />
            <input type="hidden" name="pdfFile:extension" value="file" />
            <input type="hidden" name="pdfFile@extension" value="pdf" />
        </td>
    </tr>
</table>

これでエントリーを編集しても画像が消えることはなくなりました!

参考サイト

トラブルシューティングとして参考にさせていただきました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0