[SOLVED] Resize image before uploading with upload control

Answered
0
0

Hi, I use a WiseJ Upload control to allow users to attach/submit photos from their camera or gallery.  Afterwards there is server-side processing and resizing. The problem is, depending on their camera settings, often times the source photo is 4 to 10MB in size, and it is a time-consuming bottleneck when on a 3G (or even) 4G cellular network.  I’m wondering if we can first do a resize on the client, to reduce the size, and make the upload faster.

I know it is possible to do this with the JS file API and by using canvasses (https://stackoverflow.com/questions/23945494/use-html5-to-resize-an-image-before-upload), but I’m not sure how this would integrate with WiseJ.

The code I have now is called from the Uploaded event. Would we need to start with the Upload_Validated event?  Or would this require a custom solution beyond the scope of the Upload control? Where should I start?

thanks,

Andrew

 

Current code: https://pastebin.com/MJcYg1wz

  • You must to post comments
Best Answer
0
0

Hi Andrew,

The upload control uses the <input type=”file”> element (there is no other way to upload files). Our control (source code is here: https://github.com/iceteagroup/wisej-js/blob/master/wisej.web.Upload.js) attaches the “change” event, reads the files list (see getFiles()) and uses the static method uploadFiles (same js code) to send the file through an ajax request using the FormData javascript class.

On the server side, the request is handled by the ASP.NET file upload handler and you get the uploaded file collection.

If you want to resize the image on the client you have to do it obviously before it is sent to the server. And since the file selected by the <input type=”file”> is not an image yet, you have to create an <img> element (or Image class), load the file, process the onload event to get the image, draw it scaled on a canvas, get the image back as a data uri from the canvas, convert it to a file object and send it to the server. Not too easy.

You can override the upload method in Wisej easily like this:

qx.Mixin.define("my.UploadPatch", {

   statics: {
      uploadFiles: function (files, submitUrl, filter, maxSize, callbacks) {
         
           // process the files
           
           // call the base implementation or replace with a custom ajax request.
           this.base(arguments, files, submitUrl, filter, maxSize, callbacks);

      }
   }

});

qx.Class.patch(wisej.web.Upload, my.UploadPatch);

HTH

  • Andrew
    So it sounds like if I can patch the QX function, and write a helper function that takes in “files” and returns a resized “files”, that would work. However I can’t even get QX to patch. Where is that code supposed to go? I placed it in default.html and Unfortunately I am still lost.
  • Luca (ITG)
    I don’ t know how to modify the files collection returned by the browser. The links you posted don’t do that – they use a jquery ajax call to post a base64 string. With Wisej you can use a web method. The patch can go in in Default.html in Wisej.onLoad = function() { … } since you need to patch the class it after it’s loaded. In alternative you can always use an HtmlPanel and put in html code.
  • Andrew
    There is a non-jQuery solution as well on the StackOverflow url, its the 2nd answer. It looks like the formData.append(‘file’, file, file.name) method (line 191 in /wisej.web.Upload.js) can also take a blob instead of a file (https://developer.mozilla.org/en-US/docs/Web/API/FormData/append). And there are base64-to-blob methods like dataURItoBlob(). So with that and considering wisej.web.Upload.js has acccess to a file instance at line 191, could we use Santiago Hernández’s solution to check for image, resize it, and post a blob instead?
  • You must to post comments
0
1

I was finally able to achieve what I was looking for from your sample (resize to a limited width and height while preserving the aspect ratio, and without risking a skew of the image)

in wisej.web.ext.ImageUpload.js I modified the img.onload function like this

 img.onload = function () {

 //set max width and height we are willing to accept
 var maxWidth = imageSize.width;//800;
 var maxHeight = imageSize.height;// 600;

 //get the original source photo width and height
 var srcWidth = img.width;
 var srcHeight = img.height;

 //define our target size variables
 var newWidth = srcWidth;
 var newHeight = srcHeight;

 //only need to resize if source dimensions exceed our maximum dimensions
 if ((srcWidth > maxWidth) || (srcHeight > maxHeight)) {
 //Conserve aspect ratio of the original 
 var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);

 //set new dimensions with aspect ratio preserved
 newWidth = srcWidth * ratio;
 newHeight = srcHeight * ratio;
 }

 canvas.width = newWidth;
 canvas.height = newHeight;

 ctx.drawImage(img, 0, 0, newWidth, newHeight);
....

(the rest is identical)

in the bottom, below  document.body.appendChild(img); , I commented out the setting of img.width = imageSize.width and img.height = imageSize.height.  Essentially this changes the behavior so the input values specify a MAXIMUM width and height, instead of a fixed width and height.

Next step is trying to implement in an existing project.

Would you be interested in adding these changes and including the ImageUpload class in a future WiseJ?

regards,

Andrew

  • Luca (ITG)
    Sorry I forgot to reply. The sample I sent you already supported preserving the aspect ratio, it was in the comments in the code, If you leave width or height to 0 it will be automatically calculated to preserve the ratio.
  • Andrew
    True, but then it doesn’t resize, and we can’t limit the width and height.
  • You must to post comments
0
0

Wow that is pretty much a complete implementation! Thanks  🙂

I tried extending it to support a “ImageSizePercent” field that could resize width and height by a percent, instead of fixed amounts (we don’t always know the orientation or size of images coming in, so its hard to resize to a fixed width and height without risking a skew of the image). Something like

if (imageSizePercent > 0) {
//resize by a percentage
img.width = img.width * imageSizePercent;
img.height = img.height * imageSizePercent;
}
else {
//resize into specified dimensions
if (imageSize.width)
img.width = imageSize.width;
if (imageSize.height)
img.height = imageSize.height;
}

 

where it overrides.

I added the new properties to ImageUpload.js and ImageUpload.cs, and while it compiles I can’t get it to work, and nothing is logged in the console.  Attached is the sample.  I can keep hacking at it but I suspect you may see what’s wrong right away.

 

 

 

  • Andrew
    45 min later I’m still nowhere :/
  • You must to post comments
0
0

See attached sample. It’s a more complete than what you find online.

  • You must to post comments
Showing 4 results
Your Answer

Please first to submit.