Mercurial > fife-parpg
comparison ext/libpng-1.2.29/contrib/gregbook/rpng-win.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
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 } |