Convert Image to Base64 in JavaScript without Canvas

Convert Image to Base64 in JavaScript without Canvas
Code Snippet:Base64 Image Encoder via HTML5 Canvas
Author: Monkey Raptor
Published: May 2, 2024
Last Updated: May 2, 2024
Downloads: 61
License: MIT
Edit Code online: View on CodePen
Read More

This JavaScript code helps you to convert an image to Base64 without using Canvas. It allows users to select either a local file or an external URL. For local files, it validates supported image formats before converting them to Base64. For external URLs, it checks the URL’s validity and fetches the image to encode it as Base64. The encoded Base64 data can then be used for various purposes like embedding images in HTML or CSS.

You can use this code in web development projects to convert images to Base64 format effortlessly. It’s handy for embedding images directly into HTML or CSS files, reducing server requests and speeding up page loading times. Additionally, it’s useful for creating dynamic image processing applications without relying on server-side processing.

How to Convert Image to base64 in JavaScript without Canvas

1. Start by creating the HTML structure. You’ll need elements to input local files and external URLs, as well as placeholders to display the converted Base64 data. Refer to the provided HTML code for the necessary elements and their classes or IDs.

<noscript>
    <div class="ns pt5"><span style="font-size:24px">This demo needs JavaScript</span></div>
</noscript>
<div class="all_wrapper">
    <div class="ib">
        <p class="ms"><span id="note" data-title="Use local file" class="sbg">Use local file</span></p>
        <p class="pm0 ms">
            <input type="file" id="inp" class="ms">
        </p>
    </div>
    <div class="ib">
        <p class="ms"><span data-title="Use external URL" id="notee" class="sbg">Use external URL</span></p>
        <p class="pm0 ms">
            <input type="url" id="inp_url" placeholder="image url" class="ms green">
            <input type="button" value="submit" class="ms" id="submit_url" disabled>
        </p>
    </div>
    <div class="inner_holder">
        <canvas class="canvas_styling" id="imageCanvas"></canvas>
    </div>
    <div class="inner_holder">
        <p id="st" class="ms"><small>Click below to select</small></p>
        <textarea rows="1" id="output_url" class="URI_textarea ms" onclick="this.select();document.getElementById('st').innerHTML=this.getAttribute('data-text')?'...':'Selected..';" onblur="document.getElementById('st').innerHTML=!this.getAttribute('data-text')?'Click below to select':this.getAttribute('data-text');"
        wrap="off" readonly></textarea>
        <h3 class="sub_title ms" id="sub_title">Your base-64 encoded image!</h3>
    </div>
</div>

2. Apply CSS styling to make the interface visually appealing and user-friendly. You can customize the appearance of input elements, buttons, and notification messages according to your design preferences. The provided CSS code offers a starting point for styling.

body {
    background-color: #eee;
}

* {
    line-height: normal !important;
}

body,
.ms {
    font-family: consolas, monaco, menlo, courier, monospace;
    text-align: center;
}

.pm0 {
    padding: 0;
    margin: 0;
}

.pt5 {
    padding-top: 5px;
}

.URI_textarea {
    font-size: 14px;
    padding: 10px;
    margin: 0;
    border: 0;
    box-shadow: 1px 1px 2px #555 inset;
    background-color: #ddd;
    color: darkgreen;
    resize: none;
}

.canvas_styling {
    opacity: 0;
    transition: opacity .5s;
    display: inline-block;
    border-radius: 8px;
    padding: 20px;
    background-color: #888;
    box-shadow: 0 0 20px #555 inset;
}

.inner_holder {
    box-sizing: border-box;
    overflow: auto;
    border-radius: 4px;
}

.URI_textarea,
.canvas_holder,
.all_wrapper,
.ib,
input {
    box-sizing: border-box;
}

.all_wrapper,
.URI_textarea {
    width: 100%;
}

.all_wrapper p,
.sub_title,
.all_wrapper,
.ns {
    text-align: center;
}

#inp:hover {
    cursor: pointer;
}

.sub_title {
    color: darkgreen;
}

input[type="button"] {
    background-color: #ddd;
}

.sbg,
input[type="button"],
#inp_url {
    border-radius: 4px;
    padding: 10px 20px;
}

#inp::-webkit-file-upload-button {
    border-radius: 4px;
    padding: 10px 20px;
    font-family: consolas, monaco, menlo, courier, monospace;
    border: 1px solid #555;
}

input[type="button"],
#inp_url {
    border: 1px solid #555;
}

#inp_url,
#submit_url {
    display: block;
    width: 100%;
    margin: 0 auto;
}

#submit_url {
    margin-top: 10px;
}

input[type="button"]:hover {
    background-color: #888;
    color: #fff;
    cursor: pointer;
}

#inp::-webkit-file-upload-button:hover {
    background-color: #888;
    color: #fff;
    cursor: pointer;
}

input[type="button"]:disabled {
    cursor: not-allowed;
    background-color: #ccc;
    color: #777;
}

input[type="button"]:focus {
    outline-color: #333;
}

#inp::-webkit-file-upload-button:focus {
    outline-color: #333;
}

.sbg {
    background-color: #333;
    color: #fff;
    padding: 10px 20px;
}

.all_wrapper {
    padding: 10px 0;
}

.ib {
    display: inline-block;
    vertical-align: top;
    margin-bottom: 20px;
}

.green {
    color: darkgreen;
}

.all_wrapper,
.inner_holder {
    display: none;
}

@media (max-width:640px) {
    .ib {
        display: block;
        margin: 0;
        width: 100%;
    }
    .ib:nth-child(2) {
        margin-top: 5px;
        margin-bottom: 20px;
    }
    #inp_url,
    #submit_url {
        width: 200px;
        max-width: 100%;
    }
    .pt5 {
        padding: 0;
    }
}

3. The core functionality lies in the JavaScript code. It consists of several functions to handle local file selection, external URL validation, and image conversion to Base64. Each function serves a specific purpose, such as checking file formats and loading images.

Integrate the JavaScript code into your HTML document. Ensure that the script is properly linked and executed within the <script> tags. Test the functionality by selecting local files or entering external URLs to see the Base64-encoded output.

//Updated the explanation and the coding below on May 2, 2024.
(function (d) {
    "use strict";
    //Elements/objects global variables
    var inp, out, note, notee, st, sut, iu, su, ch, aw, canvas, c2d;

    //Get element(s) (by Id or Class)
    function q(a) {        
        var buff;
        if (!(/^\./.test(a))) {
            if (d.getElementById(a)) {
                buff = d.getElementById(a);
            } else {
                buff = d.querySelector(a);
            }
        } else {
            buff = Array.prototype.slice.call(d.querySelectorAll(a));
        }
        return buff;
    }

    //IMG TESTER
    function imt(a) { // test the local file's tail-strings (allowed image format/extension)
        return (/jpe?g|gif|png|bmp|webp|svg/i).test(a);
    }

    //ELEMENTS/OBJECTS VARS INIT
    inp = q("inp"); //input file
    out = q("output_url"); //the base64 URI output text
    note = q("note"); //local file notification
    notee = q("notee"); //external url notification
    st = q("st"); //the "select"
    sut = q("sub_title"); //the bottom notification
    iu = q("inp_url"); //external url input
    su = q("submit_url"); //external url button
    ch = q(".inner_holder"); //inner holders (plural)
    aw = q(".all_wrapper")[0]; //outer holder
    canvas = q("imageCanvas"); //the canvas
    //[canvas] related
    c2d = canvas.getContext("2d");

    //CHECK HTML5 COMPATIBILITY
    (function () {
        aw.style.display = "block";
        if ((typeof canvas !== "object") && (typeof FileReader !== "function")) {
            aw.innerHTML = "<span style='font-size:24px'>Your browser doesn't support <strong>HTML5</strong> built-in API.</span>";
            //all functions below will have no triggers, because the "all_wrapper" content is changed to be just that "span" above.
        }
    }());

    //COMMON HANDLERS
    function loadThis(a) {
        canvas.width = a.width;
        canvas.height = a.height;
        c2d.drawImage(a, 0, 0);
    }
    function showElms() {
        ch.forEach(function (v) {
            v.style.display = "block";
        });
        canvas.style.opacity = 1;
    }
    function hideElms() {
        ch.forEach(function (v) {
            v.style.display = "none";
        });
        out.removeAttribute("style");
        out.value = "";
        inp.value = "";
        canvas.removeAttribute("style");
        st.removeAttribute("style");
        sut.removeAttribute("style");
        c2d.clearRect(0, 0, canvas.width, canvas.height);
        note.innerHTML = note.getAttribute("data-title");
        notee.innerHTML = notee.getAttribute("data-title");
        if (out.getAttribute("data-text")) {
            out.removeAttribute("data-text");
        }
        su.disabled = 1;
    }

    //EXTERNAL URL CHECKER
    function check_img_URL(a, b) {
        var protocol = /^https?:\/\//.test(a.value),
            btn = q(b);
        //RESET LOCAL INPUT AND OUTPUT
        if (inp.value.length) {
            inp.value = "";
        }
        note.innerHTML = note.getAttribute("data-title");
        a.removeAttribute("style");
        hideElms();
        //CHECK URL STARTS HERE
        if (protocol && a.value.length > 20 &&
                a.value.match(/\//g).length > 2 &&
                a.value.match(/\./g).length > 1 &&
                imt(a.value)) {
            btn.disabled = 0;
        } else if (a.value.length === 0) {
            hideElms();
        } else {
            a.style.color = "brown";
            btn.disabled = 1;
        }
    }

    //EXTERNAL URL HANDLER (BUTTON CLICK)
    function handle_img_URL() {
        var img_url = iu.value,
            new_img = d.createElement("img"),
            word;
        new_img.src = img_url;
        new_img.addEventListener("load", function () {
            if (new_img.complete) {
                try { //umm...
                    loadThis(new_img); //draw the image to [canvas].
                    out.value = c2d.getImageData(0, 0, new_img.width, new_img.height).data; //get URI.
                    notee.innerHTML = "Done!"; //not really.
                } catch (error) { //this'd certainly happen.
                    if (error) {
                        word = error.toString();
                        word = word.substring(0, word.indexOf(":"));
                        out.setAttribute("data-text", "<span style='color:red'>" + word + "</span>");
                        out.value = error.message;
                        out.style.color = "purple";
                        if (window.innerWidth > 1024) {
                            out.style.overflowX = "hidden";
                        }
                        st.innerHTML = "<span style='color:red'>" + word + "</span>";
                        sut.style.display = "none";
                        notee.innerHTML = "<span style='color:violet'>" + word + "</span>";
                    }
                }
                su.disabled = 1;
                showElms();
            }
        }, 0);
    }

    //LOCAL FILE HANDLER
    function handleImage(e) { // http://stackoverflow.com/a/10906961
        //the "e" is the "change" event object from the input[type='file'].
        //you can console.log(e) to find out the what's in it.
        var reader = new FileReader(),
            theFile = e.target.files[0]; //the file object being loaded.
        try {
            if (imt(theFile.type)) { //test if it has the allowed format, using imt() function - declared above.
                //to get the file size, use [size] key                
                //as in: theFile.size (using the variable "theFile") <- it's in Bytes (number).
                //to get the file name, use [name] key
                //example: theFile.name <- returns string
                reader.readAsDataURL(theFile);
                //wait for the image to load.
                reader.addEventListener("load", function (ev) {
                    //the "ev" parameter is the "reader" variable load event object.
                    //you can console.log(ev) to find out what's in it.
                    var img = d.createElement("img"); //create [img] object.
                    //the conversion product is right here [ev.target.result]
                    img.src = ev.target.result; //the [img] source -> base64 URI strings.
                    //And then listen to the load event of that [img] object.
                    img.addEventListener("load", function () {
                        loadThis(img); //draw that [img] to the [canvas].
                    }, 0);
                    out.value = img.src; //base64 URI strings.

                    note.innerHTML = "Done!"; //notification.
                    st.innerHTML = "Click below to select"; //notification.
                }, 0);
            } else {
                window.alert("Only jpg, jpeg, gif, png, bmp, webp, and svg");
                hideElms();
                return;
            }
        } catch (error) {
            if (error) { // This happens when we cancel the file window opener.
                hideElms();
                return;
            }
        }
        out.removeAttribute("style");
        showElms();
    }

    //EVENT LISTENERS
    su.onclick = handle_img_URL;
    inp.onclick = function () {
        hideElms();
        iu.value = "";
    };
    inp.onchange = handleImage;
    iu.oninput = function () {
        check_img_URL(iu, "submit_url");
    };
    iu.onclick = function () {
        iu.select();
    };
}(document));
//This demo uses the built-in input[type="file"] display with subtle CSS override.
//This is a neat snippet by Chris Coyier for styling that exciting HTML5 element: https://css-tricks.com/snippets/css/custom-file-input-styling-webkitblink/

Feel free to customize the code to suit your project requirements. You can modify the interface, add error handling mechanisms, or enhance the image processing capabilities. Experiment with different features and functionalities to create a tailored solution.

That’s all! hopefully, you have successfully created a tool to convert images to base64 in JavaScript without canvas. If you have any questions or suggestions, feel free to comment below.

Leave a Comment