Alternative Approaches
It should go without saying that the program presented here is among the
simplest of many possibilities. It would also have been possible to write
it monolithically, either as a single readpng function or even as inlined
code within main(), which is precisely how the sample code
in the libpng documentation reads. Libpng allows user-defined I/O routines
(in place of standard file I/O), custom memory allocators, and alternate error
handlers to be installed, although there is currently no provision for an
error-handling function that returns control to the libpng routine that called
it.
There are also other options for the platform-dependent front ends, of
course; reading an image from a file is often undesirable. One method
in particular is worth mentioning, since it does not appear to be documented
anywhere else at the time of this writing. On the 32-bit Windows platform, a
``private'' clipboard may be used to transfer PNG images between applications.
The data format is simply the normal PNG stream, beginning with the signature
bytes and ending with the IEND chunk. An application like rpng-win
would register the private clipboard and then read PNG data from it in the
usual way. The following code fragment outlines the essential steps:
UINT clipbd_format = RegisterClipboardFormat("PNG");
if (clipbd_format == 0) {
/* call failed: use GetLastError() for extended info */
} else if (OpenClipboard(NULL)) {
HANDLE handle = GetClipboardData(clipbd_format);
if (handle == NULL) {
/* call failed: use GetLastError() for info */
} else {
int data_length = GlobalSize(handle); /* upper bound */
if (data_length == 0) {
/* call failed: use GetLastError() for info */
} else {
BYTE *data_ptr = GlobalLock(handle);
if (data_ptr == NULL) {
/* call failed: use GetLastError() for info */
} else {
/*================================================*/
/* copy PNG data immediately, but don't flag an */
/* error if there are some extra bytes after IEND */
/*================================================*/
if (GlobalUnlock(handle) == 0) {
/* call failed: use GetLastError() for info */
}
}
}
}
if (CloseClipboard()) {
/* call failed: use GetLastError() for info */
}
} else {
/* another window has the clipboard open */
/* (can use GetOpenClipboardWindow() to get handle to it) */
}
That one can do something like this in principle isn't new or unusual;
what is new is that the "PNG" clipboard has
already been implemented in
some Microsoft apps, including Office 2000. All any other application needs in
order to interoperate via this clipboard is its name and data format, which
I've just described. Thanks to John Bowler for providing this information
to the PNG Development Group.
In the next chapter, I'll look at a more radical alternative to the basic PNG
decoder: a version that feeds libpng data at its own pace, rather than letting
libpng read (and possibly wait for) as much data as it wants. Progressive
viewers are at the heart of most online browsers, so we'll look at how to
write one for PNG images.
|