diff options
Diffstat (limited to 'analyzer')
-rw-r--r-- | analyzer/pamgetcolor.c | 409 | ||||
-rw-r--r-- | analyzer/pamsumm.c | 26 | ||||
-rw-r--r-- | analyzer/ppmhist.c | 2 |
3 files changed, 252 insertions, 185 deletions
diff --git a/analyzer/pamgetcolor.c b/analyzer/pamgetcolor.c index 993dd79d..cd9d2028 100644 --- a/analyzer/pamgetcolor.c +++ b/analyzer/pamgetcolor.c @@ -3,98 +3,115 @@ #include <pm_gamma.h> #include <pam.h> +#include "pm_c_util.h" #include "shhopt.h" #include "mallocvar.h" typedef unsigned int uint; -/* specification of a cirtular "region" over which to measre the avg. color: */ typedef struct { +/*---------------------------------------------------------------------------- + Specification of a circular "region" over which to measure the average color +-----------------------------------------------------------------------------*/ uint x; /* coordinates of the center */ uint y; /* of the region; */ - char const * label; /* optional label supplied on the command line */ + const char * label; /* optional label supplied on the command line */ } RegSpec; -/* represents a single color measurement over a "region": */ typedef struct { +/*---------------------------------------------------------------------------- + Represents a single color measurement over a "region" +-----------------------------------------------------------------------------*/ uint area; /* area in pixels over which to average the color */ /* cumulative normalised intensity-proportiunal value of the region: */ double color[3]; } RegData; -/*command-line parameters: */ typedef struct { +/*---------------------------------------------------------------------------- + All the information the user supplied in the command line, in a form easy + for the program to use. +-----------------------------------------------------------------------------*/ uint linear; uint radius; uint regN; /* number of regions */ uint maxLbLen; /* maximum label length */ RegSpec * regSpecs; /* list of points to sample, dymamically allocated*/ - char const * formatStr; /* output color format as string */ + const char * formatStr; /* output color format as string */ uint formatId; /* the Id of the selected color format */ uint formatArg; /* the argument to the color formatting function */ - char const * infile; -} CmdlineInfo; + const char * infile; +} CmdLineInfo; /* Generic pointer to a color-formatting function. Returns the textual representation of the color <tuple> in terms of the image pointed-to by <pamP>. <param> is a generic integer parameter that depends on the specific funcion and may denote precison or maxval. */ -typedef char const * +typedef const char * (*FormatColor)(struct pam * const pamP, tuple const color, uint const param); -/* The color format specificaiton: */ typedef struct ColorFormat { - /* format id (compared against the -format command-line argument): */ +/*---------------------------------------------------------------------------- + The color format specification +-----------------------------------------------------------------------------*/ char const * id; - /* function that returns converts a color into this format: */ + /* format id (compared against the -format command-line argument) */ FormatColor const formatColor; - /* meaning of the <param> argument of <formatColor>(): */ + /* function that returns converts a color into this format */ char const * argName; - uint const defParam; /* default value of that argument */ - uint const maxParam; /* maximum value of that argument */ + /* meaning of the <param> argument of <formatColor>() */ + uint const defParam; + /* default value of that argument */ + uint const maxParam; + /* maximum value of that argument */ } ColorFormat; -static char const * +static const char * fcInt(struct pam * const pamP, tuple const color, uint const param) { -/* format <color> as an integer tuple with maxval <param> */ +/*---------------------------------------------------------------------------- + Format 'color' as an integer tuple with maxval 'param' +-----------------------------------------------------------------------------*/ return pnm_colorspec_rgb_integer(pamP, color, param); } -static char const * +static const char * fcNorm(struct pam * const pamP, tuple const color, uint const param) { -/* format <color> as normalised tuple with precision <param> */ +/*---------------------------------------------------------------------------- + Format 'color' as normalized tuple with precision 'param' +-----------------------------------------------------------------------------*/ return pnm_colorspec_rgb_norm(pamP, color, param); } -static char const * +static const char * fcX11(struct pam * const pamP, tuple const color, uint const param) { -/* format <color> as hexadecimal tuple with <param> digits*/ +/*---------------------------------------------------------------------------- + Format 'color' as hexadecimal tuple with 'param' digits +-----------------------------------------------------------------------------*/ return pnm_colorspec_rgb_x11(pamP, color, param); } -#define FormatsN 3 +static int const defaultFormat = 0; -static int const DefaultFormat = 0; /* Table with the full information about color formats */ -ColorFormat formats[ FormatsN ] = { +ColorFormat const formats[ 3 ] = { /* Id Function Argument name Default Max */ { "int", &fcInt, "maxval", 255, 65535 }, { "norm", &fcNorm, "digit count", 3, 6 }, @@ -112,12 +129,14 @@ sqri(int const v) { static RegSpec -parseRegSpec(char const * const s) { +parsedRegSpec(const char * const s) { /*---------------------------------------------------------------------------- - Parse region specification <s> from the command line and return its - structured representation. A specification is of the format <x,y[:label]. + The region specification represented by command line argument 's'. + + 's' is of the format x,y[:label]. -----------------------------------------------------------------------------*/ - char* end, *start; + char * end; + char *start; RegSpec res; start = (char *)s; @@ -146,8 +165,7 @@ parseRegSpec(char const * const s) { break; /* empty label */ return res; } - } - while (1 == 0); + } while (false); pm_error("Wrong region specification: %s", s); @@ -157,126 +175,157 @@ parseRegSpec(char const * const s) { static void -parseColorFmt(CmdlineInfo * const cmdLineP) { +parseColorFmt(const char * const formatStr, + uint * const formatIdP, + uint * const formatArgP) { /*---------------------------------------------------------------------------- - Parse the color format specificaction from the command line stored in the - <formatStr> member of <cmdLineP> and save it into members <formatId> and - <formatArg>. A format specification is <format>[:<arg>]. + Parse the color format specification string 'formatStr' as + *formatIdP and *formatArgP. + + A format specification string is of format format[:arg]. -----------------------------------------------------------------------------*/ - const int FmtNotFound = -1; - const char * ErrSpec = "Wrong color format specification: "; - const char * formatStr; - char * colonLoc; /* location of the colon in the specification */ + int const FmtNotFound = -1; + const char * const errSpec = "Wrong color format specification: "; + + const char * colonLoc; /* location of the colon in the specification */ uint n, f; - ColorFormat * formatP; + const ColorFormat * formatP; + uint formatId; - formatStr = cmdLineP->formatStr; colonLoc = strchr(formatStr, ':'); if (colonLoc != NULL) n = colonLoc - formatStr; else n = strlen(formatStr); - cmdLineP->formatId = FmtNotFound; - - for (f = 0; f < FormatsN; f++) { - if (strncmp(formatStr, formats[f].id, n) == 0) { - cmdLineP->formatId = f; - break; - } + for (f = 0, formatId = FmtNotFound; + f < ARRAY_SIZE(formats) && formatId == FmtNotFound; ++f) { + if (strncmp(formatStr, formats[f].id, n) == 0) + formatId = f; } - if (cmdLineP->formatId == FmtNotFound) { + if (formatId == FmtNotFound) pm_error("Color format not recognised."); - } - formatP = &formats[cmdLineP->formatId]; - if (colonLoc != NULL) { + + *formatIdP = formatId; + + formatP = &formats[formatId]; + + if (colonLoc) { long int arg; - char *argStart, *argEnd; + const char * argStart; + char * argEnd; argStart = colonLoc + 1; + if (*argStart == '\0') pm_error("%sthe colon should be followed by %s.", - ErrSpec, formatP->argName); + errSpec, formatP->argName); arg = strtol(argStart, &argEnd, 10); + if (*argEnd != '\0') pm_error("%sfailed to parse the %s: %s.", - ErrSpec, formatP->argName, argStart); + errSpec, formatP->argName, argStart); if (arg < 1) pm_error("%s%s must be greater than zero.", - ErrSpec, formatP->argName); + errSpec, formatP->argName); if (arg > formatP->maxParam) pm_error("%s%s cannot exceed %i.", - ErrSpec, formatP->argName, formatP->maxParam); - cmdLineP->formatArg = arg; - } - else - cmdLineP->formatArg = formatP->defParam; + errSpec, formatP->argName, formatP->maxParam); + + *formatArgP = arg; + } else + *formatArgP = formatP->defParam; } -static CmdlineInfo -parseCommandLine(int argc, char const ** argv) { -/*---------------------------------------------------------------------------- - Parse the command-line arguments and store them in a form convenient for the - program. ------------------------------------------------------------------------------*/ - int r; - uint formatSet; - CmdlineInfo cmdLine; - optStruct3 opt; - uint option_def_index = 0; +static CmdLineInfo +parsedCommandLine(int argc, + const char ** const argv) { optEntry * option_def; - MALLOCARRAY_NOFAIL(option_def, 100); + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; - cmdLine.radius = 0; + CmdLineInfo cmdLine; - opt.opt_table = option_def; - opt.short_allowed = 0; - opt.allowNegNum = 0; + uint infileSpec, radiusSpec, formatSpec, linearSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); - OPTENT3(0, "infile", OPT_STRING, &cmdLine.infile, NULL, 0); - OPTENT3(0, "radius", OPT_INT, &cmdLine.radius, NULL, 0); - OPTENT3(0, "format", OPT_STRING, &cmdLine.formatStr, &formatSet, 0); - OPTENT3(0, "linear", OPT_FLAG, &cmdLine.linear, NULL, 0); - OPTENT3(0, 0, OPT_END, NULL, NULL, 0); + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "infile", OPT_STRING, &cmdLine.infile, &infileSpec, 0); + OPTENT3(0, "radius", OPT_INT, &cmdLine.radius, &radiusSpec, 0); + OPTENT3(0, "format", OPT_STRING, &cmdLine.formatStr, &formatSpec, 0); + OPTENT3(0, "linear", OPT_FLAG, &cmdLine.linear, &linearSpec, 0); + OPTENT3(0, 0, OPT_END, NULL, NULL, 0); - cmdLine.radius = 0; - cmdLine.linear = 0; - cmdLine.infile = "-"; + 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_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); - if (formatSet) { - parseColorFmt(&cmdLine); + if (!infileSpec) + cmdLine.infile = "-"; + + if (!radiusSpec) + cmdLine.radius = 0; + + if (formatSpec) { + parseColorFmt(cmdLine.formatStr, + &cmdLine.formatId, &cmdLine.formatArg); } else { - cmdLine.formatId = DefaultFormat; - cmdLine.formatArg = formats[DefaultFormat].defParam; + cmdLine.formatId = defaultFormat; + cmdLine.formatArg = formats[defaultFormat].defParam; } - cmdLine.regN = argc - 1; - MALLOCARRAY_NOFAIL(cmdLine.regSpecs, cmdLine.regN); + if (!linearSpec) + cmdLine.radius = 0; - cmdLine.maxLbLen = 0; - if (argc < 2) + if (argc-1 < 1) pm_error("No regions specified."); - for (r = 0; r < argc - 1; r++) { - size_t lbLen; - cmdLine.regSpecs[r] = parseRegSpec(argv[r+1]); - lbLen = strlen(cmdLine.regSpecs[r].label); - if (lbLen > cmdLine.maxLbLen) - cmdLine.maxLbLen = lbLen; + cmdLine.regN = argc - 1; + + MALLOCARRAY(cmdLine.regSpecs, cmdLine.regN); + + if (!cmdLine.regSpecs) + pm_error("Could not get memory for %u region specifications", + cmdLine.regN); + + { + uint r; + uint maxLbLen; + + for (r = 0, maxLbLen = 0; r < argc - 1; ++r) { + size_t lbLen; + cmdLine.regSpecs[r] = parsedRegSpec(argv[r+1]); + lbLen = strlen(cmdLine.regSpecs[r].label); + maxLbLen = MAX(maxLbLen, lbLen); + } + cmdLine.maxLbLen = maxLbLen; } free(option_def); + return cmdLine; } +static void +freeCommandLine(CmdLineInfo const cmdLine) { + + free(cmdLine.regSpecs); +} + + + static RegData * allocRegSamples(uint n) { /*---------------------------------------------------------------------------- Allocate an array of <n> initialised region samles. The array should be @@ -299,7 +348,7 @@ static RegData * allocRegSamples(uint n) { static uint getYmax(struct pam * const pamP, - CmdlineInfo const cmdLine) { + CmdLineInfo const cmdLine) { /*---------------------------------------------------------------------------- Find the maximum row in the image that contains a pixel from a region. -----------------------------------------------------------------------------*/ @@ -330,16 +379,17 @@ readChord(RegData * const dataP, uint const x0, uint const x1) { /*---------------------------------------------------------------------------- - Update region sample <dataP> with the data from horisontal chord lying in - row <row> and going from <x0> to <x1>. <linear> denotes whether <pamP> is - true PPM or the linear variation. + Update region sample *dataP with the data from horizontal chord lying in row + 'row' and going from 'x0' to 'x1'. 'linear' means tuples in 'row' are the + intensity-linear values as opposed to normal libnetpbm gamma-adjusted + values. -----------------------------------------------------------------------------*/ uint x; - for (x = x0; x <= x1; x++) { + for (x = x0; x <= x1; ++x) { uint l; - for (l = 0; l < 3; l++) { + for (l = 0; l < 3; ++l) { double val; val = (double)row[x][l] / pamP->maxval; @@ -348,7 +398,7 @@ readChord(RegData * const dataP, val = pm_ungamma709(val); dataP->color[l] += val; } - dataP->area++; + ++dataP->area; } } @@ -358,86 +408,95 @@ static void processRow(tuple * const row, uint const y, struct pam * const pamP, - CmdlineInfo const * cmdLineP, + CmdLineInfo const * cmdLineP, RegData * const regSamples) { /*---------------------------------------------------------------------------- - Reads a row from image <pamP> into allocated tuple array <row>, and updates - region samples <regSamples[]> from it. <y> is the position of the row. + Read a row from image described by *pamP into 'row', and update region + samples regSamples[] from it. 'y' is the position of the row. -----------------------------------------------------------------------------*/ uint r; pnm_readpamrow(pamP, row); - for (r = 0; r < cmdLineP->regN; r++) { - RegSpec spec; - RegData * dataP; - uint xd, xd2; - int yd; - int x0, x1; - - spec = cmdLineP->regSpecs[r]; - dataP = ®Samples[r]; - yd = (int)spec.y - (int)y; - if (abs(yd) > cmdLineP->radius) - continue; /* to avoid the slow root operation when possible */ - xd2 = sqri(cmdLineP->radius) - sqri(yd); - xd = (int)(sqrt((double)xd2) + 0.5); - x0 = spec.x - xd; - x1 = spec.x + xd; - - /* clip horisontal chord to image boundaries: */ - if (x0 < 0) - x0 = 0; - if (x1 >= pamP->width) - x1 = pamP->width - 1; - - readChord(dataP, cmdLineP->linear, pamP, row, x0, x1); + + for (r = 0; r < cmdLineP->regN; ++r) { + RegSpec const spec = cmdLineP->regSpecs[r]; + RegData * const dataP = ®Samples[r]; + int const yd = (int)spec.y - (int)y; + + if (abs(yd) > cmdLineP->radius) { + /* Row is entirely above or below the region; Avoid the slow root + operation + */ + } else { + uint const xd2 = sqri(cmdLineP->radius) - sqri(yd); + uint const xd = ROUNDU(sqrt((double)xd2)); + + int x0, x1; + + x0 = spec.x - xd; /* initial value */ + x1 = spec.x + xd; /* initial value */ + + /* clip horizontal chord to image boundaries: */ + if (x0 < 0) + x0 = 0; + if (x1 >= pamP->width) + x1 = pamP->width - 1; + + readChord(dataP, cmdLineP->linear, pamP, row, x0, x1); + } } } static RegData * -getColors(struct pam * const pamP, - CmdlineInfo const cmdLine) { +colorsFmImage(struct pam * const pamP, + CmdLineInfo const cmdLine) { /*---------------------------------------------------------------------------- - Scans image <pamP> and collects color data for the regions. + Color data for the regions requested by 'cmdLine' in the image described by + *pamP. -----------------------------------------------------------------------------*/ uint y, ymax; - RegData * samples; + RegData * samplesP; tuple * row; - FILE * inFile; + FILE * ifP; + + ifP = pm_openr(cmdLine.infile); - inFile = pm_openr(cmdLine.infile); - pnm_readpaminit(inFile, pamP, PAM_STRUCT_SIZE(tuple_type)); + pnm_readpaminit(ifP, pamP, PAM_STRUCT_SIZE(tuple_type)); - ymax = getYmax( pamP, cmdLine ); + ymax = getYmax(pamP, cmdLine); - samples = allocRegSamples( cmdLine.regN ); - row = pnm_allocpamrow(pamP); - y = 0; - for (y = 0; y <= ymax; y++) - processRow( row, y, pamP, &cmdLine, samples ); + samplesP = allocRegSamples(cmdLine.regN); + row = pnm_allocpamrow(pamP); + + for (y = 0; y <= ymax; ++y) + processRow(row, y, pamP, &cmdLine, samplesP); pnm_freepamrow(row); - pm_close(inFile); - return samples; + pm_close(ifP); + + return samplesP; } -static char const * -formatColor(RegData const data, - CmdlineInfo const cmdLine, - struct pam * const pamP, - tuple const tup) { +static const char * +outputColorSpec(RegData const data, + CmdLineInfo const cmdLine, + struct pam * const pamP, + tuple const tup) { /*---------------------------------------------------------------------------- - Format the color of region sample <data> according to the format specified - in <cmdLine>. The image <pamP> and tuple <tup> are required by the Netpbm - formatting functions. + Color of region sample 'data' formatted for output as requested by + 'cmdLine'. + + *pamP tells how to interpret 'data'. + + 'tup' is working space for internal use. -----------------------------------------------------------------------------*/ uint l; - for (l = 0; l < 3; l++) + for (l = 0; l < 3; ++l) tup[l] = pm_gamma709(data.color[l]/data.area) * pamP->maxval; return formats[cmdLine.formatId]. @@ -447,29 +506,37 @@ formatColor(RegData const data, static void -printColors(struct pam * const pamP, - CmdlineInfo const cmdLine, - FILE * const outChan, - RegData const regSamples[]) { +printColors(struct pam * const pamP, + CmdLineInfo const cmdLine, + FILE * const ofP, + const RegData * const regSamples) { /*---------------------------------------------------------------------------- - Prints the colors or <regSamples> to channel <outChan> in the format - specified in <cmdLine>. <pamP> is required by the formatting function. + Print the colors regSamples[] to *ofP in the format + requested by 'cmdLine'. + + *pamP tells how to interpret regSamples[] -----------------------------------------------------------------------------*/ char fmt[20]; uint r; tuple tup; tup = pnm_allocpamtuple(pamP); - sprintf(fmt, "%%%is: %%s\n", cmdLine.maxLbLen); - for (r = 0; r < cmdLine.regN; r++) { + + pm_snprintf(fmt, sizeof(fmt), "%%%is: %%s\n", cmdLine.maxLbLen); + + for (r = 0; r < cmdLine.regN; ++r) { RegSpec spec; RegData data; - char const * color; + const char * color; spec = cmdLine.regSpecs[r]; + data = regSamples[r]; - color = formatColor( data, cmdLine, pamP, tup ); - fprintf(outChan, fmt, spec.label, color); + + color = outputColorSpec(data, cmdLine, pamP, tup); + + fprintf(ofP, fmt, spec.label, color); + pm_strfree(color); } pnm_freepamtuple(tup); @@ -478,21 +545,21 @@ printColors(struct pam * const pamP, int -main(int argc, char const *argv[]) { +main(int argc, const char *argv[]) { RegData * regSamples; - CmdlineInfo cmdLine; + CmdLineInfo cmdLine; struct pam pam; pm_proginit(&argc, argv); - cmdLine = parseCommandLine(argc, argv); + cmdLine = parsedCommandLine(argc, argv); - regSamples = getColors(&pam, cmdLine); + regSamples = colorsFmImage(&pam, cmdLine); printColors(&pam, cmdLine, stdout, regSamples); - free(cmdLine.regSpecs); /* Asymmetrical: maybe write freeCommandLine() ? */ + freeCommandLine(cmdLine); free(regSamples); return 0; diff --git a/analyzer/pamsumm.c b/analyzer/pamsumm.c index 7d2c000a..9b74e789 100644 --- a/analyzer/pamsumm.c +++ b/analyzer/pamsumm.c @@ -69,18 +69,18 @@ parseCommandLine(int argc, const char ** const argv, cmdlineP->function = FN_MIN; } else if (maxSpec) { cmdlineP->function = FN_MAX; - } else + } else pm_error("You must specify one of -sum, -min, -max, or -mean"); - + 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 + else cmdlineP->inputFileName = argv[1]; - + free(option_def); } @@ -122,11 +122,11 @@ aggregate(struct pam * const inpamP, unsigned int plane; for (plane = 0; plane < inpamP->depth; ++plane) { switch(function) { - case FN_ADD: - case FN_MEAN: + case FN_ADD: + case FN_MEAN: accumulatorP->u.sum += tupleRow[col][plane]; break; - case FN_MIN: + case FN_MIN: if (tupleRow[col][plane] < accumulatorP->u.min) accumulatorP->u.min = tupleRow[col][plane]; break; @@ -134,7 +134,7 @@ aggregate(struct pam * const inpamP, if (tupleRow[col][plane] > accumulatorP->u.min) accumulatorP->u.min = tupleRow[col][plane]; break; - } + } } } } @@ -150,7 +150,7 @@ printSummary(struct Accum const accumulator, bool const brief) { switch (function) { - case FN_ADD: { + case FN_ADD: { const char * const intro = brief ? "" : "the sum of all samples is "; if (mustNormalize) @@ -169,7 +169,7 @@ printSummary(struct Accum const accumulator, } break; case FN_MIN: { - const char * const intro = + const char * const intro = brief ? "" : "the minimum of all samples is "; if (mustNormalize) @@ -179,7 +179,7 @@ printSummary(struct Accum const accumulator, } break; case FN_MAX: { - const char * const intro = + const char * const intro = brief ? "" : "the maximum of all samples is "; if (mustNormalize) @@ -221,11 +221,11 @@ main(int argc, const char *argv[]) { aggregate(&inpam, inputRow, cmdline.function, &accumulator); } printSummary(accumulator, (unsigned)inpam.maxval, - inpam.height * inpam.width * inpam.depth, + inpam.height * inpam.width * inpam.depth, cmdline.function, cmdline.normalize, cmdline.brief); pnm_freepamrow(inputRow); pm_close(inpam.file); - + return 0; } diff --git a/analyzer/ppmhist.c b/analyzer/ppmhist.c index 299ab6ca..c4ab3581 100644 --- a/analyzer/ppmhist.c +++ b/analyzer/ppmhist.c @@ -172,7 +172,7 @@ universalMaxval(pixval const maxval, int const format) { /*---------------------------------------------------------------------------- A maxval that makes it impossible for a pixel to be invalid in an image that - states it maxval as 'maxval' and has format 'format'. + states its maxval as 'maxval' and has format 'format'. E.g. in a one-byte-per-sample image, it's not possible to read a sample value greater than 255, so a maxval of 255 makes it impossible for a sample |