readpng2_decode_data()
Back in the main program, after dealing with various windowing-system
chores, the code sets a few variables in the mainprog_info struct.
The following excerpt is from the X version of the code, but the Windows
code is the same, aside from prefixing function names with rpng2_win_
instead of rpng2_x_:
if (user_did_not_specify_a_background_color_or_pattern)
rpng2_info.need_bgcolor = TRUE;
rpng2_info.mainprog_init = rpng2_x_init;
rpng2_info.mainprog_display_row = rpng2_x_display_row;
rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
Unlike the basic viewer, where the main program called a special function
to check for and retrieve the image's background color, the progressive
viewer simply sets the need_bgcolor flag in the struct. It also
sets three function pointers corresponding to the three readpng2 callbacks.
The reason for this apparent duplication will become clear when we look at
the callbacks in detail.
Having prepared everything for decoding, the main program begins the data
loop that is at its core, reading file data into a buffer and passing it
to the PNG-decoding function:
for (;;) {
if (readpng2_decode_data(&rpng2_info, inbuf, incount))
++error;
if (error || feof(infile) || rpng2_info.done)
break;
if (timing)
sleep(1);
incount = fread(inbuf, 1, INBUFSIZE, infile);
}
Note the call to readpng2_decode_data() at the beginning of the
loop, before fread(); it handles the initial chunk of data we read
prior to calling readpng2_init().
The only remarkable feature of the loop itself is the conditional call to
the sleep() function. Because this is a demo program, and because
it is intended to be a rough simulation of how a web browser functions,
I chose to give the user the option of simulating how an image download
over a fast modem would appear. The sleep() function is an extremely
crude method of doing this--it has only one-second precision, which is
too coarse to allow for a smooth simulation--but it is relatively portable
and ubiquitous. Less portable but more precise alternatives include
usleep() and various Windows API calls. But since no sane programmer
would intentionally add a delay like this to the inner loop of a program
except for demonstration purposes, I judged that sleep() was
good enough for this. The combination of a one-second sleep interval and
the default buffer size of 4096 bytes results in an apparent download speed
that is 10% to 20% faster than a 33.6K modem can manage. In fact, it's
close to the average connection speed of a 56K modem over typical phone
lines.
As to readpng2_decode_data() itself, it is little more than a
wrapper function for the libpng routine png_process_data(). Its
arguments include a pointer to our mainprog_info struct, a pointer
to the input buffer, and the number of bytes of input data; the only things
it does besides calling libpng are copy the struct pointers and set up
the usual error-handling code:
int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf,
ulg length)
{
png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
if (setjmp(mainprog_ptr->jmpbuf)) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
mainprog_ptr->png_ptr = NULL;
mainprog_ptr->info_ptr = NULL;
return 2;
}
png_process_data(png_ptr, info_ptr, rawbuf, length);
return 0;
}
The struct pointers are copied merely because the alternative is to typedef
them; the latter may be more efficient (though not necessarily, due to the
extra level of indirection inherent in the -> operator), but it
is also uglier and makes the code somewhat less readable.[101]
|