動かざることバグの如し

近づきたいよ 君の理想に

PHPで複数画像を1枚の画像に結合する

環境

多分7以降でも動くと思う(未検証

やりたいこと

例えば以下のような画像3枚があったとして

f:id:thr3a:20181108215923j:plain

f:id:thr3a:20181108215926j:plain

f:id:thr3a:20181108215922j:plain

こんな感じに縦並びで1枚の画像に結合したい

f:id:thr3a:20181108220121j:plain

ImageMagickを使う方法

PHPからImageMagickを叩くことができる(imagick.soのインストールが必要)

さすがPHPといったところか、専用のメソッドがあるのでわずか数行で完成する。

<?php

$images = ["gazo1.jpg", "gazo2.jpg", "gazo3.jpg"];

$result = new Imagick();
foreach ($images as $path) {
  $im = new Imagick($path);
  $result->addImage($im);
}
$result->resetIterator();
$combined = $result->appendImages(true);
$combined->setImageFormat("jpeg");
header("Content-Type: image/jpeg");
echo $combined;

appendImages()時にtrueを渡しているのは縦並びに結合したいから。他の言語使ってると???ってなるが、引数にtrueだと縦並び、falseだと横並びに結合してくれる。

GDを使う場合

が、いろいろあってサーバーにImageMagickがインストールできない場合、GDを使う手もある。

<?php

function mergeImages($images) {
  $total_w = 0;
  $total_h = 0;
  foreach ($images as $path) {
    list($w, $h) = getimagesize($path);
    $total_h += $h;
    if ($w > $total_w) {
      $total_w = $w;
    }
  }

  $result_im = imagecreatetruecolor($total_w, $total_h);
  $merged_img_h_sum = 0;
  foreach ($images as $path) {
    $img = imagecreatefromjpeg($path);
    list($width, $height) = getimagesize($path);
    // コピー先の画像,コピー元の画像,コピー先のx座標,コピー先のy座標,コピー元のx座標,コピー元のy座標,コピー元の幅,コピー元の高さ
    imagecopy($result_im, $img, 0, $merged_img_h_sum, 0, 0, $width, $height);
    imagedestroy($img);
    // どこのy座標まで画像を展開したかを記録
    $merged_img_h_sum += $height;
  }
  // ブラウザに表示
  header("Content-Type: image/jpeg");
  imagejpeg($result_im);
  imagedestroy($result_im);
  // ファイルに保存
  $save_path = 'result.jpg';
  imagejpeg($result_im, $save_path);
}

$images = ["gazo1.jpg", "gazo2.jpg", "gazo3.jpg"];
mergeImages($images);

こっちは流石に関数化するレベルの行だが、やってることはそんなに難しくはない。先に空の画像を用意してforEachでそれぞれ画像を上から下へ貼り付けているイメージ。

参考リンク