Largest potential PNG size given certain dimensions
Asked Answered
H

1

7

I'm currently creating an HTML5 canvas-based drawing program. The user can draw an image, or several 'pages' of images, and save it to the cloud for quick retrieval later. This is for use on an interactive whiteboard; the teacher cannot always be certain that the IWB they plan the lesson on is the one they will use in that class, so I want to make the data accessible from anywhere.

I am sending the canvas data to the server as data URIs via Ajax, storing the data on the file system and a reference to the file in a database. My problem is that I'm not sure how much space on the file system these images will eventually take up.

The files are saved as PNGs with an alpha transparency layer, and are 1280x720px. Depending on what is drawn, the file size varies significantly, which I assume is because PNGs are compressed. Because of this, I'm having trouble calculating the maximum possible file size that such an image could be. Since I want to assume a worst-case scenario, I'll assume that the PNG compression does nothing to decrease the file size. Given that, would the maximum file size be:

1280 x 720 x colordepth

? If so, what value should colordepth be, given I am exporting the images using canvas.toDataURL()? Would it differ depending on browser implementations of canvas? I'm totally in the dark here.

I know PNG compression doesn't do well with photo-style images, so I have been trying to create something not easily compressible (mainly soft, fairly random gradients). The largest I have been able to create was about 675KB, but I'm sure that is nowhere near the potential maximum size.

So I either need to know what the maximum file size could be, or what kind of image would offer the least potential for compression in a PNG, so I can experiment better.

I hope this makes sense.


There are a few similar questions on SO:

but none seemed to answer my question. Do enlighten me if I have missed something.


UPDATE

I've given Ken Fyrstenberg's idea a try, and the preliminary results are quite something. Storing the image as a serialized object results in a set of data less than a quarter the size of the equivalent dataURL string. And this is before I've even begun to optimize it. I highly recommend anyone in a similar situation gives this method a try.


ANOTHER UPDATE

When I first started this, I was using SVG. However, the more the user drew, the more DOMElements had to be onscreen at once, and the slower the response time became (especially with > 1000 elements). I had assumed that doing it with canvas and storing each stroke in an array as the user made it, there would be a similar issue. 'Tis not so.

I guess there is much less overhead in simply storing path data, as compared to keeping track of a DOM element and all its properties, position in the document and relation to other elements.

Upshot is, no matter how many strokes I stick into the array, the redraw operation is always lightning fast. This in addition to the aforementioned reduction in size when storing the data for later use, and incredibly easy implementation of undo/redo. Very impressed with both Javascript and canvas right now.

Hildredhildreth answered 6/12, 2013 at 4:3 Comment(0)
E
8

To calculate the size of the bitmap PNG uses assuming alpha channel is present

width x height x 4

will give you size as raw uncompressed bytes.

The reason 4 is used is because RGBA will be (typically) represented as 32-bits (hence 4 bytes).

If no alpha channel is present than multiply with 3 instead (24-bit, RGB each 8-bits).

In addition to that header and chunks will add to the size but compression will reduce the size.

I however think this will give you a good enough number for this purpose as a max value.

In your case the size will be max:

1280 x 720 x 4 = 3 686 400 bytes

To get to kilobytes divide on 1024, to get that to mb divide again on 1024 (here the result would be 3.5mb).

Tip: For sharing drawings you might want to consider sharing serialized objects instead of the data-uri as the data-uri creation is performance hungry and will create unnecessary overhead, while serialized objects typically has low size and low performance impact. They are easier to transfer over net as well. Objects could contain the lines positions, colors etc.

Endgame answered 6/12, 2013 at 4:8 Comment(6)
Wow, thank you! That's so easy to understand. Do you know if canvas always outputs as RGBA? I have been looking at the spec but cannot find a specific reference to it.Hildredhildreth
@DavidJohnWelsh No problem! :) and yes, canvas will always give you RGBA. The only exception is with toDataURL (ie. jpeg and similar RGB formats)Endgame
Actually, when I originally started this I was doing it as an SVG, thinking that it would be easier to store the data and simpler to implement stuff like undo (which I am doing now using layered canvases). Now you've got me wondering if I should just store each path as the user creates it; this would also mean I could do everything without the extra canvases and, as you say, probably decrease the storage required significantly... very interesting idea, thank you! Wish I could upvote again....Hildredhildreth
"compression will reduce the size" That's often (almost always) true, but not always. If the image is pure noise, compression will actually increase (very little) the size, in adittion to the headers+chunks overhead.Ludendorff
@Ludendorff he is drawing on a canvas. it's very hard to make noise images that way.. I think it's fairly safe to say the scenario where compression increase size is unlikely here.Endgame
@Ludendorff Ken is right - unless a user deliberately and painstakingly decided to paint noise one pixel at a time, it is not likely to be an issue. I didn't know noise could have that effect on compression though, so thanks. Might come in handy down the road.Hildredhildreth

© 2022 - 2024 — McMap. All rights reserved.