LoginSignup
5
1

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-12-13

背景

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

ソースコード

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

<input 
    type="file"
    name="multipleImages[]"
    class="form-control-file"
    onchange="resize(event)"
    accept=".jpg,.png,.jpeg,image/jpg,image/png,image/jpeg"
/>
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 })
        }


ソースコード詳細

if (uploadedFiles[i].size >= 2000000) {

容量が2MB以上だとリサイズ画像、それ以外はオリジナル画像をアップロード対象にする

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

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