Search code examples
javascriptimagefirefoxfilereader

FileReader() not working with Firefox and gib files


If I upload a large image with e.g. 20 MB, it is not displayed in Firefox, but it works without any problems in other browsers such as Chrome, Brave, Edge or Opera. For smaller images with e.g. 5 MB, the image is displayed on Firefox.

Is there any way to fix this, or is this a general bug in Firefox?

One solution would be to use URL.createObjectURL(file), but I need the image content because I also send the image to my backend.

Is there a solution to use FileReader() with Firefox?

Alternatively, I would have to display the image via URL.createObjectURL(file) and get the content via FileReader().

Code:

window.addEventListener("load", () => {
    document.getElementById("error").addEventListener("change", e => {

        const reader = new FileReader()

        reader.addEventListener("load", () => {
            document.getElementById("error_img").src = reader.result
        })
        reader.readAsDataURL(e.target.files[0])
    })

    document.getElementById("success").addEventListener("change", e => {
        document.getElementById("success_img").src = URL.createObjectURL(e.target.files[0])
    })
})
div {
    display: grid;
    grid-template:
        "a b"
        "c d";
}

img {
    display: block;
    object-fit: contain;
    width: 90%;
    height: 90%;
}
<div>
    <label>
        Error
        <input type="file" id="error">
    </label>

    <label>
        Works
        <input type="file" id="success">
    </label>

    <img src="" alt="" id="error_img">
    <img src="" alt="" id="success_img">
</div>


Solution

  • You could read the data into an ArrayBuffer and Blob (to send to the server) and create the object URL from that data for use in the img. That only reads the data once, but uses it for both things. (You could also just use the File twice, but I figured you were probably trying to avoid reading the data twice. That said, I wouldn't expect reading the data twice to cause a significant delay, and the browser may even cache it [I don't know whether it does].)

    document.getElementById("error").addEventListener("change", (e) => {
        (async () => {
            try {
                // Read the data so we can send it to the server...
                const data = await e.target.files[0].arrayBuffer();
                const blob = new Blob([data]);
                // Create URL for image
                const url = URL.createObjectURL(blob);
                document.getElementById("error_img").src = url;
    
                // ...use `data` or `blob` to send to server...
            } catch (error) {
                // ...handle/report error...
            }
        })();
    });
    

    or if you prefer:

    document.getElementById("error").addEventListener("change", (e) => {
        // Read the data so we can send it to the server...
        e.target.files[0].arrayBuffer()
        .then((data) => {
            const blob = new Blob([data]);
            // Create URL for image
            const url = URL.createObjectURL(blob);
            document.getElementById("error_img").src = url;
    
            // ...use `data` or `blob` to send to server...
        })
        .catch((error) => {
            // ...handle/report error...
        });
    });
    

    window.addEventListener("load", () => {
        document.getElementById("error").addEventListener("change", (e) => {
            (async () => {
                try {
                    const data = await e.target.files[0].arrayBuffer();
                    // Create URL for image
                    const url = URL.createObjectURL(new Blob([data]));
                    document.getElementById("error_img").src = url;
    
                    // ...use `data` to send to server...
                } catch (error) {
                    // ...handle/report error...
                }
            })();
        });
    
        document.getElementById("success").addEventListener("change", (e) => {
            document.getElementById("success_img").src = URL.createObjectURL(e.target.files[0]);
        });
    });
    div {
        display: grid;
        grid-template:
            "a b"
            "c d";
    }
    
    img {
        display: block;
        object-fit: contain;
        width: 90%;
        height: 90%;
    }
    <div>
        <label>
            Error
            <input type="file" id="error">
        </label>
    
        <label>
            Works
            <input type="file" id="success">
        </label>
    
        <img src="" alt="" id="error_img">
        <img src="" alt="" id="success_img">
    </div>