diff options
Diffstat (limited to 'generator/pamgradient.c')
-rw-r--r-- | generator/pamgradient.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/generator/pamgradient.c b/generator/pamgradient.c new file mode 100644 index 00000000..7717bf4b --- /dev/null +++ b/generator/pamgradient.c @@ -0,0 +1,215 @@ +#include <string.h> + +#include "pam.h" +#include "shhopt.h" +#include "mallocvar.h" + + + +struct cmdlineInfo { + tuple colorTopLeft; + tuple colorTopRight; + tuple colorBottomLeft; + tuple colorBottomRight; + unsigned depth; + unsigned int cols; + unsigned int rows; + unsigned int maxval; +}; + +static void +parseCommandLine(int argc, char **argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Convert program invocation arguments (argc,argv) into a format the + program can use easily, struct cmdlineInfo. Validate arguments along + the way and exit program with message if invalid. + + Note that some string information we return as *cmdlineP is in the storage + argv[] points to. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int maxvalSpec; + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, &maxvalSpec, 0); + + 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 */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!maxvalSpec) + cmdlineP->maxval = 255; + else { + if (cmdlineP->maxval > PAM_OVERALL_MAXVAL) + pm_error("The value you specified for -maxval (%u) is too big. " + "Max allowed is %u", cmdlineP->maxval, + PAM_OVERALL_MAXVAL); + + if (cmdlineP->maxval < 1) + pm_error("You cannot specify 0 for -maxval"); + } + + if (argc-1 != 6) { + pm_error("Need 6 arguments: colorTopLeft, colorTopRight, " + "colorBottomLeft, colorBottomRight, width, height"); + } else { + cmdlineP->colorTopLeft = pnm_parsecolor(argv[1], cmdlineP->maxval); + cmdlineP->colorTopRight = pnm_parsecolor(argv[2], cmdlineP->maxval); + cmdlineP->colorBottomLeft = pnm_parsecolor(argv[3], cmdlineP->maxval); + cmdlineP->colorBottomRight = pnm_parsecolor(argv[4], cmdlineP->maxval); + cmdlineP->cols = atoi(argv[5]); + cmdlineP->rows = atoi(argv[6]); + if (cmdlineP->cols <= 0) + pm_error("width argument must be a positive number. You " + "specified '%s'", argv[5]); + if (cmdlineP->rows <= 0) + pm_error("height argument must be a positive number. You " + "specified '%s'", argv[6]); + } +} + + + +static void +freeCmdline(struct cmdlineInfo const cmdline) { + + pnm_freepamtuple(cmdline.colorTopLeft); + pnm_freepamtuple(cmdline.colorTopRight); + pnm_freepamtuple(cmdline.colorBottomLeft); + pnm_freepamtuple(cmdline.colorBottomRight); +} + + + +static void +interpolate(struct pam * const pamP, + tuple * const tuplerow, + tuple const first, + tuple const last) { + + unsigned int plane; + + for (plane = 0; plane < pamP->depth; ++plane) { + int const spread = last[plane] - first[plane]; + + int col; + + if (INT_MAX / pamP->width < abs(spread)) + pm_error("Arithmetic overflow. You must reduce the width of " + "the image (now %u) or the range of color values " + "(%u in plane %u) so that their " + "product is less than %d", + pamP->width, abs(spread), plane, INT_MAX); + + for (col = 0; col < pamP->width; ++col) + tuplerow[col][plane] = + first[plane] + (spread * col / (int)pamP->width); + } +} + + + +static int +isgray(struct pam * const pamP, + tuple const color) { + + return (pamP->depth == 1) + || ((pamP->depth == 3) + && (color[PAM_RED_PLANE] == color[PAM_GRN_PLANE]) + && (color[PAM_RED_PLANE] == color[PAM_BLU_PLANE])); +} + + + +static tuple * +createEdge(const struct pam * const pamP, + tuple const topColor, + tuple const bottomColor) { +/*---------------------------------------------------------------------------- + Create a left or right edge, interpolating from top to bottom. +-----------------------------------------------------------------------------*/ + struct pam interpPam; + tuple * tupleRow; + + interpPam = *pamP; /* initial value */ + interpPam.width = pamP->height; + interpPam.height = 1; + + tupleRow = pnm_allocpamrow(&interpPam); + + interpolate(&interpPam, tupleRow, topColor, bottomColor); + + return tupleRow; +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + struct pam pam; + tuple * tupleRow; + tuple * leftEdge; + tuple * rightEdge; + unsigned int row; + + pnm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + pam.size = sizeof pam; + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = stdout; + pam.plainformat = 0; + pam.width = cmdline.cols; + pam.height = cmdline.rows; + pam.maxval = cmdline.maxval; + pam.bytes_per_sample = pnm_bytespersample(pam.maxval); + pam.format = PAM_FORMAT; + if (isgray(&pam, cmdline.colorTopLeft) + && isgray(&pam, cmdline.colorTopRight) + && isgray(&pam, cmdline.colorBottomLeft) + && isgray(&pam, cmdline.colorBottomRight)) { + pam.depth = 1; + strcpy(pam.tuple_type, PAM_PGM_TUPLETYPE); + } else { + pam.depth = 3; + strcpy(pam.tuple_type, PAM_PPM_TUPLETYPE); + } + + pnm_writepaminit(&pam); + + tupleRow = pnm_allocpamrow(&pam); + + leftEdge = createEdge(&pam, + cmdline.colorTopLeft, cmdline.colorBottomLeft); + rightEdge = createEdge(&pam, + cmdline.colorTopRight, cmdline.colorBottomRight); + + /* interpolate each row between the left edge and the right edge */ + for (row = 0; row < pam.height; ++row) { + interpolate(&pam, tupleRow, leftEdge[row], rightEdge[row]); + pnm_writepamrow(&pam, tupleRow); + } + + pm_close(stdout); + pnm_freepamrow(rightEdge); + pnm_freepamrow(leftEdge); + pnm_freepamrow(tupleRow); + + freeCmdline(cmdline); + + return 0; +} |