Mercurial > fife-parpg
comparison ext/libpng-1.2.29/contrib/gregbook/wpng.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
1 /*--------------------------------------------------------------------------- | |
2 | |
3 wpng - simple PNG-writing program wpng.c | |
4 | |
5 This program converts certain NetPBM binary files (grayscale and RGB, | |
6 maxval = 255) to PNG. Non-interlaced PNGs are written progressively; | |
7 interlaced PNGs are read and written in one memory-intensive blast. | |
8 | |
9 Thanks to Jean-loup Gailly for providing the necessary trick to read | |
10 interactive text from the keyboard while stdin is redirected. Thanks | |
11 to Cosmin Truta for Cygwin fixes. | |
12 | |
13 NOTE: includes provisional support for PNM type "8" (portable alphamap) | |
14 images, presumed to be a 32-bit interleaved RGBA format; no pro- | |
15 vision for possible interleaved grayscale+alpha (16-bit) format. | |
16 THIS IS UNLIKELY TO BECOME AN OFFICIAL NETPBM ALPHA FORMAT! | |
17 | |
18 to do: | |
19 - delete output file if quit before calling any writepng routines | |
20 - process backspace with -text option under DOS/Win? (currently get ^H) | |
21 | |
22 --------------------------------------------------------------------------- | |
23 | |
24 Changelog: | |
25 - 1.01: initial public release | |
26 - 1.02: modified to allow abbreviated options | |
27 - 1.03: removed extraneous character from usage screen; fixed bug in | |
28 command-line parsing | |
29 - 1.04: fixed DOS/OS2/Win32 detection, including partial Cygwin fix | |
30 (see http://home.att.net/~perlspinr/diffs/GregBook_cygwin.diff) | |
31 - 2.00: dual-licensed (added GNU GPL) | |
32 | |
33 [REPORTED BUG (win32 only): "contrib/gregbook/wpng.c - cmd line | |
34 dose not work! In order to do something useful I needed to redirect | |
35 both input and output, with cygwin and with bcc32 as well. Under | |
36 Linux, the same wpng appears to work fine. I don't know what is | |
37 the problem."] | |
38 | |
39 --------------------------------------------------------------------------- | |
40 | |
41 Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. | |
42 | |
43 This software is provided "as is," without warranty of any kind, | |
44 express or implied. In no event shall the author or contributors | |
45 be held liable for any damages arising in any way from the use of | |
46 this software. | |
47 | |
48 The contents of this file are DUAL-LICENSED. You may modify and/or | |
49 redistribute this software according to the terms of one of the | |
50 following two licenses (at your option): | |
51 | |
52 | |
53 LICENSE 1 ("BSD-like with advertising clause"): | |
54 | |
55 Permission is granted to anyone to use this software for any purpose, | |
56 including commercial applications, and to alter it and redistribute | |
57 it freely, subject to the following restrictions: | |
58 | |
59 1. Redistributions of source code must retain the above copyright | |
60 notice, disclaimer, and this list of conditions. | |
61 2. Redistributions in binary form must reproduce the above copyright | |
62 notice, disclaimer, and this list of conditions in the documenta- | |
63 tion and/or other materials provided with the distribution. | |
64 3. All advertising materials mentioning features or use of this | |
65 software must display the following acknowledgment: | |
66 | |
67 This product includes software developed by Greg Roelofs | |
68 and contributors for the book, "PNG: The Definitive Guide," | |
69 published by O'Reilly and Associates. | |
70 | |
71 | |
72 LICENSE 2 (GNU GPL v2 or later): | |
73 | |
74 This program is free software; you can redistribute it and/or modify | |
75 it under the terms of the GNU General Public License as published by | |
76 the Free Software Foundation; either version 2 of the License, or | |
77 (at your option) any later version. | |
78 | |
79 This program is distributed in the hope that it will be useful, | |
80 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
81 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
82 GNU General Public License for more details. | |
83 | |
84 You should have received a copy of the GNU General Public License | |
85 along with this program; if not, write to the Free Software Foundation, | |
86 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
87 | |
88 ---------------------------------------------------------------------------*/ | |
89 | |
90 #define PROGNAME "wpng" | |
91 #define VERSION "2.00 of 2 June 2007" | |
92 #define APPNAME "Simple PGM/PPM/PAM to PNG Converter" | |
93 | |
94 #if defined(__MSDOS__) || defined(__OS2__) | |
95 # define DOS_OS2_W32 | |
96 #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) | |
97 # ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */ | |
98 # define DOS_OS2_W32 | |
99 # endif | |
100 #endif | |
101 | |
102 #include <stdio.h> | |
103 #include <stdlib.h> | |
104 #include <string.h> | |
105 #include <setjmp.h> /* for jmpbuf declaration in writepng.h */ | |
106 #include <time.h> | |
107 | |
108 #ifdef DOS_OS2_W32 | |
109 # include <io.h> /* for isatty(), setmode() prototypes */ | |
110 # include <fcntl.h> /* O_BINARY for fdopen() without text translation */ | |
111 # ifdef __EMX__ | |
112 # ifndef getch | |
113 # define getch() _read_kbd(0, 1, 0) /* need getche() */ | |
114 # endif | |
115 # else /* !__EMX__ */ | |
116 # ifdef __GO32__ | |
117 # include <pc.h> | |
118 # define getch() getkey() /* GRR: need getche() */ | |
119 # else | |
120 # include <conio.h> /* for getche() console input */ | |
121 # endif | |
122 # endif /* ?__EMX__ */ | |
123 # define FGETS(buf,len,stream) dos_kbd_gets(buf,len) | |
124 #else | |
125 # include <unistd.h> /* for isatty() prototype */ | |
126 # define FGETS fgets | |
127 #endif | |
128 | |
129 /* #define DEBUG : this enables the Trace() macros */ | |
130 | |
131 /* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any | |
132 text that includes control characters discouraged by the PNG spec; text | |
133 that includes an escape character (27) must be re-entered regardless */ | |
134 | |
135 #include "writepng.h" /* typedefs, common macros, writepng prototypes */ | |
136 | |
137 | |
138 | |
139 /* local prototypes */ | |
140 | |
141 static int wpng_isvalid_latin1(uch *p, int len); | |
142 static void wpng_cleanup(void); | |
143 | |
144 #ifdef DOS_OS2_W32 | |
145 static char *dos_kbd_gets(char *buf, int len); | |
146 #endif | |
147 | |
148 | |
149 | |
150 static mainprog_info wpng_info; /* lone global */ | |
151 | |
152 | |
153 | |
154 int main(int argc, char **argv) | |
155 { | |
156 #ifndef DOS_OS2_W32 | |
157 FILE *keybd; | |
158 #endif | |
159 #ifdef sgi | |
160 FILE *tmpfile; /* or we could just use keybd, since no overlap */ | |
161 char tmpline[80]; | |
162 #endif | |
163 char *inname = NULL, outname[256]; | |
164 char *p, pnmchar, pnmline[256]; | |
165 char *bgstr, *textbuf = NULL; | |
166 ulg rowbytes; | |
167 int rc, len = 0; | |
168 int error = 0; | |
169 int text = FALSE; | |
170 int maxval; | |
171 double LUT_exponent; /* just the lookup table */ | |
172 double CRT_exponent = 2.2; /* just the monitor */ | |
173 double default_display_exponent; /* whole display system */ | |
174 double default_gamma = 0.0; | |
175 | |
176 | |
177 wpng_info.infile = NULL; | |
178 wpng_info.outfile = NULL; | |
179 wpng_info.image_data = NULL; | |
180 wpng_info.row_pointers = NULL; | |
181 wpng_info.filter = FALSE; | |
182 wpng_info.interlaced = FALSE; | |
183 wpng_info.have_bg = FALSE; | |
184 wpng_info.have_time = FALSE; | |
185 wpng_info.have_text = 0; | |
186 wpng_info.gamma = 0.0; | |
187 | |
188 | |
189 /* First get the default value for our display-system exponent, i.e., | |
190 * the product of the CRT exponent and the exponent corresponding to | |
191 * the frame-buffer's lookup table (LUT), if any. If the PNM image | |
192 * looks correct on the user's display system, its file gamma is the | |
193 * inverse of this value. (Note that this is not an exhaustive list | |
194 * of LUT values--e.g., OpenStep has a lot of weird ones--but it should | |
195 * cover 99% of the current possibilities. This section must ensure | |
196 * that default_display_exponent is positive.) */ | |
197 | |
198 #if defined(NeXT) | |
199 /* third-party utilities can modify the default LUT exponent */ | |
200 LUT_exponent = 1.0 / 2.2; | |
201 /* | |
202 if (some_next_function_that_returns_gamma(&next_gamma)) | |
203 LUT_exponent = 1.0 / next_gamma; | |
204 */ | |
205 #elif defined(sgi) | |
206 LUT_exponent = 1.0 / 1.7; | |
207 /* there doesn't seem to be any documented function to | |
208 * get the "gamma" value, so we do it the hard way */ | |
209 tmpfile = fopen("/etc/config/system.glGammaVal", "r"); | |
210 if (tmpfile) { | |
211 double sgi_gamma; | |
212 | |
213 fgets(tmpline, 80, tmpfile); | |
214 fclose(tmpfile); | |
215 sgi_gamma = atof(tmpline); | |
216 if (sgi_gamma > 0.0) | |
217 LUT_exponent = 1.0 / sgi_gamma; | |
218 } | |
219 #elif defined(Macintosh) | |
220 LUT_exponent = 1.8 / 2.61; | |
221 /* | |
222 if (some_mac_function_that_returns_gamma(&mac_gamma)) | |
223 LUT_exponent = mac_gamma / 2.61; | |
224 */ | |
225 #else | |
226 LUT_exponent = 1.0; /* assume no LUT: most PCs */ | |
227 #endif | |
228 | |
229 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ | |
230 default_display_exponent = LUT_exponent * CRT_exponent; | |
231 | |
232 | |
233 /* If the user has set the SCREEN_GAMMA environment variable as suggested | |
234 * (somewhat imprecisely) in the libpng documentation, use that; otherwise | |
235 * use the default value we just calculated. Either way, the user may | |
236 * override this via a command-line option. */ | |
237 | |
238 if ((p = getenv("SCREEN_GAMMA")) != NULL) { | |
239 double exponent = atof(p); | |
240 | |
241 if (exponent > 0.0) | |
242 default_gamma = 1.0 / exponent; | |
243 } | |
244 | |
245 if (default_gamma == 0.0) | |
246 default_gamma = 1.0 / default_display_exponent; | |
247 | |
248 | |
249 /* Now parse the command line for options and the PNM filename. */ | |
250 | |
251 while (*++argv && !error) { | |
252 if (!strncmp(*argv, "-i", 2)) { | |
253 wpng_info.interlaced = TRUE; | |
254 } else if (!strncmp(*argv, "-time", 3)) { | |
255 wpng_info.modtime = time(NULL); | |
256 wpng_info.have_time = TRUE; | |
257 } else if (!strncmp(*argv, "-text", 3)) { | |
258 text = TRUE; | |
259 } else if (!strncmp(*argv, "-gamma", 2)) { | |
260 if (!*++argv) | |
261 ++error; | |
262 else { | |
263 wpng_info.gamma = atof(*argv); | |
264 if (wpng_info.gamma <= 0.0) | |
265 ++error; | |
266 else if (wpng_info.gamma > 1.01) | |
267 fprintf(stderr, PROGNAME | |
268 " warning: file gammas are usually less than 1.0\n"); | |
269 } | |
270 } else if (!strncmp(*argv, "-bgcolor", 4)) { | |
271 if (!*++argv) | |
272 ++error; | |
273 else { | |
274 bgstr = *argv; | |
275 if (strlen(bgstr) != 7 || bgstr[0] != '#') | |
276 ++error; | |
277 else { | |
278 unsigned r, g, b; /* this way quiets compiler warnings */ | |
279 | |
280 sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); | |
281 wpng_info.bg_red = (uch)r; | |
282 wpng_info.bg_green = (uch)g; | |
283 wpng_info.bg_blue = (uch)b; | |
284 wpng_info.have_bg = TRUE; | |
285 } | |
286 } | |
287 } else { | |
288 if (**argv != '-') { | |
289 inname = *argv; | |
290 if (argv[1]) /* shouldn't be any more args after filename */ | |
291 ++error; | |
292 } else | |
293 ++error; /* not expecting any other options */ | |
294 } | |
295 } | |
296 | |
297 | |
298 /* open the input and output files, or register an error and abort */ | |
299 | |
300 if (!inname) { | |
301 if (isatty(0)) { | |
302 fprintf(stderr, PROGNAME | |
303 ": must give input filename or provide image data via stdin\n"); | |
304 ++error; | |
305 } else { | |
306 #ifdef DOS_OS2_W32 | |
307 /* some buggy C libraries require BOTH setmode() and fdopen(bin) */ | |
308 setmode(fileno(stdin), O_BINARY); | |
309 setmode(fileno(stdout), O_BINARY); | |
310 #endif | |
311 if ((wpng_info.infile = fdopen(fileno(stdin), "rb")) == NULL) { | |
312 fprintf(stderr, PROGNAME | |
313 ": unable to reopen stdin in binary mode\n"); | |
314 ++error; | |
315 } else | |
316 if ((wpng_info.outfile = fdopen(fileno(stdout), "wb")) == NULL) { | |
317 fprintf(stderr, PROGNAME | |
318 ": unable to reopen stdout in binary mode\n"); | |
319 fclose(wpng_info.infile); | |
320 ++error; | |
321 } else | |
322 wpng_info.filter = TRUE; | |
323 } | |
324 } else if ((len = strlen(inname)) > 250) { | |
325 fprintf(stderr, PROGNAME ": input filename is too long [%d chars]\n", | |
326 len); | |
327 ++error; | |
328 } else if (!(wpng_info.infile = fopen(inname, "rb"))) { | |
329 fprintf(stderr, PROGNAME ": can't open input file [%s]\n", inname); | |
330 ++error; | |
331 } | |
332 | |
333 if (!error) { | |
334 fgets(pnmline, 256, wpng_info.infile); | |
335 if (pnmline[0] != 'P' || ((pnmchar = pnmline[1]) != '5' && | |
336 pnmchar != '6' && pnmchar != '8')) | |
337 { | |
338 fprintf(stderr, PROGNAME | |
339 ": input file [%s] is not a binary PGM, PPM or PAM file\n", | |
340 inname); | |
341 ++error; | |
342 } else { | |
343 wpng_info.pnmtype = (int)(pnmchar - '0'); | |
344 if (wpng_info.pnmtype != 8) | |
345 wpng_info.have_bg = FALSE; /* no need for bg if opaque */ | |
346 do { | |
347 fgets(pnmline, 256, wpng_info.infile); /* lose any comments */ | |
348 } while (pnmline[0] == '#'); | |
349 sscanf(pnmline, "%ld %ld", &wpng_info.width, &wpng_info.height); | |
350 do { | |
351 fgets(pnmline, 256, wpng_info.infile); /* more comment lines */ | |
352 } while (pnmline[0] == '#'); | |
353 sscanf(pnmline, "%d", &maxval); | |
354 if (wpng_info.width <= 0L || wpng_info.height <= 0L || | |
355 maxval != 255) | |
356 { | |
357 fprintf(stderr, PROGNAME | |
358 ": only positive width/height, maxval == 255 allowed \n"); | |
359 ++error; | |
360 } | |
361 wpng_info.sample_depth = 8; /* <==> maxval 255 */ | |
362 | |
363 if (!wpng_info.filter) { | |
364 /* make outname from inname */ | |
365 if ((p = strrchr(inname, '.')) == NULL || | |
366 (p - inname) != (len - 4)) | |
367 { | |
368 strcpy(outname, inname); | |
369 strcpy(outname+len, ".png"); | |
370 } else { | |
371 len -= 4; | |
372 strncpy(outname, inname, len); | |
373 strcpy(outname+len, ".png"); | |
374 } | |
375 /* check if outname already exists; if not, open */ | |
376 if ((wpng_info.outfile = fopen(outname, "rb")) != NULL) { | |
377 fprintf(stderr, PROGNAME ": output file exists [%s]\n", | |
378 outname); | |
379 fclose(wpng_info.outfile); | |
380 ++error; | |
381 } else if (!(wpng_info.outfile = fopen(outname, "wb"))) { | |
382 fprintf(stderr, PROGNAME ": can't open output file [%s]\n", | |
383 outname); | |
384 ++error; | |
385 } | |
386 } | |
387 } | |
388 if (error) { | |
389 fclose(wpng_info.infile); | |
390 wpng_info.infile = NULL; | |
391 if (wpng_info.filter) { | |
392 fclose(wpng_info.outfile); | |
393 wpng_info.outfile = NULL; | |
394 } | |
395 } | |
396 } | |
397 | |
398 | |
399 /* if we had any errors, print usage and die horrible death...arrr! */ | |
400 | |
401 if (error) { | |
402 fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, APPNAME); | |
403 writepng_version_info(); | |
404 fprintf(stderr, "\n" | |
405 "Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n" | |
406 "or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n" | |
407 " exp \ttransfer-function exponent (``gamma'') of the image in\n" | |
408 "\t\t floating-point format (e.g., ``%.5f''); if image looks\n" | |
409 "\t\t correct on given display system, image gamma is equal to\n" | |
410 "\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n" | |
411 "\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n" | |
412 "\t\t first varies, second is usually 2.2, all are positive)\n" | |
413 " bg \tdesired background color for alpha-channel images, in\n" | |
414 "\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n" | |
415 "\t\t same as HTML colors)\n" | |
416 " -text\tprompt interactively for text info (tEXt chunks)\n" | |
417 " -time\tinclude a tIME chunk (last modification time)\n" | |
418 " -interlace\twrite interlaced PNG image\n" | |
419 "\n" | |
420 "pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n" | |
421 "unofficial and unsupported!) PAM (`P8') file. Currently it is required\n" | |
422 "to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n" | |
423 "is converted to the corresponding PNG file with the same base name but a\n" | |
424 "``.png'' extension; files read from stdin are converted and sent to stdout.\n" | |
425 "The conversion is progressive (low memory usage) unless interlacing is\n" | |
426 "requested; in that case the whole image will be buffered in memory and\n" | |
427 "written in one call.\n" | |
428 "\n", PROGNAME, PROGNAME, default_gamma); | |
429 exit(1); | |
430 } | |
431 | |
432 | |
433 /* prepare the text buffers for libpng's use; note that even though | |
434 * PNG's png_text struct includes a length field, we don't have to fill | |
435 * it out */ | |
436 | |
437 if (text && | |
438 #ifndef DOS_OS2_W32 | |
439 (keybd = fdopen(fileno(stderr), "r")) != NULL && | |
440 #endif | |
441 (textbuf = (char *)malloc((5 + 9)*75)) != NULL) | |
442 { | |
443 int i, valid, result; | |
444 | |
445 fprintf(stderr, | |
446 "Enter text info (no more than 72 characters per line);\n"); | |
447 fprintf(stderr, "to skip a field, hit the <Enter> key.\n"); | |
448 /* note: just <Enter> leaves len == 1 */ | |
449 | |
450 do { | |
451 valid = TRUE; | |
452 p = textbuf + TEXT_TITLE_OFFSET; | |
453 fprintf(stderr, " Title: "); | |
454 fflush(stderr); | |
455 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { | |
456 if (p[len-1] == '\n') | |
457 p[--len] = '\0'; | |
458 wpng_info.title = p; | |
459 wpng_info.have_text |= TEXT_TITLE; | |
460 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
461 fprintf(stderr, " " PROGNAME " warning: character code" | |
462 " %u is %sdiscouraged by the PNG\n specification " | |
463 "[first occurrence was at character position #%d]\n", | |
464 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
465 result+1); | |
466 fflush(stderr); | |
467 #ifdef FORBID_LATIN1_CTRL | |
468 wpng_info.have_text &= ~TEXT_TITLE; | |
469 valid = FALSE; | |
470 #else | |
471 if (p[result] == 27) { /* escape character */ | |
472 wpng_info.have_text &= ~TEXT_TITLE; | |
473 valid = FALSE; | |
474 } | |
475 #endif | |
476 } | |
477 } | |
478 } while (!valid); | |
479 | |
480 do { | |
481 valid = TRUE; | |
482 p = textbuf + TEXT_AUTHOR_OFFSET; | |
483 fprintf(stderr, " Author: "); | |
484 fflush(stderr); | |
485 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { | |
486 if (p[len-1] == '\n') | |
487 p[--len] = '\0'; | |
488 wpng_info.author = p; | |
489 wpng_info.have_text |= TEXT_AUTHOR; | |
490 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
491 fprintf(stderr, " " PROGNAME " warning: character code" | |
492 " %u is %sdiscouraged by the PNG\n specification " | |
493 "[first occurrence was at character position #%d]\n", | |
494 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
495 result+1); | |
496 fflush(stderr); | |
497 #ifdef FORBID_LATIN1_CTRL | |
498 wpng_info.have_text &= ~TEXT_AUTHOR; | |
499 valid = FALSE; | |
500 #else | |
501 if (p[result] == 27) { /* escape character */ | |
502 wpng_info.have_text &= ~TEXT_AUTHOR; | |
503 valid = FALSE; | |
504 } | |
505 #endif | |
506 } | |
507 } | |
508 } while (!valid); | |
509 | |
510 do { | |
511 valid = TRUE; | |
512 p = textbuf + TEXT_DESC_OFFSET; | |
513 fprintf(stderr, " Description (up to 9 lines):\n"); | |
514 for (i = 1; i < 10; ++i) { | |
515 fprintf(stderr, " [%d] ", i); | |
516 fflush(stderr); | |
517 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) | |
518 p += len; /* now points at NULL; char before is newline */ | |
519 else | |
520 break; | |
521 } | |
522 if ((len = p - (textbuf + TEXT_DESC_OFFSET)) > 1) { | |
523 if (p[-1] == '\n') { | |
524 p[-1] = '\0'; | |
525 --len; | |
526 } | |
527 wpng_info.desc = textbuf + TEXT_DESC_OFFSET; | |
528 wpng_info.have_text |= TEXT_DESC; | |
529 p = textbuf + TEXT_DESC_OFFSET; | |
530 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
531 fprintf(stderr, " " PROGNAME " warning: character code" | |
532 " %u is %sdiscouraged by the PNG\n specification " | |
533 "[first occurrence was at character position #%d]\n", | |
534 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
535 result+1); | |
536 fflush(stderr); | |
537 #ifdef FORBID_LATIN1_CTRL | |
538 wpng_info.have_text &= ~TEXT_DESC; | |
539 valid = FALSE; | |
540 #else | |
541 if (p[result] == 27) { /* escape character */ | |
542 wpng_info.have_text &= ~TEXT_DESC; | |
543 valid = FALSE; | |
544 } | |
545 #endif | |
546 } | |
547 } | |
548 } while (!valid); | |
549 | |
550 do { | |
551 valid = TRUE; | |
552 p = textbuf + TEXT_COPY_OFFSET; | |
553 fprintf(stderr, " Copyright: "); | |
554 fflush(stderr); | |
555 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { | |
556 if (p[len-1] == '\n') | |
557 p[--len] = '\0'; | |
558 wpng_info.copyright = p; | |
559 wpng_info.have_text |= TEXT_COPY; | |
560 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
561 fprintf(stderr, " " PROGNAME " warning: character code" | |
562 " %u is %sdiscouraged by the PNG\n specification " | |
563 "[first occurrence was at character position #%d]\n", | |
564 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
565 result+1); | |
566 fflush(stderr); | |
567 #ifdef FORBID_LATIN1_CTRL | |
568 wpng_info.have_text &= ~TEXT_COPY; | |
569 valid = FALSE; | |
570 #else | |
571 if (p[result] == 27) { /* escape character */ | |
572 wpng_info.have_text &= ~TEXT_COPY; | |
573 valid = FALSE; | |
574 } | |
575 #endif | |
576 } | |
577 } | |
578 } while (!valid); | |
579 | |
580 do { | |
581 valid = TRUE; | |
582 p = textbuf + TEXT_EMAIL_OFFSET; | |
583 fprintf(stderr, " E-mail: "); | |
584 fflush(stderr); | |
585 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { | |
586 if (p[len-1] == '\n') | |
587 p[--len] = '\0'; | |
588 wpng_info.email = p; | |
589 wpng_info.have_text |= TEXT_EMAIL; | |
590 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
591 fprintf(stderr, " " PROGNAME " warning: character code" | |
592 " %u is %sdiscouraged by the PNG\n specification " | |
593 "[first occurrence was at character position #%d]\n", | |
594 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
595 result+1); | |
596 fflush(stderr); | |
597 #ifdef FORBID_LATIN1_CTRL | |
598 wpng_info.have_text &= ~TEXT_EMAIL; | |
599 valid = FALSE; | |
600 #else | |
601 if (p[result] == 27) { /* escape character */ | |
602 wpng_info.have_text &= ~TEXT_EMAIL; | |
603 valid = FALSE; | |
604 } | |
605 #endif | |
606 } | |
607 } | |
608 } while (!valid); | |
609 | |
610 do { | |
611 valid = TRUE; | |
612 p = textbuf + TEXT_URL_OFFSET; | |
613 fprintf(stderr, " URL: "); | |
614 fflush(stderr); | |
615 if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { | |
616 if (p[len-1] == '\n') | |
617 p[--len] = '\0'; | |
618 wpng_info.url = p; | |
619 wpng_info.have_text |= TEXT_URL; | |
620 if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { | |
621 fprintf(stderr, " " PROGNAME " warning: character code" | |
622 " %u is %sdiscouraged by the PNG\n specification " | |
623 "[first occurrence was at character position #%d]\n", | |
624 (unsigned)p[result], (p[result] == 27)? "strongly " : "", | |
625 result+1); | |
626 fflush(stderr); | |
627 #ifdef FORBID_LATIN1_CTRL | |
628 wpng_info.have_text &= ~TEXT_URL; | |
629 valid = FALSE; | |
630 #else | |
631 if (p[result] == 27) { /* escape character */ | |
632 wpng_info.have_text &= ~TEXT_URL; | |
633 valid = FALSE; | |
634 } | |
635 #endif | |
636 } | |
637 } | |
638 } while (!valid); | |
639 | |
640 #ifndef DOS_OS2_W32 | |
641 fclose(keybd); | |
642 #endif | |
643 | |
644 } else if (text) { | |
645 fprintf(stderr, PROGNAME ": unable to allocate memory for text\n"); | |
646 text = FALSE; | |
647 wpng_info.have_text = 0; | |
648 } | |
649 | |
650 | |
651 /* allocate libpng stuff, initialize transformations, write pre-IDAT data */ | |
652 | |
653 if ((rc = writepng_init(&wpng_info)) != 0) { | |
654 switch (rc) { | |
655 case 2: | |
656 fprintf(stderr, PROGNAME | |
657 ": libpng initialization problem (longjmp)\n"); | |
658 break; | |
659 case 4: | |
660 fprintf(stderr, PROGNAME ": insufficient memory\n"); | |
661 break; | |
662 case 11: | |
663 fprintf(stderr, PROGNAME | |
664 ": internal logic error (unexpected PNM type)\n"); | |
665 break; | |
666 default: | |
667 fprintf(stderr, PROGNAME | |
668 ": unknown writepng_init() error\n"); | |
669 break; | |
670 } | |
671 exit(rc); | |
672 } | |
673 | |
674 | |
675 /* free textbuf, since it's a completely local variable and all text info | |
676 * has just been written to the PNG file */ | |
677 | |
678 if (text && textbuf) { | |
679 free(textbuf); | |
680 textbuf = NULL; | |
681 } | |
682 | |
683 | |
684 /* calculate rowbytes on basis of image type; note that this becomes much | |
685 * more complicated if we choose to support PBM type, ASCII PNM types, or | |
686 * 16-bit-per-sample binary data [currently not an official NetPBM type] */ | |
687 | |
688 if (wpng_info.pnmtype == 5) | |
689 rowbytes = wpng_info.width; | |
690 else if (wpng_info.pnmtype == 6) | |
691 rowbytes = wpng_info.width * 3; | |
692 else /* if (wpng_info.pnmtype == 8) */ | |
693 rowbytes = wpng_info.width * 4; | |
694 | |
695 | |
696 /* read and write the image, either in its entirety (if writing interlaced | |
697 * PNG) or row by row (if non-interlaced) */ | |
698 | |
699 fprintf(stderr, "Encoding image data...\n"); | |
700 fflush(stderr); | |
701 | |
702 if (wpng_info.interlaced) { | |
703 long i; | |
704 ulg bytes; | |
705 ulg image_bytes = rowbytes * wpng_info.height; /* overflow? */ | |
706 | |
707 wpng_info.image_data = (uch *)malloc(image_bytes); | |
708 wpng_info.row_pointers = (uch **)malloc(wpng_info.height*sizeof(uch *)); | |
709 if (wpng_info.image_data == NULL || wpng_info.row_pointers == NULL) { | |
710 fprintf(stderr, PROGNAME ": insufficient memory for image data\n"); | |
711 writepng_cleanup(&wpng_info); | |
712 wpng_cleanup(); | |
713 exit(5); | |
714 } | |
715 for (i = 0; i < wpng_info.height; ++i) | |
716 wpng_info.row_pointers[i] = wpng_info.image_data + i*rowbytes; | |
717 bytes = fread(wpng_info.image_data, 1, image_bytes, wpng_info.infile); | |
718 if (bytes != image_bytes) { | |
719 fprintf(stderr, PROGNAME ": expected %lu bytes, got %lu bytes\n", | |
720 image_bytes, bytes); | |
721 fprintf(stderr, " (continuing anyway)\n"); | |
722 } | |
723 if (writepng_encode_image(&wpng_info) != 0) { | |
724 fprintf(stderr, PROGNAME | |
725 ": libpng problem (longjmp) while writing image data\n"); | |
726 writepng_cleanup(&wpng_info); | |
727 wpng_cleanup(); | |
728 exit(2); | |
729 } | |
730 | |
731 } else /* not interlaced: write progressively (row by row) */ { | |
732 long j; | |
733 ulg bytes; | |
734 | |
735 wpng_info.image_data = (uch *)malloc(rowbytes); | |
736 if (wpng_info.image_data == NULL) { | |
737 fprintf(stderr, PROGNAME ": insufficient memory for row data\n"); | |
738 writepng_cleanup(&wpng_info); | |
739 wpng_cleanup(); | |
740 exit(5); | |
741 } | |
742 error = 0; | |
743 for (j = wpng_info.height; j > 0L; --j) { | |
744 bytes = fread(wpng_info.image_data, 1, rowbytes, wpng_info.infile); | |
745 if (bytes != rowbytes) { | |
746 fprintf(stderr, PROGNAME | |
747 ": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes, | |
748 bytes, wpng_info.height-j); | |
749 ++error; | |
750 break; | |
751 } | |
752 if (writepng_encode_row(&wpng_info) != 0) { | |
753 fprintf(stderr, PROGNAME | |
754 ": libpng problem (longjmp) while writing row %ld\n", | |
755 wpng_info.height-j); | |
756 ++error; | |
757 break; | |
758 } | |
759 } | |
760 if (error) { | |
761 writepng_cleanup(&wpng_info); | |
762 wpng_cleanup(); | |
763 exit(2); | |
764 } | |
765 if (writepng_encode_finish(&wpng_info) != 0) { | |
766 fprintf(stderr, PROGNAME ": error on final libpng call\n"); | |
767 writepng_cleanup(&wpng_info); | |
768 wpng_cleanup(); | |
769 exit(2); | |
770 } | |
771 } | |
772 | |
773 | |
774 /* OK, we're done (successfully): clean up all resources and quit */ | |
775 | |
776 fprintf(stderr, "Done.\n"); | |
777 fflush(stderr); | |
778 | |
779 writepng_cleanup(&wpng_info); | |
780 wpng_cleanup(); | |
781 | |
782 return 0; | |
783 } | |
784 | |
785 | |
786 | |
787 | |
788 | |
789 static int wpng_isvalid_latin1(uch *p, int len) | |
790 { | |
791 int i, result = -1; | |
792 | |
793 for (i = 0; i < len; ++i) { | |
794 if (p[i] == 10 || (p[i] > 31 && p[i] < 127) || p[i] > 160) | |
795 continue; /* character is completely OK */ | |
796 if (result < 0 || (p[result] != 27 && p[i] == 27)) | |
797 result = i; /* mark location of first questionable one */ | |
798 } /* or of first escape character (bad) */ | |
799 | |
800 return result; | |
801 } | |
802 | |
803 | |
804 | |
805 | |
806 | |
807 static void wpng_cleanup(void) | |
808 { | |
809 if (wpng_info.outfile) { | |
810 fclose(wpng_info.outfile); | |
811 wpng_info.outfile = NULL; | |
812 } | |
813 | |
814 if (wpng_info.infile) { | |
815 fclose(wpng_info.infile); | |
816 wpng_info.infile = NULL; | |
817 } | |
818 | |
819 if (wpng_info.image_data) { | |
820 free(wpng_info.image_data); | |
821 wpng_info.image_data = NULL; | |
822 } | |
823 | |
824 if (wpng_info.row_pointers) { | |
825 free(wpng_info.row_pointers); | |
826 wpng_info.row_pointers = NULL; | |
827 } | |
828 } | |
829 | |
830 | |
831 | |
832 | |
833 #ifdef DOS_OS2_W32 | |
834 | |
835 static char *dos_kbd_gets(char *buf, int len) | |
836 { | |
837 int ch, count=0; | |
838 | |
839 do { | |
840 buf[count++] = ch = getche(); | |
841 } while (ch != '\r' && count < len-1); | |
842 | |
843 buf[count--] = '\0'; /* terminate string */ | |
844 if (buf[count] == '\r') /* Enter key makes CR, so change to newline */ | |
845 buf[count] = '\n'; | |
846 | |
847 fprintf(stderr, "\n"); /* Enter key does *not* cause a newline */ | |
848 fflush(stderr); | |
849 | |
850 return buf; | |
851 } | |
852 | |
853 #endif /* DOS_OS2_W32 */ |