blob: 0c8ddeba223930f379fe21f648c68aa8798f6f06 [file] [log] [blame]
The Android Open Source Project893912b2009-03-03 19:30:05 -08001/*---------------------------------------------------------------------------
2
3 rpng2 - progressive-model PNG display program rpng2-x.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 the X Window System (tested by the author under Unix and by Martin
10 Zinser under OpenVMS; may work under OS/2 with a little tweaking).
11
12 Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond"
13 and "radial waves" patterns, respectively.
14
15 to do (someday, maybe):
16 - fix expose/redraw code: don't draw entire row if only part exposed
17 - 8-bit (colormapped) X support
18 - finish resizable checkerboard-gradient (sizes 4-128?)
19 - use %.1023s to simplify truncation of title-bar string?
20
21 ---------------------------------------------------------------------------
22
23 Changelog:
24 - 1.01: initial public release
25 - 1.02: modified to allow abbreviated options; fixed char/uchar mismatch
26 - 1.10: added support for non-default visuals; fixed X pixel-conversion
27 - 1.11: added -usleep option for demos; fixed command-line parsing bug
28 - 1.12: added -pause option for demos and testing
29 - 1.20: added runtime MMX-enabling/disabling and new -mmx* options
30 - 1.21: fixed some small X memory leaks (thanks to François Petitjean)
31 - 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche)
32 - 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares)
33 - 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp =
34 24; added support for X resources (thanks to Gerhard Niklasch)
35 - 1.31: added code to skip unused chunks (thanks to Glenn Randers-Pehrson)
36 - 1.32: added AMD64/EM64T support (__x86_64__); added basic expose/redraw
37 handling
38 - 2.00: dual-licensed (added GNU GPL)
39 - 2.01: fixed 64-bit typo in readpng2.c; fixed -pause usage description
40 - 2.02: fixed improper display of usage screen on PNG error(s); fixed
41 unexpected-EOF and file-read-error cases; fixed Trace() cut-and-
42 paste bugs
Chris Craikca2bf812013-07-29 15:28:30 -070043 - 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options
Matt Sarett9ea75692016-01-08 13:00:42 -050044 - 2.04: Added "void(foo);" statements to quiet pedantic compiler warnings
45 about unused variables (GR-P)
46 - 2.05: Use nanosleep() instead of usleep(), which is deprecated (GR-P).
The Android Open Source Project893912b2009-03-03 19:30:05 -080047 ---------------------------------------------------------------------------
48
Matt Sarett9ea75692016-01-08 13:00:42 -050049 Copyright (c) 1998-2010, 2014-2015 Greg Roelofs. All rights reserved.
The Android Open Source Project893912b2009-03-03 19:30:05 -080050
51 This software is provided "as is," without warranty of any kind,
52 express or implied. In no event shall the author or contributors
53 be held liable for any damages arising in any way from the use of
54 this software.
55
56 The contents of this file are DUAL-LICENSED. You may modify and/or
57 redistribute this software according to the terms of one of the
58 following two licenses (at your option):
59
60
61 LICENSE 1 ("BSD-like with advertising clause"):
62
63 Permission is granted to anyone to use this software for any purpose,
64 including commercial applications, and to alter it and redistribute
65 it freely, subject to the following restrictions:
66
67 1. Redistributions of source code must retain the above copyright
68 notice, disclaimer, and this list of conditions.
69 2. Redistributions in binary form must reproduce the above copyright
70 notice, disclaimer, and this list of conditions in the documenta-
71 tion and/or other materials provided with the distribution.
72 3. All advertising materials mentioning features or use of this
73 software must display the following acknowledgment:
74
75 This product includes software developed by Greg Roelofs
76 and contributors for the book, "PNG: The Definitive Guide,"
77 published by O'Reilly and Associates.
78
79
80 LICENSE 2 (GNU GPL v2 or later):
81
82 This program is free software; you can redistribute it and/or modify
83 it under the terms of the GNU General Public License as published by
84 the Free Software Foundation; either version 2 of the License, or
85 (at your option) any later version.
86
87 This program is distributed in the hope that it will be useful,
88 but WITHOUT ANY WARRANTY; without even the implied warranty of
89 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90 GNU General Public License for more details.
91
92 You should have received a copy of the GNU General Public License
93 along with this program; if not, write to the Free Software Foundation,
94 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
95
96 ---------------------------------------------------------------------------*/
97
98#define PROGNAME "rpng2-x"
99#define LONGNAME "Progressive PNG Viewer for X"
Matt Sarett9ea75692016-01-08 13:00:42 -0500100#define VERSION "2.04 of 15 June 2014"
Chris Craikca2bf812013-07-29 15:28:30 -0700101#define RESNAME "rpng2" /* our X resource application name */
102#define RESCLASS "Rpng" /* our X resource class name */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800103
104#include <stdio.h>
105#include <stdlib.h>
106#include <ctype.h>
107#include <string.h>
108#include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
109#include <time.h>
110#include <math.h> /* only for PvdM background code */
111#include <X11/Xlib.h>
112#include <X11/Xutil.h>
113#include <X11/Xos.h>
114#include <X11/keysym.h> /* defines XK_* macros */
115
Matt Sarett9ea75692016-01-08 13:00:42 -0500116#if _POSIX_C_SOURCE >= 199309L /* have nanosleep() */
117# undef usleep
118# define usleep(usec) { \
119 struct timespec ts; \
120 ts.tv_sec = 0; \
121 ts.tv_nsec = (usec) * 1000; \
122 nanosleep(&ts, NULL); }
123# endif
124
125#ifndef usleep /* have neither nanosleep() nor usleep() */
126# define usleep(x) sleep(((x)+499999)/1000000)
127#endif
128
The Android Open Source Project893912b2009-03-03 19:30:05 -0800129#ifdef VMS
130# include <unistd.h>
131#endif
132
133/* all for PvdM background code: */
134#ifndef PI
135# define PI 3.141592653589793238
136#endif
137#define PI_2 (PI*0.5)
138#define INV_PI_360 (360.0 / PI)
139#define MAX(a,b) (a>b?a:b)
140#define MIN(a,b) (a<b?a:b)
141#define CLIP(a,min,max) MAX(min,MIN((a),max))
142#define ABS(a) ((a)<0?-(a):(a))
143#define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
144#define ROUNDF(f) ((int)(f + 0.5))
145
146#define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) || \
147 (e.type == KeyPress && /* v--- or 1 for shifted keys */ \
148 ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
149
Chris Craikca2bf812013-07-29 15:28:30 -0700150#define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800151
152#define rgb1_max bg_freq
153#define rgb1_min bg_gray
154#define rgb2_max bg_bsat
155#define rgb2_min bg_brot
156
157/* #define DEBUG */ /* this enables the Trace() macros */
158
159#include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
160
161
162/* could just include png.h, but this macro is the only thing we need
163 * (name and typedefs changed to local versions); note that side effects
164 * only happen with alpha (which could easily be avoided with
165 * "ush acopy = (alpha);") */
166
167#define alpha_composite(composite, fg, alpha, bg) { \
168 ush temp = ((ush)(fg)*(ush)(alpha) + \
169 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
170 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
171}
172
173
174#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
175 * block size corresponds roughly to a download
176 * speed 10% faster than theoretical 33.6K maximum
177 * (assuming 8 data bits, 1 stop bit and no other
178 * overhead) */
179
180/* local prototypes */
181static void rpng2_x_init (void);
182static int rpng2_x_create_window (void);
183static int rpng2_x_load_bg_image (void);
184static void rpng2_x_display_row (ulg row);
185static void rpng2_x_finish_display (void);
186static void rpng2_x_redisplay_image (ulg startcol, ulg startrow,
187 ulg width, ulg height);
188#ifdef FEATURE_LOOP
189static void rpng2_x_reload_bg_image (void);
190static int is_number (char *p);
191#endif
192static void rpng2_x_cleanup (void);
193static int rpng2_x_msb (ulg u32val);
194
195
196static char titlebar[1024], *window_name = titlebar;
197static char *appname = LONGNAME;
198static char *icon_name = PROGNAME;
199static char *res_name = RESNAME;
200static char *res_class = RESCLASS;
201static char *filename;
202static FILE *infile;
203
204static mainprog_info rpng2_info;
205
206static uch inbuf[INBUFSIZE];
207static int incount;
208
209static int pat = 6; /* must be less than num_bgpat */
210static int bg_image = 0;
211static int bgscale, bgscale_default = 16;
212static ulg bg_rowbytes;
213static uch *bg_data;
214
215int pause_after_pass = FALSE;
216int demo_timing = FALSE;
217ulg usleep_duration = 0L;
218
219static struct rgb_color {
220 uch r, g, b;
221} rgb[] = {
222 { 0, 0, 0}, /* 0: black */
223 {255, 255, 255}, /* 1: white */
224 {173, 132, 57}, /* 2: tan */
225 { 64, 132, 0}, /* 3: medium green */
226 {189, 117, 1}, /* 4: gold */
227 {253, 249, 1}, /* 5: yellow */
228 { 0, 0, 255}, /* 6: blue */
229 { 0, 0, 120}, /* 7: medium blue */
230 {255, 0, 255}, /* 8: magenta */
231 { 64, 0, 64}, /* 9: dark magenta */
232 {255, 0, 0}, /* 10: red */
233 { 64, 0, 0}, /* 11: dark red */
234 {255, 127, 0}, /* 12: orange */
235 {192, 96, 0}, /* 13: darker orange */
236 { 24, 60, 0}, /* 14: dark green-yellow */
237 { 85, 125, 200}, /* 15: ice blue */
238 {192, 192, 192} /* 16: Netscape/Mosaic gray */
239};
240/* not used for now, but should be for error-checking:
241static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
242 */
243
244/*
245 This whole struct is a fairly cheesy way to keep the number of
246 command-line options to a minimum. The radial-waves background
247 type is a particularly poor fit to the integer elements of the
248 struct...but a few macros and a little fixed-point math will do
249 wonders for ya.
250
251 type bits:
252 F E D C B A 9 8 7 6 5 4 3 2 1 0
253 | | | | |
254 | | +-+-+-- 0 = sharp-edged checkerboard
255 | | 1 = soft diamonds
256 | | 2 = radial waves
257 | | 3-7 = undefined
258 | +-- gradient #2 inverted?
259 +-- alternating columns inverted?
260 */
261static struct background_pattern {
262 ush type;
263 int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */
264 int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/
265} bg[] = {
266 {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */
267 {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
268 {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
269 {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
270 {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
271 {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
272 {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
273 {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
274 {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
275 {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
276 {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
277 {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
278 {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
279 {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
280 {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
281 {2, 16, 256, 100, 250}, /* radial: very tight spiral */
282 {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
283};
284static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
285
286
287/* X-specific variables */
288static char *displayname;
289static XImage *ximage;
290static Display *display;
291static int depth;
292static Visual *visual;
293static XVisualInfo *visual_list;
294static int RShift, GShift, BShift;
295static ulg RMask, GMask, BMask;
296static Window window;
297static GC gc;
298static Colormap colormap;
299
300static int have_nondefault_visual = FALSE;
301static int have_colormap = FALSE;
302static int have_window = FALSE;
303static int have_gc = FALSE;
304
305
306
307
308int main(int argc, char **argv)
309{
310#ifdef sgi
311 char tmpline[80];
312#endif
313 char *p, *bgstr = NULL;
314 int rc, alen, flen;
315 int error = 0;
316 int timing = FALSE;
317 int have_bg = FALSE;
318#ifdef FEATURE_LOOP
319 int loop = FALSE;
Chris Craikca2bf812013-07-29 15:28:30 -0700320 long loop_interval = -1; /* seconds (100,000 max) */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800321#endif
322 double LUT_exponent; /* just the lookup table */
323 double CRT_exponent = 2.2; /* just the monitor */
324 double default_display_exponent; /* whole display system */
325 XEvent e;
326 KeySym k;
327
328
329 /* First initialize a few things, just to be sure--memset takes care of
330 * default background color (black), booleans (FALSE), pointers (NULL),
331 * etc. */
332
333 displayname = (char *)NULL;
334 filename = (char *)NULL;
335 memset(&rpng2_info, 0, sizeof(mainprog_info));
336
337
338 /* Set the default value for our display-system exponent, i.e., the
339 * product of the CRT exponent and the exponent corresponding to
340 * the frame-buffer's lookup table (LUT), if any. This is not an
341 * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
342 * ones), but it should cover 99% of the current possibilities. */
343
344#if defined(NeXT)
345 /* third-party utilities can modify the default LUT exponent */
346 LUT_exponent = 1.0 / 2.2;
347 /*
348 if (some_next_function_that_returns_gamma(&next_gamma))
349 LUT_exponent = 1.0 / next_gamma;
350 */
351#elif defined(sgi)
352 LUT_exponent = 1.0 / 1.7;
353 /* there doesn't seem to be any documented function to
354 * get the "gamma" value, so we do it the hard way */
355 infile = fopen("/etc/config/system.glGammaVal", "r");
356 if (infile) {
357 double sgi_gamma;
358
359 fgets(tmpline, 80, infile);
360 fclose(infile);
361 sgi_gamma = atof(tmpline);
362 if (sgi_gamma > 0.0)
363 LUT_exponent = 1.0 / sgi_gamma;
364 }
365#elif defined(Macintosh)
366 LUT_exponent = 1.8 / 2.61;
367 /*
368 if (some_mac_function_that_returns_gamma(&mac_gamma))
369 LUT_exponent = mac_gamma / 2.61;
370 */
371#else
372 LUT_exponent = 1.0; /* assume no LUT: most PCs */
373#endif
374
375 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
376 default_display_exponent = LUT_exponent * CRT_exponent;
377
378
379 /* If the user has set the SCREEN_GAMMA environment variable as suggested
380 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
381 * use the default value we just calculated. Either way, the user may
382 * override this via a command-line option. */
383
384 if ((p = getenv("SCREEN_GAMMA")) != NULL)
385 rpng2_info.display_exponent = atof(p);
386 else
387 rpng2_info.display_exponent = default_display_exponent;
388
389
390 /* Now parse the command line for options and the PNG filename. */
391
392 while (*++argv && !error) {
393 if (!strncmp(*argv, "-display", 2)) {
394 if (!*++argv)
395 ++error;
396 else
397 displayname = *argv;
398 } else if (!strncmp(*argv, "-gamma", 2)) {
399 if (!*++argv)
400 ++error;
401 else {
402 rpng2_info.display_exponent = atof(*argv);
403 if (rpng2_info.display_exponent <= 0.0)
404 ++error;
405 }
406 } else if (!strncmp(*argv, "-bgcolor", 4)) {
407 if (!*++argv)
408 ++error;
409 else {
410 bgstr = *argv;
411 if (strlen(bgstr) != 7 || bgstr[0] != '#')
412 ++error;
413 else {
414 have_bg = TRUE;
415 bg_image = FALSE;
416 }
417 }
418 } else if (!strncmp(*argv, "-bgpat", 4)) {
419 if (!*++argv)
420 ++error;
421 else {
422 pat = atoi(*argv);
423 if (pat >= 0 && pat < num_bgpat) {
424 bg_image = TRUE;
425 have_bg = FALSE;
426 } else
427 ++error;
428 }
429 } else if (!strncmp(*argv, "-usleep", 2)) {
430 if (!*++argv)
431 ++error;
432 else {
433 usleep_duration = (ulg)atol(*argv);
434 demo_timing = TRUE;
435 }
436 } else if (!strncmp(*argv, "-pause", 2)) {
437 pause_after_pass = TRUE;
438 } else if (!strncmp(*argv, "-timing", 2)) {
439 timing = TRUE;
440#ifdef FEATURE_LOOP
441 } else if (!strncmp(*argv, "-loop", 2)) {
442 loop = TRUE;
443 if (!argv[1] || !is_number(argv[1]))
444 loop_interval = 2;
445 else {
446 ++argv;
447 loop_interval = atol(*argv);
448 if (loop_interval < 0)
449 loop_interval = 2;
450 else if (loop_interval > 100000) /* bit more than one day */
451 loop_interval = 100000;
452 }
453#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -0800454 } else {
455 if (**argv != '-') {
456 filename = *argv;
457 if (argv[1]) /* shouldn't be any more args after filename */
458 ++error;
459 } else
460 ++error; /* not expecting any other options */
461 }
462 }
463
464 if (!filename)
465 ++error;
466
467
468 /* print usage screen if any errors up to this point */
469
470 if (error) {
471 fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
472 readpng2_version_info();
473 fprintf(stderr, "\n"
Matt Sarett9ea75692016-01-08 13:00:42 -0500474 "Usage: ");
475 fprintf(stderr,
476 "%s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
477 " %*s [-usleep dur | -timing] [-pause]\n",
478 PROGNAME, (int)strlen(PROGNAME), " ");
479 fprintf(stderr,
The Android Open Source Project893912b2009-03-03 19:30:05 -0800480#ifdef FEATURE_LOOP
Matt Sarett9ea75692016-01-08 13:00:42 -0500481 " [-loop [sec]]"
The Android Open Source Project893912b2009-03-03 19:30:05 -0800482#endif
Matt Sarett9ea75692016-01-08 13:00:42 -0500483 " file.png\n\n");
484 fprintf(stderr,
The Android Open Source Project893912b2009-03-03 19:30:05 -0800485 " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
486 " exp \ttransfer-function exponent (``gamma'') of the display\n"
487 "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
Matt Sarett9ea75692016-01-08 13:00:42 -0500488 "\t\t to the product of the lookup-table exponent (varies)\n",
489 default_display_exponent);
490 fprintf(stderr,
The Android Open Source Project893912b2009-03-03 19:30:05 -0800491 "\t\t and the CRT exponent (usually 2.2); must be positive\n"
492 " bg \tdesired background color in 7-character hex RGB format\n"
493 "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
494 "\t\t used with transparent images; overrides -bgpat\n"
495 " pat \tdesired background pattern number (0-%d); used with\n"
Matt Sarett9ea75692016-01-08 13:00:42 -0500496 "\t\t transparent images; overrides -bgcolor\n",
497 num_bgpat-1);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800498#ifdef FEATURE_LOOP
Matt Sarett9ea75692016-01-08 13:00:42 -0500499 fprintf(stderr,
The Android Open Source Project893912b2009-03-03 19:30:05 -0800500 " -loop\tloops through background images after initial display\n"
501 "\t\t is complete (depends on -bgpat)\n"
Matt Sarett9ea75692016-01-08 13:00:42 -0500502 " sec \tseconds to display each background image (default = 2)\n");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800503#endif
Matt Sarett9ea75692016-01-08 13:00:42 -0500504 fprintf(stderr,
The Android Open Source Project893912b2009-03-03 19:30:05 -0800505 " dur \tduration in microseconds to wait after displaying each\n"
506 "\t\t row (for demo purposes)\n"
507 " -timing\tenables delay for every block read, to simulate modem\n"
508 "\t\t download of image (~36 Kbps)\n"
509 " -pause\tpauses after displaying each pass until mouse clicked\n"
510 "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
Matt Sarett9ea75692016-01-08 13:00:42 -0500511 "is displayed) to quit.\n");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800512 exit(1);
513 }
514
The Android Open Source Project893912b2009-03-03 19:30:05 -0800515 if (!(infile = fopen(filename, "rb"))) {
516 fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
517 ++error;
518 } else {
519 incount = fread(inbuf, 1, INBUFSIZE, infile);
520 if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
521 fprintf(stderr, PROGNAME
522 ": [%s] is not a PNG file: incorrect signature\n",
523 filename);
524 ++error;
525 } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
526 switch (rc) {
527 case 2:
528 fprintf(stderr, PROGNAME
529 ": [%s] has bad IHDR (libpng longjmp)\n", filename);
530 break;
531 case 4:
532 fprintf(stderr, PROGNAME ": insufficient memory\n");
533 break;
534 default:
535 fprintf(stderr, PROGNAME
536 ": unknown readpng2_init() error\n");
537 break;
538 }
539 ++error;
540 } else {
541 Trace((stderr, "about to call XOpenDisplay()\n"))
542 display = XOpenDisplay(displayname);
543 if (!display) {
544 readpng2_cleanup(&rpng2_info);
545 fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
546 displayname? displayname : "default");
547 ++error;
548 }
549 }
550 if (error)
551 fclose(infile);
552 }
553
554
555 if (error) {
556 fprintf(stderr, PROGNAME ": aborting.\n");
557 exit(2);
558 }
559
560
561 /* set the title-bar string, but make sure buffer doesn't overflow */
562
563 alen = strlen(appname);
564 flen = strlen(filename);
565 if (alen + flen + 3 > 1023)
566 sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
567 else
568 sprintf(titlebar, "%s: %s", appname, filename);
569
570
571 /* set some final rpng2_info variables before entering main data loop */
572
573 if (have_bg) {
574 unsigned r, g, b; /* this approach quiets compiler warnings */
575
576 sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
577 rpng2_info.bg_red = (uch)r;
578 rpng2_info.bg_green = (uch)g;
579 rpng2_info.bg_blue = (uch)b;
580 } else
581 rpng2_info.need_bgcolor = TRUE;
582
583 rpng2_info.state = kPreInit;
584 rpng2_info.mainprog_init = rpng2_x_init;
585 rpng2_info.mainprog_display_row = rpng2_x_display_row;
586 rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
587
588
589 /* OK, this is the fun part: call readpng2_decode_data() at the start of
590 * the loop to deal with our first buffer of data (read in above to verify
591 * that the file is a PNG image), then loop through the file and continue
592 * calling the same routine to handle each chunk of data. It in turn
593 * passes the data to libpng, which will invoke one or more of our call-
594 * backs as decoded data become available. We optionally call sleep() for
595 * one second per iteration to simulate downloading the image via an analog
596 * modem. */
597
598 for (;;) {
599 Trace((stderr, "about to call readpng2_decode_data()\n"))
600 if (readpng2_decode_data(&rpng2_info, inbuf, incount))
601 ++error;
602 Trace((stderr, "done with readpng2_decode_data()\n"))
603
604 if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
605 if (rpng2_info.state == kDone) {
606 Trace((stderr, "done decoding PNG image\n"))
607 } else if (ferror(infile)) {
608 fprintf(stderr, PROGNAME
609 ": error while reading PNG image file\n");
610 exit(3);
611 } else if (feof(infile)) {
612 fprintf(stderr, PROGNAME ": end of file reached "
613 "(unexpectedly) while reading PNG image file\n");
614 exit(3);
615 } else /* if (error) */ {
Chris Craikca2bf812013-07-29 15:28:30 -0700616 /* will print error message below */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800617 }
618 break;
619 }
620
621 if (timing)
622 sleep(1);
623
624 incount = fread(inbuf, 1, INBUFSIZE, infile);
625 }
626
627
628 /* clean up PNG stuff and report any decoding errors */
629
630 fclose(infile);
631 Trace((stderr, "about to call readpng2_cleanup()\n"))
632 readpng2_cleanup(&rpng2_info);
633
634 if (error) {
635 fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
636 exit(3);
637 }
638
639
640#ifdef FEATURE_LOOP
641
642 if (loop && bg_image) {
643 Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n"))
644 for (;;) {
645 int i, use_sleep;
646 struct timeval now, then;
647
648 /* get current time and add loop_interval to get target time */
649 if (gettimeofday(&then, NULL) == 0) {
650 then.tv_sec += loop_interval;
651 use_sleep = FALSE;
652 } else
653 use_sleep = TRUE;
654
655 /* do quick check for a quit event but don't wait for it */
656 /* GRR BUG: should also check for Expose events and redraw... */
657 if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e))
658 if (QUIT(e,k))
659 break;
660
661 /* generate next background image */
662 if (++pat >= num_bgpat)
663 pat = 0;
664 rpng2_x_reload_bg_image();
665
666 /* wait for timeout, using whatever means are available */
667 if (use_sleep || gettimeofday(&now, NULL) != 0) {
668 for (i = loop_interval; i > 0; --i) {
669 sleep(1);
670 /* GRR BUG: also need to check for Expose (and redraw!) */
671 if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask,
672 &e) && QUIT(e,k))
673 break;
674 }
675 } else {
676 /* Y2038 BUG! */
677 if (now.tv_sec < then.tv_sec ||
678 (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec))
679 {
680 int quit = FALSE;
681 long seconds_to_go = then.tv_sec - now.tv_sec;
682 long usleep_usec;
683
684 /* basically chew up most of remaining loop-interval with
685 * calls to sleep(1) interleaved with checks for quit
686 * events, but also recalc time-to-go periodically; when
687 * done, clean up any remaining time with usleep() call
688 * (could also use SIGALRM, but signals are a pain...) */
689 while (seconds_to_go-- > 1) {
690 int seconds_done = 0;
691
692 for (i = seconds_to_go; i > 0 && !quit; --i) {
693 sleep(1);
694 /* GRR BUG: need to check for Expose and redraw */
695 if (XCheckMaskEvent(display, KeyPressMask |
696 ButtonPressMask, &e) && QUIT(e,k))
697 quit = TRUE;
698 if (++seconds_done > 1000)
699 break; /* time to redo seconds_to_go meas. */
700 }
701 if (quit)
702 break;
703
704 /* OK, more than 1000 seconds since last check:
705 * correct the time-to-go measurement for drift */
706 if (gettimeofday(&now, NULL) == 0) {
707 if (now.tv_sec >= then.tv_sec)
708 break;
709 seconds_to_go = then.tv_sec - now.tv_sec;
710 } else
711 ++seconds_to_go; /* restore what we subtracted */
712 }
713 if (quit)
714 break; /* breaks outer do-loop, skips redisplay */
715
716 /* since difference between "now" and "then" is already
717 * eaten up to within a couple of seconds, don't need to
718 * worry about overflow--but might have overshot (neg.) */
719 if (gettimeofday(&now, NULL) == 0) {
720 usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) +
721 then.tv_usec - now.tv_usec;
722 if (usleep_usec > 0)
723 usleep((ulg)usleep_usec);
724 }
725 }
726 }
727
728 /* composite image against new background and display (note that
729 * we do not take into account the time spent doing this...) */
730 rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height);
731 }
732
733 } else /* FALL THROUGH and do the normal thing */
734
735#endif /* FEATURE_LOOP */
736
737 /* wait for the user to tell us when to quit */
738
739 if (rpng2_info.state >= kWindowInit) {
740 Trace((stderr, "entering final wait-for-quit-event loop\n"))
741 do {
742 XNextEvent(display, &e);
743 if (e.type == Expose) {
744 XExposeEvent *ex = (XExposeEvent *)&e;
745 rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height);
746 }
747 } while (!QUIT(e,k));
748 } else {
749 fprintf(stderr, PROGNAME ": init callback never called: probable "
750 "libpng error while decoding PNG metadata\n");
751 exit(4);
752 }
753
754
755 /* we're done: clean up all image and X resources and go away */
756
757 Trace((stderr, "about to call rpng2_x_cleanup()\n"))
758 rpng2_x_cleanup();
759
Matt Sarett9ea75692016-01-08 13:00:42 -0500760 (void)argc; /* Unused */
761
The Android Open Source Project893912b2009-03-03 19:30:05 -0800762 return 0;
763}
764
765
766
767
768
769/* this function is called by readpng2_info_callback() in readpng2.c, which
770 * in turn is called by libpng after all of the pre-IDAT chunks have been
771 * read and processed--i.e., we now have enough info to finish initializing */
772
773static void rpng2_x_init(void)
774{
775 ulg i;
776 ulg rowbytes = rpng2_info.rowbytes;
777
778 Trace((stderr, "beginning rpng2_x_init()\n"))
779 Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes))
780 Trace((stderr, " width = %ld\n", rpng2_info.width))
781 Trace((stderr, " height = %ld\n", rpng2_info.height))
782
783 rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
784 if (!rpng2_info.image_data) {
785 readpng2_cleanup(&rpng2_info);
786 return;
787 }
788
789 rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
790 if (!rpng2_info.row_pointers) {
791 free(rpng2_info.image_data);
792 rpng2_info.image_data = NULL;
793 readpng2_cleanup(&rpng2_info);
794 return;
795 }
796
797 for (i = 0; i < rpng2_info.height; ++i)
798 rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
799
800
801 /* do the basic X initialization stuff, make the window, and fill it with
802 * the user-specified, file-specified or default background color or
803 * pattern */
804
805 if (rpng2_x_create_window()) {
806
807 /* GRR TEMPORARY HACK: this is fundamentally no different from cases
Chris Craikca2bf812013-07-29 15:28:30 -0700808 * above; libpng should call our error handler to longjmp() back to us
809 * when png_ptr goes away. If we/it segfault instead, seems like a
810 * libpng bug... */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800811
812 /* we're here via libpng callback, so if window fails, clean and bail */
813 readpng2_cleanup(&rpng2_info);
814 rpng2_x_cleanup();
815 exit(2);
816 }
817
818 rpng2_info.state = kWindowInit;
819}
820
821
822
823
824
825static int rpng2_x_create_window(void)
826{
827 ulg bg_red = rpng2_info.bg_red;
828 ulg bg_green = rpng2_info.bg_green;
829 ulg bg_blue = rpng2_info.bg_blue;
830 ulg bg_pixel = 0L;
831 ulg attrmask;
832 int need_colormap = FALSE;
833 int screen, pad;
834 uch *xdata;
835 Window root;
836 XEvent e;
837 XGCValues gcvalues;
838 XSetWindowAttributes attr;
839 XTextProperty windowName, *pWindowName = &windowName;
840 XTextProperty iconName, *pIconName = &iconName;
841 XVisualInfo visual_info;
842 XSizeHints *size_hints;
843 XWMHints *wm_hints;
844 XClassHint *class_hints;
845
846
847 Trace((stderr, "beginning rpng2_x_create_window()\n"))
848
849 screen = DefaultScreen(display);
850 depth = DisplayPlanes(display, screen);
851 root = RootWindow(display, screen);
852
853#ifdef DEBUG
854 XSynchronize(display, True);
855#endif
856
857 if (depth != 16 && depth != 24 && depth != 32) {
858 int visuals_matched = 0;
859
860 Trace((stderr, "default depth is %d: checking other visuals\n",
861 depth))
862
863 /* 24-bit first */
864 visual_info.screen = screen;
865 visual_info.depth = 24;
866 visual_list = XGetVisualInfo(display,
867 VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
868 if (visuals_matched == 0) {
869/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
870 fprintf(stderr, "default screen depth %d not supported, and no"
871 " 24-bit visuals found\n", depth);
872 return 2;
873 }
874 Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
875 visuals_matched))
876 visual = visual_list[0].visual;
877 depth = visual_list[0].depth;
878/*
879 colormap_size = visual_list[0].colormap_size;
880 visual_class = visual->class;
881 visualID = XVisualIDFromVisual(visual);
882 */
883 have_nondefault_visual = TRUE;
884 need_colormap = TRUE;
885 } else {
886 XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
887 visual = visual_info.visual;
888 }
889
890 RMask = visual->red_mask;
891 GMask = visual->green_mask;
892 BMask = visual->blue_mask;
893
894/* GRR: add/check 8-bit support */
895 if (depth == 8 || need_colormap) {
896 colormap = XCreateColormap(display, root, visual, AllocNone);
897 if (!colormap) {
898 fprintf(stderr, "XCreateColormap() failed\n");
899 return 2;
900 }
901 have_colormap = TRUE;
902 if (depth == 8)
903 bg_image = FALSE; /* gradient just wastes palette entries */
904 }
905 if (depth == 15 || depth == 16) {
906 RShift = 15 - rpng2_x_msb(RMask); /* these are right-shifts */
907 GShift = 15 - rpng2_x_msb(GMask);
908 BShift = 15 - rpng2_x_msb(BMask);
909 } else if (depth > 16) {
910 RShift = rpng2_x_msb(RMask) - 7; /* these are left-shifts */
911 GShift = rpng2_x_msb(GMask) - 7;
912 BShift = rpng2_x_msb(BMask) - 7;
913 }
914 if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
915 fprintf(stderr, "rpng2 internal logic error: negative X shift(s)!\n");
916 return 2;
917 }
918
919/*---------------------------------------------------------------------------
920 Finally, create the window.
921 ---------------------------------------------------------------------------*/
922
923 attr.backing_store = Always;
924 attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
925 attrmask = CWBackingStore | CWEventMask;
926 if (have_nondefault_visual) {
927 attr.colormap = colormap;
928 attr.background_pixel = 0;
929 attr.border_pixel = 1;
930 attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
931 }
932
933 window = XCreateWindow(display, root, 0, 0, rpng2_info.width,
934 rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr);
935
936 if (window == None) {
937 fprintf(stderr, "XCreateWindow() failed\n");
938 return 2;
939 } else
940 have_window = TRUE;
941
942 if (depth == 8)
943 XSetWindowColormap(display, window, colormap);
944
945 if (!XStringListToTextProperty(&window_name, 1, pWindowName))
946 pWindowName = NULL;
947 if (!XStringListToTextProperty(&icon_name, 1, pIconName))
948 pIconName = NULL;
949
950 /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
951
952 if ((size_hints = XAllocSizeHints()) != NULL) {
953 /* window will not be resizable */
954 size_hints->flags = PMinSize | PMaxSize;
955 size_hints->min_width = size_hints->max_width = (int)rpng2_info.width;
956 size_hints->min_height = size_hints->max_height =
957 (int)rpng2_info.height;
958 }
959
960 if ((wm_hints = XAllocWMHints()) != NULL) {
961 wm_hints->initial_state = NormalState;
962 wm_hints->input = True;
963 /* wm_hints->icon_pixmap = icon_pixmap; */
964 wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
965 }
966
967 if ((class_hints = XAllocClassHint()) != NULL) {
968 class_hints->res_name = res_name;
969 class_hints->res_class = res_class;
970 }
971
972 XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
973 size_hints, wm_hints, class_hints);
974
975 /* various properties and hints no longer needed; free memory */
976 if (pWindowName)
977 XFree(pWindowName->value);
978 if (pIconName)
979 XFree(pIconName->value);
980 if (size_hints)
981 XFree(size_hints);
982 if (wm_hints)
983 XFree(wm_hints);
984 if (class_hints)
985 XFree(class_hints);
986
987 XMapWindow(display, window);
988
989 gc = XCreateGC(display, window, 0, &gcvalues);
990 have_gc = TRUE;
991
992/*---------------------------------------------------------------------------
993 Allocate memory for the X- and display-specific version of the image.
994 ---------------------------------------------------------------------------*/
995
996 if (depth == 24 || depth == 32) {
997 xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height);
998 pad = 32;
999 } else if (depth == 16) {
1000 xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height);
1001 pad = 16;
1002 } else /* depth == 8 */ {
1003 xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height);
1004 pad = 8;
1005 }
1006
1007 if (!xdata) {
1008 fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
1009 return 4;
1010 }
1011
1012 ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
1013 (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0);
1014
1015 if (!ximage) {
1016 fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
1017 free(xdata);
1018 return 3;
1019 }
1020
1021 /* to avoid testing the byte order every pixel (or doubling the size of
1022 * the drawing routine with a giant if-test), we arbitrarily set the byte
1023 * order to MSBFirst and let Xlib worry about inverting things on little-
1024 * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
1025 * most efficient approach (the giant if-test would be better), but in
1026 * the interest of clarity, we'll take the easy way out... */
1027
1028 ximage->byte_order = MSBFirst;
1029
1030/*---------------------------------------------------------------------------
1031 Fill window with the specified background color (default is black) or
1032 faked "background image" (but latter is disabled if 8-bit; gradients
1033 just waste palette entries).
1034 ---------------------------------------------------------------------------*/
1035
1036 if (bg_image)
1037 rpng2_x_load_bg_image(); /* resets bg_image if fails */
1038
1039 if (!bg_image) {
1040 if (depth == 24 || depth == 32) {
1041 bg_pixel = (bg_red << RShift) |
1042 (bg_green << GShift) |
1043 (bg_blue << BShift);
1044 } else if (depth == 16) {
1045 bg_pixel = (((bg_red << 8) >> RShift) & RMask) |
1046 (((bg_green << 8) >> GShift) & GMask) |
1047 (((bg_blue << 8) >> BShift) & BMask);
1048 } else /* depth == 8 */ {
1049
1050 /* GRR: add 8-bit support */
1051
1052 }
1053 XSetForeground(display, gc, bg_pixel);
1054 XFillRectangle(display, window, gc, 0, 0, rpng2_info.width,
1055 rpng2_info.height);
1056 }
1057
1058/*---------------------------------------------------------------------------
1059 Wait for first Expose event to do any drawing, then flush and return.
1060 ---------------------------------------------------------------------------*/
1061
1062 do
1063 XNextEvent(display, &e);
1064 while (e.type != Expose || e.xexpose.count);
1065
1066 XFlush(display);
1067
1068 return 0;
1069
1070} /* end function rpng2_x_create_window() */
1071
1072
1073
1074
1075
1076static int rpng2_x_load_bg_image(void)
1077{
1078 uch *src;
1079 char *dest;
1080 uch r1, r2, g1, g2, b1, b2;
1081 uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1082 int k, hmax, max;
1083 int xidx, yidx, yidx_max;
1084 int even_odd_vert, even_odd_horiz, even_odd;
1085 int invert_gradient2 = (bg[pat].type & 0x08);
1086 int invert_column;
1087 int ximage_rowbytes = ximage->bytes_per_line;
1088 ulg i, row;
1089 ulg pixel;
1090
1091/*---------------------------------------------------------------------------
1092 Allocate buffer for fake background image to be used with transparent
1093 images; if this fails, revert to plain background color.
1094 ---------------------------------------------------------------------------*/
1095
1096 bg_rowbytes = 3 * rpng2_info.width;
1097 bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
1098 if (!bg_data) {
1099 fprintf(stderr, PROGNAME
1100 ": unable to allocate memory for background image\n");
1101 bg_image = 0;
1102 return 1;
1103 }
1104
1105 bgscale = (pat == 0)? 8 : bgscale_default;
1106 yidx_max = bgscale - 1;
1107
1108/*---------------------------------------------------------------------------
1109 Vertical gradients (ramps) in NxN squares, alternating direction and
1110 colors (N == bgscale).
1111 ---------------------------------------------------------------------------*/
1112
1113 if ((bg[pat].type & 0x07) == 0) {
1114 uch r1_min = rgb[bg[pat].rgb1_min].r;
1115 uch g1_min = rgb[bg[pat].rgb1_min].g;
1116 uch b1_min = rgb[bg[pat].rgb1_min].b;
1117 uch r2_min = rgb[bg[pat].rgb2_min].r;
1118 uch g2_min = rgb[bg[pat].rgb2_min].g;
1119 uch b2_min = rgb[bg[pat].rgb2_min].b;
1120 int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1121 int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1122 int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1123 int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1124 int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1125 int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1126
1127 for (row = 0; row < rpng2_info.height; ++row) {
1128 yidx = (int)(row % bgscale);
1129 even_odd_vert = (int)((row / bgscale) & 1);
1130
1131 r1 = r1_min + (r1_diff * yidx) / yidx_max;
1132 g1 = g1_min + (g1_diff * yidx) / yidx_max;
1133 b1 = b1_min + (b1_diff * yidx) / yidx_max;
1134 r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1135 g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1136 b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1137
1138 r2 = r2_min + (r2_diff * yidx) / yidx_max;
1139 g2 = g2_min + (g2_diff * yidx) / yidx_max;
1140 b2 = b2_min + (b2_diff * yidx) / yidx_max;
1141 r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1142 g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1143 b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1144
1145 dest = (char *)bg_data + row*bg_rowbytes;
1146 for (i = 0; i < rpng2_info.width; ++i) {
1147 even_odd_horiz = (int)((i / bgscale) & 1);
1148 even_odd = even_odd_vert ^ even_odd_horiz;
1149 invert_column =
1150 (even_odd_horiz && (bg[pat].type & 0x10));
1151 if (even_odd == 0) { /* gradient #1 */
1152 if (invert_column) {
1153 *dest++ = r1_inv;
1154 *dest++ = g1_inv;
1155 *dest++ = b1_inv;
1156 } else {
1157 *dest++ = r1;
1158 *dest++ = g1;
1159 *dest++ = b1;
1160 }
1161 } else { /* gradient #2 */
1162 if ((invert_column && invert_gradient2) ||
1163 (!invert_column && !invert_gradient2))
1164 {
1165 *dest++ = r2; /* not inverted or */
1166 *dest++ = g2; /* doubly inverted */
1167 *dest++ = b2;
1168 } else {
1169 *dest++ = r2_inv;
1170 *dest++ = g2_inv; /* singly inverted */
1171 *dest++ = b2_inv;
1172 }
1173 }
1174 }
1175 }
1176
1177/*---------------------------------------------------------------------------
1178 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1179 M. Costello.
1180 ---------------------------------------------------------------------------*/
1181
1182 } else if ((bg[pat].type & 0x07) == 1) {
1183
1184 hmax = (bgscale-1)/2; /* half the max weight of a color */
1185 max = 2*hmax; /* the max weight of a color */
1186
1187 r1 = rgb[bg[pat].rgb1_max].r;
1188 g1 = rgb[bg[pat].rgb1_max].g;
1189 b1 = rgb[bg[pat].rgb1_max].b;
1190 r2 = rgb[bg[pat].rgb2_max].r;
1191 g2 = rgb[bg[pat].rgb2_max].g;
1192 b2 = rgb[bg[pat].rgb2_max].b;
1193
1194 for (row = 0; row < rpng2_info.height; ++row) {
1195 yidx = (int)(row % bgscale);
1196 if (yidx > hmax)
1197 yidx = bgscale-1 - yidx;
1198 dest = (char *)bg_data + row*bg_rowbytes;
1199 for (i = 0; i < rpng2_info.width; ++i) {
1200 xidx = (int)(i % bgscale);
1201 if (xidx > hmax)
1202 xidx = bgscale-1 - xidx;
1203 k = xidx + yidx;
1204 *dest++ = (k*r1 + (max-k)*r2) / max;
1205 *dest++ = (k*g1 + (max-k)*g2) / max;
1206 *dest++ = (k*b1 + (max-k)*b2) / max;
1207 }
1208 }
1209
1210/*---------------------------------------------------------------------------
1211 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1212 soids will equal bgscale?]. This one is slow but very cool. Code con-
1213 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1214 ---------------------------------------------------------------------------*/
1215
1216 } else if ((bg[pat].type & 0x07) == 2) {
1217 uch ch;
1218 int ii, x, y, hw, hh, grayspot;
1219 double freq, rotate, saturate, gray, intensity;
1220 double angle=0.0, aoffset=0.0, maxDist, dist;
1221 double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1222
1223 fprintf(stderr, "%s: computing radial background...",
1224 PROGNAME);
1225 fflush(stderr);
1226
1227 hh = (int)(rpng2_info.height / 2);
1228 hw = (int)(rpng2_info.width / 2);
1229
1230 /* variables for radial waves:
1231 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
1232 * freq: number of color beams originating from the center
1233 * grayspot: size of the graying center area (anti-alias)
1234 * rotate: rotation of the beams as a function of radius
1235 * saturate: saturation of beams' shape azimuthally
1236 */
1237 angle = CLIP(angle, 0.0, 360.0);
1238 grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
1239 freq = MAX((double)bg[pat].bg_freq, 0.0);
1240 saturate = (double)bg[pat].bg_bsat * 0.1;
1241 rotate = (double)bg[pat].bg_brot * 0.1;
1242 gray = 0.0;
1243 intensity = 0.0;
1244 maxDist = (double)((hw*hw) + (hh*hh));
1245
1246 for (row = 0; row < rpng2_info.height; ++row) {
1247 y = (int)(row - hh);
1248 dest = (char *)bg_data + row*bg_rowbytes;
1249 for (i = 0; i < rpng2_info.width; ++i) {
1250 x = (int)(i - hw);
1251 angle = (x == 0)? PI_2 : atan((double)y / (double)x);
1252 gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
1253 gray = MIN(1.0, gray);
1254 dist = (double)((x*x) + (y*y)) / maxDist;
1255 intensity = cos((angle+(rotate*dist*PI)) * freq) *
1256 gray * saturate;
1257 intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
1258 hue = (angle + PI) * INV_PI_360 + aoffset;
1259 s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
1260 s = MIN(MAX(s,0.0), 1.0);
1261 v = MIN(MAX(intensity,0.0), 1.0);
1262
1263 if (s == 0.0) {
1264 ch = (uch)(v * 255.0);
1265 *dest++ = ch;
1266 *dest++ = ch;
1267 *dest++ = ch;
1268 } else {
1269 if ((hue < 0.0) || (hue >= 360.0))
1270 hue -= (((int)(hue / 360.0)) * 360.0);
1271 hue /= 60.0;
1272 ii = (int)hue;
1273 f = hue - (double)ii;
1274 p = (1.0 - s) * v;
1275 q = (1.0 - (s * f)) * v;
1276 t = (1.0 - (s * (1.0 - f))) * v;
1277 if (ii == 0) { red = v; green = t; blue = p; }
1278 else if (ii == 1) { red = q; green = v; blue = p; }
1279 else if (ii == 2) { red = p; green = v; blue = t; }
1280 else if (ii == 3) { red = p; green = q; blue = v; }
1281 else if (ii == 4) { red = t; green = p; blue = v; }
1282 else if (ii == 5) { red = v; green = p; blue = q; }
1283 *dest++ = (uch)(red * 255.0);
1284 *dest++ = (uch)(green * 255.0);
1285 *dest++ = (uch)(blue * 255.0);
1286 }
1287 }
1288 }
1289 fprintf(stderr, "done.\n");
1290 fflush(stderr);
1291 }
1292
1293/*---------------------------------------------------------------------------
1294 Blast background image to display buffer before beginning PNG decode.
1295 ---------------------------------------------------------------------------*/
1296
1297 if (depth == 24 || depth == 32) {
1298 ulg red, green, blue;
1299 int bpp = ximage->bits_per_pixel;
1300
1301 for (row = 0; row < rpng2_info.height; ++row) {
1302 src = bg_data + row*bg_rowbytes;
1303 dest = ximage->data + row*ximage_rowbytes;
Chris Craikca2bf812013-07-29 15:28:30 -07001304 if (bpp == 32) { /* slightly optimized version */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001305 for (i = rpng2_info.width; i > 0; --i) {
1306 red = *src++;
1307 green = *src++;
1308 blue = *src++;
1309 pixel = (red << RShift) |
1310 (green << GShift) |
1311 (blue << BShift);
1312 /* recall that we set ximage->byte_order = MSBFirst above */
1313 *dest++ = (char)((pixel >> 24) & 0xff);
1314 *dest++ = (char)((pixel >> 16) & 0xff);
1315 *dest++ = (char)((pixel >> 8) & 0xff);
1316 *dest++ = (char)( pixel & 0xff);
1317 }
1318 } else {
1319 for (i = rpng2_info.width; i > 0; --i) {
1320 red = *src++;
1321 green = *src++;
1322 blue = *src++;
1323 pixel = (red << RShift) |
1324 (green << GShift) |
1325 (blue << BShift);
1326 /* recall that we set ximage->byte_order = MSBFirst above */
1327 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1328 /* (probably need to use RShift, RMask, etc.) */
1329 *dest++ = (char)((pixel >> 16) & 0xff);
1330 *dest++ = (char)((pixel >> 8) & 0xff);
1331 *dest++ = (char)( pixel & 0xff);
1332 }
1333 }
1334 }
1335
1336 } else if (depth == 16) {
1337 ush red, green, blue;
1338
1339 for (row = 0; row < rpng2_info.height; ++row) {
1340 src = bg_data + row*bg_rowbytes;
1341 dest = ximage->data + row*ximage_rowbytes;
1342 for (i = rpng2_info.width; i > 0; --i) {
1343 red = ((ush)(*src) << 8); ++src;
1344 green = ((ush)(*src) << 8); ++src;
1345 blue = ((ush)(*src) << 8); ++src;
1346 pixel = ((red >> RShift) & RMask) |
1347 ((green >> GShift) & GMask) |
1348 ((blue >> BShift) & BMask);
1349 /* recall that we set ximage->byte_order = MSBFirst above */
1350 *dest++ = (char)((pixel >> 8) & 0xff);
1351 *dest++ = (char)( pixel & 0xff);
1352 }
1353 }
1354
1355 } else /* depth == 8 */ {
1356
1357 /* GRR: add 8-bit support */
1358
1359 }
1360
1361 XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width,
1362 rpng2_info.height);
1363
1364 return 0;
1365
1366} /* end function rpng2_x_load_bg_image() */
1367
1368
1369
1370
1371
1372static void rpng2_x_display_row(ulg row)
1373{
1374 uch bg_red = rpng2_info.bg_red;
1375 uch bg_green = rpng2_info.bg_green;
1376 uch bg_blue = rpng2_info.bg_blue;
1377 uch *src, *src2=NULL;
1378 char *dest;
1379 uch r, g, b, a;
1380 int ximage_rowbytes = ximage->bytes_per_line;
1381 ulg i, pixel;
1382 static int rows=0, prevpass=(-1);
1383 static ulg firstrow;
1384
1385/*---------------------------------------------------------------------------
1386 rows and firstrow simply track how many rows (and which ones) have not
1387 yet been displayed; alternatively, we could call XPutImage() for every
1388 row and not bother with the records-keeping.
1389 ---------------------------------------------------------------------------*/
1390
1391 Trace((stderr, "beginning rpng2_x_display_row()\n"))
1392
1393 if (rpng2_info.pass != prevpass) {
1394 if (pause_after_pass && rpng2_info.pass > 0) {
1395 XEvent e;
1396 KeySym k;
1397
1398 fprintf(stderr,
1399 "%s: end of pass %d of 7; click in image window to continue\n",
1400 PROGNAME, prevpass + 1);
1401 do
1402 XNextEvent(display, &e);
1403 while (!QUIT(e,k));
1404 }
1405 fprintf(stderr, "%s: pass %d of 7\r", PROGNAME, rpng2_info.pass + 1);
1406 fflush(stderr);
1407 prevpass = rpng2_info.pass;
1408 }
1409
1410 if (rows == 0)
1411 firstrow = row; /* first row that is not yet displayed */
1412
1413 ++rows; /* count of rows received but not yet displayed */
1414
1415/*---------------------------------------------------------------------------
1416 Aside from the use of the rpng2_info struct, the lack of an outer loop
1417 (over rows) and moving the XPutImage() call outside the "if (depth)"
1418 tests, this routine is identical to rpng_x_display_image() in the non-
1419 progressive version of the program.
1420 ---------------------------------------------------------------------------*/
1421
1422 if (depth == 24 || depth == 32) {
1423 ulg red, green, blue;
1424 int bpp = ximage->bits_per_pixel;
1425
1426 src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1427 if (bg_image)
1428 src2 = bg_data + row*bg_rowbytes;
1429 dest = ximage->data + row*ximage_rowbytes;
1430 if (rpng2_info.channels == 3) {
1431 for (i = rpng2_info.width; i > 0; --i) {
1432 red = *src++;
1433 green = *src++;
1434 blue = *src++;
1435 pixel = (red << RShift) |
1436 (green << GShift) |
1437 (blue << BShift);
1438 /* recall that we set ximage->byte_order = MSBFirst above */
1439 if (bpp == 32) {
1440 *dest++ = (char)((pixel >> 24) & 0xff);
1441 *dest++ = (char)((pixel >> 16) & 0xff);
1442 *dest++ = (char)((pixel >> 8) & 0xff);
1443 *dest++ = (char)( pixel & 0xff);
1444 } else {
1445 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1446 /* (probably need to use RShift, RMask, etc.) */
1447 *dest++ = (char)((pixel >> 16) & 0xff);
1448 *dest++ = (char)((pixel >> 8) & 0xff);
1449 *dest++ = (char)( pixel & 0xff);
1450 }
1451 }
1452 } else /* if (rpng2_info.channels == 4) */ {
1453 for (i = rpng2_info.width; i > 0; --i) {
1454 r = *src++;
1455 g = *src++;
1456 b = *src++;
1457 a = *src++;
1458 if (bg_image) {
1459 bg_red = *src2++;
1460 bg_green = *src2++;
1461 bg_blue = *src2++;
1462 }
1463 if (a == 255) {
1464 red = r;
1465 green = g;
1466 blue = b;
1467 } else if (a == 0) {
1468 red = bg_red;
1469 green = bg_green;
1470 blue = bg_blue;
1471 } else {
1472 /* this macro (from png.h) composites the foreground
1473 * and background values and puts the result into the
1474 * first argument */
1475 alpha_composite(red, r, a, bg_red);
1476 alpha_composite(green, g, a, bg_green);
1477 alpha_composite(blue, b, a, bg_blue);
1478 }
1479 pixel = (red << RShift) |
1480 (green << GShift) |
1481 (blue << BShift);
1482 /* recall that we set ximage->byte_order = MSBFirst above */
1483 if (bpp == 32) {
1484 *dest++ = (char)((pixel >> 24) & 0xff);
1485 *dest++ = (char)((pixel >> 16) & 0xff);
1486 *dest++ = (char)((pixel >> 8) & 0xff);
1487 *dest++ = (char)( pixel & 0xff);
1488 } else {
1489 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1490 /* (probably need to use RShift, RMask, etc.) */
1491 *dest++ = (char)((pixel >> 16) & 0xff);
1492 *dest++ = (char)((pixel >> 8) & 0xff);
1493 *dest++ = (char)( pixel & 0xff);
1494 }
1495 }
1496 }
1497
1498 } else if (depth == 16) {
1499 ush red, green, blue;
1500
1501 src = rpng2_info.row_pointers[row];
1502 if (bg_image)
1503 src2 = bg_data + row*bg_rowbytes;
1504 dest = ximage->data + row*ximage_rowbytes;
1505 if (rpng2_info.channels == 3) {
1506 for (i = rpng2_info.width; i > 0; --i) {
1507 red = ((ush)(*src) << 8);
1508 ++src;
1509 green = ((ush)(*src) << 8);
1510 ++src;
1511 blue = ((ush)(*src) << 8);
1512 ++src;
1513 pixel = ((red >> RShift) & RMask) |
1514 ((green >> GShift) & GMask) |
1515 ((blue >> BShift) & BMask);
1516 /* recall that we set ximage->byte_order = MSBFirst above */
1517 *dest++ = (char)((pixel >> 8) & 0xff);
1518 *dest++ = (char)( pixel & 0xff);
1519 }
1520 } else /* if (rpng2_info.channels == 4) */ {
1521 for (i = rpng2_info.width; i > 0; --i) {
1522 r = *src++;
1523 g = *src++;
1524 b = *src++;
1525 a = *src++;
1526 if (bg_image) {
1527 bg_red = *src2++;
1528 bg_green = *src2++;
1529 bg_blue = *src2++;
1530 }
1531 if (a == 255) {
1532 red = ((ush)r << 8);
1533 green = ((ush)g << 8);
1534 blue = ((ush)b << 8);
1535 } else if (a == 0) {
1536 red = ((ush)bg_red << 8);
1537 green = ((ush)bg_green << 8);
1538 blue = ((ush)bg_blue << 8);
1539 } else {
1540 /* this macro (from png.h) composites the foreground
1541 * and background values and puts the result back into
1542 * the first argument (== fg byte here: safe) */
1543 alpha_composite(r, r, a, bg_red);
1544 alpha_composite(g, g, a, bg_green);
1545 alpha_composite(b, b, a, bg_blue);
1546 red = ((ush)r << 8);
1547 green = ((ush)g << 8);
1548 blue = ((ush)b << 8);
1549 }
1550 pixel = ((red >> RShift) & RMask) |
1551 ((green >> GShift) & GMask) |
1552 ((blue >> BShift) & BMask);
1553 /* recall that we set ximage->byte_order = MSBFirst above */
1554 *dest++ = (char)((pixel >> 8) & 0xff);
1555 *dest++ = (char)( pixel & 0xff);
1556 }
1557 }
1558
1559 } else /* depth == 8 */ {
1560
1561 /* GRR: add 8-bit support */
1562
1563 }
1564
1565
1566/*---------------------------------------------------------------------------
1567 Display after every 16 rows or when on one of last two rows. (Region
1568 may include previously displayed lines due to interlacing--i.e., not
1569 contiguous. Also, second-to-last row is final one in interlaced images
1570 with odd number of rows.) For demos, flush (and delay) after every 16th
1571 row so "sparse" passes don't go twice as fast.
1572 ---------------------------------------------------------------------------*/
1573
1574 if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) {
1575 XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1576 (int)firstrow, rpng2_info.width, row - firstrow + 1);
1577 XFlush(display);
1578 rows = 0;
1579 usleep(usleep_duration);
1580 } else
1581 if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) {
1582 XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1583 (int)firstrow, rpng2_info.width, row - firstrow + 1);
1584 XFlush(display);
1585 rows = 0;
1586 }
1587
1588}
1589
1590
1591
1592
1593
1594static void rpng2_x_finish_display(void)
1595{
1596 Trace((stderr, "beginning rpng2_x_finish_display()\n"))
1597
1598 /* last row has already been displayed by rpng2_x_display_row(), so we
1599 * have nothing to do here except set a flag and let the user know that
1600 * the image is done */
1601
1602 rpng2_info.state = kDone;
1603 printf(
1604 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1605 fflush(stdout);
1606}
1607
1608
1609
1610
1611
1612static void rpng2_x_redisplay_image(ulg startcol, ulg startrow,
1613 ulg width, ulg height)
1614{
1615 uch bg_red = rpng2_info.bg_red;
1616 uch bg_green = rpng2_info.bg_green;
1617 uch bg_blue = rpng2_info.bg_blue;
1618 uch *src, *src2=NULL;
1619 char *dest;
1620 uch r, g, b, a;
1621 ulg i, row, lastrow = 0;
1622 ulg pixel;
1623 int ximage_rowbytes = ximage->bytes_per_line;
1624
1625
1626 Trace((stderr, "beginning display loop (image_channels == %d)\n",
1627 rpng2_info.channels))
1628 Trace((stderr, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
1629 rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes))
1630 Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
1631 Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
1632 "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
1633
1634/*---------------------------------------------------------------------------
1635 Aside from the use of the rpng2_info struct and of src2 (for background
1636 image), this routine is identical to rpng_x_display_image() in the non-
1637 progressive version of the program--for the simple reason that redisplay
1638 of the image against a new background happens after the image is fully
1639 decoded and therefore is, by definition, non-progressive.
1640 ---------------------------------------------------------------------------*/
1641
1642 if (depth == 24 || depth == 32) {
1643 ulg red, green, blue;
1644 int bpp = ximage->bits_per_pixel;
1645
1646 for (lastrow = row = startrow; row < startrow+height; ++row) {
1647 src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1648 if (bg_image)
1649 src2 = bg_data + row*bg_rowbytes;
1650 dest = ximage->data + row*ximage_rowbytes;
1651 if (rpng2_info.channels == 3) {
1652 for (i = rpng2_info.width; i > 0; --i) {
1653 red = *src++;
1654 green = *src++;
1655 blue = *src++;
1656#ifdef NO_24BIT_MASKS
1657 pixel = (red << RShift) |
1658 (green << GShift) |
1659 (blue << BShift);
1660 /* recall that we set ximage->byte_order = MSBFirst above */
1661 if (bpp == 32) {
1662 *dest++ = (char)((pixel >> 24) & 0xff);
1663 *dest++ = (char)((pixel >> 16) & 0xff);
1664 *dest++ = (char)((pixel >> 8) & 0xff);
1665 *dest++ = (char)( pixel & 0xff);
1666 } else {
1667 /* this assumes bpp == 24 & bits are packed low */
1668 /* (probably need to use RShift, RMask, etc.) */
1669 *dest++ = (char)((pixel >> 16) & 0xff);
1670 *dest++ = (char)((pixel >> 8) & 0xff);
1671 *dest++ = (char)( pixel & 0xff);
1672 }
1673#else
1674 red = (RShift < 0)? red << (-RShift) : red >> RShift;
1675 green = (GShift < 0)? green << (-GShift) : green >> GShift;
1676 blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
1677 pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1678 /* recall that we set ximage->byte_order = MSBFirst above */
1679 if (bpp == 32) {
1680 *dest++ = (char)((pixel >> 24) & 0xff);
1681 *dest++ = (char)((pixel >> 16) & 0xff);
1682 *dest++ = (char)((pixel >> 8) & 0xff);
1683 *dest++ = (char)( pixel & 0xff);
1684 } else {
1685 /* GRR BUG */
1686 /* this assumes bpp == 24 & bits are packed low */
1687 /* (probably need to use RShift/RMask/etc. here, too) */
1688 *dest++ = (char)((pixel >> 16) & 0xff);
1689 *dest++ = (char)((pixel >> 8) & 0xff);
1690 *dest++ = (char)( pixel & 0xff);
1691 }
1692#endif
1693 }
1694
1695 } else /* if (rpng2_info.channels == 4) */ {
1696 for (i = rpng2_info.width; i > 0; --i) {
1697 r = *src++;
1698 g = *src++;
1699 b = *src++;
1700 a = *src++;
1701 if (bg_image) {
1702 bg_red = *src2++;
1703 bg_green = *src2++;
1704 bg_blue = *src2++;
1705 }
1706 if (a == 255) {
1707 red = r;
1708 green = g;
1709 blue = b;
1710 } else if (a == 0) {
1711 red = bg_red;
1712 green = bg_green;
1713 blue = bg_blue;
1714 } else {
1715 /* this macro (from png.h) composites the foreground
1716 * and background values and puts the result into the
1717 * first argument */
1718 alpha_composite(red, r, a, bg_red);
1719 alpha_composite(green, g, a, bg_green);
1720 alpha_composite(blue, b, a, bg_blue);
1721 }
1722#ifdef NO_24BIT_MASKS
1723 pixel = (red << RShift) |
1724 (green << GShift) |
1725 (blue << BShift);
1726 /* recall that we set ximage->byte_order = MSBFirst above */
1727 if (bpp == 32) {
1728 *dest++ = (char)((pixel >> 24) & 0xff);
1729 *dest++ = (char)((pixel >> 16) & 0xff);
1730 *dest++ = (char)((pixel >> 8) & 0xff);
1731 *dest++ = (char)( pixel & 0xff);
1732 } else {
1733 /* this assumes bpp == 24 & bits are packed low */
1734 /* (probably need to use RShift, RMask, etc.) */
1735 *dest++ = (char)((pixel >> 16) & 0xff);
1736 *dest++ = (char)((pixel >> 8) & 0xff);
1737 *dest++ = (char)( pixel & 0xff);
1738 }
1739#else
1740 red = (RShift < 0)? red << (-RShift) : red >> RShift;
1741 green = (GShift < 0)? green << (-GShift) : green >> GShift;
1742 blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
1743 pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1744 /* recall that we set ximage->byte_order = MSBFirst above */
1745 if (bpp == 32) {
1746 *dest++ = (char)((pixel >> 24) & 0xff);
1747 *dest++ = (char)((pixel >> 16) & 0xff);
1748 *dest++ = (char)((pixel >> 8) & 0xff);
1749 *dest++ = (char)( pixel & 0xff);
1750 } else {
1751 /* GRR BUG */
1752 /* this assumes bpp == 24 & bits are packed low */
1753 /* (probably need to use RShift/RMask/etc. here, too) */
1754 *dest++ = (char)((pixel >> 16) & 0xff);
1755 *dest++ = (char)((pixel >> 8) & 0xff);
1756 *dest++ = (char)( pixel & 0xff);
1757 }
1758#endif
1759 }
1760 }
1761 /* display after every 16 lines */
1762 if (((row+1) & 0xf) == 0) {
1763 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1764 (int)lastrow, rpng2_info.width, 16);
1765 XFlush(display);
1766 lastrow = row + 1;
1767 }
1768 }
1769
1770 } else if (depth == 16) {
1771 ush red, green, blue;
1772
1773 for (lastrow = row = startrow; row < startrow+height; ++row) {
1774 src = rpng2_info.row_pointers[row];
1775 if (bg_image)
1776 src2 = bg_data + row*bg_rowbytes;
1777 dest = ximage->data + row*ximage_rowbytes;
1778 if (rpng2_info.channels == 3) {
1779 for (i = rpng2_info.width; i > 0; --i) {
1780 red = ((ush)(*src) << 8);
1781 ++src;
1782 green = ((ush)(*src) << 8);
1783 ++src;
1784 blue = ((ush)(*src) << 8);
1785 ++src;
1786 pixel = ((red >> RShift) & RMask) |
1787 ((green >> GShift) & GMask) |
1788 ((blue >> BShift) & BMask);
1789 /* recall that we set ximage->byte_order = MSBFirst above */
1790 *dest++ = (char)((pixel >> 8) & 0xff);
1791 *dest++ = (char)( pixel & 0xff);
1792 }
1793 } else /* if (rpng2_info.channels == 4) */ {
1794 for (i = rpng2_info.width; i > 0; --i) {
1795 r = *src++;
1796 g = *src++;
1797 b = *src++;
1798 a = *src++;
1799 if (bg_image) {
1800 bg_red = *src2++;
1801 bg_green = *src2++;
1802 bg_blue = *src2++;
1803 }
1804 if (a == 255) {
1805 red = ((ush)r << 8);
1806 green = ((ush)g << 8);
1807 blue = ((ush)b << 8);
1808 } else if (a == 0) {
1809 red = ((ush)bg_red << 8);
1810 green = ((ush)bg_green << 8);
1811 blue = ((ush)bg_blue << 8);
1812 } else {
1813 /* this macro (from png.h) composites the foreground
1814 * and background values and puts the result back into
1815 * the first argument (== fg byte here: safe) */
1816 alpha_composite(r, r, a, bg_red);
1817 alpha_composite(g, g, a, bg_green);
1818 alpha_composite(b, b, a, bg_blue);
1819 red = ((ush)r << 8);
1820 green = ((ush)g << 8);
1821 blue = ((ush)b << 8);
1822 }
1823 pixel = ((red >> RShift) & RMask) |
1824 ((green >> GShift) & GMask) |
1825 ((blue >> BShift) & BMask);
1826 /* recall that we set ximage->byte_order = MSBFirst above */
1827 *dest++ = (char)((pixel >> 8) & 0xff);
1828 *dest++ = (char)( pixel & 0xff);
1829 }
1830 }
1831 /* display after every 16 lines */
1832 if (((row+1) & 0xf) == 0) {
1833 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1834 (int)lastrow, rpng2_info.width, 16);
1835 XFlush(display);
1836 lastrow = row + 1;
1837 }
1838 }
1839
1840 } else /* depth == 8 */ {
1841
1842 /* GRR: add 8-bit support */
1843
1844 }
1845
1846 Trace((stderr, "calling final XPutImage()\n"))
1847 if (lastrow < startrow+height) {
1848 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1849 (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow);
1850 XFlush(display);
1851 }
1852
Matt Sarett9ea75692016-01-08 13:00:42 -05001853 (void)startcol;
1854 (void)width;
1855
The Android Open Source Project893912b2009-03-03 19:30:05 -08001856} /* end function rpng2_x_redisplay_image() */
1857
1858
1859
1860
1861
1862#ifdef FEATURE_LOOP
1863
1864static void rpng2_x_reload_bg_image(void)
1865{
1866 char *dest;
1867 uch r1, r2, g1, g2, b1, b2;
1868 uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1869 int k, hmax, max;
1870 int xidx, yidx, yidx_max;
1871 int even_odd_vert, even_odd_horiz, even_odd;
1872 int invert_gradient2 = (bg[pat].type & 0x08);
1873 int invert_column;
1874 ulg i, row;
1875
1876
1877 bgscale = (pat == 0)? 8 : bgscale_default;
1878 yidx_max = bgscale - 1;
1879
1880/*---------------------------------------------------------------------------
1881 Vertical gradients (ramps) in NxN squares, alternating direction and
1882 colors (N == bgscale).
1883 ---------------------------------------------------------------------------*/
1884
1885 if ((bg[pat].type & 0x07) == 0) {
1886 uch r1_min = rgb[bg[pat].rgb1_min].r;
1887 uch g1_min = rgb[bg[pat].rgb1_min].g;
1888 uch b1_min = rgb[bg[pat].rgb1_min].b;
1889 uch r2_min = rgb[bg[pat].rgb2_min].r;
1890 uch g2_min = rgb[bg[pat].rgb2_min].g;
1891 uch b2_min = rgb[bg[pat].rgb2_min].b;
1892 int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1893 int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1894 int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1895 int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1896 int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1897 int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1898
1899 for (row = 0; row < rpng2_info.height; ++row) {
1900 yidx = (int)(row % bgscale);
1901 even_odd_vert = (int)((row / bgscale) & 1);
1902
1903 r1 = r1_min + (r1_diff * yidx) / yidx_max;
1904 g1 = g1_min + (g1_diff * yidx) / yidx_max;
1905 b1 = b1_min + (b1_diff * yidx) / yidx_max;
1906 r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1907 g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1908 b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1909
1910 r2 = r2_min + (r2_diff * yidx) / yidx_max;
1911 g2 = g2_min + (g2_diff * yidx) / yidx_max;
1912 b2 = b2_min + (b2_diff * yidx) / yidx_max;
1913 r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1914 g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1915 b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1916
1917 dest = (char *)bg_data + row*bg_rowbytes;
1918 for (i = 0; i < rpng2_info.width; ++i) {
1919 even_odd_horiz = (int)((i / bgscale) & 1);
1920 even_odd = even_odd_vert ^ even_odd_horiz;
1921 invert_column =
1922 (even_odd_horiz && (bg[pat].type & 0x10));
1923 if (even_odd == 0) { /* gradient #1 */
1924 if (invert_column) {
1925 *dest++ = r1_inv;
1926 *dest++ = g1_inv;
1927 *dest++ = b1_inv;
1928 } else {
1929 *dest++ = r1;
1930 *dest++ = g1;
1931 *dest++ = b1;
1932 }
1933 } else { /* gradient #2 */
1934 if ((invert_column && invert_gradient2) ||
1935 (!invert_column && !invert_gradient2))
1936 {
1937 *dest++ = r2; /* not inverted or */
1938 *dest++ = g2; /* doubly inverted */
1939 *dest++ = b2;
1940 } else {
1941 *dest++ = r2_inv;
1942 *dest++ = g2_inv; /* singly inverted */
1943 *dest++ = b2_inv;
1944 }
1945 }
1946 }
1947 }
1948
1949/*---------------------------------------------------------------------------
1950 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1951 M. Costello.
1952 ---------------------------------------------------------------------------*/
1953
1954 } else if ((bg[pat].type & 0x07) == 1) {
1955
1956 hmax = (bgscale-1)/2; /* half the max weight of a color */
1957 max = 2*hmax; /* the max weight of a color */
1958
1959 r1 = rgb[bg[pat].rgb1_max].r;
1960 g1 = rgb[bg[pat].rgb1_max].g;
1961 b1 = rgb[bg[pat].rgb1_max].b;
1962 r2 = rgb[bg[pat].rgb2_max].r;
1963 g2 = rgb[bg[pat].rgb2_max].g;
1964 b2 = rgb[bg[pat].rgb2_max].b;
1965
1966 for (row = 0; row < rpng2_info.height; ++row) {
1967 yidx = (int)(row % bgscale);
1968 if (yidx > hmax)
1969 yidx = bgscale-1 - yidx;
1970 dest = (char *)bg_data + row*bg_rowbytes;
1971 for (i = 0; i < rpng2_info.width; ++i) {
1972 xidx = (int)(i % bgscale);
1973 if (xidx > hmax)
1974 xidx = bgscale-1 - xidx;
1975 k = xidx + yidx;
1976 *dest++ = (k*r1 + (max-k)*r2) / max;
1977 *dest++ = (k*g1 + (max-k)*g2) / max;
1978 *dest++ = (k*b1 + (max-k)*b2) / max;
1979 }
1980 }
1981
1982/*---------------------------------------------------------------------------
1983 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1984 soids will equal bgscale?]. This one is slow but very cool. Code con-
1985 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1986 ---------------------------------------------------------------------------*/
1987
1988 } else if ((bg[pat].type & 0x07) == 2) {
1989 uch ch;
1990 int ii, x, y, hw, hh, grayspot;
1991 double freq, rotate, saturate, gray, intensity;
1992 double angle=0.0, aoffset=0.0, maxDist, dist;
1993 double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1994
1995 hh = (int)(rpng2_info.height / 2);
1996 hw = (int)(rpng2_info.width / 2);
1997
1998 /* variables for radial waves:
1999 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
2000 * freq: number of color beams originating from the center
2001 * grayspot: size of the graying center area (anti-alias)
2002 * rotate: rotation of the beams as a function of radius
2003 * saturate: saturation of beams' shape azimuthally
2004 */
2005 angle = CLIP(angle, 0.0, 360.0);
2006 grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
2007 freq = MAX((double)bg[pat].bg_freq, 0.0);
2008 saturate = (double)bg[pat].bg_bsat * 0.1;
2009 rotate = (double)bg[pat].bg_brot * 0.1;
2010 gray = 0.0;
2011 intensity = 0.0;
2012 maxDist = (double)((hw*hw) + (hh*hh));
2013
2014 for (row = 0; row < rpng2_info.height; ++row) {
2015 y = (int)(row - hh);
2016 dest = (char *)bg_data + row*bg_rowbytes;
2017 for (i = 0; i < rpng2_info.width; ++i) {
2018 x = (int)(i - hw);
2019 angle = (x == 0)? PI_2 : atan((double)y / (double)x);
2020 gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
2021 gray = MIN(1.0, gray);
2022 dist = (double)((x*x) + (y*y)) / maxDist;
2023 intensity = cos((angle+(rotate*dist*PI)) * freq) *
2024 gray * saturate;
2025 intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
2026 hue = (angle + PI) * INV_PI_360 + aoffset;
2027 s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
2028 s = MIN(MAX(s,0.0), 1.0);
2029 v = MIN(MAX(intensity,0.0), 1.0);
2030
2031 if (s == 0.0) {
2032 ch = (uch)(v * 255.0);
2033 *dest++ = ch;
2034 *dest++ = ch;
2035 *dest++ = ch;
2036 } else {
2037 if ((hue < 0.0) || (hue >= 360.0))
2038 hue -= (((int)(hue / 360.0)) * 360.0);
2039 hue /= 60.0;
2040 ii = (int)hue;
2041 f = hue - (double)ii;
2042 p = (1.0 - s) * v;
2043 q = (1.0 - (s * f)) * v;
2044 t = (1.0 - (s * (1.0 - f))) * v;
2045 if (ii == 0) { red = v; green = t; blue = p; }
2046 else if (ii == 1) { red = q; green = v; blue = p; }
2047 else if (ii == 2) { red = p; green = v; blue = t; }
2048 else if (ii == 3) { red = p; green = q; blue = v; }
2049 else if (ii == 4) { red = t; green = p; blue = v; }
2050 else if (ii == 5) { red = v; green = p; blue = q; }
2051 *dest++ = (uch)(red * 255.0);
2052 *dest++ = (uch)(green * 255.0);
2053 *dest++ = (uch)(blue * 255.0);
2054 }
2055 }
2056 }
2057 }
2058
2059} /* end function rpng2_x_reload_bg_image() */
2060
2061
2062
2063
2064
2065static int is_number(char *p)
2066{
2067 while (*p) {
2068 if (!isdigit(*p))
2069 return FALSE;
2070 ++p;
2071 }
2072 return TRUE;
2073}
2074
2075#endif /* FEATURE_LOOP */
2076
2077
2078
2079
2080
2081static void rpng2_x_cleanup(void)
2082{
2083 if (bg_image && bg_data) {
2084 free(bg_data);
2085 bg_data = NULL;
2086 }
2087
2088 if (rpng2_info.image_data) {
2089 free(rpng2_info.image_data);
2090 rpng2_info.image_data = NULL;
2091 }
2092
2093 if (rpng2_info.row_pointers) {
2094 free(rpng2_info.row_pointers);
2095 rpng2_info.row_pointers = NULL;
2096 }
2097
2098 if (ximage) {
2099 if (ximage->data) {
2100 free(ximage->data); /* we allocated it, so we free it */
2101 ximage->data = (char *)NULL; /* instead of XDestroyImage() */
2102 }
2103 XDestroyImage(ximage);
2104 ximage = NULL;
2105 }
2106
2107 if (have_gc)
2108 XFreeGC(display, gc);
2109
2110 if (have_window)
2111 XDestroyWindow(display, window);
2112
2113 if (have_colormap)
2114 XFreeColormap(display, colormap);
2115
2116 if (have_nondefault_visual)
2117 XFree(visual_list);
2118}
2119
2120
2121
2122
2123
2124static int rpng2_x_msb(ulg u32val)
2125{
2126 int i;
2127
2128 for (i = 31; i >= 0; --i) {
2129 if (u32val & 0x80000000L)
2130 break;
2131 u32val <<= 1;
2132 }
2133 return i;
2134}