Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
wpng.c
Go to the documentation of this file.
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);
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 */
char * email
Definition: writepng.h:105
char * url
Definition: writepng.h:106
GLfloat GLfloat p
#define NULL
Definition: ftobjs.h:61
#define TEXT_DESC
Definition: writepng.h:74
FILE * outfile
Definition: writepng.h:96
#define TEXT_URL_OFFSET
Definition: writepng.h:83
#define TEXT_TITLE
Definition: writepng.h:72
int writepng_encode_image(mainprog_info *mainprog_ptr)
Definition: writepng.c:257
#define TEXT_URL
Definition: writepng.h:77
char * malloc()
#define TEXT_DESC_OFFSET
Definition: writepng.h:84
#define TEXT_AUTHOR_OFFSET
Definition: writepng.h:80
unsigned long ulg
Definition: zutil.h:38
GLboolean GLboolean GLboolean b
png_uint_32 i
Definition: png.h:2640
GLenum GLuint GLenum GLsizei const GLchar * buf
char * author
Definition: writepng.h:102
int sample_depth
Definition: writepng.h:109
int main(int argc, char **argv)
Definition: wpng.c:154
void writepng_cleanup(mainprog_info *mainprog_ptr)
Definition: writepng.c:354
double gamma
Definition: writepng.h:91
#define VERSION
Definition: wpng.c:91
GLint exponent[16]
GLenum GLsizei len
#define TEXT_EMAIL
Definition: writepng.h:76
FT_Error error
Definition: cffdrivr.c:411
GLdouble GLdouble GLdouble r
#define TEXT_TITLE_OFFSET
Definition: writepng.h:79
void writepng_version_info(void)
Definition: writepng.c:69
int free()
char * title
Definition: writepng.h:101
int writepng_encode_finish(mainprog_info *mainprog_ptr)
Definition: writepng.c:325
FILE * infile
Definition: writepng.h:95
#define TEXT_EMAIL_OFFSET
Definition: writepng.h:82
#define FALSE
Definition: ftobjs.h:57
typedef int
Definition: png.h:978
int writepng_encode_row(mainprog_info *mainprog_ptr)
Definition: writepng.c:295
uch * image_data
Definition: readpng2.h:91
GLuint64EXT * result
GLboolean GLboolean g
#define FGETS
Definition: wpng.c:126
#define APPNAME
Definition: wpng.c:92
GLuint GLuint GLsizei count
#define PROGNAME
Definition: wpng.c:90
char * desc
Definition: writepng.h:103
time_t modtime
Definition: writepng.h:94
#define TEXT_COPY
Definition: writepng.h:75
int writepng_init(mainprog_info *mainprog_ptr)
Definition: writepng.c:83
uch ** row_pointers
Definition: readpng2.h:92
#define TRUE
Definition: ftobjs.h:53
#define TEXT_AUTHOR
Definition: writepng.h:73
unsigned char uch
Definition: zutil.h:34
#define TEXT_COPY_OFFSET
Definition: writepng.h:81
char * copyright
Definition: writepng.h:104