2010-05-02

Overlay two or more images for interesting effects

What happens when we overlay multiple images, using opacity/transparency to blend them? This is an idea I had a couple years ago, and I decided to sit down and try it out. And it works pretty well.



Basically, the transparent parts of a front-most image will allow anything behind it to show through.  A semi-transparent area in front will appear as if it is mixing the pixels in front with the pixels behind.

With current browser technology, transparent areas in gif images are 100% transparent, while png images may have semi-transparent pixels, by adding an "alpha" channel.  But browsers also allow you to specify the opacity (the inverse of transparency) of any element, including images with no transparency.  And this opacity can be controlled in the browser so you don't have to live with generating new images each time you want to change the transparency.  It applies to the whole element equally, however, so there are limitations.

So quickly, here is what I have in mind for combining multiple images to produce interesting effects.  Let's start with a couple of simple images to make it clear what is going on.

image1 has dimenions 23x53, 1219 pixels, 288 bytes: 

image2 is slightly larger at 29x59, 1711 pixels, 304 bytes:

If we overlay them with a pair of nested divs, like so:

(dang it all, the blogger editor is removing my whitespace, and sorting attributes alphabetically. Use your imagination.)

... it will look like this (after setting the background images correctly, and constraining it to a smaller container):

Note that the pattern appears to be non-repeating, but it actually does repeat, only the size of the repeating pattern is rather huge. I chose the sizes of the images so that they had dimensions that were relatively prime, meaning that the numbers for the widths are not divisors of each other, and the same for the heights. This means that repetitions of each image do not coincide or re-sync with each other until we reach a size that is the product of the two values.

For the width, that is 23 * 29 == 667, and for the height we get 53 * 59 == 3127. The pixel size of the two images adds up to just 2930 pixels (compressed to 592 bytes) but an image with this unique pattern would otherwise require 667 * 3127 == 2085709 pixels (ignoring compression). A huge savings!

So what can we do with this technique that might be more interesting?  How about creating a woodgrain pattern that doesn't look so boring?  If we use and as a backgrounds, we get this:
and (respectively) this:

But if we overlay them, we get this much more interesting pattern that looks more like real wood:

But here is a puzzle.  If we add a third image to the mix, how should we set the opacity of each layer? Notice that when we had just two layers, the front layer (the innermost one) had opacity:0.5, meaning that the browser would show half of that layer, and half of everything behind it, so we set the back layer to have opacity:1 to see as much as the front layer would let through.  That sounds reasonable, but I am not sure it is true.

Therefore it would make sense for a third layer that is in front of the other two to have opacity:0.33, and we keep the other two the same (at 0.5 and 1), since we are dividing between three layers. In other words, the front layer shows only 1/3, and lets through 2/3 of the other two layers behind it, which are equally divided between themselves as before. Sounds good, but this doesn't seem to be working, in my experience. More later when I figure it out, or when you tell me what I am missing.

Try it yourself:

Images can be any sizes - try non-primes as well. Seamless tile images work best.

Modify any image URL or opacity, and click the Update button.

Image1:
url:
opacity:

Image2:
url:
opacity:

Image3:
url:
opacity:





Unique texture (in the dark box) has width: height:


Note: using position:relative on inner divs doesn't work right in IE - they are not bounded by container with overflow:auto. IE also seems to have some problem supporting transparency in the same way in the last example, where we set the opacity programmatically.
For reference, here are the prime numbers up to 100: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, and 97.

No comments: