LoginSignup
0
1

More than 3 years have passed since last update.

【PHP】Blurhashでぼかし画像を生成する

Last updated at Posted at 2020-07-09

概要

Blurhashを利用して、blur画像(ぼかし画像)を動的に生成します。

用途としては、実際に表示される画像の想像ができるblur画像をプレースホルダーとして表示することで、読み込み時間のUXを改善しようというものです。

▼右がblur画像を用いた例
qiita_blur1.png

Blurhashの準備

公式のGithubリポジトリからソースを入手します。
複数の言語に対応しており、今回はPHPバージョンを利用します。

環境の都合でComposerを使用せず、ソースをDLして使います。
「Download ZIP」からzipをDLすることが出来ます。
qiita_blur2.png

zipを解凍すると「php-blurhash-master」というディレクトリができます。
使い勝手を考慮して「blurhash」にリネームし、ディレクトリごと好きな場所に置きます。

Blurhashを実装

Blurhashで行う処理はエンコードとデコードの2つです。

①オリジナル画像をblur画像化し、短い文字列を生成する(エンコード)
②文字列をblur画像に戻す(デコード)

qiita_blur.png

まずは必要なファイルを読み込みます。
Composerを利用していないので、requireで各ファイルを読み込む必要があります。

encode.php
<?php
use kornrunner\Blurhash\Blurhash;
use kornrunner\Blurhash\Color;
use kornrunner\Blurhash\DC;
use kornrunner\Blurhash\AC;
use kornrunner\Blurhash\Base83;

require_once('blurhash/src/Blurhash.php');
require_once('blurhash/src/Color.php');
require_once('blurhash/src/DC.php');
require_once('blurhash/src/AC.php');
require_once('blurhash/src/Base83.php');

// Composerを利用した場合は下記2行だけでOK
// require_once('vendor/autoload.php');
// use kornrunner\Blurhash\Blurhash;

// メモリが足りなければ調整
// ini_set('memory_limit', '512M');
:
:
// 続きの処理

 
まずはオリジナル画像をblur画像にして文字列にエンコードします。

encode.php
$file = 'original.png';
$image = imagecreatefromstring(file_get_contents($file));
$width = imagesx($image);
$height = imagesy($image);

$pixels = [];
for ($y = 0; $y < $height; ++$y) {
    $row = [];
    for ($x = 0; $x < $width; ++$x) {
        $index = imagecolorat($image, $x, $y);
        $colors = imagecolorsforindex($image, $index);

        $row[] = [$colors['red'], $colors['green'], $colors['blue']];
    }
    $pixels[] = $row;
}

$components_x = 3;
$components_y = 4;
$blurhash = Blurhash::encode($pixels, $components_x, $components_y);

echo $blurhash;
// 出力結果
// LEHV9uae2yk8pyo0adR*.7kCMdnj

ソースはGithubのサンプルまんまです。

ファイルを渡して処理すると、短い文字列が生成されます。
この文字列をデコードするとblur画像になります。

オリジナル画像を渡して動的にエンコード~デコードまで行うと処理に少し時間がかかりました。

そのため、オリジナル画像をエンコードして文字列を保存しておき、表示するタイミングでデコードして画像を表示させる…などといった使い方になると思います。(多分)
 

次はデコードしてblur画像を表示します。
今回はimgタグで表示させるために、getパラメータでエンコードした文字列を渡します。

view.html
<img src="decode.php?image=LEHV9uae2yk8pyo0adR*.7kCMdnj">
decode.php
$blurhash = $_GET['image']; // 生成した文字列を取得

// 画像のサイズを取得(もしくは生成したいサイズを入力)
$fileinfo = getimagesize('original.png');
$width    = $fileinfo[0];
$height   = $fileinfo[1];

$pixels = Blurhash::decode($blurhash, $width, $height);
$image  = imagecreatetruecolor($width, $height);
for ($y = 0; $y < $height; ++$y) {
    for ($x = 0; $x < $width; ++$x) {
        [$r, $g, $b] = $pixels[$y][$x];
        // if($r > 255) {$r = 255;} // 場合によって追記
        // if($g > 255) {$g = 255;} // 場合によって追記
        // if($b > 255) {$b = 255;} // 場合によって追記
        imagesetpixel($image, $x, $y, imagecolorallocate($image, $r, $g, $b));
    }
}
// 画像を出力
header('Content-Type: image/png');
imagepng($image);

これで、decode.phpに渡した文字列がデコードされ、画像として表示されます。

// 場合によって追記の3行に関しては、画像によって(例えば真っ白の画像など)RGBの値を超える?エラーが出るため、上限を設定しています。

ちなみに、公式ではデコードに関してはJavaScript/TypeScriptを使うのをおすすめしています。

blur画像を保存したい場合

blur画像を保存せずに表示する方法を書きましたが、保存も可能です。

decode.phpをブラウザで実行すれば画像が表示されるので、右クリックで保存

②最終行を下記に変更すれば、指定した先に保存されます。

// header('Content-Type: image/png');
imagepng($image, '保存先/保存名.png');

blur画像をbase64で表示する

blur画像は保存したくないけど、動的にデコード処理をするのが嫌な場合。
画像をbase64にエンコードしてsrcに渡すことで表示することができます。

decode.php
// decode.phpの最終行を以下に書き換える
// header('Content-Type: image/png');
// imagepng($image);

// 画像のGDリソースをbase64に変換する
ob_start(); 
imagepng($image); 
$image_data = ob_get_contents(); 
ob_end_clean(); 

$image_data_base64 = base64_encode($image_data);

echo $image_data_base64;
// 出力結果
// iVBORw0KGgoAAAANSUhEUgAAAeAAAAFACAIAAADrqjgsAAAACXBIWXMAAA7E....

 
base64に変換したものを保存しておき、下記のように渡すと画像が表示できます。
(ただし文字列が尋常じゃなく長い場合があるので、実装には向かない)

view.html
<img src="data:image/jpeg;base64,<?= $image_data_base64 ?>" alt="">

参考URL

0
1
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
1