2

I'm writing an application in HTML5 + JS, and at some point I need to upload the contents of a <canvas> element, which has some PNG file drawn on it. So I'm doing:

$('#img').val(canvasElement.toDataURL()); 

As You can see, I provide no arguments to toDataURL function, so the extracted image will be in PNG format. #img is a text input (with name attribute "img") that is used later to upload base64 representation of the image, extracted from canvas, to the server. I do it with AJAX, requesting a PHP file which contains the code below:

$data = explode(',', $_POST['img']);
$imgdata = base64_decode($data[1]);

$ifp = fopen('superGraphicFile.png', "wb");
fwrite($ifp, $imgdata); 
fclose($ifp);

That works, but unfortunately 300x600 PNG file is enough to make AJAX request last really long (like 20 seconds), because the file size is around 400 kB then. The amount of time needed is unacceptable in my case.

I was wondering about how to reduce the amount of data sent to the server and I thought that sending it as JPG would be cool, as we can specify the quality of the JPEG image extracted from canvas. For example, calling toDataURL('image/jpeg',0.7), makes the file over 10 times smaller than calling it with no arguments. However, I have to preserve information about transparency from the original PNG file, and since JPG can't do it, I would like to invent some way to recreate the original PNG on the server side.

At first, I thought about filling all the transparent pixels from the original PNG with some specific color, convert it to JPG, send to the server, and replace all pixels having that color with transparent pixels. This, however, would probably not work, because I also need to preserve semi-transparent pixels from the original image. Maybe there is some method to extract the alpha channel from original image, send it to the server as another JPG and apply it as a mask on the server side, recreating the original PNG that way? Or maybe I'm missing some other solution?

I thank You in advance for all Your advices.

EDIT: The 20 seconds I write about might have been some problems with my internet connection, because I didn't change anything and now it takes around a second to transfer 400 kb of data. But I still think, that saving server resources by ten and making an app work faster would be a cool thing to do.

kremuwa
  • 447
  • 2
  • 5
  • 20
  • Can JS generate a second JPG file containing the alpha channel as a simple black/white image? – ToBe Mar 18 '14 at 15:18
  • 400kb should not take 20 seconds to transfer – Turnip Mar 18 '14 at 15:18
  • @3rror404 Depends on your connection, does't it? – deceze Mar 18 '14 at 15:18
  • Well yeah. That would be a very slow connection though. I'd suggest that perhaps some of the image processing is running slow rather than just the tranfer – Turnip Mar 18 '14 at 15:22
  • @ToBe I'm asking exactly about that, I just didn't refer specifically to the mask being black and white :) – kremuwa Mar 18 '14 at 15:31
  • @3rror404 I think I have a really quick internet connection (60 Mb/s), but I check the AJAX response time in Firebug and it says 20 s :( – kremuwa Mar 18 '14 at 15:31
  • Right, didnt read all of it, sry – ToBe Mar 18 '14 at 15:41
  • 1
    Why not just display some progress bar instead of creating another image format – VitaliyG Mar 18 '14 at 16:01
  • @VitaliyG You're right, I could do that. However, I think that making an application quite a bit faster, and saving server resources (by ten!) at the same time (I mean data transfer of course, not disk space) would make such approach really sensible. And I can't see any downsides (maybe apart of more complicated code). It's just that PNGs created by toDataURL are quite large and sometimes necessary (if the application requires transparency). [Here](http://blog.import.io/tech-blog/html5-canvas-todataurl-webm-vs-png-vs-jpeg)'s a good article comparing individual formats characteristics. – kremuwa Mar 18 '14 at 16:48
  • You should also consider problem with semitransparent pixels: when image is converted to jpeg - they will be mixed with background, so you will have to restore original color somehow. IMHO this task is possible to do, but effort needed does not payoff – VitaliyG Mar 19 '14 at 15:49
  • I indicated this in the question title, and my idea (the JPEG containing an alpha channel of the PNG) would resolve this. I just don't know if it's possible to get that channel and send it as a second JPEG and then apply it with PHP on the server's side. If You have a site with hundreds of thousands of users, saving data transfer is very important, cutting it by ten seems like a reasonable payoff to me. – kremuwa Mar 19 '14 at 17:06

1 Answers1

0

I'm afraid, that you're trying to solve your problem with a dirty workaround (no offense). Converting a PNG to JPEG and back to PNG will always be a lossy transformation (including the loss of alpha channel) and will consume much more CPU cycles than just sending of the original file.

The best would probably be to look inside the code and try to optimize it somehow. In todays networks and PCs transferring/handling of 400kB should not take 20 seconds. Also in some cases a JPEG may be much bigger than a PNG - for example a screen shot of a window will be e.g. 141kB in PNG, but 245kB in JPEG.

On the other hand if it's really better to use a lossy format, than you can look at this. I have found, that there are also some other types that support transparency. Maybe you could try to use a tiff image format, which can include both the image data and the alpha channel (hopefully with JPEG compression). The only problem is, that I know only about one browser which supports TIFF out of the box (Safari).

Probably the best option is to convert to GIF. It's lossless and it will preserve transparency. Of course with no semi transparency and with limited colors.

Another option is to use JPEG 2000 as it has a higher compression with lower loss of quality and support alpha channel as well. Again Safari supports it, but Firefox needs an addon. I remember that a few years ago I had an addon for M$ Internet Explorer for JPEG 2k. I don't know about any other "major" browser with support of JPEG 2k.

Stybi
  • 41
  • 6
  • It surely is a lossy transformation (with the loss being pretty unnoticeable though), but in this case it would be a perfect solution. Forget the 20 seconds, it might be temporary problems with my internet connection. Focus on that fact: sending the PNG image as a JPG with another JPG containing alpha channel, can save server resources by ten and make the app quite a bit faster. Isn't it worth it? I'd really appreciate a possibility to increase the compression of original PNG file (even losing some of its quality), but AFAIK it's not possible. – kremuwa Mar 18 '14 at 23:19
  • Also consider, that many times PNG has much better compression ratio than JPEG itself. OK I'm not talking about a photo, where JPEG is truly much better. But when you have an alpha channel it almost surely is NOT a photo. Therefore the compression of PNG is way better than JPEG (if you don't use a 5% quality and loose all image information in it). ;-) – Stybi May 05 '14 at 09:56