-1

How can I convert the image to Base64 and send it via AJAX for processing without using any external library?

Simple HTML

<input type="file" id="image" accept="image/*">

AJAX

$(document).on('click', '.btn-report', function(e){
  e.preventDefault();
  var image = $("#image").val(); // I WANT TO CONVERT THIS INTO BASE64
  $.ajax({
    type: "POST",
    url: "processes/report.php",
    data: 'image='+image,
    cache: false,
    enctype: 'multipart/form-data',
    beforeSend: function(){
      $(".message").hide();
    },
    success: function(data){
      $(".message").html(data).fadeIn();
      $("html, body").animate({ scrollTop: 0 }, "slow");
    }
  });
});

Is it possible? If yes, how?

Shubham Jha
  • 97
  • 10
  • https://stackoverflow.com/questions/17710147/image-convert-to-base64/17711190 pls check this link – Lovely Jun 21 '21 at 12:05
  • First question why do you want to send it with Base64, this maybe be [XY problem](https://xyproblem.info/). But if you really want to convert image to base64 you can use canvas for that [canvas to base64 on image src](https://stackoverflow.com/q/37405505/387194) – jcubic Jun 21 '21 at 12:06
  • @jcubic that's because I have a PHP function written already to upload base64 images using croppie.js. I want to use the same PHP function here too without using croppie.js and do not want to write multiple functions for single task. – Shubham Jha Jun 21 '21 at 12:08
  • Then just use canvas to draw your image and get the data url. – jcubic Jun 21 '21 at 12:16
  • @jcubic explanations don't work bro.. Can you please post an answer using my code? – Shubham Jha Jun 21 '21 at 13:36

2 Answers2

0

You need to use FileReader API to read file as base64 data URI:

$(send).on('click', () => {
    const reader = new FileReader();
    reader.addEventListener('load', (event) => {
        output.innerHTML = event.target.result;
    });
    reader.readAsDataURL(image.files[0]);
});
pre {
    white-space: pre-wrap;
    word-break: break-word;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" id="image" accept="image/*">
<button id="send">send</button>
<pre id="output"></pre>

EDIT:

$(document).on('click', '.btn-report', function(e){
    e.preventDefault();
    const reader = new FileReader();
    reader.addEventListener('load', (event) => {
        var image = event.target.result;

        $.ajax({
            type: "POST",
            url: "processes/report.php",
            data: 'image='+image,
            cache: false,
            enctype: 'multipart/form-data',
            beforeSend: function(){
                $(".message").hide();
            },
            success: function(data){
                $(".message").html(data).fadeIn();
                $("html, body").animate({ scrollTop: 0 }, "slow");
            }
        });
    });
    reader.readAsDataURL($("#image")[0].files[0]);
});
jcubic
  • 61,973
  • 54
  • 229
  • 402
  • That seems like Vanilla JS code. How can I implement that in my code? I am using jquery as you can see..! – Shubham Jha Jun 21 '21 at 14:43
  • @ShubhamJha `event.target.result` is a string with the base64 encoded data as you can see when running the demo, so just use `var image = event.target.result` and your ajax request needs to be in load function. – jcubic Jun 21 '21 at 15:03
  • @ShubhamJha Also, you can't make it more jQuery than it is. FileReader is a Native browser API. – jcubic Jun 21 '21 at 15:05
  • Not really helping. I mean, your code seems to work but I am not being able to figure out how to get the obtained Base64 value into my image variable. That's why I had asked you to show an example using my code in the question. – Shubham Jha Jun 21 '21 at 15:37
  • 1
    @ShubhamJha I've updated the question and copy-pasted (merged) your code with mine. – jcubic Jun 22 '21 at 07:57
  • I already have got the solution. See my own answer below. – Shubham Jha Jun 26 '21 at 13:46
-2

Okay so I cracked the optimal solution. For anybody who comes looking for a similar answer in the future, here it goes.

Add a new hidden input field in HTML to store the Base64 string every time the image changes.

<input type="file" id="image" accept="image/*" onchange="encodeImgtoBase64(this)">
<input type="hidden" id="b64"> // THIS WILL CONTAIN THE BASE64 STRING

Obtaining Base64 String using File Reader and using it to store the string in the above field.

function encodeImgtoBase64(element) {
  var img = element.files[0];
  var reader = new FileReader();
  reader.onloadend = function() {
    $("#b64").val(reader.result);
  }
  reader.readAsDataURL(img);
}

Finally, we will perform a simple AJAX call based upon the button on click.

$(".btn-report").on("click", function(e){
  e.preventDefault();
  var form = $(this).closest("form");
  var image = encodeURIComponent($('#b64').val());
  $.ajax({
    type: "POST",
    url: form.attr('url'),
    data: 'image='+image,
    cache: false,
    success: function(data){
      // YOUR CODES HERE
    }
  });
});

Done! Solved forever! Enjoy :D

Shubham Jha
  • 97
  • 10
  • I think that your code will never work because you will need to add encodeImgtoBase64 on change even and you will have a race condition. It may upload the previous file because the file didn't get converted yet (fileReader is async). – jcubic Jun 28 '21 at 08:25
  • What are you taking about? I posted my answer after clearing all the tests. You "think" while I have already "tried and tested" it before posting an answer. It's working great as expected (as I wanted it to be). On the contrary, you never seemed to understand my question properly and your answer wasn't exactly what I wanted. Please read my question again and then look at my answer to understand the relation between them, what I wanted and why my answer works. – Shubham Jha Jun 29 '21 at 06:24
  • 1
    If you click fast you may break your code. It will break for instance if you use automated tests that don't wait. – jcubic Jun 29 '21 at 20:37
  • Click fast what? User will click on browse button, select an image from his phone's then upload it. This process will take time. – Shubham Jha Jul 05 '21 at 11:38
  • 1
    It looks like race condition and it may fail just look at this code click runs instantly and encoded code is async and send encoded image on click instantly. The code looks broken. `reader.onloadend` will not be invoked at the same time when you click on the button. The processing of Base64 can take timem but you don't wait for the Base664 image to be decoded you send it instantly to the server. So you may end up sending empty request or when you send next request you may send previous file. This is not how you write async code. It may work but just by mistake of the browser and may fail. – jcubic Jul 05 '21 at 13:11