You say it’s not possible? Just wait, but let me start from the beginning …
It was about two years ago, when I started to program another website for another client. It was a product website for premium wines of an Austrian winemaker. The design was supplied by Typejockeys, an excellent design studio with really great designers. They have built an awesome appearance and I was excited that I was allowed to realize a functional website from it. I have built many websites before, so it couldn’t be such a challenge for me.
The requirement was, to make a modern website, that behaves great on each device. Because the pictured wines are premium quality products, it was really important to communicate that fact also with a high quality website.
The last ten years there appeared a lot of very different devices, but there is one special type which challenged me anyway. But one after the other.
I built the website within a few days and showed the result to the designers. All in all they were very happy with it but there was one thing, which they asked about. It was something I actually already have registered but ignored until that moment, because I knew it would get a challenge. They asked me about one sub-page, because it loaded very slow. Actually only the images of the page loaded slow.
To understand the problem, I have to explain the design and layout of this page a little bit. On this sub-page there were a list of all wines, each with one photo of the wine bottle and one detail photo of the label. The bottle photo had to be about 80 × 350 pixels and the detail photo about 600 × 560 pixels. But actually I talk about CSS pixels. That means in mind of retina displays I had to double the widths and heights, so that the images were four times bigger on such devices. There were eight premium wines in sum on that page. So we had eight bottle images 160 × 700 pixel sized and eight detail images 1200 × 1120 pixel sized.
Ok, these are a few big images on one sub-page, but if a good compression is used, that’s not such a problem today. The worldwide average size of a sub-page is about three megabytes. And if you use a suitable compression for all the photos, it’s possible to keep the whole sub-page smaller than that average. The website surely would not be the fastest, but faster than 50% of all websites out there would be an acceptable value in that case.
… so far so good …
But then a tiny design detail brought the challenge. The designers planned a color gradient behind the bottle images which should stretch over the whole website width. This gradient should be adjacent directly to the bottles. So the photo background should be cut away. And like that is not enough, there should also be a parallax effect. So if the page get scrolled, the color gradient and the bottles should move in different speeds.
In other words: I needed an alpha transparency for the images to realize all that. Until now the only image format, that is supported in all major browsers and supports alpha transparency and additionally can handle enough colors to display a high quality photo, is the PNG format. This is a really excellent format and I remember how happy I was, those days when finally all browsers supported it. It can handle many colors and supports alpha transparency and usually have a great compression result too. But there is one single thing, which is not a good idea regarding to the PNG format. One thing that would immediately increase the file size enormously and make all the great qualities completely useless. And that single thing is, to use it for photos.
However, since the PNG format was the only format that supported all the requirements, I simply used it. But when I have shown the website to the designers, the sub-page, where all the images were placed, was in size over ten megabytes. And you could watch the pictures slowly building up while loading. It felt like those days when we had a 65k modem. It was definitely much too slow for a high quality website nowadays. But which other options would we have?
First I tried to optimize the compression of the images by using several tools like tinypng.com multiple times in serial. In fact I was hoping for a miracle, because actually I knew that it can’t really get the needed result. I thought, the hope dies last. But I should be right, it brought only a few kilobytes. So nearly nothing.
… but what was this? …
… the images weren’t there and the fan of my PC revved up. Was the decoder buggy? Maybe an endless loop? Or have I made a mistake? And suddenly the first image appeared … short time later the second one … and then the third … and so on.
Actually it worked. The images looked great. But it was even slower than the PNG files. This time not the loading process was the problem, but the decoder process.
So, back to the start.
Because the BPG files were so small, I knew that in principle it would be possible to bring the image contents from the server to the browser in an acceptable time. I thought about whether I can change the decoder a little bit to make it faster. But I should have invested a lot of time to understand how the decoder works. And I didn’t know if it’s possible at all to make it faster. So it seemed not adequate to me and I discarded that idea again quickly.
I kept pursuing this idea and I thought about how I could load and read the file. First I thought to load it via an IMG element, but I couldn’t image that there is a way to read the binary data from it. I needed the binary data to separate the two parts of the file, the JPEG part and the transparency part. So next I thought about load it via Ajax. In that case I would be able to read the binary data. Because I would have my own data format for the transparency part, I would be also able to at least paint the transparency on the canvas element then. Actually I didn’t know at that moment in which format I would save the transparency, but I thought that would be easily solvable. First I had to solve a more difficult issue. The JPEG part would be in binary format too and I knew a way to paint image data from an IMG element to a canvas element, but I didn’t know a way to paint binary data of an image on a canvas element. I thought about a few options. I considered whether I need a JPEG decoder, but I thought there must be a better solution. I thought maybe I could inject it into an IMG element somehow and then transfer it from the IMG element to the canvas element.
While I kept thinking about it, I daydreamed that it would be great to already have the JPEG part of the file in an own IMG tag, while the transparency is somewhere else.
Booom!!! … and suddenly the solution was revealed step by step!
The answers to all my questions came in quick succession. It was so incredible simple. I wondered that I didn’t realized it earlier.
Of course I hadn’t have to load the JPEG data and the transparency as one single file. I could load the JPEG file separately in an IMG element, while the transparency is anywhere else. So it would be really easy and fast to bring the photo on the canvas element. And the transparency? Actually I already had a solution for the transparency. The solution, to load it via Ajax, would work, but I would still need a suitable data format. Originally I rather thought to create an own format, but well actually, which format would be better suited to this task then the great PNG format? With these ideas all my problems seemed disappeared. I wouldn’t need an own data format and I also wouldn’t need Ajax anymore, because I could load the PNG via an IMG element too. Just like the photo.
The rest was relatively easy. I created two image files for each displayed image. In the JPEG file there was just the photo with a consistent background color. Then I created the PNG file with exactly the same width and height. The parts, that should be transparent in the result, had to be transparent in the PNG. The color of the visible parts didn’t matter, because I only needed the information where the transparency needs to be. Because the compression of a PNG works best for consistent color areas, I just made the visible parts black.
Although the path was somewhat frustrating in some situations, I love such adventures. What do you think about it? And so far, what has been your biggest challenge that you remember most? I’m very curious! Type your thoughts below ?
Do you like my article? Maybe someone could need that technique. So, don’t keep it secret, just share it ? …