5

Any way to convert any image to webp with filepond?

This is my code:

import vueFilePond, { setOptions } from 'vue-filepond'

// ...

setOptions({
  server: {
    process: (field, file) => {
      file.name = String(file.name.substr(0, file.name.lastIndexOf('.'))) + '.webp';
      file.type = 'image/webp';
      // ... upload to firebase storage
    }
  }
})

Cannot assign to read only property 'name' of object '#'

Rimuru Tempest
  • 153
  • 1
  • 2
  • 7

2 Answers2

6

You can't "just" change the name and the type of the file and be done with it.

  1. The file name and type are readonly, you'll have to create a new file based on the old one and then you can assign a new name and type.
const myRenamedFile = new File([myOriginalFile], 'my-new-name');

More on renaming files

  1. Changing the type property doesn't change the actual file data. Rename a .png to .jpeg and the file data (the bits) will still be a JPEG compressed image.

To transform the data you need to read the original file and then transform it to the WEBP format. You can do so with the .toBlob() method available on the canvas element.

const image = new Image();
image.onload = () => {

  const canvas = document.createElement('canvas');
  canvas.width = image.naturalWidth;
  canvas.height = image.naturalHeight;
  canvas.getContext('2d').drawImage(image, 0, 0);
  canvas.toBlob((blob) => {
    
    // Now we have a `blob` containing webp data

    // Use the file rename trick to turn it back into a file
    const myImage = new File([blob], 'my-new-name.webp', { type: blob.type });

  }, 'image/webp');

};

image.src = URL.createObjectURL(myFile);

Obviously creating a WEBP image doesn't work on browsers that don't support WEBP like Safari 13.x, IE11, and Edge 17. Support on Firefox is available since the start of 2019 and Chrome has supported WEBP for ages.

If you need to support those browsers you could use a separate JavaScript library to do the image encoding. For example webpjs.

drglove
  • 638
  • 1
  • 6
  • 21
Rik
  • 3,328
  • 1
  • 20
  • 23
  • This doesn't currently work in Firefox 84. Even with supposed webp support, toBlob with image/webp falls back to a png encoded blob. – drglove Jan 25 '21 at 08:06
  • link is brken. how can this be done now without canvas? – Yeets Sep 04 '22 at 23:06
1

Yes, You can do it with the below source code it's not just changing your image format to .webp but also converting the whole image.

It gives the option to convert .jpeg, .png file to a .webp format.

Source Code : Image To Webp Converter

let refs = {};
refs.imagePreviews = document.querySelector('#previews');
refs.fileSelector = document.querySelector('input[type=file]');

function addImageBox(container) {
  let imageBox = document.createElement("div");
  let progressBox = document.createElement("progress");
  imageBox.appendChild(progressBox);
  container.appendChild(imageBox);
  
  return imageBox;
}

function processFile(file) {
  if (!file) {
    return;
  }
  console.log(file);

  let imageBox = addImageBox(refs.imagePreviews);

  // Load the data into an image
  new Promise(function (resolve, reject) {
    let rawImage = new Image();

    rawImage.addEventListener("load", function () {
      resolve(rawImage);
    });

    rawImage.src = URL.createObjectURL(file);
  })
  .then(function (rawImage) {
    // Convert image to webp ObjectURL via a canvas blob
    return new Promise(function (resolve, reject) {
      let canvas = document.createElement('canvas');
      let ctx = canvas.getContext("2d");

      canvas.width = rawImage.width;
      canvas.height = rawImage.height;
      ctx.drawImage(rawImage, 0, 0);

      canvas.toBlob(function (blob) {
        resolve(URL.createObjectURL(blob));
      }, "image/webp");
    });
  })
  .then(function (imageURL) {
    // Load image for display on the page
    return new Promise(function (resolve, reject) {
      let scaledImg = new Image();

      scaledImg.addEventListener("load", function () {
        resolve({imageURL, scaledImg});
      });

      scaledImg.setAttribute("src", imageURL);
    });
  })
  .then(function (data) {
    // Inject into the DOM
    let imageLink = document.createElement("a");

    imageLink.setAttribute("href", data.imageURL);
    imageLink.setAttribute('download', `${file.name}.webp`);
    imageLink.appendChild(data.scaledImg);

    imageBox.innerHTML = "";
    imageBox.appendChild(imageLink);
  });
}

function processFiles(files) {
  for (let file of files) {
    processFile(file);
  }
}

function fileSelectorChanged() {
  processFiles(refs.fileSelector.files);
  refs.fileSelector.value = "";
}

refs.fileSelector.addEventListener("change", fileSelectorChanged);

// Set up Drag and Drop
function dragenter(e) {
  e.stopPropagation();
  e.preventDefault();
}

function dragover(e) {
  e.stopPropagation();
  e.preventDefault();
}

function drop(callback, e) {
  e.stopPropagation();
  e.preventDefault();
  callback(e.dataTransfer.files);
}

function setDragDrop(area, callback) {
  area.addEventListener("dragenter", dragenter, false);
  area.addEventListener("dragover", dragover, false);
  area.addEventListener("drop", function (e) { drop(callback, e); }, false);
}
setDragDrop(document.documentElement, processFiles);
Sagar Ambade
  • 49
  • 2
  • 16