laravel アプリケーションで　canvas を使って画像をリサイズする

## 背景
laravel アプリケーションで、画像アップロードする際に容量の問題でアップロードできない事象が発生。
画像アップロード時にフロント側で画像をリサイズする必要が出てきた。
画像リサイズ処理に canvas API なるものが使えそうだということがわかったので、
canvas 使って画像をリサイズする方針。
フロントフレームワークを使っていないので、bladeファイルにそのまま jquery を書く実装を選択。

## ソースコード

複数枚画像をアップロードするケースを想定。

```html
<input 
    type="file"
    name="multipleImages[]"
    class="form-control-file"
    onchange="resize(event)"
    accept=".jpg,.png,.jpeg,image/jpg,image/png,image/jpeg"
/>
```

```javascript
function resize(event) {
        let element = event.target
        let uploadedFiles = element.files
        let fileLength = element.files.length

        for (i = 0; i < fileLength; i++) {
            let image = new Image();
            let reader = new FileReader();
            let uploadedFile = uploadedFiles[i];
            let canvas = document.createElement('canvas')
            reader.onload = function (e) {
                image.onload = function () {
                    const MAX_WIDTH = 4000;
                    const MAX_HEIGHT = 4000;
                    let width = image.width;
                    let height = image.height;

                    if (width > height) {
                        if (width > MAX_WIDTH) {
                            height *= MAX_WIDTH / width;
                            width = MAX_WIDTH;
                        }
                    } else {
                        if (height > MAX_HEIGHT) {
                            width *= MAX_HEIGHT / height;
                            height = MAX_HEIGHT;
                        }
                    }
                    canvas.width = width;
                    canvas.height = height;
                    canvas.name = uploadedFile.name
                    canvas.type = uploadedFile.type
                    canvas.size = uploadedFile.size

                    let ctx = canvas.getContext('2d')
                    ctx.drawImage(image, 0, 0, width, height)
                    canvasList.push(canvas)

                    if (canvasList.length == fileLength) {
                        const dataTransfer = new DataTransfer();

                        for (let i = 0; i < fileLength; i++) {
                            if (uploadedFiles[i].size >= 2000000) { 
                                let blob = toBlob(canvasList[i])
                                let resizedFile = new File([blob], canvasList[i].name, {type: canvasList[i].type})
                                dataTransfer.items.add(resizedFile);
                            } else {
                                let originalFile = uploadedFiles[i]
                                dataTransfer.items.add(originalFile);
                            }
                        }

                        element.files = dataTransfer.files;
                    }
                }
                image.src = e.target.result;

            }
            reader.readAsDataURL(uploadedFile);
        }

        function toBlob(canvas) {
            let base64 = canvas.toDataURL(canvas.type)
            let bin = atob(base64.replace(/^.*,/, ''))
            let buffer = new Uint8Array(bin.length);
            for (var i = 0; i < bin.length; i++) {
                buffer[i] = bin.charCodeAt(i);
            }
            return new Blob([buffer.buffer], { type: canvas.type })
        }


```

## ソースコード詳細
```javascript
if (uploadedFiles[i].size >= 2000000) {
```
容量が2MB以上だとリサイズ画像、それ以外はオリジナル画像をアップロード対象にする


```javascript
element.files = dataTransfer.files;
```
ajaxではなく、laravel標準のフォームから画像をアップロードしたかったので、
リサイズ後の画像を再度、input要素に格納する

## 参考
https://stackblitz.com/edit/react-canvas-image-resize?file=src%2FApp.js
https://qiita.com/ysks-y/items/086d7b5a4e18f0c27929