Hacker News new | past | comments | ask | show | jobs | submit login
Using canvas to create alpha-channel JPEGs - 33% the size of PNGs (jackadam.net)
124 points by thegrossman on Oct 5, 2010 | hide | past | web | favorite | 32 comments

Instead of using canvas, for webkit at least it makes more sense to use http://webkit.org/blog/181/css-masks/ Canvas is a good fall-back for other browsers.

Yeah, CSS masks make a lot of sense.

Internet Explorer also has some weird filter properties that almost -- but not quite -- do what we need. If someone can figure it out, it would be significantly better than using FlashCanvas.

You would have to invert the mask so that the black was the content you wanted to keep and the white was the content you wanted transparent to get it to work with CSS masks, instead of the other way around as in this demo.

For even bigger bandwidth savings paint a solid color over the non-visible portion of the jpg. There's no need to transmit all that image data if you aren't going to show it.

For this example I was able to quickly trim the jpg size from 35k to ~24k in about 60 seconds using Photoshop.

Since JPEG is lossy just by adjusting the quality level you can save JPEG in any size.

So your test doesn't tell us anything - maybe you just used a lower quality level.

(Although I agree with the basic premise, post editing the image isn't such a good idea. Instead use a lossless jpeg editor that can selectively cut out portions of the jpeg.)

> Since JPEG is lossy just by adjusting the quality level you can save JPEG in any size.

And get a blocky crapbucket as a result. By making unused/un-displayed sections of the JPEG (or PNG or whatever) file easier to compress (which still requires some basic insight as to how the file's compression is performed), you lower the file's size at constant perceived quality. That would be the point.

I think what he's saying is that the original parent might not know what the quality setting was that they were using in the post, and as such the quality setting may very well differ. This would lead to varying file sizes despite the presence of the blanked area.

I think we can agree that my 60 second test wasn't very scientific (nor was it meant to be), but I'm confident that the result is still typical of the type of savings you'd see using a more controlled process.

Since we're nitpicking, I might as well point out that you can't "cut out" portions of a jpeg either.

Actually you can. See the jpegtran command - it works losslessly on the DCT.

If you do want to cut out the alpha region, do not trim right up to the image. Instead trim only in 16 pixel blocks. By having a sharp edge inside a macroblock you increase the storage requirements.

No one has written it currently as far as I know, but it's also possible to selectively remove/replace 16x16 pixel blocks inside the jpeg losslessly.

This was a common technique in game development a years ago, back when gospel was no larger than 10MB for downloadable casual games. You can get great compression with GIF/PNG for alpha channel and JPG or JPEG2000 for color data. The downside is you usually get multiple compression artifacts on screen (assuming texture compression like DXT), which doesn't apply for web use.

I take it he means an 8-bit alpha channel, not a 24-bit alpha channel?

Anyway, here's the JPEG FAQ explaining why using JPEG for alpha wouldn't be a good idea even if it was supported: http://www.faqs.org/faqs/jpeg-faq/part1/section-12.html

Yep, but that article goes on to say:

The only real solution is to combine lossy JPEG storage of the image with lossless storage of a transparency mask using some other algorithm.

Which is exactly what the OP has done.

Sure, I didn't mean to imply that it contradicts the OP's hack.

One thing that hasn't been addressed is the cost of making the second image request. There is probably a break even point for this technique where it becomes useful, but the added complexity greatly limits its utility.

  >  In one case we got a 573KB 24-bit PNG down to a
  > 49KB JPEG with a 4KB PNG alpha-mask!
I somehow don't think that the cost of using two requests vs just one really matters with that kind of size difference (unless you're serving high-latency customers on satellite internet or something).

> I somehow don't think that the cost of using two requests vs just one really matters with that kind of size difference

On DSL it probably doesn't (let's consider a 150ms ping, we'll take that as the time to initiate an HTTP connection, with 10Mbps of bandwidth or 1.25MB/s): the single image will take 150ms + 440ms (download) for a total of 590ms, whereas the pair will take 2x150ms + 40ms + 3ms for a total of 343ms.

Now consider 3G: 3.6Mbps (460KB/s) (we'll consider a pretty basic HSDPA) and pings of around 600ms are common. The single image takes 600ms + 1246ms for a total of 1846ms, whereas the pair takes 2x600ms + 100ms + 9ms for a total of 1309ms. Still lower, but we're getting closer. 7.2Mbps HSDPA bumps the bandwidth to 920KB/s and doesn't change the ping significantly. Now the single image only takes 632ms to download for a total of 1232ms, and the pair takes 54ms for a total of 1254ms.

And cell data usage will only grow further.

Now of course, a 573KB full-color PNG is going to be hell on a mobile browser and its cache, but still, HTTP request cost is coming back with a vengeance as HSPA makes high amounts of bandwidth available.

That would certainly be beyond the break even point. :) In that case it's definitely another tool to keep in the back pocket in case needed.

(Somehow I missed that line in the article by focusing in on the code.)

Could also use a data uri for the mask if a second request is really an issue.

Maybe this should be done by extending JPEG to support alpha channel?

It might have better chances for adoption than completely new format like WebP.

We'll just have another decade of complaining that IE doesn't support alpha, but we've been there and survived :)

Actually, this is completely doable, even backwards compatible, with javascript:

JPEG has support for arbitrary metadata, mostly used today to put EXIF data in the files. IIRC, there's no reason we couldn't store a base64'd or even binary raw PNG file in there.

Once we put it in, we need to be able to extract it. There are EXIF javascript libraries out there, so that shouldn't be too much of a problem, since it's the same idea. I'm unsure if a binary raw PNG file could be used to generate the alpha channel like in the original article, but at least using the base64-encoded bitstream should be possible since that's natively supported.

It's backwards compatible since it uses the same structure as EXIF uses, which just gets ignored by non-compatible image viewers. Something easier might be to store a URL to the alpha channel PNG image in the EXIF, and then use javascript to download that image and use it as the alpha channel.

If I wasn't getting ready for a 2 month trip, I'd spend an hour or two whipping this up. Feel free to take this info and whip something up yourself!

That is a neat implementation and a nice hack to implement it with XOR.

You've also taught me another valuable less: I created exactly this (actually with slightly different masking method) about a year ago, but I never got around to releasing it. Thank you for reminding me that real artists ship.

Seems to crash safari on the iPad too.

Sure it's 33% the size of PNGs. It's 33% the quality. Am I the only person in existence who hates the "quantization" look?

edit: The strength of PNGs is not photography, but images with large blocks of solid colors; screenshots, etc. That's why the example in the article didn't suffer.

You shouldn't use this JPEG-transparency hack if you're dealing with images where PNGs are a better fit. (Which is why the example demonstrated an image where PNGs aren't a good fit).

"The right tool for the job" and all that jazz.

I think you've missed the point. This is a way to get transparency in JPEG style images for less 'weight' than downloading a PNG.

Neat hack, the lesson most of us should draw from this though is avoid designs that use big images with alpha transparency as they are many kbs! If you have to you maybe able to use this someday . . . for some of your users.

Uses more requests, though.

Now that is one very clever hack. It worked fine for me on ff 3.5.6.

Yup. Crashes on iPad.

Smart Hack.

down vote?

Two words comments are not appreciated here. They don' add anything to the discussion.

Read the unofficiql faq here: http://news.ycombinator.com/item?id=1755533 (read the main article)

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact