Skip to content Skip to sidebar Skip to footer

Specify The Type Returned From FileReader ReadAsDataURL() As PNG And Not TIFF?

I'm getting an image that has been pasted into the content editable div and during paste the types in listed in the Clipboard include 'image/png' and 'image/tiff'. When I get that

Solution 1:

You don't.
FileReader.readAsDataURL() only converts the binary data held in the passed Blob to a base64 string, it doesn't do any other conversion.
It will only prepend the corresponding MIME header to whatever it thinks this data is (this check is first done against the Blob's type, and then probably against magic-numbers), but you can't force it to convert the data to something else.

const fr = new FileReader();
const fakeGif = new Blob(['foo'], {type:'image/gif'});
fr.onload = onload;
fr.readAsDataURL(fakeGif);

function onload(){
  console.log(fr.result); // with image/gif MIME
  console.log(atob(fr.result.split(',')[1])) // still just "foo"...
}

Now to your case, since Safari still doesn't support the DataTransferItem interface, you are out of luck.

Even though Grab utility does save a png File in the clipboard, Safari chose to display the tiff raw data.

You can check this assertion in your dev's Network panel, where you will see that the image is fetched as image/tiff.

Browsers that do support DataTransferItem interface can retrieve the png file attached in the clipboard though, so let's hope Safari implement this interface soon enough.

So one way to convert this TIFF image to a png one, is to go through a canvas element:

// an Array to hold pasted Files
var files = [];

// We start by checking if the browser supports the 
// DataTransferItem interface. If not, we need to create a 
// contenteditable element that catches all pasted data 
if (!window.DataTransferItem) {
  var pasteCatcher = document.createElement("div");
  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;
    itemcount = items.length;
    if (itemcount) {
      // Loop through all items, looking for any kind of image
      for (var i = 0; i < items.length; i++) {
        getItem(items[i]);
      }
    } else {
      // 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);
  }
}
/* For browsers that support DataTransferItem interface */
function getItem(item)  {
  if (item.type.indexOf("image") !== -1) {
    // We need to represent the image as a file,
    var blob = item instanceof Blob ? item : item.getAsFile();
    // save the File for later use if needed
    files.push(blob);
    // 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);
  }
}
/* For older browsers */
/* Parse the input in the paste catcher element */
function checkInput() {

  // Store the pasted content in a variable
  var child = pasteCatcher.childNodes[0];

  if (child) {
    // If the user pastes an image, the src attribute
    // will represent the image as a base64 encoded string.
    if (child.tagName === "IMG") {
      getPngFromIMG(child, function(blob) {
        // Clear the inner html to make sure we're always
        // getting the latest inserted content
        pasteCatcher.innerHTML = "";
        // save the png blob in our list
        files.push(blob);
        createImage(URL.createObjectURL(blob));
      });
    }
  }
}

function getPngFromIMG(img, callback) {
  if (img.naturalWidth) // if already loaded
    draw();
  else
    img.onload = draw;

  function draw() {
    var canvas = document.createElement('canvas');
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;
    canvas.getContext('2d').drawImage(img, 0, 0);
    canvas.toBlob(callback);
  }
}
/* Creates a new image from a given source */
function createImage(source) {
  var pastedImage = new Image();
  pastedImage.onload = function(e) {
    loadImage.src = e.target.src;
  }
  pastedImage.src = source;
}

btn.onclick = function() {
  console.log(files);
}
<textarea id="pasteArea" placeholder="Paste Image Here"></textarea>
<img id="loadImage" />
<button id="btn">do something with pasted files</button>

Post a Comment for "Specify The Type Returned From FileReader ReadAsDataURL() As PNG And Not TIFF?"