サムネイルを作ってみよう【PHP】

## はじめに

サムネイルを作成する機会がありPHPで作れるのかと思ってましたが、調べたらライブラリを使えば作れるということだったので作ってみました。

**サムネイルとは**
>画像や印刷物ページなどを表示する際に視認性を高めるために縮小させた見本のこと
 from [wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%A0%E3%83%8D%E3%82%A4%E3%83%AB)

画像を一覧で表示させたいときなど、オリジナルサイズの画像を配置するとサイズが大きかったりバラバラだったりするので、読み込むのに時間がかかってしまいます。
それを解消するために、サイズや画質を落としてサムネイル画像を作成して管理します。


PHPでは[GD](https://www.php.net/manual/ja/book.image.php)というライブラリを使って作成することが可能です。

## やること
- 画像をアップロード
- 画像形式別にサムネイル作成
- アップロードされた画像をサイズに分けて出力
- 作成したサムネイルをS3へアップロード  
※S3へのアップロード処理の中身は割愛します

### 画像形式別にサムネイル作成
```php
function makeThumb ($originalFile, $thumbSize)
{
    // 画像の横幅・高さ取得
    list($originalWidth, $originalHeight) = getimagesize($originalFile);

    // サムネイルの横幅指定
    $thumbWidth = $thumbSize;
    // サムネイルの高さ算出
    $thumbHeight = round($originalHeight * $thumbWidth / $originalWidth );

    $fileType = substr($originalFile, strrpos($originalFile, '.') + 1);

    // ファイルタイプ別に作成
    if ($fileType === "jpg" || $fileType === "jpeg") {

        $originalImage = imagecreatefromjpeg($orginalFile);
        $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);

    } elseif ($fileType === "png") {

        $originalImage = imagecreatefrompng($originalFile);
        $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);

        // ※アルファチャンネル保存
        imagealphablending($thumbImage, false);
        imagesavealpha($thumbImage, true);

    } elseif ($fileType === "gif") {

        $originalImage = imagecreatefromgif($originalFile);
        $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);

        // 透明色を定義する
        $transparent = imagecolortransparent($originalImage);
        imagefill($thumbImage, 0, 0, $transparent);
        imagecolortransparent($thumbImage, $transparent);

    } else { 

        return '画像形式が正しくありません'; }

    }

    // 
    imagecopyresampled($thumbImage, $originalImage, 0, 0, 0, 0,
            $thumbWidth, $thumbHeight, $originalWidth, $originalHeight);

    // テンポラリファイルに画像出力
    $tmpFile = $_FILES['image']['tmp_name'];
    if ($fileType === "jpg" || $fileType === "jpeg"){
        imagejpeg($thumbImage, $tmpFile); 
    } elseif ($fileType === "png") {
        imagepng($thumbImage, $tmpFile);
    } elseif ($fileType === "gif") {
        imagegif($thumbImage, $tmpFile);
    } 

    // 画像破棄
    imagedestroy($originalImage);
    imagedestroy($thumbImage);
}


```

>αチャンネル（アルファチャンネル、英: alpha channel）とは画像処理分野において、各ピクセルに対し色表現のデータとは別にもたせた補助データのこと。一般に画素の不透明度 (opacity) を表現する。
from [wikipedia](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%AB%E3%83%95%E3%82%A1%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB)


### サイズ毎の画像をS3へアップロード
オリジナル、S、M、Lにサイズを分けてサムネイル画像を出力し、S3にアップロードする

```php
function uploadFile() {
    $tmpFile = $_FILES['image']['tmp_name'];
    
    // サーバーへ一時保存
    move_uploaded_file($tmpFile, 'images/test.png');
    $image = 'images/test.png';

    // サムネイルのサイズ指定   
    list($originalSize) = getimagesize($image);
    $thumbSizes = [$original_size, 200, 400, 800];
    $fileSizeNames = ['or_', 's_', 'm_', 'l_'];
    $thumbSizeAndName = array_map(NULL, $thumbSizes, $fileSizeNames);
    
    // サイズと名前を合わせてそれぞれS3にアップロード
    foreach ($thumbSizeAndName as [$thumbSize, $filSizeName]) {
        $this->makeThumb($image, $thumbSize);
        $fileName = 'images/' . $fileSizeName . 'test.png';
        $file = fopen($tmpFile, 'rb');
        
        // S3にアップロード 処理割愛
        uploadS3($file, $fileName);
    }

    //サーバー上のファイル削除
    unlink($image);
}
```
### 結果

左：L　右上：M　右下：S
![スクリーンショット 2021-01-26 23.17.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/02c21c16-7f89-b142-ecdd-5c4a86ac643f.png)
![スクリーンショット 2021-01-26 23.15.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/66ada390-5cc3-7c59-e8d8-fee0c653dc4c.png)



## 詰まったポイント

- 画像サイズに合わせて対応するサイズ名をファイルにつける

`array_map`を使って一つの変数にサイズと名前を対応させた配列を作る
第一引数がnullの場合は入力された配列を返す
foreachで回してサイズと名前を取得する
`$thumbSizeAndName = array_map(NULL, $thumbSizes, $fileSizeNames);`の結果↓

```
array(4) {
  [0]=>
  array(2) {
    [0]=>
    int(50)
    [1]=>
    string(3) "or_"
  }
  [1]=>
  array(2) {
    [0]=>
    int(200)
    [1]=>
    string(2) "s_"
  }
  [2]=>
  array(2) {
    [0]=>
    int(400)
    [1]=>
    string(2) "m_"
  }
  [3]=>
  array(2) {
    [0]=>
    int(800)
    [1]=>
    string(2) "l_"
  }
}
```


### 参考文献
[サムネイル画像の作成方法](https://webkaru.net/php/image-thumbnail/)
[PHPでサムネイル画像を作る](https://kats-eye.net/info/2019/03/07/thumbnail/)