Using the same process (combining data into a png => sending to browser => reading out specific chunks from the png), could you also have a script that combines all the images in your stylesheet into a CSS sprite, sends it to the browser, and then crops out each image on the client-side?
Then you wouldn't have to mess with all the trickery required to layout a CSS sprite and positioning it properly in your stylesheet. Of course the compromise would be the performance hit the first time the browser loads your site and has to crop the images out.
Interesting. What are your experiences with handling the disadvantages of using data URIs? [1] The biggest disadvantage that I see is:
Data URIs are not separately cached from their containing documents (e.g. CSS or HTML files) so data is downloaded every time the containing documents are redownloaded.
Content must be re-encoded and re-embedded every time a change is made.
Based on this, it seems like this would still work well for images specified in your stylesheet, but not so much for images that are specified directly in your HTML, because it would bloat HTML file size, and unless the user's browser caches the HTML file itself, they'll have to re-download the large HTML file over and over again.
Also, according to Wikipedia, base64 encoding makes the file size 33% larger than the binary file, and compressing it (as with gzip) only shaves off 2-3% of the base64 file size. Is this accurate? If so, it seems gzip encoding the transfer doesn't really recover the file size bloat you mentioned.
EDIT: Now that I think about it, if you base64 encode all the images in your stylesheet, won't that make your website look like ass for as long as it takes to download that stylesheet? Usually, this isn't a big deal because a text stylesheet gets downloaded pretty quickly, but now it will be larger in file size than the total sum of all the images that were specified in the stylesheet.
Also, according to Wikipedia, base64 encoding makes the file size 33% larger than the binary file, and compressing it (as with gzip) only shaves off 2-3% of the base64 file size.
Nope, the second part is wrong. See also the discussion here http://news.ycombinator.com/item?id=1491165 - overhead of compressed base64 tends to be very small, smaller than the HTTP protocol overhead. Base64 has only 6 bits of entropy and Huffman coding is able to take advantage of this.
Well, our approach works great for rich JavaScript web applications like those built with Cappuccino, not so much for websites. We don't have image URLs specified in stylesheets at all, but rather we use JavaScript to build up the DOM and set the src of all img tags (or background-image style properties, or canvas drawing, etc). That gives us the opportunity to replace the URLs with these data/MHTML URIs looked up through a map (URL -> data/MHTML) that gets populated when you load the sprite.
Regarding the "Flash of Unstyled Content" effect (http://en.wikipedia.org/wiki/Flash_of_unstyled_content), I believe this has been fixed by modern browsers, as long at the stylesheet is loaded in the head section, since the browser won't display anything until those resources have been loaded (not 100% sure about this, it doesn't affect the kinds of apps I'm talking about anyway)
Regarding Base64 + Gzipping, no, that's not accurate:
"Base64-encoded data URIs are 1/3 larger in size than their binary equivalent. This overhead is reduced to 2-3% if the HTTP server compresses the response using HTTP's Content-Encoding header."
This is saying the overhead is reduced from 33% to 2-3% over the raw image sizes, which is insignificant relative to the performance gained by significantly reducing the number of HTTP requests.
You last point doesn't apply to web applications where, for example, a progress bar can be displayed before showing any of the application UI.
Oh cool. Yes, I must have misread that compression stat.
We don't have image URLs specified in stylesheets at all, but rather we use JavaScript to build up the DOM and set the src of all img tags (or background-image style properties, or canvas drawing, etc).
That's really interesting. Since that's not explained in the article you had linked to, I'm assuming Cappuccino did this before switching to data URIs?
Thanks for taking the time to explain this approach more in depth.
Yeah, you should read a bit about Cappuccino, it makes drastically different decisions about how an application should be built on top of the browser, but as a result it gets to do complex things like this image spriting extremely simply.
as the ajaxian article stated, i believe that people are trying to make use of it to squeeze the most out of the size-limited javascript contests that are out there. but, i've not seen an entry that does yet (haven't looked that hard though).
It was definitely not convenient during development. When I was testing for IE9, every change in the code needed to be encoded to the PNG image. But having an automate build script really helped speeding up things. YUICompressor caught all the major bugs during the build process so as long as my un-minified/unencoded scripts worked, I was pretty sure that the PNG version would work as well.
This is what I love about JavaScript right now. The air of innovation is everywhere. It really is an exciting language to be developing in right now. It reminds me of the early days of Java.
1. show of some neat trick
2. hide code
a. hide code on a 3rd party site
b. hide code in an image that actually looks like an image ( steganography ),
thus hiding parts of the code within several images.
for a really good time, hide some unique data on
one machine that acts as a key
3. save per file system space
i think gzip uses the same compression algorithm as png files so, to reuse this is silly. the browser supports gzip anyways
i saw this as part of a 10kapart competition, and maybe they were trying to make up the difference between the actual size of the bits used and the file system size. i think although this is interesting, but, it defeats the point of the 10k limit; which, was there to show what one could do without server side scripts, and I think a build script .... counts.
It would be interesting to see how it copes with proxy servers (like the ones Opera use) that downscale images to reduce the traffic on mobile networks. It would be a good idea to checksum the code to make sure that it is what you're expecting to receive.
This post follow along the same lines, however a bit more blackhat[1]. He also did another write up about using images to store xss data a while back. It is great if the image is loaded into javascript, other wise it will not work.
For a lossy algorithm based on human vision characteristics (e.g., JPEG) it would be quite surprising. However, PNG is lossless and is based on DEFLATE, a general-purpose compression algorithm. So actually this makes perfect sense. (See http://en.wikipedia.org/wiki/Portable_Network_Graphics#Compr...)
You're being downvoted because, simply put, you're wrong.
One gigabyte is as large as any other gigabyte, yes, but the characteristics of that gigabyte may be very different. If they're predictable in some manner, you can tailor a compression algorithm to that gigabyte.
You can learn some about this by studying linear algebra.
And information theory. The salient concept here is the "entropy" of a chunk of data. The maximum degree to which a given sequence of numbers (or symbols, bits, etc) can be losslessly compressed is called Kolmogorov complexity. Wiki away! :)