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)
32 - 2.01: check for integer overflow (Glenn R-P)
34 [REPORTED BUG (win32 only): "contrib/gregbook/wpng.c - cmd line
35 dose not work! In order to do something useful I needed to redirect
36 both input and output, with cygwin and with bcc32 as well. Under
37 Linux, the same wpng appears to work fine. I don't know what is
40 ---------------------------------------------------------------------------
42 Copyright (c) 1998-2007, 2017 Greg Roelofs. All rights reserved.
44 This software is provided "as is," without warranty of any kind,
45 express or implied. In no event shall the author or contributors
46 be held liable for any damages arising in any way from the use of
49 The contents of this file are DUAL-LICENSED. You may modify and/or
50 redistribute this software according to the terms of one of the
51 following two licenses (at your option):
54 LICENSE 1 ("BSD-like with advertising clause"):
56 Permission is granted to anyone to use this software for any purpose,
57 including commercial applications, and to alter it and redistribute
58 it freely, subject to the following restrictions:
60 1. Redistributions of source code must retain the above copyright
61 notice, disclaimer, and this list of conditions.
62 2. Redistributions in binary form must reproduce the above copyright
63 notice, disclaimer, and this list of conditions in the documenta-
64 tion and/or other materials provided with the distribution.
65 3. All advertising materials mentioning features or use of this
66 software must display the following acknowledgment:
68 This product includes software developed by Greg Roelofs
69 and contributors for the book, "PNG: The Definitive Guide,"
70 published by O'Reilly and Associates.
73 LICENSE 2 (GNU GPL v2 or later):
75 This program is free software; you can redistribute it and/or modify
76 it under the terms of the GNU General Public License as published by
77 the Free Software Foundation; either version 2 of the License, or
78 (at your option) any later version.
80 This program is distributed in the hope that it will be useful,
81 but WITHOUT ANY WARRANTY; without even the implied warranty of
82 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83 GNU General Public License for more details.
85 You should have received a copy of the GNU General Public License
86 along with this program; if not, write to the Free Software Foundation,
87 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
89 ---------------------------------------------------------------------------*/
91 #define PROGNAME "wpng"
92 #define VERSION "2.00 of 2 June 2007"
93 #define APPNAME "Simple PGM/PPM/PAM to PNG Converter"
95 #if defined(__MSDOS__) || defined(__OS2__)
97 #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
98 # ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */
106 #include <setjmp.h> /* for jmpbuf declaration in writepng.h */
110 # include <io.h> /* for isatty(), setmode() prototypes */
111 # include <fcntl.h> /* O_BINARY for fdopen() without text translation */
114 # define getch() _read_kbd(0, 1, 0) /* need getche() */
116 # else /* !__EMX__ */
119 # define getch() getkey() /* GRR: need getche() */
121 # include <conio.h> /* for getche() console input */
123 # endif /* ?__EMX__ */
124 # define FGETS(buf,len,stream) dos_kbd_gets(buf,len)
126 # include <unistd.h> /* for isatty() prototype */
130 /* #define DEBUG : this enables the Trace() macros */
132 /* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any
133 text that includes control characters discouraged by the PNG spec; text
134 that includes an escape character (27) must be re-entered regardless */
136 #include "writepng.h" /* typedefs, common macros, writepng prototypes */
140 /* local prototypes */
142 static int wpng_isvalid_latin1(uch
*p
, int len
);
143 static void wpng_cleanup(void);
146 static char *dos_kbd_gets(char *buf
, int len
);
151 static mainprog_info wpng_info
; /* lone global */
155 int main(int argc
, char **argv
)
161 FILE *tmpfile
; /* or we could just use keybd, since no overlap */
164 char *inname
= NULL
, outname
[256];
165 char *p
, pnmchar
, pnmline
[256];
166 char *bgstr
, *textbuf
= NULL
;
172 double LUT_exponent
; /* just the lookup table */
173 double CRT_exponent
= 2.2; /* just the monitor */
174 double default_display_exponent
; /* whole display system */
175 double default_gamma
= 0.0;
178 wpng_info
.infile
= NULL
;
179 wpng_info
.outfile
= NULL
;
180 wpng_info
.image_data
= NULL
;
181 wpng_info
.row_pointers
= NULL
;
182 wpng_info
.filter
= FALSE
;
183 wpng_info
.interlaced
= FALSE
;
184 wpng_info
.have_bg
= FALSE
;
185 wpng_info
.have_time
= FALSE
;
186 wpng_info
.have_text
= 0;
187 wpng_info
.gamma
= 0.0;
190 /* First get the default value for our display-system exponent, i.e.,
191 * the product of the CRT exponent and the exponent corresponding to
192 * the frame-buffer's lookup table (LUT), if any. If the PNM image
193 * looks correct on the user's display system, its file gamma is the
194 * inverse of this value. (Note that this is not an exhaustive list
195 * of LUT values--e.g., OpenStep has a lot of weird ones--but it should
196 * cover 99% of the current possibilities. This section must ensure
197 * that default_display_exponent is positive.) */
200 /* third-party utilities can modify the default LUT exponent */
201 LUT_exponent
= 1.0 / 2.2;
203 if (some_next_function_that_returns_gamma(&next_gamma))
204 LUT_exponent = 1.0 / next_gamma;
207 LUT_exponent
= 1.0 / 1.7;
208 /* there doesn't seem to be any documented function to
209 * get the "gamma" value, so we do it the hard way */
210 tmpfile
= fopen("/etc/config/system.glGammaVal", "r");
214 fgets(tmpline
, 80, tmpfile
);
216 sgi_gamma
= atof(tmpline
);
218 LUT_exponent
= 1.0 / sgi_gamma
;
220 #elif defined(Macintosh)
221 LUT_exponent
= 1.8 / 2.61;
223 if (some_mac_function_that_returns_gamma(&mac_gamma))
224 LUT_exponent = mac_gamma / 2.61;
227 LUT_exponent
= 1.0; /* assume no LUT: most PCs */
230 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
231 default_display_exponent
= LUT_exponent
* CRT_exponent
;
234 /* If the user has set the SCREEN_GAMMA environment variable as suggested
235 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
236 * use the default value we just calculated. Either way, the user may
237 * override this via a command-line option. */
239 if ((p
= getenv("SCREEN_GAMMA")) != NULL
) {
240 double exponent
= atof(p
);
243 default_gamma
= 1.0 / exponent
;
246 if (default_gamma
== 0.0)
247 default_gamma
= 1.0 / default_display_exponent
;
250 /* Now parse the command line for options and the PNM filename. */
252 while (*++argv
&& !error
) {
253 if (!strncmp(*argv
, "-i", 2)) {
254 wpng_info
.interlaced
= TRUE
;
255 } else if (!strncmp(*argv
, "-time", 3)) {
256 wpng_info
.modtime
= time(NULL
);
257 wpng_info
.have_time
= TRUE
;
258 } else if (!strncmp(*argv
, "-text", 3)) {
260 } else if (!strncmp(*argv
, "-gamma", 2)) {
264 wpng_info
.gamma
= atof(*argv
);
265 if (wpng_info
.gamma
<= 0.0)
267 else if (wpng_info
.gamma
> 1.01)
268 fprintf(stderr
, PROGNAME
269 " warning: file gammas are usually less than 1.0\n");
271 } else if (!strncmp(*argv
, "-bgcolor", 4)) {
276 if (strlen(bgstr
) != 7 || bgstr
[0] != '#')
279 unsigned r
, g
, b
; /* this way quiets compiler warnings */
281 sscanf(bgstr
+1, "%2x%2x%2x", &r
, &g
, &b
);
282 wpng_info
.bg_red
= (uch
)r
;
283 wpng_info
.bg_green
= (uch
)g
;
284 wpng_info
.bg_blue
= (uch
)b
;
285 wpng_info
.have_bg
= TRUE
;
291 if (argv
[1]) /* shouldn't be any more args after filename */
294 ++error
; /* not expecting any other options */
299 /* open the input and output files, or register an error and abort */
303 fprintf(stderr
, PROGNAME
304 ": must give input filename or provide image data via stdin\n");
308 /* some buggy C libraries require BOTH setmode() and fdopen(bin) */
309 setmode(fileno(stdin
), O_BINARY
);
310 setmode(fileno(stdout
), O_BINARY
);
312 if ((wpng_info
.infile
= fdopen(fileno(stdin
), "rb")) == NULL
) {
313 fprintf(stderr
, PROGNAME
314 ": unable to reopen stdin in binary mode\n");
317 if ((wpng_info
.outfile
= fdopen(fileno(stdout
), "wb")) == NULL
) {
318 fprintf(stderr
, PROGNAME
319 ": unable to reopen stdout in binary mode\n");
320 fclose(wpng_info
.infile
);
323 wpng_info
.filter
= TRUE
;
325 } else if ((len
= strlen(inname
)) > 250) {
326 fprintf(stderr
, PROGNAME
": input filename is too long [%d chars]\n",
329 } else if (!(wpng_info
.infile
= fopen(inname
, "rb"))) {
330 fprintf(stderr
, PROGNAME
": can't open input file [%s]\n", inname
);
335 fgets(pnmline
, 256, wpng_info
.infile
);
336 if (pnmline
[0] != 'P' || ((pnmchar
= pnmline
[1]) != '5' &&
337 pnmchar
!= '6' && pnmchar
!= '8'))
339 fprintf(stderr
, PROGNAME
340 ": input file [%s] is not a binary PGM, PPM or PAM file\n",
344 wpng_info
.pnmtype
= (int)(pnmchar
- '0');
345 if (wpng_info
.pnmtype
!= 8)
346 wpng_info
.have_bg
= FALSE
; /* no need for bg if opaque */
348 fgets(pnmline
, 256, wpng_info
.infile
); /* lose any comments */
349 } while (pnmline
[0] == '#');
350 sscanf(pnmline
, "%ld %ld", &wpng_info
.width
, &wpng_info
.height
);
352 fgets(pnmline
, 256, wpng_info
.infile
); /* more comment lines */
353 } while (pnmline
[0] == '#');
354 sscanf(pnmline
, "%d", &maxval
);
355 if (wpng_info
.width
<= 0L || wpng_info
.height
<= 0L ||
358 fprintf(stderr
, PROGNAME
359 ": only positive width/height, maxval == 255 allowed \n");
362 wpng_info
.sample_depth
= 8; /* <==> maxval 255 */
364 if (!wpng_info
.filter
) {
365 /* make outname from inname */
366 if ((p
= strrchr(inname
, '.')) == NULL
||
367 (p
- inname
) != (len
- 4))
369 strcpy(outname
, inname
);
370 strcpy(outname
+len
, ".png");
373 strncpy(outname
, inname
, len
);
374 strcpy(outname
+len
, ".png");
376 /* check if outname already exists; if not, open */
377 if ((wpng_info
.outfile
= fopen(outname
, "rb")) != NULL
) {
378 fprintf(stderr
, PROGNAME
": output file exists [%s]\n",
380 fclose(wpng_info
.outfile
);
382 } else if (!(wpng_info
.outfile
= fopen(outname
, "wb"))) {
383 fprintf(stderr
, PROGNAME
": can't open output file [%s]\n",
390 fclose(wpng_info
.infile
);
391 wpng_info
.infile
= NULL
;
392 if (wpng_info
.filter
) {
393 fclose(wpng_info
.outfile
);
394 wpng_info
.outfile
= NULL
;
400 /* if we had any errors, print usage and die horrible death...arrr! */
403 fprintf(stderr
, "\n%s %s: %s\n", PROGNAME
, VERSION
, APPNAME
);
404 writepng_version_info();
406 "Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n"
407 "or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n"
408 " exp \ttransfer-function exponent (``gamma'') of the image in\n"
409 "\t\t floating-point format (e.g., ``%.5f''); if image looks\n"
410 "\t\t correct on given display system, image gamma is equal to\n"
411 "\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n"
412 "\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n"
413 "\t\t first varies, second is usually 2.2, all are positive)\n"
414 " bg \tdesired background color for alpha-channel images, in\n"
415 "\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n"
416 "\t\t same as HTML colors)\n"
417 " -text\tprompt interactively for text info (tEXt chunks)\n"
418 " -time\tinclude a tIME chunk (last modification time)\n"
419 " -interlace\twrite interlaced PNG image\n"
421 "pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n"
422 "unofficial and unsupported!) PAM (`P8') file. Currently it is required\n"
423 "to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n"
424 "is converted to the corresponding PNG file with the same base name but a\n"
425 "``.png'' extension; files read from stdin are converted and sent to stdout.\n"
426 "The conversion is progressive (low memory usage) unless interlacing is\n"
427 "requested; in that case the whole image will be buffered in memory and\n"
428 "written in one call.\n"
429 "\n", PROGNAME
, PROGNAME
, default_gamma
);
434 /* prepare the text buffers for libpng's use; note that even though
435 * PNG's png_text struct includes a length field, we don't have to fill
440 (keybd
= fdopen(fileno(stderr
), "r")) != NULL
&&
442 (textbuf
= (char *)malloc((5 + 9)*75)) != NULL
)
444 int i
, valid
, result
;
447 "Enter text info (no more than 72 characters per line);\n");
448 fprintf(stderr
, "to skip a field, hit the <Enter> key.\n");
449 /* note: just <Enter> leaves len == 1 */
453 p
= textbuf
+ TEXT_TITLE_OFFSET
;
454 fprintf(stderr
, " Title: ");
456 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
457 if (p
[len
-1] == '\n')
460 wpng_info
.have_text
|= TEXT_TITLE
;
461 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
462 fprintf(stderr
, " " PROGNAME
" warning: character code"
463 " %u is %sdiscouraged by the PNG\n specification "
464 "[first occurrence was at character position #%d]\n",
465 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
468 #ifdef FORBID_LATIN1_CTRL
469 wpng_info
.have_text
&= ~TEXT_TITLE
;
472 if (p
[result
] == 27) { /* escape character */
473 wpng_info
.have_text
&= ~TEXT_TITLE
;
483 p
= textbuf
+ TEXT_AUTHOR_OFFSET
;
484 fprintf(stderr
, " Author: ");
486 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
487 if (p
[len
-1] == '\n')
489 wpng_info
.author
= p
;
490 wpng_info
.have_text
|= TEXT_AUTHOR
;
491 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
492 fprintf(stderr
, " " PROGNAME
" warning: character code"
493 " %u is %sdiscouraged by the PNG\n specification "
494 "[first occurrence was at character position #%d]\n",
495 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
498 #ifdef FORBID_LATIN1_CTRL
499 wpng_info
.have_text
&= ~TEXT_AUTHOR
;
502 if (p
[result
] == 27) { /* escape character */
503 wpng_info
.have_text
&= ~TEXT_AUTHOR
;
513 p
= textbuf
+ TEXT_DESC_OFFSET
;
514 fprintf(stderr
, " Description (up to 9 lines):\n");
515 for (i
= 1; i
< 10; ++i
) {
516 fprintf(stderr
, " [%d] ", i
);
518 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1)
519 p
+= len
; /* now points at NULL; char before is newline */
523 if ((len
= p
- (textbuf
+ TEXT_DESC_OFFSET
)) > 1) {
528 wpng_info
.desc
= textbuf
+ TEXT_DESC_OFFSET
;
529 wpng_info
.have_text
|= TEXT_DESC
;
530 p
= textbuf
+ TEXT_DESC_OFFSET
;
531 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
532 fprintf(stderr
, " " PROGNAME
" warning: character code"
533 " %u is %sdiscouraged by the PNG\n specification "
534 "[first occurrence was at character position #%d]\n",
535 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
538 #ifdef FORBID_LATIN1_CTRL
539 wpng_info
.have_text
&= ~TEXT_DESC
;
542 if (p
[result
] == 27) { /* escape character */
543 wpng_info
.have_text
&= ~TEXT_DESC
;
553 p
= textbuf
+ TEXT_COPY_OFFSET
;
554 fprintf(stderr
, " Copyright: ");
556 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
557 if (p
[len
-1] == '\n')
559 wpng_info
.copyright
= p
;
560 wpng_info
.have_text
|= TEXT_COPY
;
561 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
562 fprintf(stderr
, " " PROGNAME
" warning: character code"
563 " %u is %sdiscouraged by the PNG\n specification "
564 "[first occurrence was at character position #%d]\n",
565 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
568 #ifdef FORBID_LATIN1_CTRL
569 wpng_info
.have_text
&= ~TEXT_COPY
;
572 if (p
[result
] == 27) { /* escape character */
573 wpng_info
.have_text
&= ~TEXT_COPY
;
583 p
= textbuf
+ TEXT_EMAIL_OFFSET
;
584 fprintf(stderr
, " E-mail: ");
586 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
587 if (p
[len
-1] == '\n')
590 wpng_info
.have_text
|= TEXT_EMAIL
;
591 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
592 fprintf(stderr
, " " PROGNAME
" warning: character code"
593 " %u is %sdiscouraged by the PNG\n specification "
594 "[first occurrence was at character position #%d]\n",
595 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
598 #ifdef FORBID_LATIN1_CTRL
599 wpng_info
.have_text
&= ~TEXT_EMAIL
;
602 if (p
[result
] == 27) { /* escape character */
603 wpng_info
.have_text
&= ~TEXT_EMAIL
;
613 p
= textbuf
+ TEXT_URL_OFFSET
;
614 fprintf(stderr
, " URL: ");
616 if (FGETS(p
, 74, keybd
) && (len
= strlen(p
)) > 1) {
617 if (p
[len
-1] == '\n')
620 wpng_info
.have_text
|= TEXT_URL
;
621 if ((result
= wpng_isvalid_latin1((uch
*)p
, len
)) >= 0) {
622 fprintf(stderr
, " " PROGNAME
" warning: character code"
623 " %u is %sdiscouraged by the PNG\n specification "
624 "[first occurrence was at character position #%d]\n",
625 (unsigned)p
[result
], (p
[result
] == 27)? "strongly " : "",
628 #ifdef FORBID_LATIN1_CTRL
629 wpng_info
.have_text
&= ~TEXT_URL
;
632 if (p
[result
] == 27) { /* escape character */
633 wpng_info
.have_text
&= ~TEXT_URL
;
646 fprintf(stderr
, PROGNAME
": unable to allocate memory for text\n");
648 wpng_info
.have_text
= 0;
652 /* allocate libpng stuff, initialize transformations, write pre-IDAT data */
654 if ((rc
= writepng_init(&wpng_info
)) != 0) {
657 fprintf(stderr
, PROGNAME
658 ": libpng initialization problem (longjmp)\n");
661 fprintf(stderr
, PROGNAME
": insufficient memory\n");
664 fprintf(stderr
, PROGNAME
665 ": internal logic error (unexpected PNM type)\n");
668 fprintf(stderr
, PROGNAME
669 ": unknown writepng_init() error\n");
676 /* free textbuf, since it's a completely local variable and all text info
677 * has just been written to the PNG file */
679 if (text
&& textbuf
) {
685 /* calculate rowbytes on basis of image type; note that this becomes much
686 * more complicated if we choose to support PBM type, ASCII PNM types, or
687 * 16-bit-per-sample binary data [currently not an official NetPBM type] */
689 if (wpng_info
.pnmtype
== 5)
690 rowbytes
= wpng_info
.width
;
691 else if (wpng_info
.pnmtype
== 6)
692 rowbytes
= wpng_info
.width
* 3;
693 else /* if (wpng_info.pnmtype == 8) */
694 rowbytes
= wpng_info
.width
* 4;
697 /* read and write the image, either in its entirety (if writing interlaced
698 * PNG) or row by row (if non-interlaced) */
700 fprintf(stderr
, "Encoding image data...\n");
703 if (wpng_info
.interlaced
) {
708 /* Guard against integer overflow */
709 if (wpng_info_height
> ((size_t)(-1)/rowbytes
||
710 wpng_info_height
> ((ulg
)(-1)/rowbytes
) {
711 fprintf(stderr
, PROGNAME
": image_data buffer too large\n");
712 writepng_cleanup(&wpng_info
);
717 image_bytes
= rowbytes
* wpng_info
.height
;
719 wpng_info
.image_data
= (uch
*)malloc(image_bytes
);
720 wpng_info
.row_pointers
= (uch
**)malloc(wpng_info
.height
*sizeof(uch
*));
721 if (wpng_info
.image_data
== NULL
|| wpng_info
.row_pointers
== NULL
) {
722 fprintf(stderr
, PROGNAME
": insufficient memory for image data\n");
723 writepng_cleanup(&wpng_info
);
727 for (i
= 0; i
< wpng_info
.height
; ++i
)
728 wpng_info
.row_pointers
[i
] = wpng_info
.image_data
+ i
*rowbytes
;
729 bytes
= fread(wpng_info
.image_data
, 1, image_bytes
, wpng_info
.infile
);
730 if (bytes
!= image_bytes
) {
731 fprintf(stderr
, PROGNAME
": expected %lu bytes, got %lu bytes\n",
733 fprintf(stderr
, " (continuing anyway)\n");
735 if (writepng_encode_image(&wpng_info
) != 0) {
736 fprintf(stderr
, PROGNAME
737 ": libpng problem (longjmp) while writing image data\n");
738 writepng_cleanup(&wpng_info
);
743 } else /* not interlaced: write progressively (row by row) */ {
747 wpng_info
.image_data
= (uch
*)malloc(rowbytes
);
748 if (wpng_info
.image_data
== NULL
) {
749 fprintf(stderr
, PROGNAME
": insufficient memory for row data\n");
750 writepng_cleanup(&wpng_info
);
755 for (j
= wpng_info
.height
; j
> 0L; --j
) {
756 bytes
= fread(wpng_info
.image_data
, 1, rowbytes
, wpng_info
.infile
);
757 if (bytes
!= rowbytes
) {
758 fprintf(stderr
, PROGNAME
759 ": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes
,
760 bytes
, wpng_info
.height
-j
);
764 if (writepng_encode_row(&wpng_info
) != 0) {
765 fprintf(stderr
, PROGNAME
766 ": libpng problem (longjmp) while writing row %ld\n",
773 writepng_cleanup(&wpng_info
);
777 if (writepng_encode_finish(&wpng_info
) != 0) {
778 fprintf(stderr
, PROGNAME
": error on final libpng call\n");
779 writepng_cleanup(&wpng_info
);
786 /* OK, we're done (successfully): clean up all resources and quit */
788 fprintf(stderr
, "Done.\n");
791 writepng_cleanup(&wpng_info
);
801 static int wpng_isvalid_latin1(uch
*p
, int len
)
805 for (i
= 0; i
< len
; ++i
) {
806 if (p
[i
] == 10 || (p
[i
] > 31 && p
[i
] < 127) || p
[i
] > 160)
807 continue; /* character is completely OK */
808 if (result
< 0 || (p
[result
] != 27 && p
[i
] == 27))
809 result
= i
; /* mark location of first questionable one */
810 } /* or of first escape character (bad) */
819 static void wpng_cleanup(void)
821 if (wpng_info
.outfile
) {
822 fclose(wpng_info
.outfile
);
823 wpng_info
.outfile
= NULL
;
826 if (wpng_info
.infile
) {
827 fclose(wpng_info
.infile
);
828 wpng_info
.infile
= NULL
;
831 if (wpng_info
.image_data
) {
832 free(wpng_info
.image_data
);
833 wpng_info
.image_data
= NULL
;
836 if (wpng_info
.row_pointers
) {
837 free(wpng_info
.row_pointers
);
838 wpng_info
.row_pointers
= NULL
;
847 static char *dos_kbd_gets(char *buf
, int len
)
852 buf
[count
++] = ch
= getche();
853 } while (ch
!= '\r' && count
< len
-1);
855 buf
[count
--] = '\0'; /* terminate string */
856 if (buf
[count
] == '\r') /* Enter key makes CR, so change to newline */
859 fprintf(stderr
, "\n"); /* Enter key does *not* cause a newline */
865 #endif /* DOS_OS2_W32 */