The PNG Guide is an eBook based on Greg Roelofs' book, originally published by O'Reilly.



Compositing and Displaying the Image

The main-program code to do all of this is almost identical to that in the first demo program, but this time around we've added a small twist: the code now supports not only a user-defined background color but also a background image of sorts. Specifically, the user has the option of choosing one of a set of predefined background patterns that simulate a tiled background image. The patterns currently include gradient-filled checkerboards (three of which are shown in the second row of Figure C-5 in the color insert), smoothly interpolated diamonds (third row of Figure C-5), and radial waves (Figure C-1 and fourth row of Figure C-5); eventually, other patterns may be defined. This approach is simple enough that it could be generated on the fly, as the image is displayed, but in the interests of speed and simplicity, I chose to define a second complete image buffer in the mainprog_init() function. The background buffer is filled as follows for the diamond pattern (contributed by Adam M. Costello):

        hmax = (bgscale-1)/2;   /* half the max weight of a color */
        max = 2*hmax;           /* the max weight of a color */

        for (row = 0;  row < rpng2_info.height;  ++row) {
            yidx = row % bgscale;
            if (yidx > hmax)
                yidx = bgscale-1 - yidx;
            dest = bg_data + row*bg_rowbytes;
            for (i = 0;  i < rpng2_info.width;  ++i) {
                xidx = i % bgscale;
                if (xidx > hmax)
                    xidx = bgscale-1 - xidx;
                k = xidx + yidx;
                *dest++ = (k*r1 + (max-k)*r2) / max;
                *dest++ = (k*g1 + (max-k)*g2) / max;
                *dest++ = (k*b1 + (max-k)*b2) / max;
            }
        }

With this approach, the inner display loop requires only a tiny change to support the background image instead of just a background color:

                r = *src++;
                g = *src++;
                b = *src++;
                a = *src++;
                if (bg_image) {                /* NEW */
                    bg_red   = *src2++;        /* NEW */
                    bg_green = *src2++;        /* NEW */
                    bg_blue  = *src2++;        /* NEW */
                }                              /* NEW */
                if (a == 255) {
                    red   = r;
                    green = g;
                    blue  = b;
                } else if (a == 0) {
                    red   = bg_red;
                    green = bg_green;
                    blue  = bg_blue;
                } else {
                    /* this macro (copied from png.h) composites
                     * the foreground and background values and
                     * puts the result into the first argument */
                    alpha_composite(red,   r, a, bg_red);
                    alpha_composite(green, g, a, bg_green);
                    alpha_composite(blue,  b, a, bg_blue);
                }

In other words, the background color used for compositing is now changed once per pixel. (Note that the src2 pointer is initialized just once per call. That's the only other change to the display routine to support the background image.) The cases in which the alpha component is either 255 or 0 are handled separately for performance reasons only; using the alpha_composite() macro would produce identical results. But because the macro employs multiplication, addition, and bit-shifting for every pixel (in fact, three times per pixel) and because fully opaque and fully transparent pixels are generally by far the most numerous, the difference in speed would probably be noticeable. It therefore makes sense to handle the two special cases separately. Whether full opacity or full transparency is handled first is less obvious; I guessed that opaque pixels are likely to be more common in images with transparency, so the 255 case is checked first.

The results, using one of the more exotic radial-wave patterns as the background, are shown in Figure C-1 in the color insert. The base image consists of partially transparent icicles hanging from opaque tree branches, seen against a completely transparent sky. The figure is a composite of the appearance after the first PNG pass (left half) and the final pass (right half).




Last Update: 2010-Nov-26