The PNG Guide is an eBook based on Greg Roelofs' book, originally published by O'Reilly. |
![]() |
Home ![]() ![]() |
||||
![]() ![]() ![]() ![]() ![]() ![]() |
||||
readpng2_info_callback()One important thing it does not do, however, is set up the usual error-handling code via the setjmp() function. The reason for this is simple: libpng requires that control never return to it when an error occurs; ordinarily, it longjumps to a user routine, which then returns an error value to the main program. But in this case it is libpng itself that calls readpng2_info_callback(), so a longjump back to here would make no sense--the only things we could do would be to return to libpng or call exit() without cleaning up, which is a rather brutal method of handling an error. (Well, actually we could do our own longjump back to the main program, but that's effectively what we are already doing. And in the last chapter I noted my dislike of big goto statements.) By not calling setjmp() within the callback, any errors will return to the location of the previous setjmp() call, which was in readpng2_decode_data(). It can then return a proper error value to the main program. There is a feature in the callback routine that has no analogue in the basic PNG reader, however: mainprog_info *mainprog_ptr; mainprog_ptr = (mainprog_info *)png_get_progressive_ptr(png_ptr); if (mainprog_ptr == NULL) { fprintf(stderr, "readpng2 error: " "main struct not recoverable in info_callback.\n"); fflush(stderr); return; } This is the way we retrieve our image-specific pointer from the bowels
of the PNG structs. (If it's invalid, we're in big trouble already, but
there's no need to compound the problem by dereferencing a NULL pointer and
crashing immediately.) Having done so, we can now stuff the image dimensions
into it, where they'll be used by the main program very shortly:
int color_type, bit_depth; png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL); As before, we called a libpng utility routine to retrieve information about the image. There are also so-called easy access functions to retrieve each item separately; the choice of one function call or several is purely a matter of taste.
See Chapter 13 for the detailed explanation, but trust me: it's not good karma.
As soon as we know the bit depth and color type of the image (via the
png_get_IHDR() call we just made), we can check
for a PNG bKGD
chunk and, if it's found, adjust its values in exactly the same way as
before:
if (mainprog_ptr->need_bgcolor && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { /* do the same png_get_bKGD() call and scale the RGB values as * required; put results in mainprog_ptr->bg_red, bg_green, * and bg_blue */ } This time, instead of passing the red, green, and blue values back through the arguments to a readpng2 function, we place them into the bg_red, bg_green, and bg_blue elements of our mainprog_info struct.
The next step is to set up the desired libpng transformations; this is
completely identical to the code in the first demo program. It is followed
by the gamma-correction setup, but here we depart slightly from the previous
example:
if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma); else png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455); Because this program is intended to provide an example of how to write a PNG reader for a web browser, we imagine that the files it will be viewing are coming from the Internet--even though the front ends we provide only read from local files, just as in the basic version. Because images from the Internet are more likely to have been either created on PC-like systems or intended for display on PC-like systems, we follow the recommendation of the sRGB proposal (see Chapter 10, "Gamma Correction and Precision Color") and assume that all unlabeled images live in the sRGB color space--which, among other things, means they have a gamma of 1/2.2 or 0.45455, the same as most PCs and workstations. This does mean that unlabeled images created on a Macintosh, SGI, or NeXT workstation and intended for display on one of these systems will appear too dark. But that, of course, is why including a gamma value in the image file is so vitally important.
There is one last ``transformation'' to register after the gamma handling
is out of the way; we want libpng to expand interlaced passes for us. This
mainprog_ptr->passes = png_set_interlace_handling(png_ptr);
Then we have libpng update the PNG struct information and return to us the final
number of channels in the image and the size of each row:
png_read_update_info(png_ptr, info_ptr); mainprog_ptr->rowbytes = png_get_rowbytes(png_ptr, info_ptr); mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr); The very last thing readpng2_info_callback() does is call its corresponding function in the main program, which allocates the image memory, initializes the windowing system, and creates the display window with the proper dimensions: (*mainprog_ptr->mainprog_init)(); return;
Recall that we saved pointers to three functions in the
mainprog_info
struct; this calls the first of the three. If we didn't care about separating
PNG code from the main program routines, we could use just one routine per
callback. But this way is a bit cleaner, and the performance hit is minimal.
|
||||
Home ![]() ![]() |