How to compress image in a mobile application

How to compress image in a mobile application

  

In my mobile application. profile photo can be uploaded like whats app, etc..

For the profile photo, I want to compress before sending it to server and saving it to database. 


I saw some solution with html canvas but I have a doubt whether it works for mobile application.


Please give me a solution for compressing images.

Hi Kartick,

Compressing images with a canvas should work without problems in mobile. Have you tried?

Hi, I also need this solution...

Can anyone give me hint about compressing / resizing using HTML Canvas?

Thanks.

Hi,

How to add this canvas tag to my page in mobile application ? Does mobile application support HTML 5 tags ?

<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">



   var c=document.getElementById("myCanvas");
    var ctx=c.getContext("2d");
    var img=document.getElementById("scream");
     ctx.drawImage(img,90,130,50,60,10,10,50,60);

You can use the HTML widget for that effect, but you can also create a canvas using JS and manipulate everything in memory without adding anything to the DOM. 

Hi,

I have the following java script on change of the upload image.The parameter "Photo" contains the binary data.

var canvas = document.createElement('canvas');

    canvas.width = 200;

    canvas.height = 200;

 var ctx = canvas.getContext("2d");

var image=$parameters.Photo;

ctx.drawImage(image, 0, 0, 200, 200);

I am receiving exception in drawImage method:

Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'


How to solve this ?


Hi Kartick,

What's that $parameters.Photo? It's the image binary?

You're probably missing some steps. You should use the image binary to create a blob. Then use that blob to set the source of an HTML image element. After pass the image element to drawImage API.

For P10 mobile app, I gladly present my new Image Utils Mobile component in Forge:

https://www.outsystems.com/forge/2078/


Resize (while maintaining aspect ratio), Crop, and Identify width/height of image binary data.

All works client-side, before sending image to server...

Thats great, Thanks Harlin, I will check it out. It will be very useful.

I have couple of questions.

Does this component take care of the orientation of the image ?

After resizing, is the image height and width in the EXIF metadata also changed to the new dimensions ?

Kartick Srinivas wrote:

Thats great, Thanks Harlin, I will check it out. It will be very useful.

I have couple of questions.

Does this component take care of the orientation of the image ?

After resizing, is the image height and width in the EXIF metadata also changed to the new dimensions ?

Hi, I'm not that advanced into Javascript...

Last year I was still an Oracle Forms Developer, this year I'm into Outsystems...

Last month was my first venture into Javascript :)

So, I cannot answer your question.


This component is using JS Canvas 2D draw function, maybe you can test it if it suits your requirement.


Source code snippet:

var imgR = document.createElement("img");

imgR.onload = function () {
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext("2d");

  if (imgR.width < imgR.height) {
    canvas.height=$parameters.MaxWidthOrHeight;
    canvas.width = canvas.height * (imgR.width / imgR.height);
  } else {
    canvas.width=$parameters.MaxWidthOrHeight;
    canvas.height = canvas.width * (imgR.height / imgR.width);
  }

  ctx.drawImage(imgR, 0, 0, imgR.width, imgR.height,
    0, 0, canvas.width, canvas.height);
   
  var imageResized = canvas.toDataURL("image/png"); // get the image in BASE64
  imageResized = imageResized.substring(imageResized.indexOf(',') + 1); // remove the data:image/jpeg, part of the returned value

  $parameters.resizedImage = imageResized;      
  $resolve();
}

imgR.setAttribute('crossOrigin', 'Anonymous');
imgR.src="data:image/png;base64,"+$parameters.image;

Hi Harlin,

I tested the component, its great. The resized image's height and width in its exif metadata is correct. 

But it has following two issues - It is not taking care of the orientation of the image and also the image looks little shaken (especially straight lines in the image look out of shape) after resizing.  

Kartick Srinivas wrote:

Hi Harlin,

I tested the component, its great. The resized image's height and width in its exif metadata is correct. 

But it has following two issues - It is not taking care of the orientation of the image and also the image looks little shaken (especially straight lines in the image look out of shape) after resizing.  

Can you give me sample for orientation problem?

I'm using camera plugin, and when I take picture horizontally I don't have orientation problem.


As for image quality when drastic resize, it is known that JS Canvas resize is not good.

It is using linear algorithm, rather than Photoshop Bicubic.

I have researched into this, and so far there is many alternatives.

If I found the solution, I will update my component.


In the meantime, you can gradually resize in 2 or 3 steps, eg:

1. First resize to halved resolution

2. Second resize to quartered resolution

3. Final resize to intended resolution (or repeat more resize)


It will yield better smoothness, but will sacrifice image sharpness.

UPDATE:

I found Hermite-resize.js image resizing algorithm, it has better image quality, though not as perfect as Photoshop bicubic.

https://github.com/viliusle/Hermite-resize


Try it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/HermiteResize_Sample/Upload

Comparison: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample/Upload


Let me know of your impression.

I will update my component soon with hermite-resize.js

Hi Harlin,

After analyzing and comparing with other tool, I found that the image looked little shaken is because of the max height or width that we give, ex: an image which is 4500x3600, giving 400 as the max height or width, makes the image go slightly out of shape after re-sizing, but if we give 1400, the quality of the image is not changed.


I compared it with Image Toolbox component from forge. It is server side re-sizing. Even if we give 400x400 as new height and width for the same 4500x3600 dimension, it checks and resizes to the 1511x853 such that the image quality is not disrupted.


And regarding orientation with java script, you can refer to the below link:

http://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin



Hi Kartick, 

I will look into orientation and tried to fix it. 

About extreme/drastically resizing from 4500x3600 to 400x320, yes my JS resizing algorithm suffers in image quality.

I will try to gradually resizing it to see if it can help.

Can you give me sample image of that resolution?

Image Toolbox server side component is using ImageMagick, which is a complex algorithm designed to run using many paralel processing in multiple cpu core.

Javascript is interpreted and executed  by browser, and have slower performance than compiled native OS executable or Java bytecode.

Hi Harlin,

I have attached a sample photo taken from Samsung S7 which is 3024x4032.

Yes, true, Image Toolbox uses ImageMagick.


Hi Kartick,

Good news, it seems I got it right by gradually resizing image.

Screenshot: http://i.imgur.com/Pu4Bgn8.png


You can try it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample/Upload


It's on Forge already, you can upgrade it to test in your app.

I will try to look into orientation problem now.

Wow, yes, the resized image looks good. Great..

Please let me know once orientation is done.

Solution

Hi Kartick,

Another great news, I have managed to fix image orientation.


But I decided to make it into separate client-side actions:

1. GetOrientation: get orientation from EXIF data

2. FixOrientation: fix image orientation (accept orientation parameter)


But the thing is, GetOrientation won't work on Resize/Crop output image binary data.

Maybe EXIF is lost during Resize/Crop.


So the step is to first GetOrientation on original image binary data, Resize the image, then FixOrientation on resized image binary data using orientation from previous GetOrientation.

Please don't use FixOrientation on original/large image binary data, it will be slow...


As usual, you can test it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample/Upload


My components on Forge are already updated:

Components: https://www.outsystems.com/forge/component/2078/image-utils-mobile/

Sample/How-to: https://www.outsystems.com/forge/component/2079/image-utils-mobile-sample/

Solution

I tested it, it works great. Great job Harlin.. I am going to use this for my app. If there are any more issues, I will raise it in the forge discussions. Thank you once again.

I am using the component for my app and its great. Thanks Harlin,


Can you also create a  component for image cropping. There is already a component in forge for image cropping with rectangle shaped cropper but I want a cirlce shaped cropper like. I don't know if it is possible, but wanted to ask.


Thanks,,

Hi Kartick,

You can crop square using my component's crop action or Cropper mobile, then just apply css "img-circle" if I'm not mistaken.

There are 2 css in P10 mobile for image visual manipulation, img-circle and img-rounded.

Hi Kartick,

I have updated my component.

I added Sharpen client-side action, and updated Resize client-side action to automatically sharpen image.

Both action have input parameter sharpenFactor (decimal) with default set to 0.2


You can try it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample


Thanks Harlin. I will take update of the component. Is the default value of 0.2 enough for sharpening the image ?

How does the sharpening factor work ?

Hi Kartick, 

The default value is more than enough.

I am even considering bringing it down to 0.1.

I need your input on default sharpening factor.

You can try it, range is 0.0 - 1.0

Hi Kartick,

How about the sharpening?

Btw, I have added new AddImageWatermark feature to my component...


You can try it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample


Hi Harlin,

Sorry, didn't have time to test sharpening effect, but I will use the value that you recommend for sharpening.

What is your recommended value for sharpening ?

Also I want to know how did u achieve the Cropped Image (Square) ? What setting should I use and what values do I give ? Because in re-size I can give only one value (MaxWidthOrHeight).



Harlin Setiadarma wrote:

Hi Kartick,

How about the sharpening?

Btw, I have added new AddImageWatermark feature to my component...


You can try it here: https://harlin.outsystemscloud.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/ImageUtilsMobile_Sample




Now resize client-side action, automatically fix orientation by default.

Don't use fixorientation again, it may double rotated.

Kartick Srinivas wrote:

Hi Harlin,

Sorry, didn't have time to test sharpening effect, but I will use the value that you recommend for sharpening.

What is your recommended value for sharpening ?

Also I want to know how did u achieve the Cropped Image (Square) ? What setting should I use and what values do I give ? Because in re-size I can give only one value (MaxWidthOrHeight).

I recommend sharpening factor between 0.1 and 0.2.

For Cropped Image (Square), I use Identify client-side logic to get width and height of resized image.

Then use Crop client-side logic with width/height set to same value (either Identify.width or Identify.height).


You can look into my sample application here: http://www.outsystems.com/forge/2079/