Cropper.jsで加工した画像をAjaxでLaravelに送り保存する。

この記事では、Cropper.jsを利用し画像を加工したあとに、加工した画像をAjaxを通してLaravelに渡し、その画像を保存する方法を紹介します。

Cropper.jsは、ライブプレビューとカスタムアスペクト比をサポートしており、JavaScript / jQueryプラグインを画像のトリミングに利用するのに便利です。

# 事前準備
## 1. フォルダの作成

ファイルを保存する先のフォルダを作成します。

今回、コントローラで指定するフォルダは「storage/app/public/upload」です。

ファイルをアップロードして画像を切り取って保存を押すと、このフォルダに保存されます。


# バックエンド側

## 2. ルーティング

次に下記のルーティングを設定してください。

```routes/web.php

Route::get('image-cropper','ImageCropperController@index');
Route::post('image-cropper/upload','ImageCropperController@upload');
```



## 3. コントローラ

次に下記のようなコントローラを作成します。

```app/Http/Controller/ImageCropperController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ImageCropperController extends Controller
{
   public function index()
   {
       return view('cropper');
   }
   public function upload(Request $request)
   {
       $folderPath = storage_path('app/public/upload/'); // 保存先のパス
       $image_parts = explode(";base64,", $request->image);
       $image_type_aux = explode("image/", $image_parts[0]); // ファイルの型を取り出す（今回は使わない）
       $image_type = $image_type_aux[1]; // ファイルの型を取り出す（今回は使わない）
       $image_base64 = base64_decode($image_parts[1]); // 画像データとして取り出す
       $file = $folderPath . uniqid() . '.png'; // 保存に使うファイル名
       file_put_contents($file, $image_base64); // ファイルを保存
       return response()->json(['success'=>'success']);　// JSONでレスポンスを返す
   }
}
```



# フロントエンド側
## 3. ビュー

最後にお待ちかねのビューを用意します。

ここにCropper.jsの処理も記述します。

```resources/views/cropper.blade.php

<!DOCTYPE html>
<html>
<head>
   <title>Laravel Crop Image Before Upload using Cropper JS - LaravelCode</title>
   <meta name="_token" content="{{ csrf_token() }}">
   <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous" />
   <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha256-WqU1JavFxSAMcLP2WIOI+GB2zWmShMI82mTpLDcqFUg=" crossorigin="anonymous"></script>
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.css" integrity="sha256-jKV9n9bkk/CTP8zbtEtnKaKf+ehRovOYeKoyfthwbC8=" crossorigin="anonymous" />
   <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.js" integrity="sha256-CgvH7sz3tHhkiVKh05kSUgG97YtzYNnWt6OXcmYzqHY=" crossorigin="anonymous"></script>
</head>
<style type="text/css">
img {
 display: block;
 max-width: 100%;
}
.preview {
 overflow: hidden;
 width: 160px; 
 height: 160px;
 margin: 10px;
 border: 1px solid red;
}
.modal-lg{
 max-width: 1000px !important;
}
</style>
<body>
<div class="container">
   <h1>Cropper.JSで加工した画像をAjaxでLaravelに送信</h1>
   <input type="file" name="image" class="image">
</div>
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
 <div class="modal-dialog modal-lg" role="document">
   <div class="modal-content">
     <div class="modal-header">
       <button type="button" class="close" data-dismiss="modal" aria-label="Close">
         <span aria-hidden="true">×</span>
       </button>
     </div>
     <div class="modal-body">
       <div class="img-container">
           <div class="row">
               <div class="col-md-8">
                   <img id="image" src="https://avatars0.githubusercontent.com/u/3456749">
               </div>
               <div class="col-md-4">
                   <div class="preview"></div>
               </div>
           </div>
       </div>
     </div>
     <div class="modal-footer">
       <button type="button" class="btn btn-secondary" data-dismiss="modal">キャンセル</button>
       <button type="button" class="btn btn-primary" id="crop">保存</button>
     </div>
   </div>
 </div>
</div>
</div>
</div>
<script>
var $modal = $('#modal');
var image = document.getElementById('image');
var cropper;
 
$("body").on("change", ".image", function(e){
   var files = e.target.files;
   var done = function (url) {
     image.src = url;
     $modal.modal('show');
   };
   var reader;
   var file;
   var url;
   if (files && files.length > 0) {
     file = files[0];
     if (URL) {
       done(URL.createObjectURL(file));
     } else if (FileReader) {
       reader = new FileReader();
       reader.onload = function (e) {
         done(reader.result);
       };
       reader.readAsDataURL(file);
     }
   }
});
$modal.on('shown.bs.modal', function () {
   cropper = new Cropper(image, {
	  aspectRatio: 1,
	  viewMode: 3,
	  preview: '.preview'
   });
}).on('hidden.bs.modal', function () {
  cropper.destroy();
  cropper = null;
});
$("#crop").click(function(){
   canvas = cropper.getCroppedCanvas({
	    width: 160,
	    height: 160,
     });
   canvas.toBlob(function(blob) {
       url = URL.createObjectURL(blob);
       var reader = new FileReader();
        reader.readAsDataURL(blob); 
        reader.onloadend = function() {
           var base64data = reader.result;	
           $.ajax({
               type: "POST",
               dataType: "json",
               url: "image-cropper/upload",
               data: {'_token': $('meta[name="_token"]').attr('content'), 'image': base64data},
               success: function(data){
                   $modal.modal('hide');
                   alert("success upload image");
               }
             });
        }
   });
})
</script>
</body>
</html> 
```



# 最後に

以上の実装でAjaxを通してLaravelにCropper.jsで加工した画像を送れるはずです。

ぜひ試してみてください。