OSDN Git Service

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