|
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 } |