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