/*============================================================================= pamtable =============================================================================== Print the raster as a table of numbers. By Bryan Henderson, San Jose CA 2017.04.15. Contributed to the public domain =============================================================================*/ #include #include "pm_c_util.h" #include "pam.h" #include "shhopt.h" #include "mallocvar.h" #include "nstring.h" enum Style {STYLE_BASIC, STYLE_TUPLE}; struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; /* Name of input file */ enum Style outputStyle; unsigned int hex; unsigned int verbose; }; static void parseCommandLine(int argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { optEntry * option_def; /* Instructions to OptParseOptions4 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; unsigned int tuple; MALLOCARRAY(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "tuple", OPT_FLAG, NULL, &tuple, 0); OPTENT3(0, "hex", OPT_FLAG, NULL, &cmdlineP->hex, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); /* For future expansion */ opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (tuple && cmdlineP->hex) pm_error("-hex is invalid with -tuple"); if (tuple) cmdlineP->outputStyle = STYLE_TUPLE; else cmdlineP->outputStyle = STYLE_BASIC; if (argc-1 > 1) pm_error("Too many arguments (%d). File name is the only argument.", argc-1); if (argc-1 < 1) cmdlineP->inputFileName = "-"; else cmdlineP->inputFileName = argv[1]; free(option_def); } typedef struct { const char * sampleFmt; /* Printf format of a sample, e.g. %3u */ const char * interSampleGutter; /* What we print between samples within a tuple */ const char * interTupleGutter; /* What we print between tuples within a row */ const char * rowStartString; /* What we print at the beginning of each row */ const char * rowEndString; /* What we print at the end of each row */ } Format; static double const log16(double const arg) { return log(arg)/log(16); } static const char * basicSampleFormat(const struct pam * const pamP, bool const wantHex) { /*---------------------------------------------------------------------------- The printf format string for a single sample in the output table. E.g "%03u". This format does not include any spacing between samples. -----------------------------------------------------------------------------*/ unsigned int cipherWidth; char formatSpecifier; const char * flag; const char * retval; if (wantHex) { formatSpecifier = 'x'; cipherWidth = ROUNDU(ceil(log16(pamP->maxval + 1))); flag = "0"; } else { formatSpecifier = 'u'; cipherWidth = ROUNDU(ceil(log10(pamP->maxval + 1))); flag = ""; } pm_asprintf(&retval, "%%%s%u%c", flag, cipherWidth, formatSpecifier); return retval; } static void makeFormat(const struct pam * const pamP, enum Style const outputStyle, bool const wantHex, Format * const formatP) { switch (outputStyle) { case STYLE_BASIC: formatP->sampleFmt = basicSampleFormat(pamP, wantHex); formatP->interSampleGutter = " "; formatP->interTupleGutter = pamP->depth > 1 ? "|" : " "; formatP->rowStartString = ""; formatP->rowEndString = "\n"; break; case STYLE_TUPLE: formatP->sampleFmt = pm_strdup("%u"); formatP->interSampleGutter = ","; formatP->interTupleGutter = ") ("; formatP->rowStartString = "("; formatP->rowEndString = ")\n"; break; } } static void unmakeFormat(Format * const formatP) { pm_strfree(formatP->sampleFmt); } static void printRow(const struct pam * const pamP, tuple * const tupleRow, Format const format, FILE * const ofP) { unsigned int col; fputs (format.rowStartString, ofP); for (col = 0; col < pamP->width; ++col) { unsigned int plane; if (col > 0) fputs(format.interTupleGutter, ofP); for (plane = 0; plane < pamP->depth; ++plane) { if (plane > 0) fputs(format.interSampleGutter, ofP); fprintf(ofP, format.sampleFmt, tupleRow[col][plane]); } } fputs (format.rowEndString, ofP); } static void printRaster(FILE * const ifP, const struct pam * const pamP, FILE * const ofP, enum Style const outputStyle, bool const wantHex) { Format format; tuple * inputRow; /* Row from input image */ unsigned int row; makeFormat(pamP, outputStyle, wantHex, &format); inputRow = pnm_allocpamrow(pamP); for (row = 0; row < pamP->height; ++row) { pnm_readpamrow(pamP, inputRow); printRow(pamP, inputRow, format, ofP); } pnm_freepamrow(inputRow); unmakeFormat(&format); } int main(int argc, const char *argv[]) { FILE * ifP; struct CmdlineInfo cmdline; struct pam inpam; /* Input PAM image */ pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); printRaster(ifP, &inpam, stdout, cmdline.outputStyle, cmdline.hex); pm_close(inpam.file); return 0; }