|
Packit |
78deda |
/* rawtopgm.c - convert raw grayscale bytes into a portable graymap
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 1989 by Jef Poskanzer.
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <math.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
#include "pgm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct cmdline_info {
|
|
Packit |
78deda |
/* All the information the user supplied in the command line,
|
|
Packit |
78deda |
in a form easy for the program to use.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * inputFileName;
|
|
Packit |
78deda |
unsigned int headerskip;
|
|
Packit |
78deda |
float rowskip;
|
|
Packit |
78deda |
int bottomfirst; /* the -bottomfirst/-bt option */
|
|
Packit |
78deda |
int autosize; /* User wants us to figure out the size */
|
|
Packit |
78deda |
unsigned int width;
|
|
Packit |
78deda |
unsigned int height;
|
|
Packit |
78deda |
int bpp;
|
|
Packit |
78deda |
/* bytes per pixel in input format. 1 or 2 */
|
|
Packit |
78deda |
int littleendian;
|
|
Packit |
78deda |
/* logical: samples in input are least significant byte first */
|
|
Packit |
78deda |
int maxval; /* -maxval option, or -1 if none */
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parse_command_line(int argc, char ** argv,
|
|
Packit |
78deda |
struct cmdline_info *cmdlineP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Note that the file spec array we return is stored in the storage that
|
|
Packit |
78deda |
was passed to us as the argv array.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
optEntry * option_def;
|
|
Packit |
78deda |
/* Instructions to OptParseOptions3 on how to parse our options.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
optStruct3 opt;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int option_def_index;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(option_def, 100);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
option_def_index = 0; /* incremented by OPTENT3 */
|
|
Packit |
78deda |
OPTENT3(0, "bottomfirst", OPT_FLAG, &cmdlineP->bottomfirst,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bt", OPT_FLAG, &cmdlineP->bottomfirst,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "topbottom", OPT_FLAG, &cmdlineP->bottomfirst,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "tb", OPT_FLAG, &cmdlineP->bottomfirst,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "headerskip", OPT_UINT, &cmdlineP->headerskip,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "rowskip", OPT_FLOAT, &cmdlineP->rowskip,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bpp", OPT_INT, &cmdlineP->bpp,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "littleendian", OPT_FLAG, &cmdlineP->littleendian,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval,
|
|
Packit |
78deda |
NULL, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Set the defaults */
|
|
Packit |
78deda |
cmdlineP->bottomfirst = FALSE;
|
|
Packit |
78deda |
cmdlineP->headerskip = 0;
|
|
Packit |
78deda |
cmdlineP->rowskip = 0.0;
|
|
Packit |
78deda |
cmdlineP->bpp = 1;
|
|
Packit |
78deda |
cmdlineP->littleendian = 0;
|
|
Packit |
78deda |
cmdlineP->maxval = -1;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
opt.opt_table = option_def;
|
|
Packit |
78deda |
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
Packit |
78deda |
opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
|
|
Packit |
78deda |
/* Uses and sets argc, argv, and some of *cmdlineP and others. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 == 0) {
|
|
Packit |
78deda |
cmdlineP->inputFileName = "-";
|
|
Packit |
78deda |
cmdlineP->autosize = TRUE;
|
|
Packit |
78deda |
} else if (argc-1 == 1) {
|
|
Packit |
78deda |
cmdlineP->inputFileName = argv[1];
|
|
Packit |
78deda |
cmdlineP->autosize = TRUE;
|
|
Packit |
78deda |
} else if (argc-1 == 2) {
|
|
Packit |
78deda |
cmdlineP->inputFileName = "-";
|
|
Packit |
78deda |
cmdlineP->autosize = FALSE;
|
|
Packit |
78deda |
cmdlineP->width = pm_parse_width(argv[1]);
|
|
Packit |
78deda |
cmdlineP->height = pm_parse_height(argv[2]);
|
|
Packit |
78deda |
} else if (argc-1 == 3) {
|
|
Packit |
78deda |
cmdlineP->inputFileName = argv[3];
|
|
Packit |
78deda |
cmdlineP->autosize = FALSE;
|
|
Packit |
78deda |
cmdlineP->width = pm_parse_width(argv[1]);
|
|
Packit |
78deda |
cmdlineP->height = pm_parse_height(argv[2]);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
pm_error("Program takes zero, one, two, or three arguments. You "
|
|
Packit |
78deda |
"specified %d", argc-1);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->bpp != 1 && cmdlineP->bpp != 2)
|
|
Packit |
78deda |
pm_error("Bytes per pixel (-bpp) must be 1 or 2. You specified %d.",
|
|
Packit |
78deda |
cmdlineP->bpp);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->maxval == 0)
|
|
Packit |
78deda |
pm_error("Maxval (-maxval) may not be zero.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->maxval > 255 && cmdlineP->bpp == 1)
|
|
Packit |
78deda |
pm_error("You have specified one byte per pixel, but a maxval "
|
|
Packit |
78deda |
"too large to fit in one byte: %d", cmdlineP->maxval);
|
|
Packit |
78deda |
if (cmdlineP->maxval > 65535)
|
|
Packit |
78deda |
pm_error("Maxval must be less than 65536. You specified %d.",
|
|
Packit |
78deda |
cmdlineP->maxval);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->rowskip && cmdlineP->autosize)
|
|
Packit |
78deda |
pm_error("If you specify -rowskip, you must also give the image "
|
|
Packit |
78deda |
"dimensions.");
|
|
Packit |
78deda |
if (cmdlineP->rowskip && cmdlineP->bottomfirst)
|
|
Packit |
78deda |
pm_error("You canot specify both -rowskip and -bottomfirst. This is "
|
|
Packit |
78deda |
"a limitation of this program.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
compute_image_size(const struct cmdline_info cmdline, const long nread,
|
|
Packit |
78deda |
int * const rows_p, int * const cols_p) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.autosize) {
|
|
Packit |
78deda |
int sqrt_trunc =
|
|
Packit |
78deda |
(int) sqrt((double) (nread-cmdline.headerskip));
|
|
Packit |
78deda |
if (sqrt_trunc*sqrt_trunc+cmdline.headerskip != nread)
|
|
Packit |
78deda |
pm_error( "You must specify the dimensions of the image unless "
|
|
Packit |
78deda |
"it is a quadratic image. This one is not quadratic: "
|
|
Packit |
78deda |
"The number of "
|
|
Packit |
78deda |
"pixels in the input is %ld, which is not a perfect "
|
|
Packit |
78deda |
"square.", nread-cmdline.headerskip);
|
|
Packit |
78deda |
*rows_p = *cols_p = sqrt_trunc;
|
|
Packit |
78deda |
pm_message( "Image size: %d cols, %d rows", *cols_p, *rows_p);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
*rows_p = cmdline.height;
|
|
Packit |
78deda |
*cols_p = cmdline.width;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
skip_header(FILE *ifp, const int headerskip) {
|
|
Packit |
78deda |
int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for ( i = 0; i < headerskip; ++i ) {
|
|
Packit |
78deda |
/* Read a byte out of the file */
|
|
Packit |
78deda |
int val;
|
|
Packit |
78deda |
val = getc( ifp );
|
|
Packit |
78deda |
if ( val == EOF )
|
|
Packit |
78deda |
pm_error("EOF / read error reading Byte %d in the header", i );
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static gray
|
|
Packit |
78deda |
read_from_file(FILE *ifp, const int bpp, const int row, const int col,
|
|
Packit |
78deda |
const int littleendian) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Return the next sample value from the input file 'ifp', assuming the
|
|
Packit |
78deda |
input stream is 'bpp' bytes per pixel (1 or 2). In the case of two
|
|
Packit |
78deda |
bytes, if 'littleendian', assume least significant byte is first.
|
|
Packit |
78deda |
Otherwise, assume MSB first.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
In error messages, say this is Column 'col', Row 'row'. Exit program if
|
|
Packit |
78deda |
error.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
gray retval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (bpp == 1) {
|
|
Packit |
78deda |
int val;
|
|
Packit |
78deda |
val = getc(ifp);
|
|
Packit |
78deda |
if (val == EOF)
|
|
Packit |
78deda |
pm_error( "EOF / read error at Row %d Column %d",
|
|
Packit |
78deda |
row, col);
|
|
Packit |
78deda |
retval = (gray) val;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
short val;
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
rc = littleendian ?
|
|
Packit |
78deda |
pm_readlittleshort(ifp, &val) : pm_readbigshort(ifp, &val;;
|
|
Packit |
78deda |
if (rc != 0)
|
|
Packit |
78deda |
pm_error( "EOF / read error at Row %d Column %d",
|
|
Packit |
78deda |
row, col);
|
|
Packit |
78deda |
retval = (gray) val;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc, char *argv[] ) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct cmdline_info cmdline;
|
|
Packit |
78deda |
FILE* ifp;
|
|
Packit |
78deda |
gray* grayrow;
|
|
Packit |
78deda |
int rows, cols;
|
|
Packit |
78deda |
gray maxval;
|
|
Packit |
78deda |
char* buf;
|
|
Packit |
78deda |
/* pixels_1 and pixels_2 are the array of pixels in the input buffer
|
|
Packit |
78deda |
(assuming we are using an input buffer). pixels_1 is the array
|
|
Packit |
78deda |
as if the pixels are one byte each. pixels_2 is the array as if
|
|
Packit |
78deda |
they are two bytes each.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
unsigned char *pixels_1;
|
|
Packit |
78deda |
unsigned short *pixels_2;
|
|
Packit |
78deda |
long nread;
|
|
Packit |
78deda |
int row;
|
|
Packit |
78deda |
float toskip;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pgm_init( &argc, argv );
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parse_command_line(argc, argv, &cmdline);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifp = pm_openr(cmdline.inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.autosize || cmdline.bottomfirst) {
|
|
Packit |
78deda |
buf = pm_read_unknown_size( ifp, &nread );
|
|
Packit |
78deda |
pixels_1 = (unsigned char *) buf;
|
|
Packit |
78deda |
pixels_2 = (unsigned short *) buf;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
buf = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
compute_image_size(cmdline, nread, &rows, &cols;;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!buf)
|
|
Packit |
78deda |
skip_header(ifp, cmdline.headerskip);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
toskip = 0.00001;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.maxval == -1)
|
|
Packit |
78deda |
maxval = (cmdline.bpp == 1 ? (gray) 255 : (gray) 65535);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
maxval = (gray) cmdline.maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pgm_writepgminit( stdout, cols, rows, maxval, 0 );
|
|
Packit |
78deda |
grayrow = pgm_allocrow( cols );
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for ( row = 0; row < rows; ++row) {
|
|
Packit |
78deda |
int col;
|
|
Packit |
78deda |
unsigned int rowpos; /* index of this row in pixel array */
|
|
Packit |
78deda |
if (cmdline.bottomfirst)
|
|
Packit |
78deda |
rowpos = (rows-row-1) * cols;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
rowpos = row * cols;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for ( col = 0; col < cols; ++col )
|
|
Packit |
78deda |
if (buf) {
|
|
Packit |
78deda |
if (cmdline.bpp == 1)
|
|
Packit |
78deda |
grayrow[col] = pixels_1[rowpos+col];
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
grayrow[col] = pixels_2[rowpos+col];
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
grayrow[col] = read_from_file(ifp, cmdline.bpp,
|
|
Packit |
78deda |
row, col,
|
|
Packit |
78deda |
cmdline.littleendian);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
for ( toskip += cmdline.rowskip; toskip >= 1.0; toskip -= 1.0 ) {
|
|
Packit |
78deda |
/* Note that if we're using a buffer, cmdline.rowskip is zero */
|
|
Packit |
78deda |
int val;
|
|
Packit |
78deda |
val = getc( ifp );
|
|
Packit |
78deda |
if ( val == EOF )
|
|
Packit |
78deda |
pm_error( "EOF / read error skipping bytes at the end "
|
|
Packit |
78deda |
"of Row %d.", row);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pgm_writepgmrow( stdout, grayrow, cols, maxval, 0 );
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (buf)
|
|
Packit |
78deda |
free(buf);
|
|
Packit |
78deda |
pm_close( ifp );
|
|
Packit |
78deda |
pm_close( stdout );
|
|
Packit |
78deda |
|
|
Packit |
78deda |
exit( 0 );
|
|
Packit |
78deda |
}
|