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!
19 - delete output file if quit before calling any writepng routines
20 - process backspace with -text option under DOS/Win? (currently get ^H)
22 ---------------------------------------------------------------------------
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
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
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
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__)
96 #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
97 # ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */
105 #include <setjmp.h> /* for jmpbuf declaration in writepng.h */
109 # include <io.h> /* for isatty(), setmode() prototypes */
110 # include <fcntl.h> /* O_BINARY for fdopen() without text translation */
113 # define getch() _read_kbd(0, 1, 0) /* need getche() */
115 # else /* !__EMX__ */
118 # define getch() getkey() /* GRR: need getche() */
120 # include <conio.h> /* for getche() console input */
122 # endif /* ?__EMX__ */
123 # define FGETS(buf,len,stream) dos_kbd_gets(buf,len)
125 # include <unistd.h> /* for isatty() prototype */
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);
145 static char *dos_kbd_gets(char *buf
, int len
);
150 static mainprog_info wpng_info
; /* lone global */
154 int main(int argc
, char **argv
)
160 FILE *tmpfile
; /* or we could just use keybd, since no overlap */
163 char *inname
= NULL
, outname
[256];
164 char *p
, pnmchar
, pnmline
[256];
165 char *bgstr
, *textbuf
= NULL
;
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.) */
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;
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");
213 fgets(tmpline
, 80, tmpfile
);
215 sgi_gamma
= atof(tmpline
);
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;
226 LUT_exponent
= 1.0; /* assume no LUT: most PCs */
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
);
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)) {
259 } else if (!strncmp(*argv
, "-gamma", 2)) {
263 wpng_info
.gamma
= atof(*argv
);
264 if (wpng_info
.gamma
<= 0.0)
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)) {
275 if (strlen(bgstr
) != 7 || bgstr
[0] != '#')
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
;
290 if (argv
[1]) /* shouldn't be any more args after filename */
293 ++error
; /* not expecting any other options */
298 /* open the input and output files, or register an error and abort */
302 fprintf(stderr
, PROGNAME
303 ": must give input filename or provide image data via stdin\n");
307 /* some buggy C libraries require BOTH setmode() and fdopen(bin) */
308 setmode(fileno(stdin
), O_BINARY
);
309 setmode(fileno(stdout
), O_BINARY
);
311 if ((wpng_info
.infile
= fdopen(fileno(stdin
), "rb")) == NULL
) {
312 fprintf(stderr
, PROGNAME
313 ": unable to reopen stdin in binary mode\n");
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
);
322 wpng_info
.filter
= TRUE
;
324 } else if ((len
= strlen(inname
)) > 250) {
325 fprintf(stderr
, PROGNAME
": input filename is too long [%d chars]\n",
328 } else if (!(wpng_info
.infile
= fopen(inname
, "rb"))) {
329 fprintf(stderr
, PROGNAME
": can't open input file [%s]\n", inname
);
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",
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 */
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
);
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 ||
357 fprintf(stderr
, PROGNAME
358 ": only positive width/height, maxval == 255 allowed \n");
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");
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",
379 fclose(wpng_info
.outfile
);
381 } else if (!(wpng_info
.outfile
= fopen(outname
, "wb"))) {
382 fprintf(stderr
, PROGNAME
": can't open output file [%s]\n",
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! */
402 fprintf(stderr
, "\n%s %s: %s\n", PROGNAME
, VERSION
, APPNAME
);
403 writepng_version_info();
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"
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
);
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
439 (keybd
= fdopen(fileno(stderr
), "r")) != NULL
&&
441 (textbuf
= (char *)malloc((5 + 9)*75)) != NULL
)
443 int i
, valid
, result
;
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 */
452 p
= textbuf
+ TEXT_TITLE_OFFSET
;
453 fprintf(stderr
, " Title: ");
455 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
456 if (p
[len
-1] == '\n')
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 " : "",
467 #ifdef FORBID_LATIN1_CTRL
468 wpng_info
.have_text
&= ~TEXT_TITLE
;
471 if (p
[result
] == 27) { /* escape character */
472 wpng_info
.have_text
&= ~TEXT_TITLE
;
482 p
= textbuf
+ TEXT_AUTHOR_OFFSET
;
483 fprintf(stderr
, " Author: ");
485 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
486 if (p
[len
-1] == '\n')
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 " : "",
497 #ifdef FORBID_LATIN1_CTRL
498 wpng_info
.have_text
&= ~TEXT_AUTHOR
;
501 if (p
[result
] == 27) { /* escape character */
502 wpng_info
.have_text
&= ~TEXT_AUTHOR
;
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
);
517 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1)
518 p
+= len
; /* now points at NULL; char before is newline */
522 if ((len
= p
- (textbuf
+ TEXT_DESC_OFFSET
)) > 1) {
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 " : "",
537 #ifdef FORBID_LATIN1_CTRL
538 wpng_info
.have_text
&= ~TEXT_DESC
;
541 if (p
[result
] == 27) { /* escape character */
542 wpng_info
.have_text
&= ~TEXT_DESC
;
552 p
= textbuf
+ TEXT_COPY_OFFSET
;
553 fprintf(stderr
, " Copyright: ");
555 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
556 if (p
[len
-1] == '\n')
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 " : "",
567 #ifdef FORBID_LATIN1_CTRL
568 wpng_info
.have_text
&= ~TEXT_COPY
;
571 if (p
[result
] == 27) { /* escape character */
572 wpng_info
.have_text
&= ~TEXT_COPY
;
582 p
= textbuf
+ TEXT_EMAIL_OFFSET
;
583 fprintf(stderr
, " E-mail: ");
585 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
586 if (p
[len
-1] == '\n')
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 " : "",
597 #ifdef FORBID_LATIN1_CTRL
598 wpng_info
.have_text
&= ~TEXT_EMAIL
;
601 if (p
[result
] == 27) { /* escape character */
602 wpng_info
.have_text
&= ~TEXT_EMAIL
;
612 p
= textbuf
+ TEXT_URL_OFFSET
;
613 fprintf(stderr
, " URL: ");
615 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
616 if (p
[len
-1] == '\n')
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 " : "",
627 #ifdef FORBID_LATIN1_CTRL
628 wpng_info
.have_text
&= ~TEXT_URL
;
631 if (p
[result
] == 27) { /* escape character */
632 wpng_info
.have_text
&= ~TEXT_URL
;
645 fprintf(stderr
, PROGNAME
": unable to allocate memory for text\n");
647 wpng_info
.have_text
= 0;
651 /* allocate libpng stuff, initialize transformations, write pre-IDAT data */
653 if ((rc
= writepng_init(&wpng_info
)) != 0) {
656 fprintf(stderr
, PROGNAME
657 ": libpng initialization problem (longjmp)\n");
660 fprintf(stderr
, PROGNAME
": insufficient memory\n");
663 fprintf(stderr
, PROGNAME
664 ": internal logic error (unexpected PNM type)\n");
667 fprintf(stderr
, PROGNAME
668 ": unknown writepng_init() error\n");
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
) {
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");
702 if (wpng_info
.interlaced
) {
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
);
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",
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
);
731 } else /* not interlaced: write progressively (row by row) */ {
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
);
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
);
752 if (writepng_encode_row(&wpng_info
) != 0) {
753 fprintf(stderr
, PROGNAME
754 ": libpng problem (longjmp) while writing row %ld\n",
761 writepng_cleanup(&wpng_info
);
765 if (writepng_encode_finish(&wpng_info
) != 0) {
766 fprintf(stderr
, PROGNAME
": error on final libpng call\n");
767 writepng_cleanup(&wpng_info
);
774 /* OK, we're done (successfully): clean up all resources and quit */
776 fprintf(stderr
, "Done.\n");
779 writepng_cleanup(&wpng_info
);
789 static int wpng_isvalid_latin1(uch
*p
, int len
)
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) */
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
;
835 static char *dos_kbd_gets(char *buf
, int len
)
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 */
847 fprintf(stderr
, "\n"); /* Enter key does *not* cause a newline */
853 #endif /* DOS_OS2_W32 */