👌

base64の画像をフォームで送るためのFileにする方法

2021/07/27に公開

経緯

画像を加工したのち、DBや、ストレージに保存したい ということで、バックエンドにフォームを送る際、Fileにしないといけなかった。

画像加工後はbase64になっているのでそれをFileクラスでラップするにはどうすればいいかで少し詰まったので備忘録。

結論から言うと、一度バイナリにしないといけなく、base64 => バイナリへの作業が必要になった。

画像をbase64にする

<div>
    <input type='file' onchange='convertToBase64()'>
    <img src='' />
</div>
function convertToBase64 () {
    const file = document.querySelector('input[type=file]').files[0]
    const preview = document.querySelector('img');
    const reader = new FileReader()
    reader.addEventListener('load', e => {
        preview.src = reader.result;
    })

    if (file) {
        reader.readAsDataURL(file);
    }
}

FileをFormにして送信する

Formにする
function convertToForm () {
    const $inputFile = document.querySelector('input[type=file]').files[0]
    const $img = document.querySelector('img')
    const imgData = $img.src

    const imgFile = _convertToFile(imgData, $inputFile)

    const fd = new FormData()
    fd.append('image', imgFile)

    console.log(fd.get('image')); // File情報

    // fileを送信
    fetch('URL', {
	method: 'POST',
	body: fd
    })
}
Fileにする
function _convertToFile (imgData, file) {
    // ここでバイナリにしている
    const blob = atob(imgData.replace(/^.*,/, ''));
    let buffer = new Uint8Array(blob.length);
    for (let i = 0; i < blob.length; i++) {
	buffer[i] = blob.charCodeAt(i);
    }
    return new File([buffer.buffer], file.name, {type: file.type});
}

全体コード

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <input type='file' onchange='convertToBase64()'>
        <button onclick='convertToForm()'>送信</button>
        <img src="" alt="">
    </div>

    <script lang='js'>
        function convertToBase64 () {
            const file = document.querySelector('input[type=file]').files[0]
            const preview = document.querySelector('img');
            const reader = new FileReader()
            reader.addEventListener('load', () => {
                preview.src = reader.result;
            })

            if (file) {
                reader.readAsDataURL(file);
            }
        }

        function convertToForm () {
            const $inputFile = document.querySelector('input[type=file]').files[0]
            const $img = document.querySelector('img')
            const imgData = $img.src

            const imgFile = _convertToFile(imgData, $inputFile)

            const fd = new FormData()
            fd.append('image', imgFile)

            console.log(fd.get('image')); // File情報

            // fileを送信
            fetch('URL', {
                method: 'POST',
                body: fd
            })
        }

        function _convertToFile (imgData, file) {
       // ここでバイナリにしている
            const blob = atob(imgData.replace(/^.*,/, ''));
            let buffer = new Uint8Array(blob.length);
            for (let i = 0; i < blob.length; i++) {
                buffer[i] = blob.charCodeAt(i);
            }
            return new File([buffer.buffer], file.name, {type: file.type});
        }
    </script>
</body>
</html>

参考

https://gray-code.com/javascript/convert-base64-format-data-to-file-object/

https://stackoverflow.com/questions/22578530/failed-to-execute-atob-on-window

https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch

Discussion