/*---------------------------------------------------------------------------
wpng - simple PNG-writing program wpng.c
This program converts certain NetPBM binary files (grayscale and RGB,
maxval = 255) to PNG. Non-interlaced PNGs are written progressively;
interlaced PNGs are read and written in one memory-intensive blast.
Thanks to Jean-loup Gailly for providing the necessary trick to read
interactive text from the keyboard while stdin is redirected.
NOTE: includes provisional support for PNM type "8" (portable alphamap)
images, presumed to be a 32-bit interleaved RGBA format; no pro-
vision for possible interleaved grayscale+alpha (16-bit) format.
THIS IS UNLIKELY TO BECOME AN OFFICIAL NETPBM ALPHA FORMAT!
to do:
- delete output file if quit before calling any writepng routines
---------------------------------------------------------------------------
Changelog:
- 1.01: initial public release
- 1.02: modified to allow abbreviated options
- 1.03: removed extraneous character from usage screen; fixed bug in
command-line parsing
---------------------------------------------------------------------------
Copyright (c) 1998-2000 Greg Roelofs. All rights reserved.
This software is provided "as is," without warranty of any kind,
express or implied. In no event shall the author or contributors
be held liable for any damages arising in any way from the use of
this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright
notice, disclaimer, and this list of conditions.
2. Redistributions in binary form must reproduce the above copyright
notice, disclaimer, and this list of conditions in the documenta-
3. All advertising materials mentioning features or use of this
software must display the following acknowledgment:
This product includes software developed by Greg Roelofs
and contributors for the book, "PNG: The Definitive Guide,"
published by O'Reilly and Associates.
---------------------------------------------------------------------------*/
# define DOS_OS2_W32
# define DOS_OS2_W32
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h> /* for jmpbuf declaration in writepng.h */
#include <time.h>
#ifdef DOS_OS2_W32
# include <io.h> /* for isatty(), setmode() prototypes */
# include <fcntl.h> /* O_BINARY for fdopen() without text translation */
# ifdef __EMX__
# ifndef getch
# endif
# else /* !__EMX__ */
# ifdef __GO32__
# include <pc.h>
# else
# include <conio.h> /* for getche() console input */
# endif
# endif /* ?__EMX__ */
#else
# include <unistd.h> /* for isatty() prototype */
#endif
/* #define DEBUG : this enables the Trace() macros */
/* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any
text that includes control characters discouraged by the PNG spec; text
that includes an escape character (27) must be re-entered regardless */
#include "writepng.h" /* typedefs, common macros, writepng prototypes */
/* local prototypes */
static void wpng_cleanup(void);
#ifdef DOS_OS2_W32
#endif
{
#ifndef DOS_OS2_W32
#endif
#ifdef sgi
#endif
int error = 0;
int maxval;
/* First get the default value for our display-system exponent, i.e.,
* the product of the CRT exponent and the exponent corresponding to
* the frame-buffer's lookup table (LUT), if any. If the PNM image
* looks correct on the user's display system, its file gamma is the
* inverse of this value. (Note that this is not an exhaustive list
* of LUT values--e.g., OpenStep has a lot of weird ones--but it should
* cover 99% of the current possibilities. This section must ensure
* that default_display_exponent is positive.) */
#if defined(NeXT)
/* third-party utilities can modify the default LUT exponent */
/*
if (some_next_function_that_returns_gamma(&next_gamma))
LUT_exponent = 1.0 / next_gamma;
*/
/* there doesn't seem to be any documented function to
* get the "gamma" value, so we do it the hard way */
if (tmpfile) {
double sgi_gamma;
if (sgi_gamma > 0.0)
}
/*
if (some_mac_function_that_returns_gamma(&mac_gamma))
LUT_exponent = mac_gamma / 2.61;
*/
#else
#endif
/* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
/* If the user has set the SCREEN_GAMMA environment variable as suggested
* (somewhat imprecisely) in the libpng documentation, use that; otherwise
* use the default value we just calculated. Either way, the user may
* override this via a command-line option. */
if (exponent > 0.0)
}
if (default_gamma == 0.0)
/* Now parse the command line for options and the PNM filename. */
if (!*++argv)
++error;
else {
++error;
" warning: file gammas are usually less than 1.0\n");
}
if (!*++argv)
++error;
else {
++error;
else {
unsigned r, g, b; /* this way quiets compiler warnings */
}
}
} else {
if (**argv != '-') {
++error;
} else
++error; /* not expecting any other options */
}
}
/* open the input and output files, or register an error and abort */
if (!inname) {
if (isatty(0)) {
": must give input filename or provide image data via stdin\n");
++error;
} else {
#ifdef DOS_OS2_W32
/* some buggy C libraries require BOTH setmode() and fdopen(bin) */
#endif
": unable to reopen stdin in binary mode\n");
++error;
} else
": unable to reopen stdout in binary mode\n");
++error;
} else
}
len);
++error;
++error;
}
if (!error) {
{
": input file [%s] is not a binary PGM, PPM or PAM file\n",
inname);
++error;
} else {
do {
} while (pnmline[0] == '#');
do {
} while (pnmline[0] == '#');
maxval != 255)
{
++error;
}
/* make outname from inname */
{
} else {
len -= 4;
}
/* check if outname already exists; if not, open */
outname);
++error;
outname);
++error;
}
}
}
if (error) {
}
}
}
/* if we had any errors, print usage and die horrible death...arrr! */
if (error) {
"Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n"
"or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n"
" exp \ttransfer-function exponent (``gamma'') of the image in\n"
"\t\t floating-point format (e.g., ``%.5f''); if image looks\n"
"\t\t correct on given display system, image gamma is equal to\n"
"\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n"
"\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n"
"\t\t first varies, second is usually 2.2, all are positive)\n"
" bg \tdesired background color for alpha-channel images, in\n"
"\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n"
"\t\t same as HTML colors)\n"
" -text\tprompt interactively for text info (tEXt chunks)\n"
" -time\tinclude a tIME chunk (last modification time)\n"
" -interlace\twrite interlaced PNG image\n"
"\n"
"pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n"
"unofficial and unsupported!) PAM (`P8') file. Currently it is required\n"
"to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n"
"is converted to the corresponding PNG file with the same base name but a\n"
"``.png'' extension; files read from stdin are converted and sent to stdout.\n"
"The conversion is progressive (low memory usage) unless interlacing is\n"
"requested; in that case the whole image will be buffered in memory and\n"
"written in one call.\n"
exit(1);
}
/* prepare the text buffers for libpng's use; note that even though
* PNG's png_text struct includes a length field, we don't have to fill
* it out */
if (text &&
#ifndef DOS_OS2_W32
#endif
{
"Enter text info (no more than 72 characters per line);\n");
/* note: just <Enter> leaves len == 1 */
do {
p = textbuf + TEXT_TITLE_OFFSET;
p[--len] = '\0';
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
do {
p = textbuf + TEXT_AUTHOR_OFFSET;
p[--len] = '\0';
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
do {
p = textbuf + TEXT_DESC_OFFSET;
for (i = 1; i < 10; ++i) {
p += len; /* now points at NULL; char before is newline */
else
break;
}
if (p[-1] == '\n') {
p[-1] = '\0';
--len;
}
p = textbuf + TEXT_DESC_OFFSET;
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
do {
p = textbuf + TEXT_COPY_OFFSET;
p[--len] = '\0';
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
do {
p = textbuf + TEXT_EMAIL_OFFSET;
p[--len] = '\0';
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
do {
p = textbuf + TEXT_URL_OFFSET;
p[--len] = '\0';
" %u is %sdiscouraged by the PNG\n specification "
"[first occurrence was at character position #%d]\n",
result+1);
#ifdef FORBID_LATIN1_CTRL
#else
}
#endif
}
}
} while (!valid);
#ifndef DOS_OS2_W32
#endif
} else if (text) {
}
/* allocate libpng stuff, initialize transformations, write pre-IDAT data */
switch (rc) {
case 2:
": libpng initialization problem (longjmp)\n");
break;
case 4:
break;
case 11:
": internal logic error (unexpected PNM type)\n");
break;
default:
": unknown writepng_init() error\n");
break;
}
}
/* free textbuf, since it's a completely local variable and all text info
* has just been written to the PNG file */
}
/* calculate rowbytes on basis of image type; note that this becomes much
* more complicated if we choose to support PBM type, ASCII PNM types, or
* 16-bit-per-sample binary data [currently not an official NetPBM type] */
else /* if (wpng_info.pnmtype == 8) */
/* read and write the image, either in its entirety (if writing interlaced
* PNG) or row by row (if non-interlaced) */
if (wpng_info.interlaced) {
long i;
wpng_cleanup();
exit(5);
}
if (bytes != image_bytes) {
image_bytes, bytes);
}
if (writepng_encode_image(&wpng_info) != 0) {
": libpng problem (longjmp) while writing image data\n");
wpng_cleanup();
exit(2);
}
} else /* not interlaced: write progressively (row by row) */ {
long j;
wpng_cleanup();
exit(5);
}
error = 0;
": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes,
++error;
break;
}
if (writepng_encode_row(&wpng_info) != 0) {
": libpng problem (longjmp) while writing row %ld\n",
++error;
break;
}
}
if (error) {
wpng_cleanup();
exit(2);
}
if (writepng_encode_finish(&wpng_info) != 0) {
wpng_cleanup();
exit(2);
}
}
/* OK, we're done (successfully): clean up all resources and quit */
wpng_cleanup();
return 0;
}
{
for (i = 0; i < len; ++i) {
if (p[i] == 10 || (p[i] > 31 && p[i] < 127) || p[i] > 160)
continue; /* character is completely OK */
result = i; /* mark location of first questionable one */
} /* or of first escape character (bad) */
return result;
}
static void wpng_cleanup(void)
{
}
}
if (wpng_info.image_data) {
}
if (wpng_info.row_pointers) {
}
}
#ifdef DOS_OS2_W32
{
do {
return buf;
}
#endif /* DOS_OS2_W32 */