symbian-qemu-0.9.1-12/libpng-1.2.32/contrib/gregbook/rpng-win.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*---------------------------------------------------------------------------
       
     2 
       
     3    rpng - simple PNG display program                             rpng-win.c
       
     4 
       
     5    This program decodes and displays PNG images, with gamma correction and
       
     6    optionally with a user-specified background color (in case the image has
       
     7    transparency).  It is very nearly the most basic PNG viewer possible.
       
     8    This version is for 32-bit Windows; it may compile under 16-bit Windows
       
     9    with a little tweaking (or maybe not).
       
    10 
       
    11    to do:
       
    12     - handle quoted command-line args (especially filenames with spaces)
       
    13     - have minimum window width:  oh well
       
    14     - use %.1023s to simplify truncation of title-bar string?
       
    15 
       
    16   ---------------------------------------------------------------------------
       
    17 
       
    18    Changelog:
       
    19     - 1.00:  initial public release
       
    20     - 1.01:  modified to allow abbreviated options; fixed long/ulong mis-
       
    21               match; switched to png_jmpbuf() macro
       
    22     - 1.02:  added extra set of parentheses to png_jmpbuf() macro; fixed
       
    23               command-line parsing bug
       
    24     - 1.10:  enabled "message window"/console (thanks to David Geldreich)
       
    25     - 2.00:  dual-licensed (added GNU GPL)
       
    26     - 2.01:  fixed improper display of usage screen on PNG error(s)
       
    27 
       
    28   ---------------------------------------------------------------------------
       
    29 
       
    30       Copyright (c) 1998-2008 Greg Roelofs.  All rights reserved.
       
    31 
       
    32       This software is provided "as is," without warranty of any kind,
       
    33       express or implied.  In no event shall the author or contributors
       
    34       be held liable for any damages arising in any way from the use of
       
    35       this software.
       
    36 
       
    37       The contents of this file are DUAL-LICENSED.  You may modify and/or
       
    38       redistribute this software according to the terms of one of the
       
    39       following two licenses (at your option):
       
    40 
       
    41 
       
    42       LICENSE 1 ("BSD-like with advertising clause"):
       
    43 
       
    44       Permission is granted to anyone to use this software for any purpose,
       
    45       including commercial applications, and to alter it and redistribute
       
    46       it freely, subject to the following restrictions:
       
    47 
       
    48       1. Redistributions of source code must retain the above copyright
       
    49          notice, disclaimer, and this list of conditions.
       
    50       2. Redistributions in binary form must reproduce the above copyright
       
    51          notice, disclaimer, and this list of conditions in the documenta-
       
    52          tion and/or other materials provided with the distribution.
       
    53       3. All advertising materials mentioning features or use of this
       
    54          software must display the following acknowledgment:
       
    55 
       
    56             This product includes software developed by Greg Roelofs
       
    57             and contributors for the book, "PNG: The Definitive Guide,"
       
    58             published by O'Reilly and Associates.
       
    59 
       
    60 
       
    61       LICENSE 2 (GNU GPL v2 or later):
       
    62 
       
    63       This program is free software; you can redistribute it and/or modify
       
    64       it under the terms of the GNU General Public License as published by
       
    65       the Free Software Foundation; either version 2 of the License, or
       
    66       (at your option) any later version.
       
    67 
       
    68       This program is distributed in the hope that it will be useful,
       
    69       but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    70       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    71       GNU General Public License for more details.
       
    72 
       
    73       You should have received a copy of the GNU General Public License
       
    74       along with this program; if not, write to the Free Software Foundation,
       
    75       Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    76 
       
    77   ---------------------------------------------------------------------------*/
       
    78 
       
    79 #define PROGNAME  "rpng-win"
       
    80 #define LONGNAME  "Simple PNG Viewer for Windows"
       
    81 #define VERSION   "2.01 of 16 March 2008"
       
    82 
       
    83 #include <stdio.h>
       
    84 #include <stdlib.h>
       
    85 #include <string.h>
       
    86 #include <time.h>
       
    87 #include <windows.h>
       
    88 #include <conio.h>      /* only for _getch() */
       
    89 
       
    90 /* #define DEBUG  :  this enables the Trace() macros */
       
    91 
       
    92 #include "readpng.h"    /* typedefs, common macros, readpng prototypes */
       
    93 
       
    94 
       
    95 /* could just include png.h, but this macro is the only thing we need
       
    96  * (name and typedefs changed to local versions); note that side effects
       
    97  * only happen with alpha (which could easily be avoided with
       
    98  * "ush acopy = (alpha);") */
       
    99 
       
   100 #define alpha_composite(composite, fg, alpha, bg) {               \
       
   101     ush temp = ((ush)(fg)*(ush)(alpha) +                          \
       
   102                 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
       
   103     (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
       
   104 }
       
   105 
       
   106 
       
   107 /* local prototypes */
       
   108 static int        rpng_win_create_window(HINSTANCE hInst, int showmode);
       
   109 static int        rpng_win_display_image(void);
       
   110 static void       rpng_win_cleanup(void);
       
   111 LRESULT CALLBACK  rpng_win_wndproc(HWND, UINT, WPARAM, LPARAM);
       
   112 
       
   113 
       
   114 static char titlebar[1024];
       
   115 static char *progname = PROGNAME;
       
   116 static char *appname = LONGNAME;
       
   117 static char *filename;
       
   118 static FILE *infile;
       
   119 
       
   120 static char *bgstr;
       
   121 static uch bg_red=0, bg_green=0, bg_blue=0;
       
   122 
       
   123 static double display_exponent;
       
   124 
       
   125 static ulg image_width, image_height, image_rowbytes;
       
   126 static int image_channels;
       
   127 static uch *image_data;
       
   128 
       
   129 /* Windows-specific variables */
       
   130 static ulg wimage_rowbytes;
       
   131 static uch *dib;
       
   132 static uch *wimage_data;
       
   133 static BITMAPINFOHEADER *bmih;
       
   134 
       
   135 static HWND global_hwnd;
       
   136 
       
   137 
       
   138 
       
   139 
       
   140 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
       
   141 {
       
   142     char *args[1024];                 /* arbitrary limit, but should suffice */
       
   143     char *p, *q, **argv = args;
       
   144     int argc = 0;
       
   145     int rc, alen, flen;
       
   146     int error = 0;
       
   147     int have_bg = FALSE;
       
   148     double LUT_exponent;              /* just the lookup table */
       
   149     double CRT_exponent = 2.2;        /* just the monitor */
       
   150     double default_display_exponent;  /* whole display system */
       
   151     MSG msg;
       
   152 
       
   153 
       
   154     filename = (char *)NULL;
       
   155 
       
   156 
       
   157     /* First reenable console output, which normally goes to the bit bucket
       
   158      * for windowed apps.  Closing the console window will terminate the
       
   159      * app.  Thanks to David.Geldreich@realviz.com for supplying the magical
       
   160      * incantation. */
       
   161 
       
   162     AllocConsole();
       
   163     freopen("CONOUT$", "a", stderr);
       
   164     freopen("CONOUT$", "a", stdout);
       
   165 
       
   166 
       
   167     /* Next set the default value for our display-system exponent, i.e.,
       
   168      * the product of the CRT exponent and the exponent corresponding to
       
   169      * the frame-buffer's lookup table (LUT), if any.  This is not an
       
   170      * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
       
   171      * ones), but it should cover 99% of the current possibilities.  And
       
   172      * yes, these ifdefs are completely wasted in a Windows program... */
       
   173 
       
   174 #if defined(NeXT)
       
   175     LUT_exponent = 1.0 / 2.2;
       
   176     /*
       
   177     if (some_next_function_that_returns_gamma(&next_gamma))
       
   178         LUT_exponent = 1.0 / next_gamma;
       
   179      */
       
   180 #elif defined(sgi)
       
   181     LUT_exponent = 1.0 / 1.7;
       
   182     /* there doesn't seem to be any documented function to get the
       
   183      * "gamma" value, so we do it the hard way */
       
   184     infile = fopen("/etc/config/system.glGammaVal", "r");
       
   185     if (infile) {
       
   186         double sgi_gamma;
       
   187 
       
   188         fgets(tmpline, 80, infile);
       
   189         fclose(infile);
       
   190         sgi_gamma = atof(tmpline);
       
   191         if (sgi_gamma > 0.0)
       
   192             LUT_exponent = 1.0 / sgi_gamma;
       
   193     }
       
   194 #elif defined(Macintosh)
       
   195     LUT_exponent = 1.8 / 2.61;
       
   196     /*
       
   197     if (some_mac_function_that_returns_gamma(&mac_gamma))
       
   198         LUT_exponent = mac_gamma / 2.61;
       
   199      */
       
   200 #else
       
   201     LUT_exponent = 1.0;   /* assume no LUT:  most PCs */
       
   202 #endif
       
   203 
       
   204     /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
       
   205     default_display_exponent = LUT_exponent * CRT_exponent;
       
   206 
       
   207 
       
   208     /* If the user has set the SCREEN_GAMMA environment variable as suggested
       
   209      * (somewhat imprecisely) in the libpng documentation, use that; otherwise
       
   210      * use the default value we just calculated.  Either way, the user may
       
   211      * override this via a command-line option. */
       
   212 
       
   213     if ((p = getenv("SCREEN_GAMMA")) != NULL)
       
   214         display_exponent = atof(p);
       
   215     else
       
   216         display_exponent = default_display_exponent;
       
   217 
       
   218 
       
   219     /* Windows really hates command lines, so we have to set up our own argv.
       
   220      * Note that we do NOT bother with quoted arguments here, so don't use
       
   221      * filenames with spaces in 'em! */
       
   222 
       
   223     argv[argc++] = PROGNAME;
       
   224     p = cmd;
       
   225     for (;;) {
       
   226         if (*p == ' ')
       
   227             while (*++p == ' ')
       
   228                 ;
       
   229         /* now p points at the first non-space after some spaces */
       
   230         if (*p == '\0')
       
   231             break;    /* nothing after the spaces:  done */
       
   232         argv[argc++] = q = p;
       
   233         while (*q && *q != ' ')
       
   234             ++q;
       
   235         /* now q points at a space or the end of the string */
       
   236         if (*q == '\0')
       
   237             break;    /* last argv already terminated; quit */
       
   238         *q = '\0';    /* change space to terminator */
       
   239         p = q + 1;
       
   240     }
       
   241     argv[argc] = NULL;   /* terminate the argv array itself */
       
   242 
       
   243 
       
   244     /* Now parse the command line for options and the PNG filename. */
       
   245 
       
   246     while (*++argv && !error) {
       
   247         if (!strncmp(*argv, "-gamma", 2)) {
       
   248             if (!*++argv)
       
   249                 ++error;
       
   250             else {
       
   251                 display_exponent = atof(*argv);
       
   252                 if (display_exponent <= 0.0)
       
   253                     ++error;
       
   254             }
       
   255         } else if (!strncmp(*argv, "-bgcolor", 2)) {
       
   256             if (!*++argv)
       
   257                 ++error;
       
   258             else {
       
   259                 bgstr = *argv;
       
   260                 if (strlen(bgstr) != 7 || bgstr[0] != '#')
       
   261                     ++error;
       
   262                 else
       
   263                     have_bg = TRUE;
       
   264             }
       
   265         } else {
       
   266             if (**argv != '-') {
       
   267                 filename = *argv;
       
   268                 if (argv[1])   /* shouldn't be any more args after filename */
       
   269                     ++error;
       
   270             } else
       
   271                 ++error;   /* not expecting any other options */
       
   272         }
       
   273     }
       
   274 
       
   275     if (!filename)
       
   276         ++error;
       
   277 
       
   278 
       
   279     /* print usage screen if any errors up to this point */
       
   280 
       
   281     if (error) {
       
   282         int ch;
       
   283 
       
   284         fprintf(stderr, "\n%s %s:  %s\n\n", PROGNAME, VERSION, appname);
       
   285         readpng_version_info();
       
   286         fprintf(stderr, "\n"
       
   287           "Usage:  %s [-gamma exp] [-bgcolor bg] file.png\n"
       
   288           "    exp \ttransfer-function exponent (``gamma'') of the display\n"
       
   289           "\t\t  system in floating-point format (e.g., ``%.1f''); equal\n"
       
   290           "\t\t  to the product of the lookup-table exponent (varies)\n"
       
   291           "\t\t  and the CRT exponent (usually 2.2); must be positive\n"
       
   292           "    bg  \tdesired background color in 7-character hex RGB format\n"
       
   293           "\t\t  (e.g., ``#ff7700'' for orange:  same as HTML colors);\n"
       
   294           "\t\t  used with transparent images\n"
       
   295           "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
       
   296           "Press Q or Esc to quit this usage screen.\n"
       
   297           "\n", PROGNAME, default_display_exponent);
       
   298         do
       
   299             ch = _getch();
       
   300         while (ch != 'q' && ch != 'Q' && ch != 0x1B);
       
   301         exit(1);
       
   302     }
       
   303 
       
   304 
       
   305     if (!(infile = fopen(filename, "rb"))) {
       
   306         fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);
       
   307         ++error;
       
   308     } else {
       
   309         if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
       
   310             switch (rc) {
       
   311                 case 1:
       
   312                     fprintf(stderr, PROGNAME
       
   313                       ":  [%s] is not a PNG file: incorrect signature\n",
       
   314                       filename);
       
   315                     break;
       
   316                 case 2:
       
   317                     fprintf(stderr, PROGNAME
       
   318                       ":  [%s] has bad IHDR (libpng longjmp)\n", filename);
       
   319                     break;
       
   320                 case 4:
       
   321                     fprintf(stderr, PROGNAME ":  insufficient memory\n");
       
   322                     break;
       
   323                 default:
       
   324                     fprintf(stderr, PROGNAME
       
   325                       ":  unknown readpng_init() error\n");
       
   326                     break;
       
   327             }
       
   328             ++error;
       
   329         }
       
   330         if (error)
       
   331             fclose(infile);
       
   332     }
       
   333 
       
   334 
       
   335     if (error) {
       
   336         int ch;
       
   337 
       
   338         fprintf(stderr, PROGNAME ":  aborting.\n");
       
   339         do
       
   340             ch = _getch();
       
   341         while (ch != 'q' && ch != 'Q' && ch != 0x1B);
       
   342         exit(2);
       
   343     } else {
       
   344         fprintf(stderr, "\n%s %s:  %s\n", PROGNAME, VERSION, appname);
       
   345         fprintf(stderr,
       
   346           "\n   [console window:  closing this window will terminate %s]\n\n",
       
   347           PROGNAME);
       
   348     }
       
   349 
       
   350 
       
   351     /* set the title-bar string, but make sure buffer doesn't overflow */
       
   352 
       
   353     alen = strlen(appname);
       
   354     flen = strlen(filename);
       
   355     if (alen + flen + 3 > 1023)
       
   356         sprintf(titlebar, "%s:  ...%s", appname, filename+(alen+flen+6-1023));
       
   357     else
       
   358         sprintf(titlebar, "%s:  %s", appname, filename);
       
   359 
       
   360 
       
   361     /* if the user didn't specify a background color on the command line,
       
   362      * check for one in the PNG file--if not, the initialized values of 0
       
   363      * (black) will be used */
       
   364 
       
   365     if (have_bg) {
       
   366         unsigned r, g, b;   /* this approach quiets compiler warnings */
       
   367 
       
   368         sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
       
   369         bg_red   = (uch)r;
       
   370         bg_green = (uch)g;
       
   371         bg_blue  = (uch)b;
       
   372     } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
       
   373         readpng_cleanup(TRUE);
       
   374         fprintf(stderr, PROGNAME
       
   375           ":  libpng error while checking for background color\n");
       
   376         exit(2);
       
   377     }
       
   378 
       
   379 
       
   380     /* do the basic Windows initialization stuff, make the window and fill it
       
   381      * with the background color */
       
   382 
       
   383     if (rpng_win_create_window(hInst, showmode))
       
   384         exit(2);
       
   385 
       
   386 
       
   387     /* decode the image, all at once */
       
   388 
       
   389     Trace((stderr, "calling readpng_get_image()\n"))
       
   390     image_data = readpng_get_image(display_exponent, &image_channels,
       
   391       &image_rowbytes);
       
   392     Trace((stderr, "done with readpng_get_image()\n"))
       
   393 
       
   394 
       
   395     /* done with PNG file, so clean up to minimize memory usage (but do NOT
       
   396      * nuke image_data!) */
       
   397 
       
   398     readpng_cleanup(FALSE);
       
   399     fclose(infile);
       
   400 
       
   401     if (!image_data) {
       
   402         fprintf(stderr, PROGNAME ":  unable to decode PNG image\n");
       
   403         exit(3);
       
   404     }
       
   405 
       
   406 
       
   407     /* display image (composite with background if requested) */
       
   408 
       
   409     Trace((stderr, "calling rpng_win_display_image()\n"))
       
   410     if (rpng_win_display_image()) {
       
   411         free(image_data);
       
   412         exit(4);
       
   413     }
       
   414     Trace((stderr, "done with rpng_win_display_image()\n"))
       
   415 
       
   416 
       
   417     /* wait for the user to tell us when to quit */
       
   418 
       
   419     printf(
       
   420       "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n");
       
   421     fflush(stdout);
       
   422 
       
   423     while (GetMessage(&msg, NULL, 0, 0)) {
       
   424         TranslateMessage(&msg);
       
   425         DispatchMessage(&msg);
       
   426     }
       
   427 
       
   428 
       
   429     /* OK, we're done:  clean up all image and Windows resources and go away */
       
   430 
       
   431     rpng_win_cleanup();
       
   432 
       
   433     return msg.wParam;
       
   434 }
       
   435 
       
   436 
       
   437 
       
   438 
       
   439 
       
   440 static int rpng_win_create_window(HINSTANCE hInst, int showmode)
       
   441 {
       
   442     uch *dest;
       
   443     int extra_width, extra_height;
       
   444     ulg i, j;
       
   445     WNDCLASSEX wndclass;
       
   446 
       
   447 
       
   448 /*---------------------------------------------------------------------------
       
   449     Allocate memory for the display-specific version of the image (round up
       
   450     to multiple of 4 for Windows DIB).
       
   451   ---------------------------------------------------------------------------*/
       
   452 
       
   453     wimage_rowbytes = ((3*image_width + 3L) >> 2) << 2;
       
   454 
       
   455     if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
       
   456                               wimage_rowbytes*image_height)))
       
   457     {
       
   458         return 4;   /* fail */
       
   459     }
       
   460 
       
   461 /*---------------------------------------------------------------------------
       
   462     Initialize the DIB.  Negative height means to use top-down BMP ordering
       
   463     (must be uncompressed, but that's what we want).  Bit count of 1, 4 or 8
       
   464     implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
       
   465     directly => wimage_data begins immediately after BMP header.
       
   466   ---------------------------------------------------------------------------*/
       
   467 
       
   468     memset(dib, 0, sizeof(BITMAPINFOHEADER));
       
   469     bmih = (BITMAPINFOHEADER *)dib;
       
   470     bmih->biSize = sizeof(BITMAPINFOHEADER);
       
   471     bmih->biWidth = image_width;
       
   472     bmih->biHeight = -((long)image_height);
       
   473     bmih->biPlanes = 1;
       
   474     bmih->biBitCount = 24;
       
   475     bmih->biCompression = 0;
       
   476     wimage_data = dib + sizeof(BITMAPINFOHEADER);
       
   477 
       
   478 /*---------------------------------------------------------------------------
       
   479     Fill in background color (black by default); data are in BGR order.
       
   480   ---------------------------------------------------------------------------*/
       
   481 
       
   482     for (j = 0;  j < image_height;  ++j) {
       
   483         dest = wimage_data + j*wimage_rowbytes;
       
   484         for (i = image_width;  i > 0;  --i) {
       
   485             *dest++ = bg_blue;
       
   486             *dest++ = bg_green;
       
   487             *dest++ = bg_red;
       
   488         }
       
   489     }
       
   490 
       
   491 /*---------------------------------------------------------------------------
       
   492     Set the window parameters.
       
   493   ---------------------------------------------------------------------------*/
       
   494 
       
   495     memset(&wndclass, 0, sizeof(wndclass));
       
   496 
       
   497     wndclass.cbSize = sizeof(wndclass);
       
   498     wndclass.style = CS_HREDRAW | CS_VREDRAW;
       
   499     wndclass.lpfnWndProc = rpng_win_wndproc;
       
   500     wndclass.hInstance = hInst;
       
   501     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
       
   502     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
       
   503     wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
       
   504     wndclass.lpszMenuName = NULL;
       
   505     wndclass.lpszClassName = progname;
       
   506     wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
       
   507 
       
   508     RegisterClassEx(&wndclass);
       
   509 
       
   510 /*---------------------------------------------------------------------------
       
   511     Finally, create the window.
       
   512   ---------------------------------------------------------------------------*/
       
   513 
       
   514     extra_width  = 2*(GetSystemMetrics(SM_CXBORDER) +
       
   515                       GetSystemMetrics(SM_CXDLGFRAME));
       
   516     extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
       
   517                       GetSystemMetrics(SM_CYDLGFRAME)) +
       
   518                       GetSystemMetrics(SM_CYCAPTION);
       
   519 
       
   520     global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
       
   521       CW_USEDEFAULT, CW_USEDEFAULT, image_width+extra_width,
       
   522       image_height+extra_height, NULL, NULL, hInst, NULL);
       
   523 
       
   524     ShowWindow(global_hwnd, showmode);
       
   525     UpdateWindow(global_hwnd);
       
   526 
       
   527     return 0;
       
   528 
       
   529 } /* end function rpng_win_create_window() */
       
   530 
       
   531 
       
   532 
       
   533 
       
   534 
       
   535 static int rpng_win_display_image()
       
   536 {
       
   537     uch *src, *dest;
       
   538     uch r, g, b, a;
       
   539     ulg i, row, lastrow;
       
   540     RECT rect;
       
   541 
       
   542 
       
   543     Trace((stderr, "beginning display loop (image_channels == %d)\n",
       
   544       image_channels))
       
   545     Trace((stderr, "(width = %ld, rowbytes = %ld, wimage_rowbytes = %d)\n",
       
   546       image_width, image_rowbytes, wimage_rowbytes))
       
   547 
       
   548 
       
   549 /*---------------------------------------------------------------------------
       
   550     Blast image data to buffer.  This whole routine takes place before the
       
   551     message loop begins, so there's no real point in any pseudo-progressive
       
   552     display...
       
   553   ---------------------------------------------------------------------------*/
       
   554 
       
   555     for (lastrow = row = 0;  row < image_height;  ++row) {
       
   556         src = image_data + row*image_rowbytes;
       
   557         dest = wimage_data + row*wimage_rowbytes;
       
   558         if (image_channels == 3) {
       
   559             for (i = image_width;  i > 0;  --i) {
       
   560                 r = *src++;
       
   561                 g = *src++;
       
   562                 b = *src++;
       
   563                 *dest++ = b;
       
   564                 *dest++ = g;   /* note reverse order */
       
   565                 *dest++ = r;
       
   566             }
       
   567         } else /* if (image_channels == 4) */ {
       
   568             for (i = image_width;  i > 0;  --i) {
       
   569                 r = *src++;
       
   570                 g = *src++;
       
   571                 b = *src++;
       
   572                 a = *src++;
       
   573                 if (a == 255) {
       
   574                     *dest++ = b;
       
   575                     *dest++ = g;
       
   576                     *dest++ = r;
       
   577                 } else if (a == 0) {
       
   578                     *dest++ = bg_blue;
       
   579                     *dest++ = bg_green;
       
   580                     *dest++ = bg_red;
       
   581                 } else {
       
   582                     /* this macro (copied from png.h) composites the
       
   583                      * foreground and background values and puts the
       
   584                      * result into the first argument; there are no
       
   585                      * side effects with the first argument */
       
   586                     alpha_composite(*dest++, b, a, bg_blue);
       
   587                     alpha_composite(*dest++, g, a, bg_green);
       
   588                     alpha_composite(*dest++, r, a, bg_red);
       
   589                 }
       
   590             }
       
   591         }
       
   592         /* display after every 16 lines */
       
   593         if (((row+1) & 0xf) == 0) {
       
   594             rect.left = 0L;
       
   595             rect.top = (LONG)lastrow;
       
   596             rect.right = (LONG)image_width;      /* possibly off by one? */
       
   597             rect.bottom = (LONG)lastrow + 16L;   /* possibly off by one? */
       
   598             InvalidateRect(global_hwnd, &rect, FALSE);
       
   599             UpdateWindow(global_hwnd);     /* similar to XFlush() */
       
   600             lastrow = row + 1;
       
   601         }
       
   602     }
       
   603 
       
   604     Trace((stderr, "calling final image-flush routine\n"))
       
   605     if (lastrow < image_height) {
       
   606         rect.left = 0L;
       
   607         rect.top = (LONG)lastrow;
       
   608         rect.right = (LONG)image_width;      /* possibly off by one? */
       
   609         rect.bottom = (LONG)image_height;    /* possibly off by one? */
       
   610         InvalidateRect(global_hwnd, &rect, FALSE);
       
   611         UpdateWindow(global_hwnd);     /* similar to XFlush() */
       
   612     }
       
   613 
       
   614 /*
       
   615     last param determines whether or not background is wiped before paint
       
   616     InvalidateRect(global_hwnd, NULL, TRUE);
       
   617     UpdateWindow(global_hwnd);
       
   618  */
       
   619 
       
   620     return 0;
       
   621 }
       
   622 
       
   623 
       
   624 
       
   625 
       
   626 
       
   627 static void rpng_win_cleanup()
       
   628 {
       
   629     if (image_data) {
       
   630         free(image_data);
       
   631         image_data = NULL;
       
   632     }
       
   633 
       
   634     if (dib) {
       
   635         free(dib);
       
   636         dib = NULL;
       
   637     }
       
   638 }
       
   639 
       
   640 
       
   641 
       
   642 
       
   643 
       
   644 LRESULT CALLBACK rpng_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP)
       
   645 {
       
   646     HDC         hdc;
       
   647     PAINTSTRUCT ps;
       
   648     int rc;
       
   649 
       
   650     switch (iMsg) {
       
   651         case WM_CREATE:
       
   652             /* one-time processing here, if any */
       
   653             return 0;
       
   654 
       
   655         case WM_PAINT:
       
   656             hdc = BeginPaint(hwnd, &ps);
       
   657                     /*                    dest                          */
       
   658             rc = StretchDIBits(hdc, 0, 0, image_width, image_height,
       
   659                     /*                    source                        */
       
   660                                     0, 0, image_width, image_height,
       
   661                                     wimage_data, (BITMAPINFO *)bmih,
       
   662                     /*              iUsage: no clue                     */
       
   663                                     0, SRCCOPY);
       
   664             EndPaint(hwnd, &ps);
       
   665             return 0;
       
   666 
       
   667         /* wait for the user to tell us when to quit */
       
   668         case WM_CHAR:
       
   669             switch (wP) {      /* only need one, so ignore repeat count */
       
   670                 case 'q':
       
   671                 case 'Q':
       
   672                 case 0x1B:     /* Esc key */
       
   673                     PostQuitMessage(0);
       
   674             }
       
   675             return 0;
       
   676 
       
   677         case WM_LBUTTONDOWN:   /* another way of quitting */
       
   678         case WM_DESTROY:
       
   679             PostQuitMessage(0);
       
   680             return 0;
       
   681     }
       
   682 
       
   683     return DefWindowProc(hwnd, iMsg, wP, lP);
       
   684 }