Reduce image size /compression before uploading using editor
Reduce image size /compression before uploading using editor
Hi all,
I have the following issue:
I worked out a small js-code, which basically take the image and resizes it.
This code works perfectly fine if I am using it with a normal HTML form.
I now wanted to apply it to the editor instances as well in order to decrease the size of uploaded images dramatically.
I used the pre-upload event for this in my js-code. As I logged everything to the console, I can see that the image compression is working properly.
However, I am not able to override the given image file by the user with my compressed version.
This what I have so far:
/*****
DEFINE PARAMETER
*****/
const MAX_WIDTH = 1000;
const MAX_HEIGHT = 1000;
const MIME_TYPE = "image/jpeg";
const QUALITY = 0.8;
//CALCULATE SIZE FUNCTION
function calculateSize(img, maxWidth, maxHeight) {
let width = img.width;
let height = img.height;
// calculate the width and height, constraining the proportions
if (width > height) {
if (width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
} else {
if (height > maxHeight) {
width = Math.round((width * maxHeight) / height);
height = maxHeight;
}
}
return [width, height];
}
editor.on( 'preUpload', function ( e, fieldName, file, ajaxData ) {
console.log(file);
var name = file.name;
const blobURL = URL.createObjectURL(file);
const img = new Image();
img.src = blobURL;
img.onerror = function () {
URL.revokeObjectURL(this.src);
// Handle the failure properly
console.log("Cannot load image");
};
img.onload = function () {
URL.revokeObjectURL(this.src);
const [newWidth, newHeight] = calculateSize(img, MAX_WIDTH, MAX_HEIGHT);
const canvas = document.createElement("canvas");
canvas.width = newWidth;
canvas.height = newHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, newWidth, newHeight);
canvas.style = "display: none";
canvas.toBlob(
(blob) => {
// Handle the compressed image. es. upload or save in local state
let file_small = new File([blob], name,{type:"image/jpeg", lastModified:new Date().getTime()});
console.log(file_small);
let container = new DataTransfer();
container.items.add(file_small);
file = container.files[0];
},
MIME_TYPE,
QUALITY
);
};
} );
Does anyone have an idea on how to achieve this / or if this is even possible here?
Thanks a lot,
Daniel
This question has an accepted answers - jump to answer
Answers
Follow up information:
So I implemented some logs and discovered the following:
The img.onload function is executed the last. So if I do a
below the img.onload function, the original file is returned. However, the right file is returned within the img.onload function.
IT seems like the img.onload is executed "too late".
Does anyone have a hint?
Thanks!
Hi,
What you need to do is, rather than changing the
file
parameter that is passed in (which just gives you access to the file - it doesn't actually get sent to the server), is modify the data insideajaxData
with the new value for the file.ajaxData.get('upload')
will get you the file, so it might be as simple as:I haven't tried that I'm afraid, but following it though, that looks right...!
Allan
Hi Allan,
thanks for the fast reply.
Yeah, I missed that one as well.
However, the last problem I am trying to solve is that the img.onload function inside the preUpload function is actually called after the upload begins.
So that's why it always uploads the "original" image.
Any idea on how to solve that?
Thanks a lot already!
Ah! Unfortunately no, at the moment there isn't a way to do that as the
onload
is async, while Editor is expecting thepreUpload
event handler to be asynchronous. I'll have a think about what we can do there - we do allow a Promise to be returned from otherpre
event handlers, so that might work nicely here as well.Allan
Ah, got you.
Yeah, that was I was thinking about as well.
Which other events could come in handy besides pre Upload?
Because I would then need to use the preUpload to resize the image,but would then need to call another event which then fires the upload.
Thanks a lot already and have a nice weekend.
The main event this is useful for is
preSubmit
- but that isn't going to help in your case here. No question for this - if you want to do resizing of images client-side it is going to need a modification to Editor to support async actions inpreUpload
. I'll look into this today and let you know.Allan
Thanks a lot Allan!
If I can help with anything, let me know.
Hi,
I've just committed a change into Editor which means things like this can now be done:
I've just used
setTimeout
there since it is a short and handy way of showing the Promise in action, but basically it means you can use an async action in the event handler now.We'll be tagging up Editor 2.0.5 later this week, but I can send you a preview if you like? Is your e-mail address using for the forum the best one to get you on?
Allan
Thanks a lot Allan!
That sounds awesome and will definitely help.
Yeah, that would be perfect. The E-Mail is the correct one.
Thanks a lot.
I'll report back here when I got a working solution.
Thanks!
Since we installed Editor 2.0.5 in our system, we were able to get client-side image compression working before uploading the files.
Thanks a lot, Allan for doing the needed changes to Editor.
I'll just share our solution here, in case it might be helpful for others.
We placed those both outside the editor.on(preUpload) function.
Now the inside of the pre-upload function:
It might not be the most elegant way to resize the images client-side before uploading, but it works indeed quite nice.
It's also nice if your user are mainly accessing Datatables and Editor from mobiles, since you can save a lot of mobile data.
Hope that helps someone and thanks again @Allan.
Kind regards,
schwaluck
Excellent, thanks for posting,
Colin