Client side image resizing before upload? Alternative to using TinyPNG after upload

Currently I’m using TinyPNG to resize images on the upload and saving to Xano. My app allows users to upload images that are then used in PDF reports, so I resize them all to 300px max in either axis. I’m finding this process takes 20-30sec as I wait for confirmation that the images have been stored. There have been suggestions on Xano community that I let the resizing occur in the background, but that doesn’t fit my use case. The users are in the field and standing in front of something that needs to be captured and moves on after, so finding out later that a picture wasn’t uploaded is not desirable.

Are there any client-side scripts that I could use in WeWeb that would resize the images prior to the file-upload?

I would probably try importing compressorjs CDN by jsDelivr - A CDN for npm and GitHub and adding custom workflow with JavaScript to compress on the client side

If you have trouble trying this feel free to post here and I will go more in depth

1 Like

@luka thanks for suggesting compressorjs. I’m close to getting it working. The issue I’m having is that I get a editor popup error in the browser after selecting an image on my computer to upload that says: “The first argument must be a File or Blob object.”.

When I open the workflow in the editor and manually test the compressorjs action, it works, and the remaining flow succeeds. Any ideas what would cause this? For context, I’m using the Input File Drop component and allow multiple images to be uploaded, hence the iterator in my workflow. The workflow converts to base64, adds item to an array, which in a second step (Upload Button) sends to Xano.

compressorjs action script:

const originalFile = context.workflow['0ff13d37-2fda-41c8-a6b6-505ca2b2120e'].loop?.['item'];
const regex = /^.*base64,/;

if (originalFile["type"].split("/")[0] !== "image") {
  this.setState({
    ...initalState,
    message: `The file selected was a not an image type and will not be reduced.`
  });
  return; // Return undefined or any other value you want to return in this case
} else {
  return new Promise((resolve, reject) => { // Return the Promise
    new Compressor(originalFile, {
      quality: 0.9,
      maxWidth: 300,
      maxHeight: 300,
      checkOrientation: false,
      success: resolve,
      error: reject
    });
  })
    .catch(error => {
      console.log("Compress error");
      window.alert(error.message);
    })
    .finally(() => {
      console.log("Compress complete");
    });
};

I think this is an asynchronous issue with how the File Upload component loads the file info. I modified the code with the help of ChatGpt and it works. I still get the error in the editor, but not in the published version. Is this the appropriate way to handle?

async function compressFile() {
  let originalFile = variables[/* Input File Drop - value */ '571a5b7d-13f3-48be-87aa-824ed44dda5f-value'];

  while (!originalFile) {
    // Wait until originalFile is not null
    await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second
    originalFile = variables[/* Input File Drop - value */ '571a5b7d-13f3-48be-87aa-824ed44dda5f-value'];
  }

  const regex = /^.*base64/;

  return new Promise((resolve, reject) => {
    new Compressor(originalFile, {
      quality: 0.9,
      maxWidth: 300,
      maxHeight: 300,
      checkOrientation: false,
      success: (result) => {
        console.log("Compression successful");
        resolve(result); // This will return the compressed file
      },
      error: reject,
    });
  })
  .catch((error) => {
    console.log("Compress error");
    window.alert(error.message);
  })
  .finally(() => {
    console.log("Compress complete");
  });
}

compressFile();

Can you screenshot your workflow?

Here you go.

As mentioned, this workflow takes the file upload data and compresses, then encodes, and adds result to an ‘Upload_images’ var to display the uploaded image to the user. Then there is a separate workflow to upload that var to Xano on a button push.

Unfortunately I’m not sure why you’re getting this error in the editor, my best guess would be that the file upload is async so that the object is not available at that time

I believe someone more technical might offer you better insight, maybe @Alexis or @aurelie can help

I think that’s because you’re not returning anything, add

return compressFile() at the end

Well, adding return compressFile() actually causes the popup to occur 2x. Clicking on ‘Ok’ on the popup does allow the image to be processed (which is did without the new return argument too).

You need to remove the previous last line, to avoid calling compressFile() two times