Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a image src from a blob string to data URI

Tags:

javascript

I have a page where the user can paste an image into a content editable div. When I get the image the src returns a string. When I look in debug tools this is what I see:

<img src="blob:http://www.example.com/3955202440-AeFf-4a9e-b82c-cae3822d96d4"/>

How do I convert that to a base 64 string?

Here is the test script, http://jsfiddle.net/bt7BU/824/.

// We start by checking if the browser supports the 
// Clipboard object. If not, we need to create a 
// contenteditable element that catches all pasted data 
if (!window.Clipboard) {
   var pasteCatcher = document.createElement("div");
    
   // Firefox allows images to be pasted into contenteditable elements
   pasteCatcher.setAttribute("contenteditable", "");
    
   // We can hide the element and append it to the body,
   pasteCatcher.style.opacity = 0.5;
   document.body.appendChild(pasteCatcher);
 
   // as long as we make sure it is always in focus
   pasteCatcher.focus();
   document.addEventListener("click", function() { pasteCatcher.focus(); });
} 
// Add the paste event listener
window.addEventListener("paste", pasteHandler);
 
/* Handle paste events */
function pasteHandler(e) {
   // We need to check if event.clipboardData is supported (Chrome)
   if (e.clipboardData) {
      // Get the items from the clipboard
      var items = e.clipboardData.items || e.clipboardData.files;
      var itemcount = items ? items.length : 0;
      pasteArea.value = "items found:"+itemcount;
      if (itemcount) {
         // Loop through all items, looking for any kind of image
         for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf("image") !== -1) {
               // We need to represent the image as a file,
               var blob = items[i].getAsFile();
               // and use a URL or webkitURL (whichever is available to the browser)
               // to create a temporary URL to the object
               var URLObj = window.URL || window.webkitURL;
               var source = URLObj.createObjectURL(blob);
                
               // The URL can then be used as the source of an image
               createImage(source);
            }
         }
      } else {
   
       			console.log("no items found. checking input");

          // This is a cheap trick to make sure we read the data
          // AFTER it has been inserted.
          setTimeout(checkInput, 1);
       }
   // If we can't handle clipboard data directly (Firefox), 
   // we need to read what was pasted from the contenteditable element
   } else {
   
   console.log("checking input");
    
      // This is a cheap trick to make sure we read the data
      // AFTER it has been inserted.
      setTimeout(checkInput, 1);
   }
}
 
/* Parse the input in the paste catcher element */
function checkInput() {
   console.log("check input");
    
   // Store the pasted content in a variable
   var child = pasteCatcher.childNodes[0];
 
   // Clear the inner html to make sure we're always
   // getting the latest inserted content
   //pasteCatcher.innerHTML = "";
   //console.log( "clearing catcher");
   console.log(child);
    
   if (child) {
      // If the user pastes an image, the src attribute
      // will represent the image as a base64 encoded string.
      if (child.tagName === "IMG") {
         createImage(child.src);
         reader = new FileReader();
         reader.readAsDataURL(child.src);
         reader.loadend = function(e) {
         		console.log(e.target.result);
         }
      }
   }
}
 
/* Creates a new image from a given source */
function createImage(source) {
   var pastedImage = new Image();
   pastedImage.onload = function(e) {
      //pasteArea.text = pastedImage.src;
      console.log(1);
      console.log(e);
      loadImage.src = e.target.src;
      console.log(loadImage.src);
      
   }
   pastedImage.src = source;
}
<textarea id="pasteArea" placeholder="Paste Image Here"></textarea>
<img id="loadImage" />

I'm testing this in Safari on Mac.

like image 601
1.21 gigawatts Avatar asked Jan 27 '18 23:01

1.21 gigawatts


2 Answers

Since the blobURI is generated automatically by the browser, you can use this, which will download the produced image as a new Blob:

const toDataURL = url => fetch(url)
  .then(response => response.blob())
  .then(blob => new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onloadend = () => resolve(reader.result)
    reader.onerror = reject
    reader.readAsDataURL(blob)
  }))

And then on your function createImage(source) { you can call it:

toDataURL(source)
  .then(dataUrl => {
    console.log('RESULT:', dataUrl)
})
like image 60
BrunoLM Avatar answered Oct 02 '22 09:10

BrunoLM


This answer is complimentary to @BrunoLM's answer for when you don't have ES6 or you want to read in a different image type.

ES6:

const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
  const reader = new FileReader()
  reader.onloadend = () => resolve(reader.result)
  reader.onerror = reject
  reader.readAsDataURL(blob)
}))

Not ES6 (seems to work the same):

const toDataURL = function(url) { 
    return fetch(url).then(function(response) { 
        return response.blob();
    }).then(function (blob) {
        var type = blob.type;
        var size = blob.size;
        return new Promise(function(resolve, reject) {
            const reader = new FileReader();
            reader.onerror = reject;
            reader.readAsDataURL(blob);
            reader.onloadend = function() {
                return resolve(reader.result);
            }
        }
     )}
)}

Based on my understanding of ES6 (ES6 to not ES6):

var a = url => fetch(url)
var a = function(url) { return fetch(url) } 
var a = function(parameter) { return statement }

var b = (parameter, parameter) => { fetch(param, param) }
var b = function(foo1, foo2) => { return fetch(param, param) }

var c = url = () => resolve(reader.result)
var c = url = function() { return resolve() }

Making a call:

toDataURL(url).then(function(dataUrl) {
    console.log("RESULT:" + dataUrl);
});

Note:
The value returned by the above method is of type "image/tiff" when run in Safari on OSX. If you want to specify another type, such as PNG, there more info on that here.

like image 43
1.21 gigawatts Avatar answered Oct 02 '22 09:10

1.21 gigawatts