VirtualBox

source: vbox/trunk/src/libs/libpng-1.2.8/contrib/gregbook/rpng2-win.c@ 8822

最後變更 在這個檔案從8822是 6395,由 vboxsync 提交於 17 年 前

export libpng and zlib so Windows and OS/2 build cleanly.

  • 屬性 svn:eol-style 設為 native
檔案大小: 42.1 KB
 
1/*---------------------------------------------------------------------------
2
3 rpng2 - progressive-model PNG display program rpng2-win.c
4
5 This program decodes and displays PNG files progressively, as if it were
6 a web browser (though the front end is only set up to read from files).
7 It supports gamma correction, user-specified background colors, and user-
8 specified background patterns (for transparent images). This version is
9 for 32-bit Windows; it may compile under 16-bit Windows with a little
10 tweaking (or maybe not). Thanks to Adam Costello and Pieter S. van der
11 Meulen for the "diamond" and "radial waves" patterns, respectively.
12
13 to do:
14 - handle quoted command-line args (especially filenames with spaces)
15 - finish resizable checkerboard-gradient (sizes 4-128?)
16 - use %.1023s to simplify truncation of title-bar string?
17 - have minimum window width: oh well
18
19 ---------------------------------------------------------------------------
20
21 Changelog:
22 - 1.01: initial public release
23 - 1.02: fixed cut-and-paste error in usage screen (oops...)
24 - 1.03: modified to allow abbreviated options
25 - 1.04: removed bogus extra argument from usage fprintf() [Glenn R-P?];
26 fixed command-line parsing bug
27 - 1.10: enabled "message window"/console (thanks to David Geldreich)
28 - 1.20: added runtime MMX-enabling/disabling and new -mmx* options
29 - 1.21: made minor tweak to usage screen to fit within 25-line console
30
31 ---------------------------------------------------------------------------
32
33 Copyright (c) 1998-2001 Greg Roelofs. All rights reserved.
34
35 This software is provided "as is," without warranty of any kind,
36 express or implied. In no event shall the author or contributors
37 be held liable for any damages arising in any way from the use of
38 this software.
39
40 Permission is granted to anyone to use this software for any purpose,
41 including commercial applications, and to alter it and redistribute
42 it freely, subject to the following restrictions:
43
44 1. Redistributions of source code must retain the above copyright
45 notice, disclaimer, and this list of conditions.
46 2. Redistributions in binary form must reproduce the above copyright
47 notice, disclaimer, and this list of conditions in the documenta-
48 tion and/or other materials provided with the distribution.
49 3. All advertising materials mentioning features or use of this
50 software must display the following acknowledgment:
51
52 This product includes software developed by Greg Roelofs
53 and contributors for the book, "PNG: The Definitive Guide,"
54 published by O'Reilly and Associates.
55
56 ---------------------------------------------------------------------------*/
57
58#define PROGNAME "rpng2-win"
59#define LONGNAME "Progressive PNG Viewer for Windows"
60#define VERSION "1.21 of 29 June 2001"
61
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
66#include <time.h>
67#include <math.h> /* only for PvdM background code */
68#include <windows.h>
69#include <conio.h> /* only for _getch() */
70
71/* all for PvdM background code: */
72#ifndef PI
73# define PI 3.141592653589793238
74#endif
75#define PI_2 (PI*0.5)
76#define INV_PI_360 (360.0 / PI)
77#define MAX(a,b) (a>b?a:b)
78#define MIN(a,b) (a<b?a:b)
79#define CLIP(a,min,max) MAX(min,MIN((a),max))
80#define ABS(a) ((a)<0?-(a):(a))
81#define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
82#define ROUNDF(f) ((int)(f + 0.5))
83
84#define rgb1_max bg_freq
85#define rgb1_min bg_gray
86#define rgb2_max bg_bsat
87#define rgb2_min bg_brot
88
89/* #define DEBUG */ /* this enables the Trace() macros */
90
91#include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
92
93
94/* could just include png.h, but this macro is the only thing we need
95 * (name and typedefs changed to local versions); note that side effects
96 * only happen with alpha (which could easily be avoided with
97 * "ush acopy = (alpha);") */
98
99#define alpha_composite(composite, fg, alpha, bg) { \
100 ush temp = ((ush)(fg)*(ush)(alpha) + \
101 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
102 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
103}
104
105
106#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
107 * block size corresponds roughly to a download
108 * speed 10% faster than theoretical 33.6K maximum
109 * (assuming 8 data bits, 1 stop bit and no other
110 * overhead) */
111
112/* local prototypes */
113static void rpng2_win_init(void);
114static int rpng2_win_create_window(void);
115static int rpng2_win_load_bg_image(void);
116static void rpng2_win_display_row(ulg row);
117static void rpng2_win_finish_display(void);
118static void rpng2_win_cleanup(void);
119LRESULT CALLBACK rpng2_win_wndproc(HWND, UINT, WPARAM, LPARAM);
120
121
122static char titlebar[1024], *window_name = titlebar;
123static char *progname = PROGNAME;
124static char *appname = LONGNAME;
125static char *icon_name = PROGNAME; /* GRR: not (yet) used */
126static char *filename;
127static FILE *infile;
128
129static mainprog_info rpng2_info;
130
131static uch inbuf[INBUFSIZE];
132static int incount;
133
134static int pat = 6; /* must be less than num_bgpat */
135static int bg_image = 0;
136static int bgscale = 16;
137static ulg bg_rowbytes;
138static uch *bg_data;
139
140static struct rgb_color {
141 uch r, g, b;
142} rgb[] = {
143 { 0, 0, 0}, /* 0: black */
144 {255, 255, 255}, /* 1: white */
145 {173, 132, 57}, /* 2: tan */
146 { 64, 132, 0}, /* 3: medium green */
147 {189, 117, 1}, /* 4: gold */
148 {253, 249, 1}, /* 5: yellow */
149 { 0, 0, 255}, /* 6: blue */
150 { 0, 0, 120}, /* 7: medium blue */
151 {255, 0, 255}, /* 8: magenta */
152 { 64, 0, 64}, /* 9: dark magenta */
153 {255, 0, 0}, /* 10: red */
154 { 64, 0, 0}, /* 11: dark red */
155 {255, 127, 0}, /* 12: orange */
156 {192, 96, 0}, /* 13: darker orange */
157 { 24, 60, 0}, /* 14: dark green-yellow */
158 { 85, 125, 200} /* 15: ice blue */
159};
160/* not used for now, but should be for error-checking:
161static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
162 */
163
164/*
165 This whole struct is a fairly cheesy way to keep the number of
166 command-line options to a minimum. The radial-waves background
167 type is a particularly poor fit to the integer elements of the
168 struct...but a few macros and a little fixed-point math will do
169 wonders for ya.
170
171 type bits:
172 F E D C B A 9 8 7 6 5 4 3 2 1 0
173 | | | | |
174 | | +-+-+-- 0 = sharp-edged checkerboard
175 | | 1 = soft diamonds
176 | | 2 = radial waves
177 | | 3-7 = undefined
178 | +-- gradient #2 inverted?
179 +-- alternating columns inverted?
180 */
181static struct background_pattern {
182 ush type;
183 int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */
184 int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/
185} bg[] = {
186 {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
187 {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
188 {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
189 {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
190 {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
191 {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
192 {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
193 {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
194 {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
195 {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
196 {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
197 {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
198 {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
199 {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
200 {2, 16, 256, 100, 250}, /* radial: very tight spiral */
201 {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
202};
203static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
204
205
206/* Windows-specific global variables (could go in struct, but messy...) */
207static ulg wimage_rowbytes;
208static uch *dib;
209static uch *wimage_data;
210static BITMAPINFOHEADER *bmih;
211
212static HWND global_hwnd;
213static HINSTANCE global_hInst;
214static int global_showmode;
215
216
217
218
219int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
220{
221 char *args[1024]; /* arbitrary limit, but should suffice */
222 char **argv = args;
223 char *p, *q, *bgstr = NULL;
224 int argc = 0;
225 int rc, alen, flen;
226 int error = 0;
227 int timing = FALSE;
228 int have_bg = FALSE;
229 double LUT_exponent; /* just the lookup table */
230 double CRT_exponent = 2.2; /* just the monitor */
231 double default_display_exponent; /* whole display system */
232 MSG msg;
233
234
235 /* First initialize a few things, just to be sure--memset takes care of
236 * default background color (black), booleans (FALSE), pointers (NULL),
237 * etc. */
238
239 global_hInst = hInst;
240 global_showmode = showmode;
241 filename = (char *)NULL;
242 memset(&rpng2_info, 0, sizeof(mainprog_info));
243
244
245 /* Next reenable console output, which normally goes to the bit bucket
246 * for windowed apps. Closing the console window will terminate the
247 * app. Thanks to [email protected] for supplying the magical
248 * incantation. */
249
250 AllocConsole();
251 freopen("CONOUT$", "a", stderr);
252 freopen("CONOUT$", "a", stdout);
253
254
255 /* Set the default value for our display-system exponent, i.e., the
256 * product of the CRT exponent and the exponent corresponding to
257 * the frame-buffer's lookup table (LUT), if any. This is not an
258 * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
259 * ones), but it should cover 99% of the current possibilities. And
260 * yes, these ifdefs are completely wasted in a Windows program... */
261
262#if defined(NeXT)
263 /* third-party utilities can modify the default LUT exponent */
264 LUT_exponent = 1.0 / 2.2;
265 /*
266 if (some_next_function_that_returns_gamma(&next_gamma))
267 LUT_exponent = 1.0 / next_gamma;
268 */
269#elif defined(sgi)
270 LUT_exponent = 1.0 / 1.7;
271 /* there doesn't seem to be any documented function to
272 * get the "gamma" value, so we do it the hard way */
273 infile = fopen("/etc/config/system.glGammaVal", "r");
274 if (infile) {
275 double sgi_gamma;
276
277 fgets(tmpline, 80, infile);
278 fclose(infile);
279 sgi_gamma = atof(tmpline);
280 if (sgi_gamma > 0.0)
281 LUT_exponent = 1.0 / sgi_gamma;
282 }
283#elif defined(Macintosh)
284 LUT_exponent = 1.8 / 2.61;
285 /*
286 if (some_mac_function_that_returns_gamma(&mac_gamma))
287 LUT_exponent = mac_gamma / 2.61;
288 */
289#else
290 LUT_exponent = 1.0; /* assume no LUT: most PCs */
291#endif
292
293 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
294 default_display_exponent = LUT_exponent * CRT_exponent;
295
296
297 /* If the user has set the SCREEN_GAMMA environment variable as suggested
298 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
299 * use the default value we just calculated. Either way, the user may
300 * override this via a command-line option. */
301
302 if ((p = getenv("SCREEN_GAMMA")) != NULL)
303 rpng2_info.display_exponent = atof(p);
304 else
305 rpng2_info.display_exponent = default_display_exponent;
306
307
308 /* Windows really hates command lines, so we have to set up our own argv.
309 * Note that we do NOT bother with quoted arguments here, so don't use
310 * filenames with spaces in 'em! */
311
312 argv[argc++] = PROGNAME;
313 p = cmd;
314 for (;;) {
315 if (*p == ' ')
316 while (*++p == ' ')
317 ;
318 /* now p points at the first non-space after some spaces */
319 if (*p == '\0')
320 break; /* nothing after the spaces: done */
321 argv[argc++] = q = p;
322 while (*q && *q != ' ')
323 ++q;
324 /* now q points at a space or the end of the string */
325 if (*q == '\0')
326 break; /* last argv already terminated; quit */
327 *q = '\0'; /* change space to terminator */
328 p = q + 1;
329 }
330 argv[argc] = NULL; /* terminate the argv array itself */
331
332
333 /* Now parse the command line for options and the PNG filename. */
334
335 while (*++argv && !error) {
336 if (!strncmp(*argv, "-gamma", 2)) {
337 if (!*++argv)
338 ++error;
339 else {
340 rpng2_info.display_exponent = atof(*argv);
341 if (rpng2_info.display_exponent <= 0.0)
342 ++error;
343 }
344 } else if (!strncmp(*argv, "-bgcolor", 4)) {
345 if (!*++argv)
346 ++error;
347 else {
348 bgstr = *argv;
349 if (strlen(bgstr) != 7 || bgstr[0] != '#')
350 ++error;
351 else {
352 have_bg = TRUE;
353 bg_image = FALSE;
354 }
355 }
356 } else if (!strncmp(*argv, "-bgpat", 4)) {
357 if (!*++argv)
358 ++error;
359 else {
360 pat = atoi(*argv) - 1;
361 if (pat < 0 || pat >= num_bgpat)
362 ++error;
363 else {
364 bg_image = TRUE;
365 have_bg = FALSE;
366 }
367 }
368 } else if (!strncmp(*argv, "-timing", 2)) {
369 timing = TRUE;
370#if (defined(__i386__) || defined(_M_IX86))
371 } else if (!strncmp(*argv, "-nommxfilters", 7)) {
372 rpng2_info.nommxfilters = TRUE;
373 } else if (!strncmp(*argv, "-nommxcombine", 7)) {
374 rpng2_info.nommxcombine = TRUE;
375 } else if (!strncmp(*argv, "-nommxinterlace", 7)) {
376 rpng2_info.nommxinterlace = TRUE;
377 } else if (!strcmp(*argv, "-nommx")) {
378 rpng2_info.nommxfilters = TRUE;
379 rpng2_info.nommxcombine = TRUE;
380 rpng2_info.nommxinterlace = TRUE;
381#endif
382 } else {
383 if (**argv != '-') {
384 filename = *argv;
385 if (argv[1]) /* shouldn't be any more args after filename */
386 ++error;
387 } else
388 ++error; /* not expecting any other options */
389 }
390 }
391
392 if (!filename) {
393 ++error;
394 } else if (!(infile = fopen(filename, "rb"))) {
395 fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
396 ++error;
397 } else {
398 incount = fread(inbuf, 1, INBUFSIZE, infile);
399 if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
400 fprintf(stderr, PROGNAME
401 ": [%s] is not a PNG file: incorrect signature\n",
402 filename);
403 ++error;
404 } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
405 switch (rc) {
406 case 2:
407 fprintf(stderr, PROGNAME
408 ": [%s] has bad IHDR (libpng longjmp)\n",
409 filename);
410 break;
411 case 4:
412 fprintf(stderr, PROGNAME ": insufficient memory\n");
413 break;
414 default:
415 fprintf(stderr, PROGNAME
416 ": unknown readpng2_init() error\n");
417 break;
418 }
419 ++error;
420 }
421 if (error)
422 fclose(infile);
423 }
424
425
426 /* usage screen */
427
428 if (error) {
429 int ch;
430
431 fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
432 readpng2_version_info();
433 fprintf(stderr, "\n"
434 "Usage: %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n"
435#if (defined(__i386__) || defined(_M_IX86))
436 " %*s [[-nommxfilters] [-nommxcombine] [-nommxinterlace] | -nommx]\n"
437#endif
438 " %*s file.png\n\n"
439 " exp \ttransfer-function exponent (``gamma'') of the display\n"
440 "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
441 "\t\t to the product of the lookup-table exponent (varies)\n"
442 "\t\t and the CRT exponent (usually 2.2); must be positive\n"
443 " bg \tdesired background color in 7-character hex RGB format\n"
444 "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
445 "\t\t used with transparent images; overrides -bgpat option\n"
446 " pat \tdesired background pattern number (1-%d); used with\n"
447 "\t\t transparent images; overrides -bgcolor option\n"
448 " -timing\tenables delay for every block read, to simulate modem\n"
449 "\t\t download of image (~36 Kbps)\n"
450#if (defined(__i386__) || defined(_M_IX86))
451 " -nommx*\tdisable optimized MMX routines for decoding row filters,\n"
452 "\t\t combining rows, and expanding interlacing, respectively\n"
453#endif
454 "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
455 "Press Q or Esc to quit this usage screen. ",
456 PROGNAME,
457#if (defined(__i386__) || defined(_M_IX86))
458 strlen(PROGNAME), " ",
459#endif
460 strlen(PROGNAME), " ", default_display_exponent, num_bgpat);
461 fflush(stderr);
462 do
463 ch = _getch();
464 while (ch != 'q' && ch != 'Q' && ch != 0x1B);
465 exit(1);
466 } else {
467 fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
468 fprintf(stderr,
469 "\n [console window: closing this window will terminate %s]\n\n",
470 PROGNAME);
471 fflush(stderr);
472 }
473
474
475 /* set the title-bar string, but make sure buffer doesn't overflow */
476
477 alen = strlen(appname);
478 flen = strlen(filename);
479 if (alen + flen + 3 > 1023)
480 sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
481 else
482 sprintf(titlebar, "%s: %s", appname, filename);
483
484
485 /* set some final rpng2_info variables before entering main data loop */
486
487 if (have_bg) {
488 unsigned r, g, b; /* this approach quiets compiler warnings */
489
490 sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
491 rpng2_info.bg_red = (uch)r;
492 rpng2_info.bg_green = (uch)g;
493 rpng2_info.bg_blue = (uch)b;
494 } else
495 rpng2_info.need_bgcolor = TRUE;
496
497 rpng2_info.done = FALSE;
498 rpng2_info.mainprog_init = rpng2_win_init;
499 rpng2_info.mainprog_display_row = rpng2_win_display_row;
500 rpng2_info.mainprog_finish_display = rpng2_win_finish_display;
501
502
503 /* OK, this is the fun part: call readpng2_decode_data() at the start of
504 * the loop to deal with our first buffer of data (read in above to verify
505 * that the file is a PNG image), then loop through the file and continue
506 * calling the same routine to handle each chunk of data. It in turn
507 * passes the data to libpng, which will invoke one or more of our call-
508 * backs as decoded data become available. We optionally call Sleep() for
509 * one second per iteration to simulate downloading the image via an analog
510 * modem. */
511
512 for (;;) {
513 Trace((stderr, "about to call readpng2_decode_data()\n"))
514 if (readpng2_decode_data(&rpng2_info, inbuf, incount))
515 ++error;
516 Trace((stderr, "done with readpng2_decode_data()\n"))
517 if (error || feof(infile) || rpng2_info.done)
518 break;
519 if (timing)
520 Sleep(1000L);
521 incount = fread(inbuf, 1, INBUFSIZE, infile);
522 }
523
524
525 /* clean up PNG stuff and report any decoding errors */
526
527 fclose(infile);
528 Trace((stderr, "about to call readpng2_cleanup()\n"))
529 readpng2_cleanup(&rpng2_info);
530
531 if (error) {
532 fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
533 exit(3);
534 }
535
536
537 /* wait for the user to tell us when to quit */
538
539 while (GetMessage(&msg, NULL, 0, 0)) {
540 TranslateMessage(&msg);
541 DispatchMessage(&msg);
542 }
543
544
545 /* we're done: clean up all image and Windows resources and go away */
546
547 Trace((stderr, "about to call rpng2_win_cleanup()\n"))
548 rpng2_win_cleanup();
549
550 return msg.wParam;
551}
552
553
554
555
556
557/* this function is called by readpng2_info_callback() in readpng2.c, which
558 * in turn is called by libpng after all of the pre-IDAT chunks have been
559 * read and processed--i.e., we now have enough info to finish initializing */
560
561static void rpng2_win_init()
562{
563 ulg i;
564 ulg rowbytes = rpng2_info.rowbytes;
565
566 Trace((stderr, "beginning rpng2_win_init()\n"))
567 Trace((stderr, " rowbytes = %ld\n", rpng2_info.rowbytes))
568 Trace((stderr, " width = %ld\n", rpng2_info.width))
569 Trace((stderr, " height = %ld\n", rpng2_info.height))
570
571 rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
572 if (!rpng2_info.image_data) {
573 readpng2_cleanup(&rpng2_info);
574 return;
575 }
576
577 rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
578 if (!rpng2_info.row_pointers) {
579 free(rpng2_info.image_data);
580 rpng2_info.image_data = NULL;
581 readpng2_cleanup(&rpng2_info);
582 return;
583 }
584
585 for (i = 0; i < rpng2_info.height; ++i)
586 rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
587
588/*---------------------------------------------------------------------------
589 Do the basic Windows initialization stuff, make the window, and fill it
590 with the user-specified, file-specified or default background color.
591 ---------------------------------------------------------------------------*/
592
593 if (rpng2_win_create_window()) {
594 readpng2_cleanup(&rpng2_info);
595 return;
596 }
597}
598
599
600
601
602
603static int rpng2_win_create_window()
604{
605 uch bg_red = rpng2_info.bg_red;
606 uch bg_green = rpng2_info.bg_green;
607 uch bg_blue = rpng2_info.bg_blue;
608 uch *dest;
609 int extra_width, extra_height;
610 ulg i, j;
611 WNDCLASSEX wndclass;
612 RECT rect;
613
614
615/*---------------------------------------------------------------------------
616 Allocate memory for the display-specific version of the image (round up
617 to multiple of 4 for Windows DIB).
618 ---------------------------------------------------------------------------*/
619
620 wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2;
621
622 if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
623 wimage_rowbytes*rpng2_info.height)))
624 {
625 return 4; /* fail */
626 }
627
628/*---------------------------------------------------------------------------
629 Initialize the DIB. Negative height means to use top-down BMP ordering
630 (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8
631 implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
632 directly => wimage_data begins immediately after BMP header.
633 ---------------------------------------------------------------------------*/
634
635 memset(dib, 0, sizeof(BITMAPINFOHEADER));
636 bmih = (BITMAPINFOHEADER *)dib;
637 bmih->biSize = sizeof(BITMAPINFOHEADER);
638 bmih->biWidth = rpng2_info.width;
639 bmih->biHeight = -((long)rpng2_info.height);
640 bmih->biPlanes = 1;
641 bmih->biBitCount = 24;
642 bmih->biCompression = 0;
643 wimage_data = dib + sizeof(BITMAPINFOHEADER);
644
645/*---------------------------------------------------------------------------
646 Fill window with the specified background color (default is black), but
647 defer loading faked "background image" until window is displayed (may be
648 slow to compute). Data are in BGR order.
649 ---------------------------------------------------------------------------*/
650
651 if (bg_image) { /* just fill with black for now */
652 memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height);
653 } else {
654 for (j = 0; j < rpng2_info.height; ++j) {
655 dest = wimage_data + j*wimage_rowbytes;
656 for (i = rpng2_info.width; i > 0; --i) {
657 *dest++ = bg_blue;
658 *dest++ = bg_green;
659 *dest++ = bg_red;
660 }
661 }
662 }
663
664/*---------------------------------------------------------------------------
665 Set the window parameters.
666 ---------------------------------------------------------------------------*/
667
668 memset(&wndclass, 0, sizeof(wndclass));
669
670 wndclass.cbSize = sizeof(wndclass);
671 wndclass.style = CS_HREDRAW | CS_VREDRAW;
672 wndclass.lpfnWndProc = rpng2_win_wndproc;
673 wndclass.hInstance = global_hInst;
674 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
675 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
676 wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
677 wndclass.lpszMenuName = NULL;
678 wndclass.lpszClassName = progname;
679 wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
680
681 RegisterClassEx(&wndclass);
682
683/*---------------------------------------------------------------------------
684 Finally, create the window.
685 ---------------------------------------------------------------------------*/
686
687 extra_width = 2*(GetSystemMetrics(SM_CXBORDER) +
688 GetSystemMetrics(SM_CXDLGFRAME));
689 extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
690 GetSystemMetrics(SM_CYDLGFRAME)) +
691 GetSystemMetrics(SM_CYCAPTION);
692
693 global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
694 CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width,
695 rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL);
696
697 ShowWindow(global_hwnd, global_showmode);
698 UpdateWindow(global_hwnd);
699
700/*---------------------------------------------------------------------------
701 Now compute the background image and display it. If it fails (memory
702 allocation), revert to a plain background color.
703 ---------------------------------------------------------------------------*/
704
705 if (bg_image) {
706 static const char *msg = "Computing background image...";
707 int x, y, len = strlen(msg);
708 HDC hdc = GetDC(global_hwnd);
709 TEXTMETRIC tm;
710
711 GetTextMetrics(hdc, &tm);
712 x = (rpng2_info.width - len*tm.tmAveCharWidth)/2;
713 y = (rpng2_info.height - tm.tmHeight)/2;
714 SetBkMode(hdc, TRANSPARENT);
715 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
716 /* this can still begin out of bounds even if x is positive (???): */
717 TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len);
718 ReleaseDC(global_hwnd, hdc);
719
720 rpng2_win_load_bg_image(); /* resets bg_image if fails */
721 }
722
723 if (!bg_image) {
724 for (j = 0; j < rpng2_info.height; ++j) {
725 dest = wimage_data + j*wimage_rowbytes;
726 for (i = rpng2_info.width; i > 0; --i) {
727 *dest++ = bg_blue;
728 *dest++ = bg_green;
729 *dest++ = bg_red;
730 }
731 }
732 }
733
734 rect.left = 0L;
735 rect.top = 0L;
736 rect.right = (LONG)rpng2_info.width; /* possibly off by one? */
737 rect.bottom = (LONG)rpng2_info.height; /* possibly off by one? */
738 InvalidateRect(global_hwnd, &rect, FALSE);
739 UpdateWindow(global_hwnd); /* similar to XFlush() */
740
741 return 0;
742
743} /* end function rpng2_win_create_window() */
744
745
746
747
748
749static int rpng2_win_load_bg_image()
750{
751 uch *src, *dest;
752 uch r1, r2, g1, g2, b1, b2;
753 uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
754 int k, hmax, max;
755 int xidx, yidx, yidx_max = (bgscale-1);
756 int even_odd_vert, even_odd_horiz, even_odd;
757 int invert_gradient2 = (bg[pat].type & 0x08);
758 int invert_column;
759 ulg i, row;
760
761/*---------------------------------------------------------------------------
762 Allocate buffer for fake background image to be used with transparent
763 images; if this fails, revert to plain background color.
764 ---------------------------------------------------------------------------*/
765
766 bg_rowbytes = 3 * rpng2_info.width;
767 bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
768 if (!bg_data) {
769 fprintf(stderr, PROGNAME
770 ": unable to allocate memory for background image\n");
771 bg_image = 0;
772 return 1;
773 }
774
775/*---------------------------------------------------------------------------
776 Vertical gradients (ramps) in NxN squares, alternating direction and
777 colors (N == bgscale).
778 ---------------------------------------------------------------------------*/
779
780 if ((bg[pat].type & 0x07) == 0) {
781 uch r1_min = rgb[bg[pat].rgb1_min].r;
782 uch g1_min = rgb[bg[pat].rgb1_min].g;
783 uch b1_min = rgb[bg[pat].rgb1_min].b;
784 uch r2_min = rgb[bg[pat].rgb2_min].r;
785 uch g2_min = rgb[bg[pat].rgb2_min].g;
786 uch b2_min = rgb[bg[pat].rgb2_min].b;
787 int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
788 int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
789 int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
790 int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
791 int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
792 int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
793
794 for (row = 0; row < rpng2_info.height; ++row) {
795 yidx = row % bgscale;
796 even_odd_vert = (row / bgscale) & 1;
797
798 r1 = r1_min + (r1_diff * yidx) / yidx_max;
799 g1 = g1_min + (g1_diff * yidx) / yidx_max;
800 b1 = b1_min + (b1_diff * yidx) / yidx_max;
801 r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
802 g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
803 b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
804
805 r2 = r2_min + (r2_diff * yidx) / yidx_max;
806 g2 = g2_min + (g2_diff * yidx) / yidx_max;
807 b2 = b2_min + (b2_diff * yidx) / yidx_max;
808 r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
809 g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
810 b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
811
812 dest = bg_data + row*bg_rowbytes;
813 for (i = 0; i < rpng2_info.width; ++i) {
814 even_odd_horiz = (i / bgscale) & 1;
815 even_odd = even_odd_vert ^ even_odd_horiz;
816 invert_column =
817 (even_odd_horiz && (bg[pat].type & 0x10));
818 if (even_odd == 0) { /* gradient #1 */
819 if (invert_column) {
820 *dest++ = r1_inv;
821 *dest++ = g1_inv;
822 *dest++ = b1_inv;
823 } else {
824 *dest++ = r1;
825 *dest++ = g1;
826 *dest++ = b1;
827 }
828 } else { /* gradient #2 */
829 if ((invert_column && invert_gradient2) ||
830 (!invert_column && !invert_gradient2))
831 {
832 *dest++ = r2; /* not inverted or */
833 *dest++ = g2; /* doubly inverted */
834 *dest++ = b2;
835 } else {
836 *dest++ = r2_inv;
837 *dest++ = g2_inv; /* singly inverted */
838 *dest++ = b2_inv;
839 }
840 }
841 }
842 }
843
844/*---------------------------------------------------------------------------
845 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
846 M. Costello.
847 ---------------------------------------------------------------------------*/
848
849 } else if ((bg[pat].type & 0x07) == 1) {
850
851 hmax = (bgscale-1)/2; /* half the max weight of a color */
852 max = 2*hmax; /* the max weight of a color */
853
854 r1 = rgb[bg[pat].rgb1_max].r;
855 g1 = rgb[bg[pat].rgb1_max].g;
856 b1 = rgb[bg[pat].rgb1_max].b;
857 r2 = rgb[bg[pat].rgb2_max].r;
858 g2 = rgb[bg[pat].rgb2_max].g;
859 b2 = rgb[bg[pat].rgb2_max].b;
860
861 for (row = 0; row < rpng2_info.height; ++row) {
862 yidx = row % bgscale;
863 if (yidx > hmax)
864 yidx = bgscale-1 - yidx;
865 dest = bg_data + row*bg_rowbytes;
866 for (i = 0; i < rpng2_info.width; ++i) {
867 xidx = i % bgscale;
868 if (xidx > hmax)
869 xidx = bgscale-1 - xidx;
870 k = xidx + yidx;
871 *dest++ = (k*r1 + (max-k)*r2) / max;
872 *dest++ = (k*g1 + (max-k)*g2) / max;
873 *dest++ = (k*b1 + (max-k)*b2) / max;
874 }
875 }
876
877/*---------------------------------------------------------------------------
878 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
879 soids will equal bgscale?]. This one is slow but very cool. Code con-
880 tributed by Pieter S. van der Meulen (originally in Smalltalk).
881 ---------------------------------------------------------------------------*/
882
883 } else if ((bg[pat].type & 0x07) == 2) {
884 uch ch;
885 int ii, x, y, hw, hh, grayspot;
886 double freq, rotate, saturate, gray, intensity;
887 double angle=0.0, aoffset=0.0, maxDist, dist;
888 double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
889
890 fprintf(stderr, "%s: computing radial background...",
891 PROGNAME);
892 fflush(stderr);
893
894 hh = rpng2_info.height / 2;
895 hw = rpng2_info.width / 2;
896
897 /* variables for radial waves:
898 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
899 * freq: number of color beams originating from the center
900 * grayspot: size of the graying center area (anti-alias)
901 * rotate: rotation of the beams as a function of radius
902 * saturate: saturation of beams' shape azimuthally
903 */
904 angle = CLIP(angle, 0.0, 360.0);
905 grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
906 freq = MAX((double)bg[pat].bg_freq, 0.0);
907 saturate = (double)bg[pat].bg_bsat * 0.1;
908 rotate = (double)bg[pat].bg_brot * 0.1;
909 gray = 0.0;
910 intensity = 0.0;
911 maxDist = (double)((hw*hw) + (hh*hh));
912
913 for (row = 0; row < rpng2_info.height; ++row) {
914 y = row - hh;
915 dest = bg_data + row*bg_rowbytes;
916 for (i = 0; i < rpng2_info.width; ++i) {
917 x = i - hw;
918 angle = (x == 0)? PI_2 : atan((double)y / (double)x);
919 gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
920 gray = MIN(1.0, gray);
921 dist = (double)((x*x) + (y*y)) / maxDist;
922 intensity = cos((angle+(rotate*dist*PI)) * freq) *
923 gray * saturate;
924 intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
925 hue = (angle + PI) * INV_PI_360 + aoffset;
926 s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
927 s = MIN(MAX(s,0.0), 1.0);
928 v = MIN(MAX(intensity,0.0), 1.0);
929
930 if (s == 0.0) {
931 ch = (uch)(v * 255.0);
932 *dest++ = ch;
933 *dest++ = ch;
934 *dest++ = ch;
935 } else {
936 if ((hue < 0.0) || (hue >= 360.0))
937 hue -= (((int)(hue / 360.0)) * 360.0);
938 hue /= 60.0;
939 ii = (int)hue;
940 f = hue - (double)ii;
941 p = (1.0 - s) * v;
942 q = (1.0 - (s * f)) * v;
943 t = (1.0 - (s * (1.0 - f))) * v;
944 if (ii == 0) { red = v; green = t; blue = p; }
945 else if (ii == 1) { red = q; green = v; blue = p; }
946 else if (ii == 2) { red = p; green = v; blue = t; }
947 else if (ii == 3) { red = p; green = q; blue = v; }
948 else if (ii == 4) { red = t; green = p; blue = v; }
949 else if (ii == 5) { red = v; green = p; blue = q; }
950 *dest++ = (uch)(red * 255.0);
951 *dest++ = (uch)(green * 255.0);
952 *dest++ = (uch)(blue * 255.0);
953 }
954 }
955 }
956 fprintf(stderr, "done.\n");
957 fflush(stderr);
958 }
959
960/*---------------------------------------------------------------------------
961 Blast background image to display buffer before beginning PNG decode;
962 calling function will handle invalidation and UpdateWindow() call.
963 ---------------------------------------------------------------------------*/
964
965 for (row = 0; row < rpng2_info.height; ++row) {
966 src = bg_data + row*bg_rowbytes;
967 dest = wimage_data + row*wimage_rowbytes;
968 for (i = rpng2_info.width; i > 0; --i) {
969 r1 = *src++;
970 g1 = *src++;
971 b1 = *src++;
972 *dest++ = b1;
973 *dest++ = g1; /* note reverse order */
974 *dest++ = r1;
975 }
976 }
977
978 return 0;
979
980} /* end function rpng2_win_load_bg_image() */
981
982
983
984
985
986static void rpng2_win_display_row(ulg row)
987{
988 uch bg_red = rpng2_info.bg_red;
989 uch bg_green = rpng2_info.bg_green;
990 uch bg_blue = rpng2_info.bg_blue;
991 uch *src, *src2=NULL, *dest;
992 uch r, g, b, a;
993 ulg i;
994 static int rows=0;
995 static ulg firstrow;
996
997/*---------------------------------------------------------------------------
998 rows and firstrow simply track how many rows (and which ones) have not
999 yet been displayed; alternatively, we could call InvalidateRect() for
1000 every row and not bother with the records-keeping.
1001 ---------------------------------------------------------------------------*/
1002
1003 Trace((stderr, "beginning rpng2_win_display_row()\n"))
1004
1005 if (rows == 0)
1006 firstrow = row; /* first row not yet displayed */
1007
1008 ++rows; /* count of rows received but not yet displayed */
1009
1010/*---------------------------------------------------------------------------
1011 Aside from the use of the rpng2_info struct and the lack of an outer
1012 loop (over rows), this routine is identical to rpng_win_display_image()
1013 in the non-progressive version of the program.
1014 ---------------------------------------------------------------------------*/
1015
1016 src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1017 if (bg_image)
1018 src2 = bg_data + row*bg_rowbytes;
1019 dest = wimage_data + row*wimage_rowbytes;
1020
1021 if (rpng2_info.channels == 3) {
1022 for (i = rpng2_info.width; i > 0; --i) {
1023 r = *src++;
1024 g = *src++;
1025 b = *src++;
1026 *dest++ = b;
1027 *dest++ = g; /* note reverse order */
1028 *dest++ = r;
1029 }
1030 } else /* if (rpng2_info.channels == 4) */ {
1031 for (i = rpng2_info.width; i > 0; --i) {
1032 r = *src++;
1033 g = *src++;
1034 b = *src++;
1035 a = *src++;
1036 if (bg_image) {
1037 bg_red = *src2++;
1038 bg_green = *src2++;
1039 bg_blue = *src2++;
1040 }
1041 if (a == 255) {
1042 *dest++ = b;
1043 *dest++ = g;
1044 *dest++ = r;
1045 } else if (a == 0) {
1046 *dest++ = bg_blue;
1047 *dest++ = bg_green;
1048 *dest++ = bg_red;
1049 } else {
1050 /* this macro (copied from png.h) composites the
1051 * foreground and background values and puts the
1052 * result into the first argument; there are no
1053 * side effects with the first argument */
1054 alpha_composite(*dest++, b, a, bg_blue);
1055 alpha_composite(*dest++, g, a, bg_green);
1056 alpha_composite(*dest++, r, a, bg_red);
1057 }
1058 }
1059 }
1060
1061/*---------------------------------------------------------------------------
1062 Display after every 16 rows or when on last row. (Region may include
1063 previously displayed lines due to interlacing--i.e., not contiguous.)
1064 ---------------------------------------------------------------------------*/
1065
1066 if ((rows & 0xf) == 0 || row == rpng2_info.height-1) {
1067 RECT rect;
1068
1069 rect.left = 0L;
1070 rect.top = (LONG)firstrow;
1071 rect.right = (LONG)rpng2_info.width; /* possibly off by one? */
1072 rect.bottom = (LONG)row + 1L; /* possibly off by one? */
1073 InvalidateRect(global_hwnd, &rect, FALSE);
1074 UpdateWindow(global_hwnd); /* similar to XFlush() */
1075 rows = 0;
1076 }
1077
1078} /* end function rpng2_win_display_row() */
1079
1080
1081
1082
1083
1084static void rpng2_win_finish_display()
1085{
1086 Trace((stderr, "beginning rpng2_win_finish_display()\n"))
1087
1088 /* last row has already been displayed by rpng2_win_display_row(), so
1089 * we have nothing to do here except set a flag and let the user know
1090 * that the image is done */
1091
1092 rpng2_info.done = TRUE;
1093 printf(
1094 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1095 fflush(stdout);
1096}
1097
1098
1099
1100
1101
1102static void rpng2_win_cleanup()
1103{
1104 if (bg_image && bg_data) {
1105 free(bg_data);
1106 bg_data = NULL;
1107 }
1108
1109 if (rpng2_info.image_data) {
1110 free(rpng2_info.image_data);
1111 rpng2_info.image_data = NULL;
1112 }
1113
1114 if (rpng2_info.row_pointers) {
1115 free(rpng2_info.row_pointers);
1116 rpng2_info.row_pointers = NULL;
1117 }
1118
1119 if (dib) {
1120 free(dib);
1121 dib = NULL;
1122 }
1123}
1124
1125
1126
1127
1128
1129LRESULT CALLBACK rpng2_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP)
1130{
1131 HDC hdc;
1132 PAINTSTRUCT ps;
1133 int rc;
1134
1135 switch (iMsg) {
1136 case WM_CREATE:
1137 /* one-time processing here, if any */
1138 return 0;
1139
1140 case WM_PAINT:
1141 hdc = BeginPaint(hwnd, &ps);
1142 rc = StretchDIBits(hdc, 0, 0, rpng2_info.width, rpng2_info.height,
1143 0, 0, rpng2_info.width, rpng2_info.height,
1144 wimage_data, (BITMAPINFO *)bmih,
1145 0, SRCCOPY);
1146 EndPaint(hwnd, &ps);
1147 return 0;
1148
1149 /* wait for the user to tell us when to quit */
1150 case WM_CHAR:
1151 switch (wP) { /* only need one, so ignore repeat count */
1152 case 'q':
1153 case 'Q':
1154 case 0x1B: /* Esc key */
1155 PostQuitMessage(0);
1156 }
1157 return 0;
1158
1159 case WM_LBUTTONDOWN: /* another way of quitting */
1160 case WM_DESTROY:
1161 PostQuitMessage(0);
1162 return 0;
1163 }
1164
1165 return DefWindowProc(hwnd, iMsg, wP, lP);
1166}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette