ImageMagickを使用してHEICの画像ファイルをJPEGの画像ファイルに変換しました。
HEICはiOS11から使用されている画像の形式で、デフォルトでこの保存方法になっています。
2021年現在、ブラウザではHEICファイルに対応していないため、表示することができません。
スマホから画像をアップロードするような処理を書く場合で、画像を画面に表示するような処理がある時には必須になりそうだと思いました。
ですが、iOS14の端末で確認したところ、input
タグを使っている場合はiPhoneからアップロードするときにjpeg
画像になっているようです。
このため、気にしておくことは、パソコンからHEICの画像をどう扱うかということだけで良さそうです。
今回はImageMagickを使用して、HEICファイルからJPEGファイルにファイルを変換します。
Dockerを使用して、PHP8で検証しています。
ImageMagickをDockerに導入する
今回はPHPのコンテナを作るために、Dockerfileを作成しています。
DockerfileにImageMagickで使用するライブラリのインストール処理とlibheif・ImageMagickのビルドをする設定を書いてみました。
FROM php:fpm
# --- 省略 ---
# php module
RUN apt-get update && apt-get install -y \
zlib1g-dev \
git \
libzip* \
libonig-dev \
libc-client-dev \
libjpeg-dev \
libpng-dev \
libwebp-dev \
libopenjp2-7-dev \
librsvg2-dev \
libde265-dev \
libkrb5-dev \
libxml2-dev
RUN rm -r /var/lib/apt/lists/*
RUN PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
&& docker-php-ext-install zip pdo_mysql mysqli mbstring imap soap
# composer install
COPY --from=composer /usr/bin/composer /usr/bin/composer
# ---- ここでlibheifのビルドとインストール ---
WORKDIR /etc
RUN git clone https://github.com/strukturag/libheif.git
WORKDIR /etc/libheif
RUN ./autogen.sh && ./configure && make && make install
# ---- ここでImageMagickのビルドとインストール ---
WORKDIR /etc
RUN curl -OL https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-10.zip && unzip 7.1.0-10.zip
WORKDIR /etc/ImageMagick-7.1.0-10
RUN ./configure && make && make install && ldconfig /user/local/lib
# ---- imagickをPHPの拡張機能として使えるようにする ---
RUN pecl install imagick && docker-php-ext-enable imagick
解説
ImageMagickでJPEGやPNGを使えるように下記のようにライブラリのインストールを書きました。
必要なライブラリがない場合は、ImageMagickでフォーマットとして使えない形式になるようです。
RUN apt-get update && apt-get install -y \
# --- 省略 ---
libjpeg-dev \
libpng-dev \
libwebp-dev \
libopenjp2-7-dev \
librsvg2-dev
下記では、libheifというライブラリをビルドして、インストールしています。
libheifはImageMagicでHEIC画像のフォーマットを扱うために必要です。
WORKDIR /etc
RUN git clone https://github.com/strukturag/libheif.git
WORKDIR /etc/libheif
RUN ./autogen.sh && ./configure && make && make install
作業するディレクトリを/etc
で行って、ライブラリをgit clone
で落としてきます。
落としてきた後に/etc/libheif
で作業ディレクトリを切り替えて、ビルドしてインストールしている形になります。
ImageMagick本体も、gitのほうで落としてきました。
WORKDIR /etc
RUN curl -OL https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-10.zip && unzip 7.1.0-10.zip
WORKDIR /etc/ImageMagick-7.1.0-10
RUN ./configure && make && make install && ldconfig /user/local/lib
こちらの方はリリースされた(バージョンが決まっている)ものをzip形式で、curl
コマンドを使用してダウンロードしました。
libheifと同じように/etc
にダウンロードした後に、解答したImageMagickのディレクトリに移動します。
その後に、ビルドしてインストールしている形になります。
ldconfigは共有ライブラリの依存関係情報を更新するコマンドらしいです。
多分インストールした各フォーマットのライブラリとの関連づけを行っているのではないでしょうか。
convert(ImageMagick)コマンドを使用して、変換できるかテストする
実際にビルドが通ってインストールが完了したら、convertコマンドが使えるようになっています。
convert -version
でバージョンや使用できるフォーマットが確認できます。
# convert -version
Version: ImageMagick 7.1.0-10 Q16-HDRI x86_64 2021-10-05 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): fontconfig freetype heic jng jp2 jpeg png webp x xml zip zlib
Compiler: gcc (10.2)
Delegatesの箇所を見ると、heicとjpegが使用できるようになっていることが確認できました。
ここにheicやjpegなど、使用したいフォーマットがないと使ったときにエラーになるので、注意です。
convert
コマンドを使用して、heicからjpegにファイルを変換するには下記のようにします。
# convert test.HEIC test.jpg
第1引数に変換したいHEICファイルを指定して、第2引数に変換後の名前を拡張子をつけて指定します。
拡張子を見て動いてくれるようで、これでコマンドによる変換が可能です。
ImageMagickがPHPで使用できるようになっているか確認する
おなじみのphpinfo関数を実行すると、ImageMagickの項目があります。
PHPで使うときにはImagickという名前で使用します。
下記のようにImagickの項目が存在して、「ImageMagick supported formats」にHEICやJPEGなど、使いたいフォーマットが書いてあれば準備完了です。
ImageMagickを使用して、HEICからJPEG変換するサンプルコード
実際にHEICファイルをJPEGファイルに変換するサンプルコードを書いてみました。
HTMLファイル
HTMLファイルを下記のように作成しました。
ファイル名はfile_upload.htmlという名前にしました。
<html lang="ja">
<head>
<title>heic upload test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="mt-3">
<form method="post" enctype="multipart/form-data" action="file_upload.php" class="d-flex">
<input type="file" name="file" class="ml-5 mr-3 mt-2" />
<input type="submit" value="送信" class="btn btn-primary pl-3 pr-3" />
</form>
</div>
</body>
</html>
シンプルにファイルだけ指定して送信するフォームです。
POST形式で、file_upload.php
に対して、リクエストを投げます。
form
タグのenctype
属性として”multipart/form-data”を指定しないとファイルが送られないので、注意が必要です。
PHPファイル
実際にアップロードするサーバーサイドの処理を下記のように作成しました。
ファイル名はfile_upload.phpという名前にしました。
<?php
// uploadするディレクトリ
$uploadDir = './';
$fileName = $_FILES['file']['name'];
$fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$filePath = $_FILES['file']['tmp_name'];
try {
if (isset($fileName)) {
$uploadFile = $uploadDir . basename($fileName);
if ($fileExtension == 'heic') {
// heicファイルの場合はjpegに変換する
$imagick = new \Imagick();
$imagick->readImage($filePath);
$imagick->setImageFormat('jpg');
$imagick->writeImage($filePath);
$imagick->clear();
$imagick->destroy();
$uploadFile = $uploadDir . $fileName = preg_replace('/\.[^.]*$/', '', $fileName) . '.jpg';
}
if (move_uploaded_file($filePath, $uploadFile)) {
echo "successfully uploaded.<br>";
} else {
echo "upload faild<br>";
}
}
} catch (\Throwable $e) {
var_dump($e);
}
アップロードされたファイルは$_FILES
という特別なグローバル変数で取得することが可能です。
$_FILES['file']['name']
でアップロードされたファイルの名前を取得します。
strtolower(pathinfo($fileName, PATHINFO_EXTENSION))
でファイルの拡張子を小文字形式で取得します。
$_FILES['file']['tmp_name']
でファイルのパスを取得します。
ファイルは送信されたときにPHPの一時ディレクトリに保持されています。そのパスです。
if (isset($fileName))
で、ファイルがあった場合は、処理をするようにしています。
実際に変換処理をしている箇所は下記のようになっています。
if ($fileExtension == 'heic') {
// heicファイルの場合はjpegに変換する
$imagick = new \Imagick();
$imagick->readImage($filePath);
$imagick->setImageFormat('jpg');
$imagick->writeImage($filePath);
$imagick->clear();
$imagick->destroy();
$uploadFile = $uploadDir . $fileName = preg_replace('/\.[^.]*$/', '', $fileName) . '.jpg';
}
拡張子がHEICのファイルだったら変換するようにしています。
ImageMagickはImagickをnewして使います。
readImage
関数にファイルパスを入れてあげると読み込みます。
setImageFormat
関数で変換後のファイルフォーマットを指定します。
writeImage
関数で、引数で渡したファイルパスに画像ファイルを書き込みます。
今回は同じファイルパスを指定しているので、HEICで読み込んで、同じパスにJPEGで出力する感じです。
clear
関数で関連づいているリソースをクリアして、destroy
関数でnewしたImagickオブジェクトを破棄しています。
その後に、実際にアップロードするパスをuploadFile
という変数名で作成しています。
最後にmove_uploaded_file
関数を使用して、ファイルを任意の場所に移動して処理完了です。
move_uploaded_file
関数は指定したファイルの移動が成功すると、true
で失敗するとfalse
が返ってきます。
動作確認する
ローカルの/file_upload.html
にアクセスすると、下記のように作成したフォームが表示されます。
HEICファイルを選択します。
選択すると、下記のようになるので、送信ボタンを押します。
送信すると下記のようにファイルの変換処理がうまくいって、メッセージが表示されました。
実際に変換後のディレクトリを見てみると、指定したHEICファイルと一緒にJPEGファイルができていることが確認できました。
まとめ
今回はDockerfileを使用して、コンテナにHEICが使えるImageMagickを導入しました。
その後に実際にPHPを使用して、HEICファイルをJPEGファイルに変換してみました。
実際に変換処理を書いてみると、Imagick自体の使い方は難しくなく、ImageMagick本体の導入が大変だなぁ…と思いました。
LaravelでもImageMagickを使って、変換処理をやってみましたが、同じようにImagickをnewして変換するだけでした。
コメント