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