お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

Laravel で画像を編集する

okuda Okuda 3 years

モジュールインストール

Intervention Image が一般的なのでこれを使う

ここでは一部紹介するので、その他のファンクションは以下を参照
Intervention Image

composer require intervention/image

読み込み

use Image;

class CheckController extends Controller
{
    public function index(Request $request)
    {
        $img = Image::make($request->file('photo'));
    }
}

引数は以下に対応

  • 画像のパス
  • 画像のURL
  • 画像データ(バイナリ)
  • data URLの画像データ
  • GDのリソース
  • ImageMagickのインスタンス
  • SplFileInfoのインスタンス
  • UploadedFileのインスタンス
$image = storage_path('app\lion.jpg');
$image = Storage::disk('local')->path('lion.jpg');
$image = Storage::disk('local')->get('lion.jpg');
$image = 'https://picsum.photos/200/300';

$img = Image::make($image);

画像操作

保存、画質

save()

  • param1: パス - string
  • param2: 画質 - int
    • デフォルト = 30
    • 値 = 0 ~ 100
// デフォルト 画質30
$path = storage_path('app\lion1.jpg');
$img->save($path);

// 画質 100
$img->save($path, 100);

ぼかし

blur()

  • param1: ぼかし - int
    • 値 = -100 ~ 100
// ぼかし小
$img->blur(0);
// ぼかし大
$img->blur(100);

モザイク

pixelate()

  • param1: モザイクの大きさ - int
$img->pixelate(10);

明るさ

brightness()

  • param2: ボケ - int
    • 値 = 0 ~ 100
// 暗い
$img->blur(0);
// 明るい
$img->blur(100);

色調

colorize()

  • param1: 赤 - int
    • 値 = -100 ~ 100
  • param2: 緑 - int
    • 値 = -100 ~ 100
  • param3: 青 - int
    • 値 = -100 ~ 100

コントラスト

contrast()

  • param1: コントラスト - int
    • 値 = -100 ~ 100

コントラスト

contrast()

  • param1: コントラスト - int
    • 値 = -100 ~ 100

トリミング

crop()

  • param1: 幅 - int
  • param2: 高さ - int
  • param3: X座標 - int
    • デフォルト = 0
  • param4: Y座標 - int
    • デフォルト = 0
$width = 200;
$height = 200;
$x = 50;
$y = 50;

$img->crop($width, $height, $x, $y);

フリップ

flip()

  • param1: 向き - stirng
    • デフォルト = h
    • 値 = h: 上下、 v: 左右
$img->flip();
$img->flip('v');

サイズ

resize()

  • param1: 幅 - int
  • param2: 高さ - int
  • param3: function
// 比率無視
$img->resize(100, 100);
$img->resize(100, null);
$img->resize(null, 100);

// 比率維持 幅は指定、高さは自動
$img->resize(100, null, function($constraint){
    // 比率を維持
    $constraint->aspectRatio();
});

サイズ 幅・高さを基準

$img->widen(); $img->highten();

  • param1: 値 - int
  • param2: function
// 横幅を基準
$img->widen(100);
// 高さを基準
$img->heighten(100);

// 自動調整
$img->widen(500, function ($constraint) {
    // もとのサイズより大きくしない
    $constraint->upsize();
});

回転

rotate()

  • param1: 度数 - int
  • param3: 背景 - string
    • デフォルト = #ffffff
$img->rotate(-45);
// 背景赤
$img->rotate(-45, '#f44336');

透過度

rotate()

  • param1: 度数 - int
  • param2: 背景 - string
    • デフォルト = #ffffff
$img->rotate(-45);
// 背景赤
$img->rotate(-45, '#f44336');

変換

encode()

  • param1: フォーマット - string
    • 値 = jpg、png、gif、tif、bmp、ico、psd、webp、data-url、
$jpg = $img->encode('jpg');

取得

// 幅
$value = $img->width();
// 高さ
$value = $img->height();
// ファイルサイズ
$value = $img->filesize();
// ファイルサイズ(バイト)
$value = $img->filesize();
// マイムタイプ
$value = $img->mime();
// 座標位置で色を取得
$value = $img->pickColor(10, 10); // デフォルトは配列を返す
$value = $img->pickColor(10, 10, 'rgba'); // rgba
$value = $img->pickColor(10, 10, 'hex'); // hex
$value = $img->pickColor(10, 10, 'int'); // int
$value = $img->pickColor(10, 10, 'obj'); // obj
// EXIFデータ
$value = $img->exif();
// でもこっちのほうが情報が多い
$value = exif_read_data($image)

// saveする前でもストリームを取得できる
$value = $img->stream(); // デフォルトは現在の画像のタイプでエンコード
$value = $img->stream('png', 50); // フォーマットと画質を指定
// 表示する
return response($value)->header('Content-type', $img->mime());
// responseを使うとこれだけで表示できる
return $img->response();
return $img->response('png', 50); // フォーマットと画質を指定

実用

ログインしないと見れないimage

s3に画像を保存

s3のphotosフォルダに保存、 public はつけない


// get disk
$s3 = Storage::disk('s3');

// ファイルオブジェクト取得
$photo = $request->file('photo');

// 拡張子を取得
$ext = $photo->extension();

// s3にprivateで保存
$res = $s3->putFileAs('photos', $photo, "{$filename}.{$ext}");

コントローラ作成

s3に保存した画像をimageコントローラを作成してimageルートにする

php artisan make:controller ImageController --invokable

app\Http\Controllers\ImageController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class ImageController extends Controller
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function __invoke(Request $request, $path)
    {
        // get disk
        $s3 = Storage::disk('s3');

        // ファイルの有無をチェック
        if($s3->missing($path)){

            // ない場合は404
            abort(404);
        }

        // マイムタイプを取得
        $mimeType = $s3->mimeType($path);

        // コンテンツを取得
        $content = $s3->get($path);

        // イメージとしてリターン
        return response($content)->header('Content-type', $mimeType);
    }
}

ルート

routes\web.php

// auth
Route::group(['middleware' => ['auth:sanctum']], function () {

        // image
        Route::get('/image/{path}', ImageController::class)->where(['path' => '.*'])->name('image');
    }
);

その他

EXIFからGPSデータを取る


$photo = $request->file('photo');
$img = Image::make($photo);
$exif = $img->exif();
$geo = getGeo($exif);

// [
//   "lat" => 34.729144416667
//   "lng" => 135.32888888889
//   "alt" => 8.3793716656787
// ]

public function getGeo($exif)
{
    // 返す値
    $result = [
        'lat' => null,
        'lng' => null,
        'alt' => null,
    ];

    // 必要な情報を取得
    $alt_ref = data_get($exif, 'GPSAltitudeRef');
    $alt_gps = data_get($exif, 'GPSAltitude');
    $lat_ref = data_get($exif, 'GPSLatitudeRef');
    $lat_gps = data_get($exif, 'GPSLatitude');
    $lng_ref = data_get($exif, 'GPSLongitudeRef');
    $lng_gps = data_get($exif, 'GPSLongitude');

    // 緯度経度がなければfalse
    if (!($lat_ref && $lat_gps && $lng_ref && $lng_gps)) {
        return false;
    }

    // 高度を取得
    if ($alt_ref && $alt_gps) {
        $segments = explode('/', $alt_gps);
        $data = (isset($segments[1])) ? $segments[0] / $segments[1] : $alt_gps;
        // 0 = 海抜、 1 =海面下
        // $ref = ord($alt_ref) == 0 ? 'above' : 'Below';
        data_set($result, 'alt', $data);
    }

    // 緯度経度を取得
    $coordinates = [
        'lat' => ["ref" => $lat_ref, "gps" => $lat_gps],
        'lng' => ["ref" => $lng_ref, "gps" => $lng_gps],
    ];

    foreach ($coordinates as $key => $coordinate) {

        $ref = $coordinate['ref'];
        $gps = $coordinate['gps'];

        // 分数からフロートに変換
        $floats = array_map(function ($gps) {
            $segments = explode('/', $gps);
            return (isset($segments[1])) ? $segments[0] / $segments[1] : $gps;
        }, $gps);

        $amount = $floats[0] + ($floats[1] / 60) + ($floats[2]) / 3600;
        $data = ($ref == 'S' || $ref == 'W') ? ($amount * -1) : $amount;

        // 値をセット
        data_set($result, $key, $data);
    }

    return $result;
}
Laravel で画像を編集する 2021-11-19 08:55:11

コメントはありません。

4757

お気軽に
お問い合わせください。

お問い合わせ
gomibako@aska-ltd.jp