beta-0.89.2
[luatex.git] / source / libs / libpng / libpng-src / contrib / gregbook / wpng.c
bloba06e3529ecb388c4a7e70c121d523fa8f4f20007
1 /*---------------------------------------------------------------------------
3 wpng - simple PNG-writing program wpng.c
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.
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.
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!
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)
22 ---------------------------------------------------------------------------
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)
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."]
39 ---------------------------------------------------------------------------
41 Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
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.
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):
53 LICENSE 1 ("BSD-like with advertising clause"):
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:
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:
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.
72 LICENSE 2 (GNU GPL v2 or later):
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.
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.
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
88 ---------------------------------------------------------------------------*/
90 #define PROGNAME "wpng"
91 #define VERSION "2.00 of 2 June 2007"
92 #define APPNAME "Simple PGM/PPM/PAM to PNG Converter"
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
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>
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
129 /* #define DEBUG : this enables the Trace() macros */
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 */
135 #include "writepng.h" /* typedefs, common macros, writepng prototypes */
139 /* local prototypes */
141 static int wpng_isvalid_latin1(uch *p, int len);
142 static void wpng_cleanup(void);
144 #ifdef DOS_OS2_W32
145 static char *dos_kbd_gets(char *buf, int len);
146 #endif
150 static mainprog_info wpng_info; /* lone global */
154 int main(int argc, char **argv)
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;
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;
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.) */
198 #if defined(NeXT)
199 /* third-party utilities can modify the default LUT exponent */
200 LUT_exponent = 1.0 / 2.2;
202 if (some_next_function_that_returns_gamma(&next_gamma))
203 LUT_exponent = 1.0 / next_gamma;
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;
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;
219 #elif defined(Macintosh)
220 LUT_exponent = 1.8 / 2.61;
222 if (some_mac_function_that_returns_gamma(&mac_gamma))
223 LUT_exponent = mac_gamma / 2.61;
225 #else
226 LUT_exponent = 1.0; /* assume no LUT: most PCs */
227 #endif
229 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
230 default_display_exponent = LUT_exponent * CRT_exponent;
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. */
238 if ((p = getenv("SCREEN_GAMMA")) != NULL) {
239 double exponent = atof(p);
241 if (exponent > 0.0)
242 default_gamma = 1.0 / exponent;
245 if (default_gamma == 0.0)
246 default_gamma = 1.0 / default_display_exponent;
249 /* Now parse the command line for options and the PNM filename. */
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");
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 */
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;
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 */
298 /* open the input and output files, or register an error and abort */
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;
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;
333 if (!error) {
334 fgets(pnmline, 256, wpng_info.infile);
335 if (pnmline[0] != 'P' || ((pnmchar = pnmline[1]) != '5' &&
336 pnmchar != '6' && pnmchar != '8'))
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)
357 fprintf(stderr, PROGNAME
358 ": only positive width/height, maxval == 255 allowed \n");
359 ++error;
361 wpng_info.sample_depth = 8; /* <==> maxval 255 */
363 if (!wpng_info.filter) {
364 /* make outname from inname */
365 if ((p = strrchr(inname, '.')) == NULL ||
366 (p - inname) != (len - 4))
368 strcpy(outname, inname);
369 strcpy(outname+len, ".png");
370 } else {
371 len -= 4;
372 strncpy(outname, inname, len);
373 strcpy(outname+len, ".png");
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;
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;
399 /* if we had any errors, print usage and die horrible death...arrr! */
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);
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 */
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)
443 int i, valid, result;
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 */
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;
475 #endif
478 } while (!valid);
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;
505 #endif
508 } while (!valid);
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;
522 if ((len = p - (textbuf + TEXT_DESC_OFFSET)) > 1) {
523 if (p[-1] == '\n') {
524 p[-1] = '\0';
525 --len;
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;
545 #endif
548 } while (!valid);
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;
575 #endif
578 } while (!valid);
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;
605 #endif
608 } while (!valid);
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;
635 #endif
638 } while (!valid);
640 #ifndef DOS_OS2_W32
641 fclose(keybd);
642 #endif
644 } else if (text) {
645 fprintf(stderr, PROGNAME ": unable to allocate memory for text\n");
646 text = FALSE;
647 wpng_info.have_text = 0;
651 /* allocate libpng stuff, initialize transformations, write pre-IDAT data */
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;
671 exit(rc);
675 /* free textbuf, since it's a completely local variable and all text info
676 * has just been written to the PNG file */
678 if (text && textbuf) {
679 free(textbuf);
680 textbuf = NULL;
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] */
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;
696 /* read and write the image, either in its entirety (if writing interlaced
697 * PNG) or row by row (if non-interlaced) */
699 fprintf(stderr, "Encoding image data...\n");
700 fflush(stderr);
702 if (wpng_info.interlaced) {
703 long i;
704 ulg bytes;
705 ulg image_bytes = rowbytes * wpng_info.height; /* overflow? */
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);
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");
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);
731 } else /* not interlaced: write progressively (row by row) */ {
732 long j;
733 ulg bytes;
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);
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;
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;
760 if (error) {
761 writepng_cleanup(&wpng_info);
762 wpng_cleanup();
763 exit(2);
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);
774 /* OK, we're done (successfully): clean up all resources and quit */
776 fprintf(stderr, "Done.\n");
777 fflush(stderr);
779 writepng_cleanup(&wpng_info);
780 wpng_cleanup();
782 return 0;
789 static int wpng_isvalid_latin1(uch *p, int len)
791 int i, result = -1;
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) */
800 return result;
807 static void wpng_cleanup(void)
809 if (wpng_info.outfile) {
810 fclose(wpng_info.outfile);
811 wpng_info.outfile = NULL;
814 if (wpng_info.infile) {
815 fclose(wpng_info.infile);
816 wpng_info.infile = NULL;
819 if (wpng_info.image_data) {
820 free(wpng_info.image_data);
821 wpng_info.image_data = NULL;
824 if (wpng_info.row_pointers) {
825 free(wpng_info.row_pointers);
826 wpng_info.row_pointers = NULL;
833 #ifdef DOS_OS2_W32
835 static char *dos_kbd_gets(char *buf, int len)
837 int ch, count=0;
839 do {
840 buf[count++] = ch = getche();
841 } while (ch != '\r' && count < len-1);
843 buf[count--] = '\0'; /* terminate string */
844 if (buf[count] == '\r') /* Enter key makes CR, so change to newline */
845 buf[count] = '\n';
847 fprintf(stderr, "\n"); /* Enter key does *not* cause a newline */
848 fflush(stderr);
850 return buf;
853 #endif /* DOS_OS2_W32 */