diff options
Diffstat (limited to 'generator')
-rw-r--r-- | generator/Makefile | 2 | ||||
-rw-r--r-- | generator/pamcrater.c | 61 | ||||
-rw-r--r-- | generator/pamgauss.c | 39 | ||||
-rw-r--r-- | generator/pamgradient.c | 11 | ||||
-rw-r--r-- | generator/pamseq.c | 346 | ||||
-rw-r--r-- | generator/pamshadedrelief.c | 12 | ||||
-rw-r--r-- | generator/pamstereogram.c | 134 | ||||
-rw-r--r-- | generator/pamstereogram.test | 70 | ||||
-rw-r--r-- | generator/pamtris/framebuffer.c | 2 | ||||
-rw-r--r-- | generator/pamtris/pamtris.c | 2 | ||||
-rw-r--r-- | generator/pamtris/triangle.c | 4 | ||||
-rw-r--r-- | generator/pamtris/utils.c | 4 | ||||
-rw-r--r-- | generator/pbmnoise.c | 485 | ||||
-rw-r--r-- | generator/pbmtext.c | 30 | ||||
-rw-r--r-- | generator/pbmtextps.c | 448 | ||||
-rw-r--r-- | generator/pbmupc.c | 481 | ||||
-rwxr-xr-x | generator/pgmcrater | 12 | ||||
-rw-r--r-- | generator/pgmkernel.c | 37 | ||||
-rw-r--r-- | generator/pgmmake.c | 4 | ||||
-rw-r--r-- | generator/pgmnoise.c | 118 | ||||
-rw-r--r-- | generator/ppmcie.c | 21 | ||||
-rw-r--r-- | generator/ppmcolors.c | 10 | ||||
-rw-r--r-- | generator/ppmforge.c | 258 | ||||
-rw-r--r-- | generator/ppmmake.c | 4 | ||||
-rw-r--r-- | generator/ppmpat.c | 654 | ||||
-rwxr-xr-x | generator/ppmrainbow | 37 | ||||
-rw-r--r-- | generator/ppmrough.c | 526 |
27 files changed, 2596 insertions, 1216 deletions
diff --git a/generator/Makefile b/generator/Makefile index d54a6cc5..761181bd 100644 --- a/generator/Makefile +++ b/generator/Makefile @@ -18,7 +18,7 @@ SUBDIRS = pamtris PORTBINARIES = pamcrater pamgauss pamgradient \ pamseq pamshadedrelief pamstereogram \ - pbmpage pbmmake pbmtext pbmupc \ + pbmpage pbmmake pbmnoise pbmtext pbmupc \ pgmkernel pgmmake pgmnoise pgmramp \ ppmcie ppmcolors ppmforge ppmmake ppmpat ppmrough ppmwheel \ diff --git a/generator/pamcrater.c b/generator/pamcrater.c index 43c27dbc..8f0e422d 100644 --- a/generator/pamcrater.c +++ b/generator/pamcrater.c @@ -48,6 +48,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" #include "nstring.h" #include "pam.h" @@ -162,18 +163,18 @@ parseCommandLine(int argc, const char ** const argv, -static double const arand = 32767.0; /* Random number parameters */ static double const CdepthPower = 1.5; /* Crater depth power factor */ static double const DepthBias2 = 0.5; /* Square of depth bias */ static double const -cast(double const high) { +cast(double const high, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- A random number in the range [0, 'high']. -----------------------------------------------------------------------------*/ - return high * ((rand() & 0x7FFF) / arand); + return high * ((double) pm_rand(randStP) / randStP->max); } @@ -220,7 +221,6 @@ terrainModP(struct pam * const pamP, - static sample terrainMod(struct pam * const pamP, tuple ** const terrain, @@ -252,11 +252,12 @@ setElev(struct pam * const pamP, static void -smallCrater(struct pam * const pamP, - tuple ** const terrain, - int const cx, - int const cy, - double const radius) { +smallCrater(struct pam * const pamP, + tuple ** const terrain, + int const cx, + int const cy, + double const radius, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Generate a crater with a special method for tiny craters. @@ -283,10 +284,10 @@ smallCrater(struct pam * const pamP, /* The mean elevation of the Moore neighborhood (9 pixels centered on the crater location). */ - + /* Perturb the mean elevation by a small random factor. */ - int const x = radius >= 1 ? ((rand() >> 8) & 0x3) - 1 : 0; + int const x = radius >= 1 ? ((pm_rand(randStP) >> 8) & 0x3) - 1 : 0; assert(axelev > 0); @@ -374,7 +375,7 @@ normalCrater(struct pam * const pamP, av = (axelev + cz) * (1 - roll) + (terrainMod(pamP, terrain, x, y) + cz) * roll; av = MAX(1000, MIN(64000, av)); - + setElev(pamP, terrain, x, y, av); } } @@ -388,19 +389,20 @@ normalCrater(struct pam * const pamP, static void -plopCrater(struct pam * const pamP, - tuple ** const terrain, - int const cx, - int const cy, - double const radius, - bool const verbose) { +plopCrater(struct pam * const pamP, + tuple ** const terrain, + int const cx, + int const cy, + double const radius, + bool const verbose, + struct pm_randSt * const randStP) { if (verbose && pm_have_float_format()) pm_message("Plopping crater at (%4d, %4d) with radius %g", cx, cy, radius); if (radius < 3) - smallCrater (pamP, terrain, cx, cy, radius); + smallCrater (pamP, terrain, cx, cy, radius, randStP); else normalCrater(pamP, terrain, cx, cy, radius); } @@ -448,6 +450,7 @@ genCraters(struct CmdlineInfo const cmdline) { -----------------------------------------------------------------------------*/ tuple ** terrain; /* elevation array */ struct pam pam; + struct pm_randSt randSt; /* Allocate the elevation array and initialize it to mean surface elevation. @@ -455,18 +458,22 @@ genCraters(struct CmdlineInfo const cmdline) { initCanvas(cmdline.width, cmdline.height, &pam, &terrain); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + if (cmdline.test) plopCrater(&pam, terrain, pam.width/2 + cmdline.offset, pam.height/2 + cmdline.offset, - (double) cmdline.radius, cmdline.verbose); + (double) cmdline.radius, cmdline.verbose, + &randSt); else { unsigned int const ncraters = cmdline.number; /* num of craters */ unsigned int l; for (l = 0; l < ncraters; ++l) { - int const cx = cast((double) pam.width - 1); - int const cy = cast((double) pam.height - 1); + int const cx = cast((double) pam.width - 1, &randSt); + int const cy = cast((double) pam.height - 1, &randSt); /* Thanks, Rudy, for this equation that maps the uniformly distributed numbers from cast() into an area-law distribution @@ -475,9 +482,11 @@ genCraters(struct CmdlineInfo const cmdline) { Produces values within the interval: 0.56419 <= radius <= 56.419 */ - double const radius = sqrt(1 / (M_PI * (1 - cast(0.9999)))); + double const radius = + sqrt(1 / (M_PI * (1 - cast(0.9999, &randSt)))); - plopCrater(&pam, terrain, cx, cy, radius, cmdline.verbose); + plopCrater(&pam, terrain, cx, cy, radius, + cmdline.verbose, &randSt); if (((l + 1) % 100000) == 0) pm_message("%u craters generated of %u (%u%% done)", @@ -485,6 +494,8 @@ genCraters(struct CmdlineInfo const cmdline) { } } + pm_randterm(&randSt); + pnm_writepam(&pam, terrain); pnm_freepamarray(terrain, &pam); @@ -503,8 +514,6 @@ main(int argc, const char ** argv) { parseCommandLine(argc, argv, &cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - genCraters(cmdline); return 0; diff --git a/generator/pamgauss.c b/generator/pamgauss.c index 9656708b..5553e757 100644 --- a/generator/pamgauss.c +++ b/generator/pamgauss.c @@ -31,11 +31,11 @@ static void parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- - Convert program invocation arguments (argc,argv) into a format the + 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 + Note that some string information we return as *cmdlineP is in the storage argv[] points to. -----------------------------------------------------------------------------*/ optEntry * option_def; @@ -49,11 +49,11 @@ parseCommandLine(int argc, const char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "tupletype", OPT_STRING, &cmdlineP->tupletype, + OPTENT3(0, "tupletype", OPT_STRING, &cmdlineP->tupletype, &tupletypeSpec, 0); - OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, &maxvalSpec, 0); - OPTENT3(0, "sigma", OPT_FLOAT, &cmdlineP->sigma, + OPTENT3(0, "sigma", OPT_FLOAT, &cmdlineP->sigma, &sigmaSpec, 0); OPTENT3(0, "maximize", OPT_FLAG, NULL, &cmdlineP->maximize, 0); @@ -75,12 +75,12 @@ parseCommandLine(int argc, const char ** argv, pm_error("The tuple type you specified is too long. " "Maximum %u characters.", (unsigned)sizeof(pam.tuple_type)-1); - } + } if (!sigmaSpec) pm_error("You must specify the -sigma option."); else if (cmdlineP->sigma <= 0.0) - pm_error("-sigma must be positive. You specified %f", + pm_error("-sigma must be positive. You specified %f", cmdlineP->sigma); if (!maxvalSpec) @@ -91,7 +91,7 @@ parseCommandLine(int argc, const char ** argv, "Maximum is %u", cmdlineP->maxval, PNM_OVERALLMAXVAL); if (cmdlineP->maxval < 1) pm_error("-maxval must be at least 1"); - } + } if (oversampleSpec) { if (cmdlineP->oversample < 1) @@ -106,8 +106,8 @@ parseCommandLine(int argc, const char ** argv, pm_error("Only two arguments allowed: width and height. " "You specified %d", argc-1); else { - cmdlineP->width = atoi(argv[1]); - cmdlineP->height = atoi(argv[2]); + cmdlineP->width = pm_parse_width(argv[1]); + cmdlineP->height = pm_parse_height(argv[2]); if (cmdlineP->width <= 0) pm_error("width argument must be a positive number. You " "specified '%s'", argv[1]); @@ -164,7 +164,7 @@ pixelValue(unsigned int const width, The gaussian function has standard deviation 'sigma' and amplitude 1. -----------------------------------------------------------------------------*/ double const offset = 1.0 / (subpixDivision * 2); - double const y0 = (double)row + offset; + double const y0 = (double)row + offset; double const x0 = (double)col + offset; double const subpixSize = 1.0 / subpixDivision; @@ -236,7 +236,7 @@ maximumKernelValue(double ** const kernel, we know the maximum value is at the center. */ return kernel[height/2][width/2]; -} +} @@ -250,13 +250,13 @@ totalKernelValue(double ** const kernel, for (row = 0, total = 0.0; row < height; ++row) { unsigned int col; - + for (col = 0; col < width; ++col) total += kernel[row][col]; } return total; -} +} @@ -311,7 +311,7 @@ writePam(double ** const kernel, unsigned int col; for (col = 0; col < pam.width; ++col) { tuplerown[col][0] = kernel[row][col] / normalizer; - + assert(tuplerown[col][0] <= 1.0); } pnm_writepamrown(&pam, tuplerown); @@ -319,7 +319,7 @@ writePam(double ** const kernel, pnm_freepamrown(tuplerown); } - + int @@ -327,7 +327,7 @@ main(int argc, const char **argv) { struct CmdlineInfo cmdline; double ** kernel; double normalizer; - + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -344,6 +344,9 @@ main(int argc, const char **argv) { normalizer, stdout); pm_freearray2((void **)kernel); - + return 0; } + + + diff --git a/generator/pamgradient.c b/generator/pamgradient.c index 526efdae..bbbaad30 100644 --- a/generator/pamgradient.c +++ b/generator/pamgradient.c @@ -53,8 +53,8 @@ parseCommandLine(int argc, const char **argv, 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); + "Max allowed is %lu", cmdlineP->maxval, + (unsigned long int) PAM_OVERALL_MAXVAL); if (cmdlineP->maxval < 1) pm_error("You cannot specify 0 for -maxval"); @@ -68,8 +68,8 @@ parseCommandLine(int argc, const char **argv, 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]); + cmdlineP->cols = pm_parse_width(argv[5]); + cmdlineP->rows = pm_parse_height(argv[6]); if (cmdlineP->cols <= 0) pm_error("width argument must be a positive number. You " "specified '%s'", argv[5]); @@ -211,3 +211,6 @@ main(int argc, const char *argv[]) { return 0; } + + + diff --git a/generator/pamseq.c b/generator/pamseq.c index 1af5252a..71905a67 100644 --- a/generator/pamseq.c +++ b/generator/pamseq.c @@ -1,3 +1,4 @@ +#include <assert.h> #include <string.h> #include <unistd.h> #include <stdlib.h> @@ -6,49 +7,173 @@ #include "pm_c_util.h" #include "pam.h" #include "shhopt.h" +#include "mallocvar.h" +#include "nstring.h" -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ unsigned int depth; sample maxval; const char * tupletype; + sample * min; /* array of size 'depth' */ + sample * max; /* array of size 'depth' */ + sample * step; /* array of size 'depth' */ }; static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { +destroyCmdline(struct CmdlineInfo * const cmdlineP) { + + if (cmdlineP->min) + free(cmdlineP->min); + if (cmdlineP->max) + free(cmdlineP->max); + if (cmdlineP->step) + free(cmdlineP->step); +} + + + +static unsigned int +entryCt(char ** const stringList) { + + unsigned int i; + + for (i = 0; stringList[i]; ++i) {} + + return i; +} + + + +static void +parseOptList(bool const isSpec, + char ** const stringList, + unsigned int const depth, + sample const maxval, + const char * const optNm, + sample ** const sampleListP) { + + if (!isSpec) + *sampleListP = NULL; + else { + unsigned int i; + sample * sampleList; + const char * memberError; + + if (entryCt(stringList) != depth) { + pm_error("Wrong number of values for -%s: %u. Need %u", + optNm, entryCt(stringList), depth); + } + + MALLOCARRAY(sampleList, depth); + + for (i = 0, memberError = NULL; i < depth && !memberError; ++i) { + char * endPtr; + long const n = strtol(stringList[i], &endPtr, 10); + + if (strlen(stringList[i]) == 0) + pm_asprintf(&memberError, "is null string"); + else if (*endPtr != '\0') + pm_asprintf(&memberError, + "contains non-numeric character '%c'", + *endPtr); + else if (n < 0) + pm_asprintf(&memberError, "is negative"); + else if (n > maxval) + pm_asprintf(&memberError, "is greater than maxval %lu", + maxval); + else + sampleList[i] = n; + } + if (memberError) { + free(sampleList); + pm_errormsg("Value in -%s %s", optNm, memberError); + pm_longjmp(); + } + *sampleListP = sampleList; + } +} + + + +static void +validateMinIsAtMostMax(sample * const min, + sample * const max, + unsigned int const depth) { + + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + if (min[plane] > max[plane]) + pm_error("-min for plane %u (%lu) is greater than -max (%lu)", + plane, min[plane], max[plane]); + } +} + + + +static void +validateStepIsPositive(sample * const step, + unsigned int const depth) { + + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + if (step[plane] <= 0) + pm_error("-step for plane %u (%lu) is not positive", + plane, step[plane]); + } +} + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- - Convert program invocation arguments (argc,argv) into a format the + 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 + Note that some string information we return as *cmdlineP is in the storage argv[] points to. -----------------------------------------------------------------------------*/ - optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to OptParseOptions2 on how to parse our options. - */ + optEntry *option_def; optStruct3 opt; - + /* Instructions to pm_optParseOptions3 on how to parse our options. */ + + unsigned int maxSpec; + char ** max; + unsigned int minSpec; + char ** min; + unsigned int stepSpec; + char ** step; unsigned int tupletypeSpec; unsigned int option_def_index; + MALLOCARRAY_NOFAIL(option_def, 100); + option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "tupletype", OPT_STRING, &cmdlineP->tupletype, + OPTENT3(0, "tupletype", OPT_STRING, &cmdlineP->tupletype, &tupletypeSpec, 0); - + OPTENT3(0, "min", OPT_STRINGLIST, &min, + &minSpec, 0); + OPTENT3(0, "max", OPT_STRINGLIST, &max, + &maxSpec, 0); + OPTENT3(0, "step", OPT_STRINGLIST, &step, + &stepSpec, 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 */ - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!tupletypeSpec) @@ -57,9 +182,9 @@ parseCommandLine(int argc, char ** argv, struct pam pam; if (strlen(cmdlineP->tupletype)+1 > sizeof(pam.tuple_type)) pm_error("The tuple type you specified is too long. " - "Maximum %u characters.", + "Maximum %u characters.", (unsigned)sizeof(pam.tuple_type)-1); - } + } if (argc-1 < 2) pm_error("Need two arguments: depth and maxval."); @@ -67,83 +192,175 @@ parseCommandLine(int argc, char ** argv, pm_error("Only two argumeents allowed: depth and maxval. " "You specified %d", argc-1); else { - cmdlineP->depth = atoi(argv[1]); - cmdlineP->maxval = atoi(argv[2]); - if (cmdlineP->depth <= 0) + const char * error; + unsigned int depth, maxval; + + pm_string_to_uint(argv[1], &depth, &error); + if (error) { + pm_error("'%s' is invalid as an image depth. %s", argv[1], error); + pm_strfree(error); + } + else if (depth <= 0) pm_error("depth argument must be a positive number. You " "specified '%s'", argv[1]); - if (cmdlineP->maxval <= 0) - pm_error("maxval argument must be a positive number. You " - "specified '%s'", argv[2]); - if (cmdlineP->maxval > PNM_OVERALLMAXVAL) + else + cmdlineP->depth = depth; + + maxval = pm_parse_maxval(argv[2]); + + if (maxval > PAM_OVERALL_MAXVAL) pm_error("The maxval you specified (%u) is too big. " - "Maximum is %u", (unsigned int) cmdlineP->maxval, - PNM_OVERALLMAXVAL); - if (pm_maxvaltobits(cmdlineP->maxval) + + "Maximum is %lu", maxval, PAM_OVERALL_MAXVAL); + else + cmdlineP->maxval = maxval; + + + if (pm_maxvaltobits(cmdlineP->maxval) + pm_maxvaltobits(cmdlineP->depth-1) > sizeof(unsigned int)*8) pm_error("The maxval (%u) and depth (%u) you specified result " "in a larger number of tuples than this program can " - "handle (roughly %u)", + "handle (roughly %u)", (unsigned int) cmdlineP->maxval, cmdlineP->depth, (unsigned int) -1); } + parseOptList(minSpec, min, cmdlineP->depth, cmdlineP->maxval, "min", + &cmdlineP->min); + parseOptList(maxSpec, max, cmdlineP->depth, cmdlineP->maxval, "max", + &cmdlineP->max); + parseOptList(stepSpec, step, cmdlineP->depth, cmdlineP->maxval, "step", + &cmdlineP->step); + + if (cmdlineP->min && cmdlineP->max) + validateMinIsAtMostMax(cmdlineP->min, cmdlineP->max, cmdlineP->depth); + + if (cmdlineP->step) + validateStepIsPositive(cmdlineP->step, cmdlineP->depth); + + if (minSpec) + free(min); + if (maxSpec) + free(max); + if (stepSpec) + free(step); } -static unsigned int -powint(unsigned int base, unsigned int exponent) { +static void +computeMinMaxStep(unsigned int const depth, + sample const maxval, + const sample * const min, + const sample * const max, + const sample * const step, + sample ** const minP, + sample ** const maxP, + sample ** const stepP) { + + unsigned int plane; + + MALLOCARRAY(*minP, depth); + MALLOCARRAY(*maxP, depth); + MALLOCARRAY(*stepP, depth); + + for (plane = 0; plane < depth; ++plane) { + (*minP)[plane] = min ? min[plane] : 0; + (*maxP)[plane] = max ? max[plane] : maxval; + (*stepP)[plane] = step ? step[plane] : 1; + } +} + + + +static int +imageWidth(unsigned int const depth, + const sample * const min, + const sample * const max, + const sample * const step) { /*---------------------------------------------------------------------------- - This is standard pow(), but for integers and optimized for small - exponents. + The width of the output image (i.e. the number of pixels in the image), + given that the minimum and maximum sample values in Plane P are min[P] and + max[P] and the samples step by step[P]. + + E.g. in the example case of min 0, max 4, and step 1 everywhere, with + depth 2, We return 5*5 = 25. -----------------------------------------------------------------------------*/ - unsigned int result; - unsigned int i; + unsigned int product; + unsigned int plane; - result = 1; /* initial value */ - for (i = 0; i < exponent; ++i) - result *= base; + for (plane = 0, product=1; plane < depth; ++plane) { + assert(max[plane] >= min[plane]); - return(result); + unsigned int const valueCtThisPlane = + ROUNDUP((max[plane] - min[plane] + 1), step[plane])/step[plane]; + + if (INT_MAX / valueCtThisPlane < product) + pm_error("Uncomputably large number of pixels (greater than %u)", + INT_MAX); + + product *= valueCtThisPlane; + } + assert(product < INT_MAX); + + return product; } + static void -permuteHigherPlanes(struct pam const pam, int const nextplane, - tuple * const tuplerow, int * const colP, - tuple const lowerPlanes) { +permuteHigherPlanes(unsigned int const depth, + const sample * const min, + const sample * const max, + const sample * const step, + unsigned int const nextPlane, + tuple * const tuplerow, + int * const colP, + tuple const lowerPlanes) { /*---------------------------------------------------------------------------- Create all the possible permutations of tuples whose lower-numbered planes contain the values from 'lowerPlanes'. I.e. vary the higher-numbered - planes between zero and maxval. + planes according to min[], max[], and step[]. Write them sequentially into *tuplerow, starting at *colP. Adjust *colP to next the column after the ones we write. - lower-numbered means with plane numbers less than 'nextplane'. + lower-numbered means with plane numbers less than 'nextPlane'. We modify 'lowerPlanes' in the higher planes to undefined values. -----------------------------------------------------------------------------*/ - if (nextplane == pam.depth - 1) { + if (nextPlane == depth - 1) { + /* lowerPlanes[] contains values for all the planes except the + highest, so we just vary the highest plane and combine that + with lowerPlanes[] and output that to tuplerow[]. + */ sample value; - for (value = 0; value <= pam.maxval; ++value) { + + for (value = min[nextPlane]; + value <= max[nextPlane]; + value += step[nextPlane]) { + unsigned int plane; - for (plane = 0; plane < nextplane; ++plane) + + for (plane = 0; plane < nextPlane; ++plane) tuplerow[*colP][plane] = lowerPlanes[plane]; - tuplerow[*colP][nextplane] = value; + + tuplerow[*colP][nextPlane] = value; + ++(*colP); } } else { sample value; - for (value = 0; value <= pam.maxval; ++value) { + for (value = min[nextPlane]; + value <= max[nextPlane]; + value += step[nextPlane]) { /* We do something sleazy here and use Caller's lowerPlanes[] variable as a local variable, modifying it in the higher plane positions. That's just for speed. */ - lowerPlanes[nextplane] = value; + lowerPlanes[nextPlane] = value; - permuteHigherPlanes(pam, nextplane+1, tuplerow, colP, lowerPlanes); + permuteHigherPlanes(depth, min, max, step, + nextPlane+1, tuplerow, colP, lowerPlanes); } } } @@ -151,52 +368,65 @@ permuteHigherPlanes(struct pam const pam, int const nextplane, int -main(int argc, char **argv) { +main(int argc, const char **argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; struct pam pam; int col; tuple lowerPlanes; /* This is working storage passed to permuteHigherPlanes(), which we call. Note that because we always pass zero as the - "planes" argument to permuteHigherPlanes(), none of the - "lower planes" value is defined as an input to + "planes" argument to permuteHigherPlanes(), none of the + "lower planes" value is defined as an input to permuteHigherPlanes(). */ tuple * tuplerow; - - pnm_init(&argc, argv); - + sample * min; /* malloc'ed array */ + sample * max; /* malloc'ed array */ + sample * step; /* malloc'ed array */ + + pm_proginit(&argc, argv); + parseCommandLine(argc, argv, &cmdline); + computeMinMaxStep(cmdline.depth, cmdline.maxval, + cmdline.min, cmdline.max, cmdline.step, + &min, &max, &step); + pam.size = sizeof(pam); pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = stdout; pam.format = PAM_FORMAT; pam.plainformat = 0; - pam.width = powint(cmdline.maxval+1, cmdline.depth); + pam.width = imageWidth(cmdline.depth, min, max, step); pam.height = 1; pam.depth = cmdline.depth; pam.maxval = cmdline.maxval; strcpy(pam.tuple_type, cmdline.tupletype); pnm_writepaminit(&pam); - + tuplerow = pnm_allocpamrow(&pam); lowerPlanes = pnm_allocpamtuple(&pam); col = 0; - permuteHigherPlanes(pam, 0, tuplerow, &col, lowerPlanes); + permuteHigherPlanes(pam.depth, min, max, step, + 0, tuplerow, &col, lowerPlanes); if (col != pam.width) pm_error("INTERNAL ERROR: Wrote %d columns; should have written %d.", col, pam.width); pnm_writepamrow(&pam, tuplerow); - + pnm_freepamrow(tuplerow); + destroyCmdline(&cmdline); + return 0; } + + + diff --git a/generator/pamshadedrelief.c b/generator/pamshadedrelief.c index 35d1e3e0..80b34a0d 100644 --- a/generator/pamshadedrelief.c +++ b/generator/pamshadedrelief.c @@ -8,7 +8,7 @@ The input array is a one-channel PAM image. The sample values are elevations of terrain. - + This is derived from John Walker's 'pgmcrater' which not only does this shading, but first generates a terrain map of fractal craters on which to run it. @@ -95,7 +95,7 @@ parseCommandLine(int argc, const char ** const argv, if (cmdlineP->gamma <= 0.0) pm_error("gamma correction must be greater than 0"); - if (argc-1 == 0) + if (argc-1 == 0) cmdlineP->inputFileName = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " @@ -201,7 +201,7 @@ writeShadedRelief(struct pam * const terrainPamP, } { /* Wrap around to determine shade of pixel on right edge */ - int const slope = + int const slope = terrain[row][0][0] - terrain[row][outpam.width-1][0]; outrow[outpam.width - 1][0] = brightnessOfSlope(slope, slopeGrayMap); @@ -222,8 +222,8 @@ readTerrain(FILE * const ifP, *tuplesP = pnm_readpam(ifP, pamP, PAM_STRUCT_SIZE(tuple_type)); } - - + + int main(int argc, const char ** argv) { @@ -243,7 +243,7 @@ main(int argc, const char ** argv) { readTerrain(ifP, &terrainPam, &terrain); writeShadedRelief(&terrainPam, terrain, cmdline.gamma, stdout); - + return 0; } diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c index 9b861b51..4bc1ea92 100644 --- a/generator/pamstereogram.c +++ b/generator/pamstereogram.c @@ -16,7 +16,7 @@ * * ---------------------------------------------------------------------- * - * Copyright (C) 2006-2020 Scott Pakin <scott+pbm@pakin.org> + * Copyright (C) 2006-2021 Scott Pakin <scott+pbm@pakin.org> * * All rights reserved. * @@ -58,11 +58,12 @@ #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" +#include "rand.h" #include "shhopt.h" #include "pam.h" -enum outputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR}; +enum OutputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR}; /* ---------------------------------------------------------------------- */ @@ -85,13 +86,14 @@ struct cmdlineInfo { unsigned int magnifypat; /* -magnifypat option */ int xshift; /* -xshift option */ int yshift; /* -yshift option */ + int yfillshift; /* -yfillshift option */ const char * patfile; /* -patfile option. Null if none */ const char * texfile; /* -texfile option. Null if none */ const char * bgcolor; /* -bgcolor option */ unsigned int smoothing; /* -smoothing option */ unsigned int randomseed; /* -randomseed option */ unsigned int randomseedSpec; /* -randomseed option count */ - enum outputType outputType; /* Type of output file */ + enum OutputType outputType; /* Type of output file */ unsigned int xbegin; /* -xbegin option */ unsigned int xbeginSpec; /* -xbegin option count */ unsigned int tileable; /* -tileable option */ @@ -153,8 +155,8 @@ parseCommandLine(int argc, unsigned int option_def_index; unsigned int patfileSpec, texfileSpec, dpiSpec, eyesepSpec, depthSpec, - guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec, - bgcolorSpec, smoothingSpec, planesSpec; + guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec, yfillshiftSpec, + bgcolorSpec, smoothingSpec, planesSpec; unsigned int blackandwhite, grayscale, color; const char ** planes; @@ -194,6 +196,8 @@ parseCommandLine(int argc, &xshiftSpec, 0); OPTENT3(0, "yshift", OPT_INT, &cmdlineP->yshift, &yshiftSpec, 0); + OPTENT3(0, "yfillshift", OPT_INT, &cmdlineP->yfillshift, + &yfillshiftSpec, 0); OPTENT3(0, "patfile", OPT_STRING, &cmdlineP->patfile, &patfileSpec, 0); OPTENT3(0, "texfile", OPT_STRING, &cmdlineP->texfile, @@ -282,9 +286,10 @@ parseCommandLine(int argc, if (!xshiftSpec) cmdlineP->xshift = 0; - if (!yshiftSpec) cmdlineP->yshift = 0; + if (!yfillshiftSpec) + cmdlineP->yfillshift = 0; if (xshiftSpec && !cmdlineP->patfile) pm_error("-xshift is valid only with -patfile"); @@ -402,11 +407,12 @@ typedef struct outGenerator { -struct randomState { +struct RandomState { /* The state of a randomColor generator. */ unsigned int magnifypat; tuple * currentRow; unsigned int prevy; + struct pm_randSt * randStP; }; @@ -421,7 +427,7 @@ randomColor(outGenerator * const outGenP, /*---------------------------------------------------------------------------- Return a random RGB value. -----------------------------------------------------------------------------*/ - struct randomState * const stateP = outGenP->stateP; + struct RandomState * const stateP = outGenP->stateP; /* Every time we start a new row, we select a new sequence of random colors. @@ -436,7 +442,7 @@ randomColor(outGenerator * const outGenP, unsigned int plane; for (plane = 0; plane < outGenP->pam.depth; ++plane) { - unsigned int const randval = rand(); + unsigned int const randval = pm_rand(stateP->randStP); thisTuple[plane] = randval % modulus; } } @@ -456,9 +462,13 @@ static outGenStateTerm termRandomColor; static void termRandomColor(outGenerator * const outGenP) { - struct randomState * const stateP = outGenP->stateP; + struct RandomState * const stateP = outGenP->stateP; pnm_freepamrow(stateP->currentRow); + + pm_randterm(stateP->randStP); + + free(stateP->randStP); } @@ -468,7 +478,7 @@ initRandomColor(outGenerator * const outGenP, const struct pam * const inPamP, struct cmdlineInfo const cmdline) { - struct randomState * stateP; + struct RandomState * stateP; outGenP->pam.format = PAM_FORMAT; outGenP->pam.plainformat = 0; @@ -499,6 +509,10 @@ initRandomColor(outGenerator * const outGenP, stateP->magnifypat = cmdline.magnifypat; stateP->prevy = (unsigned int)(-cmdline.magnifypat); + MALLOCVAR_NOFAIL(stateP->randStP); + pm_randinit(stateP->randStP); + pm_srand2(stateP->randStP, cmdline.randomseedSpec, cmdline.randomseed); + outGenP->stateP = stateP; outGenP->getTuple = &randomColor; outGenP->terminateState = &termRandomColor; @@ -1178,6 +1192,8 @@ static void makeImageRow(outGenerator * const outGenP, unsigned int const row, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, const unsigned int * const sameL, const unsigned int * const sameR, const tuple * const outRow) { @@ -1200,42 +1216,59 @@ makeImageRow(outGenerator * const outGenP, sameL[N] > N is not allowed. -----------------------------------------------------------------------------*/ - int col; - int lastLinked; + unsigned int const width = outGenP->pam.width; + unsigned int const height = outGenP->pam.height; - for (col = (int)xbegin, lastLinked = INT_MIN; - col < outGenP->pam.width; - ++col) { + unsigned int col; + bool colHasBeenLinked; + unsigned int lastLinkedCol; + /* Last column to have been linked; meaningless if 'colHasBeenLinked' + is false. + */ + + for (col = xbegin, colHasBeenLinked = false; col < width; ++col) { tuple newtuple; - if (sameL[col] == col || sameL[col] < (int)xbegin) { - if (lastLinked == col - 1) - newtuple = outRow[col - 1]; - else - newtuple = outGenP->getTuple(outGenP, col, row); + if (sameL[col] == col || sameL[col] < xbegin) { + if (colHasBeenLinked && lastLinkedCol == col - 1) + newtuple = outRow[lastLinkedCol]; + else { + if (col < xbegin + farWidth) + newtuple = outGenP->getTuple(outGenP, col, row); + else + newtuple = outGenP->getTuple( + outGenP, col, (row + height - yfillshift) % height); + } } else { - newtuple = outRow[sameL[col]]; - lastLinked = col; - /* Keep track of the last pixel to be constrained. */ + newtuple = outRow[sameL[col]]; + colHasBeenLinked = true; + lastLinkedCol = col; + /* Keep track of the last pixel to be constrained. */ } pnm_assigntuple(&outGenP->pam, outRow[col], newtuple); } - for (col = (int)xbegin - 1, lastLinked = INT_MIN; col >= 0; --col) { + for (col = xbegin, colHasBeenLinked = false; col > 0; --col) { tuple newtuple; - if (sameR[col] == col) { - if (lastLinked == col + 1) - newtuple = outRow[col + 1]; - else - newtuple = outGenP->getTuple(outGenP, col, row); + if (sameR[col-1] == col-1) { + if (colHasBeenLinked && lastLinkedCol == col) + newtuple = outRow[lastLinkedCol]; + else { + if (col > xbegin - farWidth) + newtuple = outGenP->getTuple(outGenP, col-1, row); + else + newtuple = outGenP->getTuple( + outGenP, col-1, (row + height - yfillshift) % height); + } } else { - newtuple = outRow[sameR[col]]; - lastLinked = col; + newtuple = outRow[sameR[col-1]]; + colHasBeenLinked = true; + lastLinkedCol = col - 1; /* Keep track of the last pixel to be constrained. */ } - pnm_assigntuple(&outGenP->pam, outRow[col], newtuple); + pnm_assigntuple(&outGenP->pam, outRow[col-1], newtuple); } } @@ -1261,6 +1294,8 @@ makeOneImageRow(unsigned int const row, const unsigned int * const sameR, unsigned int * const colNumBuffer, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, tuple * const rowBuffer, tuple * const outRow) { @@ -1272,7 +1307,7 @@ makeOneImageRow(unsigned int const row, rowBuffer, outRow); else makeImageRow(outputGeneratorP, row, - xbegin, sameL, sameR, outRow); + xbegin, farWidth, yfillshift, sameL, sameR, outRow); } } @@ -1284,6 +1319,8 @@ constructRowTileable(const struct pam * const inPamP, bool const makeMask, const unsigned int * const sameL, const unsigned int * const sameR, + unsigned int const farWidth, + int const yfillshift, unsigned int const row, tuple * const outRow, tuple * const outRowBuf1, @@ -1300,10 +1337,10 @@ constructRowTileable(const struct pam * const inPamP, xbegin=maximum case. */ makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - 0, outRowBuf2, outRow); + farWidth, yfillshift, 0, outRowBuf2, outRow); makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - inPamP->width - 1, outRowBuf2, outRowMax); + farWidth, yfillshift, inPamP->width - 1, outRowBuf2, outRowMax); for (col = 0; col < inPamP->width; ++col) { unsigned int plane; @@ -1362,6 +1399,8 @@ doRow(const struct pam * const inPamP, unsigned int const magnifypat, unsigned int const smoothing, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, unsigned int const row, tuple * const inRow, tuple * const outRowBuf0, @@ -1397,13 +1436,16 @@ doRow(const struct pam * const inPamP, /* Construct a single row. */ if (tileable) { constructRowTileable(inPamP, outputGeneratorP, makeMask, - sameL, sameR, row, outRow, + sameL, sameR, + farWidth, yfillshift, + row, outRow, outRowBuf1, outRowBuf2, colNumBuf2); } else { makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - xbegin, outRowBuf1, outRow); + xbegin, farWidth, yfillshift, + outRowBuf1, outRow); } /* Write the resulting row. */ @@ -1423,7 +1465,8 @@ makeImageRows(const struct pam * const inPamP, bool const tileable, unsigned int const magnifypat, unsigned int const smoothing, - unsigned int const xbegin) { + unsigned int const xbegin, + int const yfillshift) { tuple * inRow; /* Buffer for use in reading from the height-map image */ tuple * outRowBuf0; /* Buffer for use in generating output rows */ @@ -1433,6 +1476,8 @@ makeImageRows(const struct pam * const inPamP, unsigned int * colNumBuf1; unsigned int * colNumBuf2; unsigned int row; /* Current row in the input and output files */ + unsigned int pixelEyesep; + unsigned int farWidth; inRow = pnm_allocpamrow(inPamP); outRowBuf0 = pnm_allocpamrow(&outputGeneratorP->pam); @@ -1451,10 +1496,13 @@ makeImageRows(const struct pam * const inPamP, pm_error("Unable to allocate space for %u column buffer", inPamP->width); + pixelEyesep = ROUNDU(eyesep * dpi); + farWidth = pixelEyesep/(magnifypat * 2); + for (row = 0; row < inPamP->height; ++row) { doRow(inPamP, outputGeneratorP, depthOfField, eyesep, dpi, crossEyed, makeMask, tileable, magnifypat, smoothing, xbegin, - row, + farWidth, yfillshift, row, inRow, outRowBuf0, outRowBuf1, outRowBuf2, colNumBuf0, colNumBuf1, colNumBuf2); } @@ -1510,7 +1558,8 @@ produceStereogram(FILE * const ifP, makeImageRows(&inPam, outputGeneratorP, cmdline.depth, cmdline.eyesep, cmdline.dpi, cmdline.crosseyed, cmdline.makemask, cmdline.tileable, - cmdline.magnifypat, cmdline.smoothing, xbegin); + cmdline.magnifypat, cmdline.smoothing, xbegin, + cmdline.yfillshift); if (cmdline.guidebottom) drawguides(cmdline.guidesize, &outputGeneratorP->pam, @@ -1567,8 +1616,6 @@ main(int argc, const char *argv[]) { if (cmdline.verbose) reportParameters(cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - ifP = pm_openr(cmdline.inputFilespec); /* Produce a stereogram. */ @@ -1580,4 +1627,3 @@ main(int argc, const char *argv[]) { } - diff --git a/generator/pamstereogram.test b/generator/pamstereogram.test deleted file mode 100644 index 80f70ee0..00000000 --- a/generator/pamstereogram.test +++ /dev/null @@ -1,70 +0,0 @@ -# Make some input files -pamdepth -quiet 255 ../testgrid.pbm >/tmp/testgrid.pgm - - -# Random pattern - -echo Test 01. Should print 610673698 293: -./pamstereogram -randomseed=1 ../testgrid.pbm | cksum -echo Test 02. Should print 610673698 293: -./pamstereogram -randomseed=1 -blackandwhite ../testgrid.pbm | cksum -echo Test 03. Should print 3439084201 170: -pamseq -tupletype=GRAYSCALE 1 100 | ./pamstereogram -randomseed=1 | cksum -echo Test 04. Should print 2484923390 1070: -pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \ - ./pamstereogram -randomseed=1 -dpi=10 | cksum - -# Makemask - -echo Test 10. Should print 1266273778 293: -./pamstereogram -randomseed=1 -makemask ../testgrid.pbm | cksum - -echo Test 11. Should print 3034751595 1070: -pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \ - ./pamstereogram -randomseed=1 -dpi=10 -makemask | cksum - -# Grayscale - -echo Test 20. Should print 2468969328 289: -./pamstereogram -randomseed=1 -grayscale ../testgrid.pbm | cksum -echo Test 21. Should print 1946982115 4068: -pamseq 1 100 | pnmtile 200 20 | \ - ./pamstereogram -randomseed=1 -dpi=10 -grayscale | \ - cksum -echo Test 22. Should print 2078013430 4068: -pamseq 1 100 | pnmtile 200 20 | \ - ./pamstereogram -randomseed=1 -dpi=10 -grayscale -maxval 255 | \ - cksum - -# Color - -echo Test 30. Should print 1319392622 731: -./pamstereogram -randomseed=1 -color ../testgrid.pbm | cksum -echo Test 31. Should print 389886159 12062: -pamseq 1 100 | pnmtile 200 20 | \ - ./pamstereogram -randomseed=1 -dpi=10 -color | \ - cksum - -# Pattern file - -echo Test 40. Should print 1834916830 660: -pamgradient black gray50 white gray50 100 50 | \ - ./pamstereogram -patfile ../testgrid.pbm -eyesep=.1 -crosseyed | cksum - -echo Test 41. Should print 4016818756 5014: -pamgradient black gray50 white gray50 100 50 | \ - ./pamstereogram -patfile /tmp/testgrid.pgm -eyesep=.1 -crosseyed | cksum - -# drawguides - -echo Test 51. Should print 2365956562 11071: -pamgradient black gray50 white gray50 100 50 | \ - ./pamstereogram -randomseed=1 -dpi 10 -guidesize=20 | cksum - -echo Test 51. Should print 3502025270 1441: -pamgradient black gray50 white gray50 100 50 | \ - ./pamstereogram -patfile=../testgrid.pbm -dpi 10 -guidesize=20 | cksum - - -# Clean up files we created -rm /tmp/testgrid.pgm diff --git a/generator/pamtris/framebuffer.c b/generator/pamtris/framebuffer.c index 5665e9a4..4318b1fc 100644 --- a/generator/pamtris/framebuffer.c +++ b/generator/pamtris/framebuffer.c @@ -320,7 +320,7 @@ draw_span(uint32_t const base, fbi->z.buffer[j] = (fbi->z.buffer[j] & ~d_mask) | (d & d_mask); for (l = 0; l < z; l++) { - varying const newval = multiply_varyings(attribs[l], inverse_w); + varying const newval = multiply_varyings(attribs[l], inverse_w); fbi->img.buffer[k + l] = (fbi->img.buffer[k + l] & ~d_mask) | diff --git a/generator/pamtris/pamtris.c b/generator/pamtris/pamtris.c index e0becf7a..477b657e 100644 --- a/generator/pamtris/pamtris.c +++ b/generator/pamtris/pamtris.c @@ -54,7 +54,7 @@ parse_command_line(int * const argc_ptr, if (!width_spec || !height_spec || (!attribs_spec && !(rgb_spec || grayscale_spec))) { pm_errormsg( "you must at least specify -width, -height and " - "either -num_attribs, -rgb or -grayscale."); + "either -num_attribs, -rgb or -grayscale."); return 0; } diff --git a/generator/pamtris/triangle.c b/generator/pamtris/triangle.c index 5143f9ee..264fc221 100644 --- a/generator/pamtris/triangle.c +++ b/generator/pamtris/triangle.c @@ -190,8 +190,8 @@ draw_triangle(Xy const xy_input, for (i = 0; i < 3; i++) { int32_to_varying_array(attribs_input._[i], attribs[i], n); - attribs[i][z] = compute_varying_z(attribs_input._[i][z]); - attribs[i][w] = inverse_varying(attribs[i][w]); + attribs[i][z] = compute_varying_z(attribs_input._[i][z]); + attribs[i][w] = inverse_varying(attribs[i][w]); multiply_varying_array_by_varying(attribs[i], attribs[i][w], z); } diff --git a/generator/pamtris/utils.c b/generator/pamtris/utils.c index a6b6e7d4..53f1ea9e 100644 --- a/generator/pamtris/utils.c +++ b/generator/pamtris/utils.c @@ -61,7 +61,7 @@ multiply_varying_array_by_varying(varying * const vars, for (i = 0; i < elements; i++) { vars[i].v *= multiplier.v; - vars[i].s = 0.0; + vars[i].s = 0.0; } } @@ -77,7 +77,7 @@ divide_varying_array_by_varying(varying * const vars, for (i = 0; i < elements; i++) { vars[i].v *= inverse_divisor; - vars[i].s = 0.0; + vars[i].s = 0.0; } } diff --git a/generator/pbmnoise.c b/generator/pbmnoise.c new file mode 100644 index 00000000..541ce92e --- /dev/null +++ b/generator/pbmnoise.c @@ -0,0 +1,485 @@ +/* pbmnoise.c - create a random bitmap of a specified size + with a specified ratio of white/black pixels + + Written by Akira F Urushibata and contributed to the public domain + December 2021 +*/ + +#include <math.h> +#include <string.h> +#include <assert.h> + +#include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "rand.h" +#include "nstring.h" + +#include "pbm.h" + + + +static void +parseFraction(const char * const fraction, + unsigned int * const numeratorP, + unsigned int * const precisionP) { + + unsigned int numerator, denominator; + + sscanf(fraction, "%u/%u", &numerator, &denominator); + + if (denominator > 65536) + pm_error("Denominator (%u) too large.", denominator); + else if (denominator == 0 || (denominator & (denominator - 1)) != 0) + pm_error("Denominator must be a power of two. You specified %u.", + denominator); + else if (numerator > denominator) + pm_error("Invalid fraction (%s). Denominator must be larger than " + "numerator.", fraction); + else { + /* Reduce fraction to lowest terms */ + unsigned int numerator2, denominator2; + /* The fraction reduced to lowest terms */ + unsigned int precision2; + + if (numerator == 0) { /* all white image */ + numerator2 = 0; + denominator2 = 1; + precision2 = 0; + } else if (numerator == denominator) { /* all black */ + numerator2 = 1; + denominator2 = 1; + precision2 = 0; + } else { + numerator2 = numerator; /* initial value */ + denominator2 = denominator; /* initial value */ + + while ((numerator2 & 0x01) != 0x01) { + denominator2 /= 2; + numerator2 /= 2; + } + precision2 = 1; + } + + if (denominator != denominator2) + pm_message("Ratio %u/%u = %u/%u", + numerator, denominator, numerator2, denominator2); + + *precisionP = (precision2 == 0) ? 0 : pm_maxvaltobits(denominator2 - 1); + /* pm_maxvaltobits(N): Max of N is 65535 */ + + *numeratorP = numerator2; + } +} + + + +static void +setRatio(const char * const ratioArg, + unsigned int * const numeratorP, + unsigned int * const precisionP) { +/*---------------------------------------------------------------------------- + Convert string "ratioArg" to ratio: numerator / (2 ^ precision) The input + string must be in fraction "n/d" form and the denominator must be a power + of 2. + + Ratio is the probability of one binary digit being "1". The ratio of "1" + (=PBM black) pixels in the entire output image will be close to this + value. + + Most invalid strings are rejected here. +----------------------------------------------------------------------------*/ + if (strspn(ratioArg, "0123456789/") == strlen(ratioArg) && + ratioArg[0] != '/' && + ratioArg[strlen(ratioArg) - 1] != '/' && + strchr(ratioArg, '/') != NULL && + strchr(ratioArg, '/') == strrchr(ratioArg, '/')) + parseFraction(ratioArg, numeratorP, precisionP); + else + pm_error("Invalid ratio: '%s'", ratioArg); +} + + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int width; + unsigned int height; + unsigned int numerator; + unsigned int precision; + unsigned int randomseed; + unsigned int randomseedSpec; + unsigned int bswap; /* boolean */ + unsigned int pack; /* boolean */ +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + const char * ratioArg; + unsigned int ratioSpec; + const char * endianArg; + unsigned int endianSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "ratio", OPT_STRING, &ratioArg, + &ratioSpec, 0); + OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, + &cmdlineP->randomseedSpec, 0); + OPTENT3(0, "endian", OPT_STRING, &endianArg, + &endianSpec, 0); + OPTENT3(0, "pack", OPT_FLAG, NULL, + &cmdlineP->pack, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + free(option_def); + + if (ratioSpec) + setRatio(ratioArg, &cmdlineP->numerator, &cmdlineP->precision); + else { + /* Set ratio to default: 1/2 */ + cmdlineP->numerator = 1; + cmdlineP->precision = 1; + } + + if (!endianSpec) + cmdlineP->bswap = false; + else { + if (streq(endianArg, "native")) + cmdlineP->bswap = false; + else if (streq(endianArg, "swap")) + cmdlineP->bswap = true; + else if (streq(endianArg, "big")) + cmdlineP->bswap = (BYTE_ORDER == LITTLE_ENDIAN); + else if (streq(endianArg, "little")) + cmdlineP->bswap = (BYTE_ORDER != LITTLE_ENDIAN); + else + pm_error("Invalid value '%s' for -endian argument.", endianArg); + } + + if (argc-1 != 2) + pm_error("Wrong number of arguments (%d). There are two " + "non-option arguments: width and height in pixels", + argc-1); + else { + cmdlineP->width = pm_parse_width (argv[1]); + cmdlineP->height = pm_parse_height(argv[2]); + } +} + + + +static void +writeSingleColorRaster(unsigned int const cols, + unsigned int const rows, + bit const color, + FILE * const ofP) { +/*----------------------------------------------------------------------------- + Generate a single-color raster of color 'color', dimensions + 'cols' by 'rows', to output file *ofP. +-----------------------------------------------------------------------------*/ + unsigned int const lastColChar = (cols - 1) / 8; + + unsigned char * bitrow0; + unsigned int i; + + bitrow0 = pbm_allocrow_packed(cols + 32); + + for (i = 0; i <= lastColChar; ++i) + bitrow0[i] = color * 0xff; + + if (color != 0) + pbm_cleanrowend_packed(bitrow0, cols); + + /* row end trimming, not necessary with white */ + + { + unsigned int row; + for (row = 0; row < rows; ++row) + pbm_writepbmrow_packed(ofP, bitrow0, cols, 0); + } + pbm_freerow(bitrow0); +} + + + +static uint32_t +randombits(unsigned int const precision, + unsigned int const numerator, + struct pm_randSt * const randStP) { +/*---------------------------------------------------------------------------- + Generate 32 random bits so that for each bit the probability of "1" + being generated is numerator / (2 ^ precision). + + How this works: + + Ratios such as 1/8, 7/8, 1/16, 15/16, 1/32, 31/32 are straightforward. How + do you get intermediate values such as 3/8, 5/8, 3/16, 5/16, 7/16? + + Imagine a set of 10 bits which are 90% 1, 10% 0 and a random number source + which produces 1 and 0 in even proportions. + + Conduct "and" and "or" on these bits: + + 0011111111 (90%) 0011111111 (90%) + and) 0101010101 (50%) or) 0101010101 (50%) + --------------------- -------------------- + 0001010101 (45%) 0111111111 (95%) + + It can be seen from this example that an "and" operation gives a new ratio + which is halfway between the old ratio (90% in this example) and 0%, while + "or" gives one at the middle of the old ratio and 100% The corresponding + binary operations for fixed-point fractions are: "right-shift by one and + insert a 0 behind the fixed point" and "right-shift by one and insert a 1 + behind the fixed point" respecatbly. + + 115/128 = 89.84% (near 90%) In binary fix-point: 0.1110011 + 0.01110011 = 115/256 = 44.92% + 0.11110011 = 243/256 = 94.92% + + So to achieve the desired ratio, start at the LSB (right end) of + 'numerator'. Initialize the output bits to zero. Conduct an "and" for each + 0 and an "or" for each 1 with a freshly drawn random number until the fixed + point is reached. + + An "and" operation of a random number and zero always yields zero. To avoid + waste, we reduce terms to eliminate the trailing zeroes in 'numerator' and + indicate the fixed point with 'precision'. Each time the program is + executed the location of the fixed point is set anew, but it stays constant + until the program exits. +----------------------------------------------------------------------------*/ + unsigned int i; + uint32_t mask; + uint32_t retval; + + for (i = 0, mask = 0x01, retval=0x00000000; + i < precision; + ++i, mask <<= 1) { + + uint32_t const randval = pm_rand32(randStP); + + if ((numerator & mask) != 0 ) + retval |= randval; + else + retval &= randval; + } + return retval; +} + + + +static uint32_t +swapWord(uint32_t const word) { +/*---------------------------------------------------------------------------- + Swap four bytes. + This swap method works regardless of native system endianness. +----------------------------------------------------------------------------*/ + uint32_t const retval = + ((word >> 24) & 0xff) | + ((word >> 8) & 0xff00) | + ((word << 8) & 0xff0000) | + ((word << 24) & 0xff000000) + ; + + return retval; +} + + + +static void +swapBitrow(unsigned char * const bitrow, + unsigned int const words, + bool const bswap) { +/*---------------------------------------------------------------------------- + Modify bits in 'bitrow', swapping as indicated. +----------------------------------------------------------------------------*/ + uint32_t * const bitrowByWord = (uint32_t *) bitrow; + + unsigned int wordCnt; + + for (wordCnt=0; wordCnt < words; ++wordCnt) { + uint32_t const inWord = bitrowByWord[wordCnt]; + + bitrowByWord[wordCnt] = bswap ? swapWord(inWord) : inWord; + } +} + + + +static void +pbmnoise(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + unsigned int const numerator, + unsigned int const precision, + bool const bswap, + struct pm_randSt * const randStP) { +/*---------------------------------------------------------------------------- + Default method of constructing rows. + + Generate pixels in units of 32 bits. + + If cols is not a multiple of 32, discard pixels beyond row end. +-----------------------------------------------------------------------------*/ + unsigned int const words = (cols + 31) / 32; + + unsigned char * bitrow; + unsigned int row; + unsigned int wordCnt; + + bitrow = pbm_allocrow_packed(cols + 32); + + for (row = 0; row < rows; ++row) { + uint32_t * const bitrowByWord = (uint32_t *) bitrow; + + for (wordCnt = 0; wordCnt < words; ++wordCnt) + bitrowByWord[wordCnt] = randombits(precision, numerator, randStP); + + if (bswap) + swapBitrow(bitrow, words, bswap); + + pbm_cleanrowend_packed(bitrow, cols); + pbm_writepbmrow_packed(ofP, bitrow, cols, 0); + } + pbm_freerow(bitrow); +} + + + +static void +pbmnoise_packed(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + unsigned int const numerator, + unsigned int const precision, + bool const bswap, + struct pm_randSt * const randStP) { +/*---------------------------------------------------------------------------- + Alternate method of constructing rows. + Like the default pbmnoise(), generate pixels in units of 32 bits + but carry over unused pixel data at row end to the next row. +-----------------------------------------------------------------------------*/ + unsigned char * bitrow0; + uint32_t * bitrowByWord; + unsigned int offset; + unsigned int row; + uint32_t wordSave; /* Pixels carried over to next row */ + + bitrow0 = pbm_allocrow_packed(cols + 63); + bitrowByWord = (uint32_t *) bitrow0; + + for (row = 0, offset = 0; row < rows; ++row) { + if (offset == 0) { + unsigned int const words = (cols + 31 ) / 32; + + unsigned int wordCnt; + + for (wordCnt = 0; wordCnt< words; ++wordCnt) { + bitrowByWord[wordCnt] = + randombits(precision, numerator, randStP); + } + + if (bswap) + swapBitrow(bitrow0, words, bswap); + + wordSave = bitrowByWord[words - 1]; + + pbm_cleanrowend_packed(bitrow0, cols); + pbm_writepbmrow_packed(ofP, bitrow0, cols, 0); + offset = cols % 32; + } else { + unsigned int const wordsToFetch = (cols - (32 - offset) + 31) / 32; + unsigned int const lastWord = wordsToFetch; + + unsigned int wordCnt; + + bitrowByWord[0] = wordSave; + + for (wordCnt = 0; wordCnt < wordsToFetch; ++wordCnt) { + bitrowByWord[wordCnt + 1] = + randombits(precision, numerator, randStP); + } + + if (bswap) + swapBitrow((unsigned char *) & bitrowByWord[1], + wordsToFetch, bswap); + + wordSave = bitrowByWord [lastWord]; + + pbm_writepbmrow_bitoffset(ofP, bitrow0, cols, 0, offset); + offset = (offset + cols) % 32; + } + } + pbm_freerow(bitrow0); +} + + +int +main(int argc, const char *argv[]) { + + struct CmdlineInfo cmdline; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + pbm_writepbminit(stdout, cmdline.width, cmdline.height, 0); + + if (cmdline.precision == 0) { + bit color; + + if (cmdline.numerator == 0) + color = PBM_WHITE; + else { + assert (cmdline.numerator == 1); + color = PBM_BLACK; + } + writeSingleColorRaster(cmdline.width, cmdline.height, color, stdout); + } else if (cmdline.width % 32 == 0 || !cmdline.pack) { + struct pm_randSt randSt; + + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + + pbmnoise(stdout, cmdline.width, cmdline.height, + cmdline.numerator, cmdline.precision, + cmdline.bswap, &randSt); + + pm_randterm(&randSt); + } else { + struct pm_randSt randSt; + + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + + pbmnoise_packed(stdout, cmdline.width, cmdline.height, + cmdline.numerator, cmdline.precision, + cmdline.bswap, &randSt); + + pm_randterm(&randSt); + } + return 0; +} + + diff --git a/generator/pbmtext.c b/generator/pbmtext.c index 7ea64857..6d4ab8c5 100644 --- a/generator/pbmtext.c +++ b/generator/pbmtext.c @@ -1,4 +1,4 @@ -/* pbmtext.c - render text into a bitmap +/* pbmtext.c - render text into a PBM ** ** Copyright (C) 1991 by Jef Poskanzer. ** @@ -81,8 +81,13 @@ textFmCmdLine(int argc, const char ** argv) { text[0] = '\0'; for (i = 1, totaltextsize = 0; i < argc; ++i) { - if (i > 1) { + if (i > 1) strcat(text, " "); + + if (strlen(argv[i]) > MAXLINECHARS) { /* avoid arithmetic overflow */ + pm_error("Command line argument %u is %u characters. " + "Cannot process longer than %u", + i, (unsigned) strlen(argv[i]), (unsigned) MAXLINECHARS); } totaltextsize += strlen(argv[i]) + (i > 1 ? 1 : 0); if (totaltextsize > MAXLINECHARS) @@ -1105,7 +1110,7 @@ getText(PM_WCHAR const cmdlineText[], unsigned int const lineBufTerm = LINEBUFSIZE - 1; - unsigned int maxlines; + unsigned int textArraySz; /* Maximum number of lines for which we currently have space in the text array */ @@ -1122,12 +1127,12 @@ getText(PM_WCHAR const cmdlineText[], buf[lineBufTerm] = L'\1'; /* Initialize to non-zero value */ /* to detect input overrun */ - maxlines = 50; /* initial value */ - MALLOCARRAY(textArray, maxlines); + textArraySz = 50; /* initial value */ + MALLOCARRAY(textArray, textArraySz); if (!textArray) pm_error("Unable to allocate memory for a buffer for up to %u " - "lines of text", maxlines); + "lines of text", textArraySz); for (lineCount = 0, eof = false; !eof; ) { const char * error; @@ -1143,9 +1148,13 @@ getText(PM_WCHAR const cmdlineText[], "is longer than %u characters. " "Cannot process", lineCount, (unsigned int) MAXLINECHARS); - if (lineCount >= maxlines) { - maxlines *= 2; - REALLOCARRAY(textArray, maxlines); + if (lineCount >= textArraySz) { + if (textArraySz > UINT_MAX/2) + pm_error("Too many lines of input for " + "computation (more than %u)", + textArraySz); + textArraySz *= 2; + REALLOCARRAY(textArray, textArraySz); if (textArray == NULL) pm_error("out of memory"); } @@ -1282,6 +1291,8 @@ computeImageWidth(struct Text const formattedText, unsigned int * const colsP, unsigned int * const maxleftbP) { + assert (pbm_maxfontwidth() < (INT_MAX - 10) / LINEBUFSIZE); + if (intercharacterSpace < 0 && fontP->maxwidth < -intercharacterSpace) pm_error("negative -space value %.2f exceeds font width", intercharacterSpace); @@ -1562,4 +1573,3 @@ main(int argc, const char *argv[]) { } - diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c index 0c3656e7..2a1173de 100644 --- a/generator/pbmtextps.c +++ b/generator/pbmtextps.c @@ -27,6 +27,7 @@ #define _XOPEN_SOURCE 500 /* Make sure popen() is in stdio.h, strdup() is in string.h */ + #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -41,6 +42,8 @@ #include "pm_system.h" #include "pbm.h" +enum InputFmt {INPUT_LITERAL, INPUT_ASCIIHEX, INPUT_ASCII85}; + static void validateFontName(const char * const name) { /*----------------------------------------------------------------------------- @@ -52,6 +55,9 @@ validateFontName(const char * const name) { -----------------------------------------------------------------------------*/ unsigned int idx; + if (name[0] == '\0') + pm_error("Font name is empty string"); + for (idx = 0; name[idx] != '\0'; ++idx) { char const c = name[idx]; @@ -71,8 +77,8 @@ validateFontName(const char * const name) { static void -asciiHexEncode(char * const inbuff, - char * const outbuff) { +asciiHexEncode(const char * const inbuff, + char * const outbuff) { /*----------------------------------------------------------------------------- Convert the input text string to ASCII-Hex encoding. @@ -83,69 +89,357 @@ asciiHexEncode(char * const inbuff, unsigned int idx; + outbuff[0] = '<'; + for (idx = 0; inbuff[idx] != '\0'; ++idx) { unsigned int const item = (unsigned char) inbuff[idx]; - outbuff[idx*2] = hexits[item >> 4]; - outbuff[idx*2+1] = hexits[item & 0xF]; + outbuff[1 + idx * 2 + 0] = hexits[item >> 4]; + outbuff[1 + idx * 2 + 1] = hexits[item & 0xF]; } - outbuff[idx * 2] = '\0'; + if (idx == 0) + pm_message("Empty input string"); + + outbuff[1 + idx * 2] = '>'; + outbuff[1 + idx * 2 + 1] = '\0'; } static void -buildTextFromArgs(int const argc, - const char ** const argv, - const char ** const asciiHexTextP) { +failForInvalidChar(char const c, + const char * const type) { + + if (c >= 0x32 || c < 0x7F) + pm_error("Invalid character '%c' in '%s' input string", c, type); + else + pm_error("Invalid character 0x%02x in '%s' input string", c, type); +} + + + +static void +formatNonemptyAsciiHex(const char * const inbuff, + char * const outbuff, + unsigned int const inLen) { + + unsigned int inIdx, outIdx; + /* Cursors in input and output buffers, respectively */ + unsigned int validCharCt; + /* Number of valid hex characters we've processed so far in input */ + unsigned int startIdx, endIdx; + /* Limits of input buffer cursor ('inIdx') */ + + if (inbuff[0] == '<') { + startIdx = 1; + endIdx = inLen - 2; + } else { + startIdx = 0; + endIdx = inLen - 1; + } + + validCharCt = 0; /* No valid characters seen yet */ + + outIdx = 0; /* Start at beginning of output buffer */ + + outbuff[outIdx++] = '<'; + + for (inIdx = startIdx; inIdx <= endIdx; ++inIdx) { + switch (inbuff[inIdx]) { + case '<': + case '>': + pm_error("Misplaced character '%c' in Ascii Hex input string", + inbuff[inIdx]); + break; + case '\f': + case '\n': + case '\r': + case ' ': + case '\t': + /* ignore whitespace chars */ + break; + default: + if ((inbuff [inIdx] >='0' && inbuff [inIdx] <='9') || + (inbuff [inIdx] >='A' && inbuff [inIdx] <='F') || + (inbuff [inIdx] >='a' && inbuff [inIdx] <='f')) { + + outbuff[outIdx++] = inbuff [inIdx]; + ++validCharCt; + } else + failForInvalidChar(inbuff[inIdx], "Ascii Hex"); + break; + } + } + + if (validCharCt == 0) + pm_message("Empty Ascii Hex input string"); + else if (validCharCt % 2 != 0) + pm_error("Number of characters in Ascii Hex input string " + "is not even"); + + outbuff[outIdx++] = '>'; + outbuff[outIdx++] = '\0'; +} + + + +static void +formatAsciiHexString(const char * const inbuff, + char * const outbuff, + unsigned int const inLen) { /*---------------------------------------------------------------------------- - Build the array of text to be included in the Postscript program to - be rendered, from the arguments of this program. - - We encode it in ASCII-Hex notation as opposed to using the plain text from - the command line because 1) the command line might have Postscript control - characters in it; and 2) the command line might have text in 8-bit or - multibyte code, but a Postscript program is supposed to be entirely - printable ASCII characters. ------------------------------------------------------------------------------*/ - char * text; + Format the ASCII Hex input 'inbuff' as a Postscript ASCII Hex string, + e.g. "<313233>". Input can be just the ASCII Hex (e.g. "313233") or already + formatted (e.g. "<313233>"). Input may also contain white space, which we + ignore -- our output never contains white space. Though in Postscript, an + ASCII NUL character counts as white space, we consider it the end of the + input. + + We consider white space outside of the <> delimiters to be an error. + + Abort with error message if there is anything other than valid hex digits in + the ASCII hex string proper. This is necessary to prevent code injection. +----------------------------------------------------------------------------*/ + if (inLen == 0 || + (inLen == 2 && inbuff[0] == '<' && inbuff[inLen-1] == '>' )) { + pm_message("Empty Ascii Hex input string"); + strncpy(outbuff, "<>", 3); + } else { + if (inbuff[0] == '<' && inbuff[inLen-1] != '>' ) + pm_error("Ascii Hex input string starts with '<' " + "but does not end with '>'"); + else if (inbuff[0] != '<' && inbuff[inLen-1] == '>' ) + pm_error("Ascii Hex input string ends with '>' " + "but does not start with '<'"); + + formatNonemptyAsciiHex(inbuff, outbuff, inLen); + } +} + + + +static void +formatNonemptyAscii85(const char * const inbuff, + char * const outbuff, + unsigned int const inLen) { + + unsigned int inIdx, outIdx; + /* Cursors in input and output buffers, respectively */ + unsigned int seqPos; + /* Position in 5-character Ascii-85 sequence where 'inIdx' points */ + unsigned int startIdx, endIdx; + /* Limits of input buffer cursor ('inIdx') */ + + if (inLen > 4 && inbuff[0] == '<' && inbuff[1] == '~' && + inbuff[inLen-2] == '~' && inbuff[inLen-1] == '>') { + startIdx = 2; + endIdx = inLen - 3; + } else { + startIdx = 0; + endIdx = inLen - 1; + } + + seqPos = 0; /* No 5-character Ascii-85 sequence encountered yet */ + outIdx = 0; /* Start filling output buffer from beginning */ + + outbuff[outIdx++] = '<'; + outbuff[outIdx++] = '~'; + + for (inIdx = startIdx; inIdx <= endIdx; ++inIdx) { + switch (inbuff[inIdx]) { + case '~': + pm_error("Misplaced character '~' in Ascii 85 input string"); + break; + case '\f': + case '\n': + case '\r': + case ' ': + case '\t': + break; + case 'z': + /* z extension */ + if (seqPos > 0) + pm_error("Special 'z' character appears in the middle of a " + "5-character Ascii-85 sequence, which is invalid"); + else + outbuff[outIdx++] = inbuff[inIdx]; + break; + default: + /* valid Ascii 85 char */ + if (inbuff [inIdx] >='!' && inbuff [inIdx] <='u') { + outbuff[outIdx++] = inbuff[inIdx]; + seqPos = (seqPos + 1) % 5; + } else + failForInvalidChar(inbuff[inIdx], "Ascii 85"); + break; + } + } + + if (outIdx == 2) { + pm_message("Empty Ascii 85 input string"); + } + + outbuff[outIdx++] = '~'; + outbuff[outIdx++] = '>'; + outbuff[outIdx++] = '\0'; +} + + + +static void +formatAscii85String(const char * const inbuff, + char * const outbuff, + unsigned int const inLen) { +/*---------------------------------------------------------------------------- + Format the Ascii-85 input 'inbuff' as a Postscript Ascii-85 string, + e.g. "<~313233~>". Input can be just the Ascii-85 (e.g. "313233") or + already formatted (e.g. "<~313233~>"). Input may also contain white space, + which we ignore -- our output never contains white space. Though in + Postscript, an ASCII NUL character counts as white space, we consider it the + end of the input. + + We consider white space outside of the <~~> delimiters to be an error. + + Abort with error message if we encounter anything other than valid Ascii-85 + encoding characters in the string proper. Note that the Adobe variant + does not support the "y" extention. +----------------------------------------------------------------------------*/ + if (inLen == 0 || (inLen == 4 && strncmp (inbuff, "<~~>", 4) == 0)) { + pm_message("Empty Ascii 85 input string"); + strncpy(outbuff,"<~~>", 5); + } else { + if (inLen >= 2) { + if (inbuff[0] == '<' && inbuff[1] == '~' && + (inLen < 4 || inbuff[inLen-2] != '~' + || inbuff[inLen-1] != '>' )) + pm_error("Ascii 85 input string starts with '<~' " + "but does not end with '~>'"); + else if (inbuff[inLen-2] == '~' && inbuff[inLen-1] == '>' && + (inLen < 4 || inbuff[0] != '<' || inbuff[1] != '~')) + pm_error("Ascii 85 input string ends with '~>' " + "but does not start with '<~'"); + } + formatNonemptyAscii85(inbuff, outbuff, inLen); + } +} + + + +static void +combineArgs(int const argc, + const char ** const argv, + const char ** const textP, + unsigned int * const textSizeP) { + unsigned int totalTextSize; + char * text; + size_t * argSize; unsigned int i; + size_t idx; + + MALLOCARRAY_NOFAIL(argSize, argc); + /* argv[0] not accessed; argSize[0] not used */ + + for (i = 1, totalTextSize = 0; i < argc; ++i) { + argSize[i] = strlen(argv[i]); + totalTextSize += argSize[i]; + } + + totalTextSize = totalTextSize + (argc - 2); /* adjust for spaces */ + + MALLOCARRAY(text, totalTextSize + 1); /* add one for \0 at end */ + if (text == NULL) + pm_error("out of memory allocating buffer for " + "%u characters of text", totalTextSize); + + strncpy(text, argv[1], argSize[1]); + for (i = 2, idx = argSize[1]; i < argc; ++i) { + text[idx++] = ' '; + strncpy(&text[idx], argv[i], argSize[i]); + idx += argSize[i]; + } + + assert(idx == totalTextSize); + + text[idx++] = '\0'; + + assert(strlen(text) == totalTextSize); + + *textP = text; + *textSizeP = totalTextSize; + + free(argSize); +} + + - text = strdup(""); - totalTextSize = 1; +static void +buildTextFromArgs(int const argc, + const char ** const argv, + const char ** const inputTextP, + enum InputFmt const inputFmt) { +/*---------------------------------------------------------------------------- + Build the string of text to be included in the Postscript program to be + rendered, from the arguments of this program. + + We encode it in either ASCII-Hex or ASCII-85 as opposed to using the plain + text from the command line because 1) the command line might have + Postscript control characters in it; and 2) the command line might have + text in 8-bit or multibyte code, but a Postscript program is supposed to be + entirely printable ASCII characters. + + Official Postscript specifications have a limit on the length of a program + line, which means there is a limit on the length of text string such as we + generate. But we don't worry about that because Ghostscript actually + accepts very long program lines. +-----------------------------------------------------------------------------*/ + const char * text; + /* All the arguments ('argv') concatenated */ + unsigned int textSize; + /* Length of 'text' */ if (argc-1 < 1) pm_error("No text"); - for (i = 1; i < argc; ++i) { - if (i > 1) { - totalTextSize += 1; - text = realloc(text, totalTextSize); - if (text == NULL) - pm_error("out of memory"); - strcat(text, " "); - } - totalTextSize += strlen(argv[i]); - text = realloc(text, totalTextSize); - if (text == NULL) - pm_error("out of memory"); - strcat(text, argv[i]); - } + combineArgs(argc, argv, &text, &textSize); - { + switch (inputFmt) { + case INPUT_LITERAL: { char * asciiHexText; - MALLOCARRAY(asciiHexText, totalTextSize * 2); - + MALLOCARRAY(asciiHexText, textSize * 2 + 3); if (!asciiHexText) pm_error("Unable to allocate memory for hex encoding of %u " - "characters of text", totalTextSize); + "characters of text", textSize); asciiHexEncode(text, asciiHexText); - *asciiHexTextP = asciiHexText; + *inputTextP = asciiHexText; + } break; + case INPUT_ASCIIHEX: { + char * asciiHexText; + + MALLOCARRAY(asciiHexText, textSize + 3); + if (!asciiHexText) + pm_error("Unable to allocate memory for hex encoding of %u " + "characters of text", textSize); + + formatAsciiHexString(text, asciiHexText, textSize); + *inputTextP = asciiHexText; + } break; + case INPUT_ASCII85: { + char * ascii85Text; + + MALLOCARRAY(ascii85Text, textSize + 5); + if (!ascii85Text) + pm_error("Unable to allocate memory for hex encoding of %u " + "characters of text", textSize); + + formatAscii85String(text, ascii85Text, textSize); + *inputTextP = ascii85Text; + } break; } + pm_strfree(text); } @@ -155,20 +449,23 @@ struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - unsigned int res; - float fontsize; - const char * font; - float stroke; - float ascent; - float descent; - float leftmargin; - float rightmargin; - float topmargin; - float bottommargin; - unsigned int pad; - unsigned int verbose; - unsigned int dump; - const char * text; + unsigned int res; + float fontsize; + const char * font; + float stroke; + float ascent; + float descent; + float leftmargin; + float rightmargin; + float topmargin; + float bottommargin; + unsigned int pad; + unsigned int verbose; + unsigned int dump; + const char * text; + /* Text to render, in Postscript format, either Ascii-hex + (e.g. <313233>) or Ascii-85 (e.g. <~aBc-~>) + */ }; @@ -189,6 +486,7 @@ parseCommandLine(int argc, const char ** argv, unsigned int cropSpec, ascentSpec, descentSpec; unsigned int leftmarginSpec, rightmarginSpec; unsigned int topmarginSpec, bottommarginSpec; + unsigned int asciihexSpec, ascii85Spec; MALLOCARRAY_NOFAIL(option_def, 100); @@ -217,6 +515,10 @@ parseCommandLine(int argc, const char ** argv, NULL, &cropSpec, 0); OPTENT3(0, "pad", OPT_FLAG, NULL, &cmdlineP->pad, 0); + OPTENT3(0, "asciihex", OPT_FLAG, + NULL, &asciihexSpec, 0); + OPTENT3(0, "ascii85", OPT_FLAG, + NULL, &ascii85Spec, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "dump-ps", OPT_FLAG, @@ -233,8 +535,6 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->leftmargin = 0; cmdlineP->topmargin = 0; cmdlineP->bottommargin = 0; - cropSpec = FALSE; - cmdlineP->pad = FALSE; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -244,6 +544,8 @@ parseCommandLine(int argc, const char ** argv, validateFontName(cmdlineP->font); + if (cmdlineP->res <= 0) + pm_error("-resolution must be positive"); if (cmdlineP->fontsize <= 0) pm_error("-fontsize must be positive"); if (cmdlineP->ascent < 0) @@ -259,7 +561,7 @@ parseCommandLine(int argc, const char ** argv, if (cmdlineP->bottommargin <0) pm_error("-bottommargin must not be negative"); - if (cropSpec == TRUE) { + if (cropSpec) { if (ascentSpec || descentSpec || leftmarginSpec || rightmarginSpec || topmarginSpec || bottommarginSpec || @@ -275,8 +577,24 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->leftmargin = cmdlineP->fontsize / 2; } - buildTextFromArgs(argc, argv, &cmdlineP->text); + { + enum InputFmt inputFmt; + + if (asciihexSpec) { + if (ascii85Spec) + pm_error("You cannot specify both -asciihex and -ascii85"); + else + inputFmt = INPUT_ASCIIHEX; + } else if (ascii85Spec) + inputFmt = INPUT_ASCII85; + else + inputFmt = INPUT_LITERAL; + + if (argc-1 < 1) + pm_error("No text"); + buildTextFromArgs(argc, argv, &cmdlineP->text, inputFmt); + } free(option_def); } @@ -325,7 +643,7 @@ postscriptProgram(struct CmdlineInfo const cmdline) { "/FindFont {/%s findfont} def\n" "/fontsize %f def\n" "/pensize %f def\n" - "/textstring <%s> def\n" + "/textstring %s def\n" "/ascent %f def\n" "/descent %f def\n" "/leftmargin %f def\n" @@ -386,6 +704,13 @@ postscriptProgram(struct CmdlineInfo const cmdline) { const char * retval; const char * psVariable; + /* According to Adobe, maximum line length in a Postscript program is + 255 characters excluding the newline. The following may generated a + line longer than that if 'cmdline.text' or 'cmdline.font' is long. + However, Ghostscript accepts much longer lines, so we don't worry + about that. + */ + pm_asprintf(&psVariable, psTemplate, cmdline.font, cmdline.fontsize, cmdline.stroke, cmdline.text, cmdline.ascent, cmdline.descent, @@ -413,11 +738,8 @@ gsArgList(const char * const outputFilename, const char ** retval; unsigned int argCt; /* Number of arguments in 'retval' so far */ - if (cmdline.res <= 0) - pm_error("Resolution (dpi) must be positive."); - - if (cmdline.fontsize <= 0) - pm_error("Font size must be positive."); + assert(cmdline.res > 0); + assert(cmdline.fontsize > 0); MALLOCARRAY_NOFAIL(retval, maxArgCt+2); diff --git a/generator/pbmupc.c b/generator/pbmupc.c index 6ef75654..28ccffb7 100644 --- a/generator/pbmupc.c +++ b/generator/pbmupc.c @@ -26,146 +26,29 @@ #define SHORT_HEIGHT ( 8 * LINES_WIDTH ) #define TALL_HEIGHT ( SHORT_HEIGHT + DIGIT_HEIGHT / 2 ) -static int alldig ARGS(( char* cp )); -static void putdigit ARGS(( int d, bit** bits, int row0, int col0 )); -static int addlines ARGS(( int d, bit** bits, int row0, int col0, int height, bit color )); -static int rect ARGS(( bit** bits, int row0, int col0, int height, int width, bit color )); -int -main( argc, argv ) - int argc; - char* argv[]; - { - register bit** bits; - int argn, style, rows, cols, row, digrow, col, digcolofs; - char* typecode; - char* manufcode; - char* prodcode; - int sum, p, lc0, lc1, lc2, lc3, lc4, rc0, rc1, rc2, rc3, rc4; - const char* const usage = "[-s1|-s2] <type> <manufac> <product>"; +static int +alldig(const char * const cp) { - pbm_init( &argc, argv ); - - argn = 1; - style = 1; - - /* Check for flags. */ - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-s1", 3 ) ) - style = 1; - else if ( pm_keymatch( argv[argn], "-s2", 3 ) ) - style = 2; - else - pm_usage( usage ); - argn++; - } - - if ( argn + 3 < argc ) - pm_usage( usage ); - typecode = argv[argn]; - manufcode = argv[argn + 1]; - prodcode = argv[argn + 2]; - argn += 3; - - if ( argn != argc ) - pm_usage( usage ); + unsigned int i; - if ( strlen( typecode ) != 1 || ( ! alldig( typecode ) ) || - strlen( manufcode ) != 5 || ( ! alldig ( manufcode ) ) || - strlen( prodcode ) != 5 || ( ! alldig ( prodcode ) ) ) - pm_error( - "type code must be one digit, and\n manufacturer and product codes must be five digits" ); - p = typecode[0] - '0'; - lc0 = manufcode[0] - '0'; - lc1 = manufcode[1] - '0'; - lc2 = manufcode[2] - '0'; - lc3 = manufcode[3] - '0'; - lc4 = manufcode[4] - '0'; - rc0 = prodcode[0] - '0'; - rc1 = prodcode[1] - '0'; - rc2 = prodcode[2] - '0'; - rc3 = prodcode[3] - '0'; - rc4 = prodcode[4] - '0'; - sum = ( 10 - ( ( ( p + lc1 + lc3 + rc0 + rc2 + rc4 ) * 3 + lc0 + lc2 + lc4 + rc1 + rc3 ) % 10 ) ) % 10; + for (i = 0; cp[i] != '\0'; ++i) + if (cp[i] < '0' || cp[i] > '9') + return 0; - rows = 2 * MARGIN + SHORT_HEIGHT + DIGIT_HEIGHT; - cols = 2 * MARGIN + 12 * LINES_WIDTH + 11 * LINE1_WIDTH; - bits = pbm_allocarray( cols, rows ); + return 1; +} - (void) rect( bits, 0, 0, rows, cols, PBM_WHITE ); - - row = MARGIN; - digrow = row + SHORT_HEIGHT; - col = MARGIN; - digcolofs = ( LINES_WIDTH - DIGIT_WIDTH ) / 2; - - if ( style == 1 ) - putdigit( p, bits, digrow, col - DIGIT_WIDTH - LINE1_WIDTH ); - else if ( style == 2 ) - putdigit( - p, bits, row + SHORT_HEIGHT / 2, col - DIGIT_WIDTH - LINE1_WIDTH ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - col = addlines( p, bits, row, col, TALL_HEIGHT, PBM_WHITE ); - putdigit( lc0, bits, digrow, col + digcolofs ); - col = addlines( lc0, bits, row, col, SHORT_HEIGHT, PBM_WHITE ); - putdigit( lc1, bits, digrow, col + digcolofs ); - col = addlines( lc1, bits, row, col, SHORT_HEIGHT, PBM_WHITE ); - putdigit( lc2, bits, digrow, col + digcolofs ); - col = addlines( lc2, bits, row, col, SHORT_HEIGHT, PBM_WHITE ); - putdigit( lc3, bits, digrow, col + digcolofs ); - col = addlines( lc3, bits, row, col, SHORT_HEIGHT, PBM_WHITE ); - putdigit( lc4, bits, digrow, col + digcolofs ); - col = addlines( lc4, bits, row, col, SHORT_HEIGHT, PBM_WHITE ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE ); - putdigit( rc0, bits, digrow, col + digcolofs ); - col = addlines( rc0, bits, row, col, SHORT_HEIGHT, PBM_BLACK ); - putdigit( rc1, bits, digrow, col + digcolofs ); - col = addlines( rc1, bits, row, col, SHORT_HEIGHT, PBM_BLACK ); - putdigit( rc2, bits, digrow, col + digcolofs ); - col = addlines( rc2, bits, row, col, SHORT_HEIGHT, PBM_BLACK ); - putdigit( rc3, bits, digrow, col + digcolofs ); - col = addlines( rc3, bits, row, col, SHORT_HEIGHT, PBM_BLACK ); - putdigit( rc4, bits, digrow, col + digcolofs ); - col = addlines( rc4, bits, row, col, SHORT_HEIGHT, PBM_BLACK ); - col = addlines( sum, bits, row, col, TALL_HEIGHT, PBM_BLACK ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE ); - col = rect( bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK ); - if ( style == 1 ) - putdigit( sum, bits, digrow, col + LINE1_WIDTH ); - - pbm_writepbm( stdout, bits, cols, rows, 0 ); - pm_close( stdout ); - - exit( 0 ); - } -static int -alldig( cp ) - char* cp; - { - for ( ; *cp != '\0'; cp++ ) - if ( *cp < '0' || *cp > '9' ) - return 0; - return 1; - } static void -putdigit( d, bits, row0, col0 ) - int d; - bit** bits; - int row0, col0; - { - int row, col; - static bit digits[10][DIGIT_HEIGHT][DIGIT_WIDTH] = { +putDigit(int const d, + bit ** const bits, + unsigned int const row0, + unsigned int const col0) { + + static bit const digits[10][DIGIT_HEIGHT][DIGIT_WIDTH] = { /* 0 */ { {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -399,7 +282,7 @@ putdigit( d, bits, row0, col0 ) {0,0,0,1,1,1,1,1,1,1,1,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0} - }, + }, /* 9 */ { {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -425,103 +308,255 @@ putdigit( d, bits, row0, col0 ) {0,0,0,0,0,1,1,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0} - } + } }; - for ( row = 0; row < DIGIT_HEIGHT; row++ ) - for ( col = 0; col < DIGIT_WIDTH; col++ ) - bits[row0 + row][col0 + col] = digits[d][row][col]; - } + unsigned int row; -static int -addlines( int d, bit** bits, int row0, int col0, int height, bit color ) - { - switch ( d ) - { - case 0: - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - break; - - case 1: - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - break; - - case 2: - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - break; - - case 3: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE4_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - break; - - case 4: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - break; - - case 5: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - break; - - case 6: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE4_WIDTH, 1 - color ); - break; - - case 7: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - break; - - case 8: - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, 1 - color ); - break; - - case 9: - col0 = rect( bits, row0, col0, height, LINE3_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, 1 - color ); - col0 = rect( bits, row0, col0, height, LINE1_WIDTH, color ); - col0 = rect( bits, row0, col0, height, LINE2_WIDTH, 1 - color ); - break; - - default: - pm_error( "can't happen" ); - } + for (row = 0; row < DIGIT_HEIGHT; ++row) { + unsigned int col; - return col0; + for (col = 0; col < DIGIT_WIDTH; ++col) + bits[row0 + row][col0 + col] = digits[d][row][col]; } +} -static int -rect( bit** bits, int row0, int col0, int height, int width, bit color ) - { - int row, col; - for ( row = row0; row < row0 + height; row++ ) - for ( col = col0; col < col0 + width; col++ ) - bits[row][col] = color; + +static unsigned int +rect(bit ** const bits, + unsigned int const row0, + unsigned int const col0, + unsigned int const height, + unsigned int const width, + bit const color) { + + unsigned int row; + + for (row = row0; row < row0 + height; ++row) { + unsigned int col; + + for (col = col0; col < col0 + width; ++col) + bits[row][col] = color; + } return col0 + width; +} + + + +static unsigned int +addLines(int const d, + bit ** const bits, + unsigned int const row0, + unsigned int const startCol, + unsigned int const height, + bit const color) { + + unsigned int col0; + + col0 = startCol; /* initial value */ + + switch (d) { + case 0: + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + break; + + case 1: + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + break; + + case 2: + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + break; + + case 3: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE4_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + break; + + case 4: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + break; + + case 5: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + break; + + case 6: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE4_WIDTH, 1 - color); + break; + + case 7: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + break; + + case 8: + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, 1 - color); + break; + + case 9: + col0 = rect(bits, row0, col0, height, LINE3_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, 1 - color); + col0 = rect(bits, row0, col0, height, LINE1_WIDTH, color); + col0 = rect(bits, row0, col0, height, LINE2_WIDTH, 1 - color); + break; + + default: + pm_error("INTERNAL ERROR: invalid digit passed to 'addlines'"); } + + return col0; +} + + + +int +main(int argc, const char ** argv) { + + const char* const usage = "[-s1|-s2] <type> <manufac> <product>"; + + bit ** bits; + int argn, style, rows, cols, row, digrow, col, digcolofs; + const char * typecode; + const char * manufcode; + const char * prodcode; + int sum, p, lc0, lc1, lc2, lc3, lc4, rc0, rc1, rc2, rc3, rc4; + + pm_proginit(&argc, argv); + + argn = 1; + style = 1; + + /* Check for flags. */ + while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) + { + if ( pm_keymatch( argv[argn], "-s1", 3 ) ) + style = 1; + else if ( pm_keymatch( argv[argn], "-s2", 3 ) ) + style = 2; + else + pm_usage( usage ); + argn++; + } + + if ( argn + 3 < argc ) + pm_usage( usage ); + typecode = argv[argn]; + manufcode = argv[argn + 1]; + prodcode = argv[argn + 2]; + argn += 3; + + if ( argn != argc ) + pm_usage( usage ); + + if ( strlen( typecode ) != 1 || ( ! alldig( typecode ) ) || + strlen( manufcode ) != 5 || ( ! alldig ( manufcode ) ) || + strlen( prodcode ) != 5 || ( ! alldig ( prodcode ) ) ) + pm_error( + "type code must be one digit, and\n manufacturer and product codes must be five digits" ); + p = typecode[0] - '0'; + lc0 = manufcode[0] - '0'; + lc1 = manufcode[1] - '0'; + lc2 = manufcode[2] - '0'; + lc3 = manufcode[3] - '0'; + lc4 = manufcode[4] - '0'; + rc0 = prodcode[0] - '0'; + rc1 = prodcode[1] - '0'; + rc2 = prodcode[2] - '0'; + rc3 = prodcode[3] - '0'; + rc4 = prodcode[4] - '0'; + sum = (10 - + (((p + lc1 + lc3 + rc0 + rc2 + rc4 ) * 3 + + lc0 + lc2 + lc4 + rc1 + rc3) + % 10) + ) + % 10; + + rows = 2 * MARGIN + SHORT_HEIGHT + DIGIT_HEIGHT; + cols = 2 * MARGIN + 12 * LINES_WIDTH + 11 * LINE1_WIDTH; + bits = pbm_allocarray(cols, rows); + + rect(bits, 0, 0, rows, cols, PBM_WHITE); + + row = MARGIN; + digrow = row + SHORT_HEIGHT; + col = MARGIN; + digcolofs = (LINES_WIDTH - DIGIT_WIDTH) / 2; + + if (style == 1) + putDigit(p, bits, digrow, col - DIGIT_WIDTH - LINE1_WIDTH); + else if (style == 2) + putDigit( + p, bits, row + SHORT_HEIGHT / 2, col - DIGIT_WIDTH - LINE1_WIDTH); + + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + col = addLines(p, bits, row, col, TALL_HEIGHT, PBM_WHITE); + putDigit(lc0, bits, digrow, col + digcolofs); + col = addLines(lc0, bits, row, col, SHORT_HEIGHT, PBM_WHITE); + putDigit(lc1, bits, digrow, col + digcolofs); + col = addLines(lc1, bits, row, col, SHORT_HEIGHT, PBM_WHITE); + putDigit(lc2, bits, digrow, col + digcolofs); + col = addLines(lc2, bits, row, col, SHORT_HEIGHT, PBM_WHITE); + putDigit(lc3, bits, digrow, col + digcolofs); + col = addLines(lc3, bits, row, col, SHORT_HEIGHT, PBM_WHITE); + putDigit(lc4, bits, digrow, col + digcolofs); + col = addLines(lc4, bits, row, col, SHORT_HEIGHT, PBM_WHITE); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE); + putDigit(rc0, bits, digrow, col + digcolofs); + col = addLines(rc0, bits, row, col, SHORT_HEIGHT, PBM_BLACK); + putDigit(rc1, bits, digrow, col + digcolofs); + col = addLines(rc1, bits, row, col, SHORT_HEIGHT, PBM_BLACK); + putDigit(rc2, bits, digrow, col + digcolofs); + col = addLines(rc2, bits, row, col, SHORT_HEIGHT, PBM_BLACK); + putDigit(rc3, bits, digrow, col + digcolofs); + col = addLines(rc3, bits, row, col, SHORT_HEIGHT, PBM_BLACK); + putDigit(rc4, bits, digrow, col + digcolofs); + col = addLines(rc4, bits, row, col, SHORT_HEIGHT, PBM_BLACK); + col = addLines(sum, bits, row, col, TALL_HEIGHT, PBM_BLACK); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_WHITE); + col = rect(bits, row, col, TALL_HEIGHT, LINE1_WIDTH, PBM_BLACK); + if (style == 1) + putDigit(sum, bits, digrow, col + LINE1_WIDTH); + + pbm_writepbm(stdout, bits, cols, rows, 0); + + pm_close(stdout ); + + exit(0); +} + + + diff --git a/generator/pgmcrater b/generator/pgmcrater index c66f5576..6d81df39 100755 --- a/generator/pgmcrater +++ b/generator/pgmcrater @@ -36,6 +36,16 @@ exec perl -w -x -S -- "$0" "$@" use strict; use Getopt::Long; +use IO::Handle; + + + +sub pm_message($) { + STDERR->print("pgmcrater: $_[0]\n"); +} + + + sub doVersionHack($) { my ($argvR) = @_; @@ -69,7 +79,7 @@ my $validOptions = GetOptions( 'randomseed=i' => \my $randomseedOpt); if (!$validOptions) { - print STDERR "Invalid syntax\n"; + pm_message("Invalid syntax"); exit(100); } diff --git a/generator/pgmkernel.c b/generator/pgmkernel.c index 37072c38..8d99a76d 100644 --- a/generator/pgmkernel.c +++ b/generator/pgmkernel.c @@ -20,7 +20,7 @@ #include "shhopt.h" #include "mallocvar.h" #include "pgm.h" - +#include "nstring.h" struct CmdlineInfo { @@ -39,11 +39,11 @@ static void parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- - Convert program invocation arguments (argc,argv) into a format the + 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 + Note that some string information we return as *cmdlineP is in the storage argv[] points to. -----------------------------------------------------------------------------*/ optEntry *option_def; @@ -57,9 +57,9 @@ parseCommandLine(int argc, const char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "weight", OPT_FLOAT, &cmdlineP->weight, + OPTENT3(0, "weight", OPT_FLOAT, &cmdlineP->weight, &weightSpec, 0); - OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, &maxvalSpec, 0); opt.opt_table = option_def; @@ -89,20 +89,30 @@ parseCommandLine(int argc, const char ** argv, if (argc-1 < 1) pm_error("Need at least one argument: size of (square) kernel"); else if (argc-1 == 1) { - if (atoi(argv[1]) <= 0) + unsigned int dimension; + const char * error; + + pm_string_to_uint(argv[1], &dimension, &error); + if (error) { + pm_error("'%s' is invalid as an image width/height. %s", argv[1], error); + pm_strfree(error); + } + if (dimension <= 0) pm_error("Dimension must be a positive number. " "You specified '%s'", argv[1]); - cmdlineP->cols = atoi(argv[1]); - cmdlineP->rows = atoi(argv[1]); + cmdlineP->cols = cmdlineP->rows = dimension; + } else if (argc-1 == 2) { - if (atoi(argv[1]) <= 0) + unsigned int const width = pm_parse_width(argv[1]); + unsigned int const height = pm_parse_height(argv[2]); + if (width <= 0) pm_error("Width must be a positive number. " "You specified '%s'", argv[1]); - if (atoi(argv[2]) <= 0) + if (height <= 0) pm_error("Height must be a positive number. " "You specified '%s'", argv[2]); - cmdlineP->cols = atoi(argv[1]); - cmdlineP->rows = atoi(argv[2]); + cmdlineP->cols = width; + cmdlineP->rows = height; } else pm_error("At most two arguments allowed. " "You specified %u", argc-1); @@ -243,3 +253,6 @@ main(int argc, const char * argv[]) { return 0; } + + + diff --git a/generator/pgmmake.c b/generator/pgmmake.c index ae706639..6fd8d426 100644 --- a/generator/pgmmake.c +++ b/generator/pgmmake.c @@ -52,11 +52,11 @@ static void parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- - Convert program invocation arguments (argc,argv) into a format the + 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 + Note that some string information we return as *cmdlineP is in the storage argv[] points to. -----------------------------------------------------------------------------*/ optEntry * option_def; diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c index e3e4eca6..ea35956b 100644 --- a/generator/pgmnoise.c +++ b/generator/pgmnoise.c @@ -7,12 +7,17 @@ #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" +#include "rand.h" #include "shhopt.h" #include "pgm.h" +/* constants */ +static unsigned long int const ceil31bits = 0x7fffffffUL; +static unsigned long int const ceil32bits = 0xffffffffUL; -struct cmdlineInfo { + +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -21,13 +26,15 @@ struct cmdlineInfo { unsigned int maxval; unsigned int randomseed; unsigned int randomseedSpec; + unsigned int verbose; }; static void -parseCommandLine(int argc, const char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, + const char ** const argv, + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -46,6 +53,8 @@ parseCommandLine(int argc, const char ** const argv, &cmdlineP->randomseedSpec, 0); OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, &maxvalSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -57,7 +66,7 @@ parseCommandLine(int argc, const char ** const argv, if (maxvalSpec) { if (cmdlineP->maxval > PGM_OVERALLMAXVAL) - pm_error("Maxval too large: %u. Maximu is %u", + pm_error("Maxval too large: %u. Maximum is %u", cmdlineP->maxval, PGM_OVERALLMAXVAL); else if (cmdlineP->maxval == 0) pm_error("Maxval must not be zero"); @@ -95,38 +104,43 @@ parseCommandLine(int argc, const char ** const argv, static unsigned int -randPool(unsigned int const digits) { +randPool(unsigned int const nDigits, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- - Draw 'digits' bits from pool of random bits. If the number of random bits - in pool is insufficient, call rand() and add 31 bits to it. + Draw 'nDigits' bits from pool of random bits. If the number of random bits + in pool is insufficient, call pm_rand() and add N bits to it. + + N is 31 or 32. In raw mode we use N = 32 regardless of the actual number of + available bits. If there are only 31 available, we use zero for the MSB. - 'digits' must be at most 16. + 'nDigits' must be at most 16. - We assume that each call to rand() generates 31 bits, or RAND_MAX == - 2147483647. + We assume that each call to pm_rand() generates 31 or 32 bits, or + randStP->max == 2147483647 or 4294967295. - The underlying logic is flexible and endian-free. The above conditions - can be relaxed. + The underlying logic is flexible and endian-free. The above conditions can + be relaxed. -----------------------------------------------------------------------------*/ static unsigned long int hold=0; /* entropy pool */ static unsigned int len=0; /* number of valid bits in pool */ - unsigned int const mask = (1 << digits) - 1; - + unsigned int const mask = (1 << nDigits) - 1; + unsigned int const randbits = (randStP->max == ceil31bits) ? 31 : 32; unsigned int retval; - assert(RAND_MAX == 2147483647 && digits <= 16); + assert(randStP->max == ceil31bits || randStP->max == ceil32bits); + assert(nDigits <= 16); retval = hold; /* initial value */ - if (len > digits) { /* Enough bits in hold to satisfy request */ - hold >>= digits; - len -= digits; - } else { /* Load another 31 bits into hold */ - hold = rand(); + if (len > nDigits) { /* Enough bits in hold to satisfy request */ + hold >>= nDigits; + len -= nDigits; + } else { /* Load another 31 or 32 bits into hold */ + hold = pm_rand(randStP); retval |= (hold << len); - hold >>= (digits - len); - len = 31 - digits + len; + hold >>= (nDigits - len); + len = randbits - nDigits + len; } return (retval & mask); } @@ -134,36 +148,61 @@ randPool(unsigned int const digits) { static void -pgmnoise(FILE * const ofP, - unsigned int const cols, - unsigned int const rows, - gray const maxval) { +reportVerbose(struct pm_randSt * const randStP, + gray const maxval, + bool const usingPool) { + + pm_message("random seed: %u", randStP->seed); + pm_message("random max: %u maxval: %u", randStP->max, maxval); + pm_message("method: %s", usingPool ? "pool" : "modulo"); +} + + - bool const usingPool = !(RAND_MAX==2147483647 && (maxval & (maxval+1))); +static void +pgmnoise(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + gray const maxval, + bool const verbose, + struct pm_randSt * const randStP) { + + bool const usingPool = + (randStP->max==ceil31bits || randStP->max==ceil32bits) && + !(maxval & (maxval+1)); unsigned int const bitLen = pm_maxvaltobits(maxval); unsigned int row; gray * destrow; /* If maxval is 2^n-1, we draw exactly n bits from the pool. - Otherwise call rand() and determine gray value by modulo. + Otherwise call pm_rand() and determine gray value by modulo. In the latter case, there is a minuscule skew toward 0 (=black) because smaller numbers are produced more frequently by modulo. Thus we employ the pool method only when it is certain that no - skew will ensue. + skew will result. To illustrate the point, consider converting the outcome of one roll of a fair, six-sided die to 5 values (0 to 4) by N % 5. The - probability for values 1, 2, 3, 4 are 1/6, but 0 alone is 2/6. + probability for values 1, 2, 3, 4 is 1/6, but 0 alone is 2/6. Average is 10/6 or 1.6667, compared to 2.0 from an ideal generator which produces exactly 5 values. With two dice average improves to 70/36 or 1.9444. The more (distinct) dice we roll, or the more binary digits we draw, the smaller the skew. + + The pool method is economical. But there is an additional merit: + No bits are lost this way. This gives us a means to check the + integrity of the random number generator. + + - Akira Urushibata, March 2021 */ + if (verbose) + reportVerbose(randStP, maxval, usingPool); + destrow = pgm_allocrow(cols); pgm_writepgminit(ofP, cols, rows, maxval, 0); @@ -172,12 +211,11 @@ pgmnoise(FILE * const ofP, if (usingPool) { unsigned int col; for (col = 0; col < cols; ++col) - destrow[col] = randPool(bitLen); - } - else { + destrow[col] = randPool(bitLen, randStP); + } else { unsigned int col; for (col = 0; col < cols; ++col) - destrow[col] = rand() % (maxval + 1); + destrow[col] = pm_rand(randStP) % (maxval + 1); } pgm_writepgmrow(ofP, destrow, cols, maxval, 0); } @@ -191,18 +229,22 @@ int main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; + struct pm_randSt randSt; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + + pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval, + cmdline.verbose, &randSt); - pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval); + pm_randterm(&randSt); return 0; } - diff --git a/generator/ppmcie.c b/generator/ppmcie.c index 86325ba6..26289c3c 100644 --- a/generator/ppmcie.c +++ b/generator/ppmcie.c @@ -26,8 +26,11 @@ Introduced option to plot 1976 u' v' chromaticities. */ +#define _C99_SOURCE /* Make sure snprintf() is in stdio.h */ + #include <assert.h> #include <math.h> +#include <stdio.h> #include "pm_c_util.h" #include "ppm.h" @@ -1114,15 +1117,15 @@ writeLabel(pixel ** const pixels, PPM_ASSIGN(rgbcolor, maxval, maxval, maxval); - pm_snprintf(sysdesc, sizeof(sysdesc), - "System: %s\n" - "Primary illuminants (X, Y)\n" - " Red: %0.4f, %0.4f\n" - " Green: %0.4f, %0.4f\n" - " Blue: %0.4f, %0.4f\n" - "White point (X, Y): %0.4f, %0.4f", - cs->name, cs->xRed, cs->yRed, cs->xGreen, cs->yGreen, - cs->xBlue, cs->yBlue, cs->xWhite, cs->yWhite); + snprintf(sysdesc, sizeof(sysdesc), + "System: %s\n" + "Primary illuminants (X, Y)\n" + " Red: %0.4f, %0.4f\n" + " Green: %0.4f, %0.4f\n" + " Blue: %0.4f, %0.4f\n" + "White point (X, Y): %0.4f, %0.4f", + cs->name, cs->xRed, cs->yRed, cs->xGreen, cs->yGreen, + cs->xBlue, cs->yBlue, cs->xWhite, cs->yWhite); sysdesc[sizeof(sysdesc)-1] = '\0'; /* for robustness */ ppmd_text(pixels, pixcols, pixrows, maxval, diff --git a/generator/ppmcolors.c b/generator/ppmcolors.c index 701812d1..ecbadf72 100644 --- a/generator/ppmcolors.c +++ b/generator/ppmcolors.c @@ -3,7 +3,7 @@ ******************************************************************************* Generate a color map containing all the colors representable with a certain maxval. - + THIS PROGRAM IS OBSOLETE. USE PAMSEQ INSTEAD. WE KEEP THIS AROUND FOR BACKWARD COMPATIBILITY. @@ -18,7 +18,7 @@ struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - unsigned int maxval; + unsigned int maxval; }; @@ -34,9 +34,9 @@ parseCommandLine(int argc, char ** argv, struct cmdlineInfo *cmdlineP) { unsigned int option_def_index; option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "maxval", OPT_UINT, + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, NULL, 0); - + opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -76,7 +76,7 @@ main(int argc, char *argv[]) { rc = system(cmd); - if (rc != 0) + if (rc != 0) pm_error("pamseq|pamtopnm pipeline failed. system() rc = %d", rc); pm_strfree(cmd); diff --git a/generator/ppmforge.c b/generator/ppmforge.c index 114f7f18..e32d2b59 100644 --- a/generator/ppmforge.c +++ b/generator/ppmforge.c @@ -34,12 +34,14 @@ #define _XOPEN_SOURCE 500 /* get M_PI in math.h */ #include <math.h> +#include <float.h> #include <assert.h> #include "pm_c_util.h" -#include "ppm.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" +#include "ppm.h" static double const hugeVal = 1e50; @@ -59,12 +61,8 @@ typedef struct { /* Definition for obtaining random numbers. */ -#define nrand 4 /* Gauss() sample count */ -#define Cast(low, high) ((low)+(((high)-(low)) * ((rand() & 0x7FFF) / arand))) - /* Local variables */ -static double arand, gaussadd, gaussfac; /* Gaussian random parameters */ static double fracdim; /* Fractal dimension */ static double powscale; /* Power law scaling exponent */ static int meshsize = 256; /* FFT mesh size */ @@ -92,6 +90,7 @@ struct CmdlineInfo { float ice; int saturation; unsigned int seed; + unsigned int seedSpec; int stars; unsigned int starsSpec; unsigned int width; @@ -172,6 +171,11 @@ parseCommandLine(int argc, const char **argv, if (cmdlineP->dimension <= 0.0) pm_error("-dimension must be greater than zero. " "You specified %f", cmdlineP->dimension); + else if (cmdlineP->dimension > 5.0 + FLT_EPSILON) + pm_error("-dimension must not be greater than 5. " + "Results are not interesting with higher numbers, so " + "we assume it is a mistake. " + "You specified %f", cmdlineP->dimension); } else cmdlineP->dimension = cmdlineP->clouds ? 2.15 : 2.4; @@ -238,7 +242,7 @@ parseCommandLine(int argc, const char **argv, static void -fourn(float * const data, +fourn(double * const data, const int * const nn, int const ndim, int const isign) { @@ -269,7 +273,7 @@ fourn(float * const data, int i1, i2, i3; int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2; int ibit, idim, k1, k2, n, nprev, nrem, ntot; - float tempi, tempr; + double tempi, tempr; double theta, wi, wpi, wpr, wr, wtemp; #define SWAP(a,b) tempr=(a); (a) = (b); (b) = tempr @@ -332,72 +336,64 @@ fourn(float * const data, nprev *= n; } } -#undef SWAP -static void -initgauss(unsigned int const seed) { +static double +cast(double const low, + double const high, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- - Initialize random number generators. - - As given in Peitgen & Saupe, page 77. + A random number in the range ['low', 'high']. -----------------------------------------------------------------------------*/ - /* Range of random generator */ - arand = pow(2.0, 15.0) - 1.0; - gaussadd = sqrt(3.0 * nrand); - gaussfac = 2 * gaussadd / (nrand * arand); - srand(seed); + return (low + (high - low) * pm_drand(randStP)); + } static double -gauss() { +randPhase(struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- - A Gaussian random number. - - As given in Peitgen & Saupe, page 77. + A random number in the range [0, 2 * PI). -----------------------------------------------------------------------------*/ - int i; - double sum; + return (2.0 * M_PI * pm_drand1(randStP)); - for (i = 1, sum = 0.0; i <= nrand; ++i) { - sum += (rand() & 0x7FFF); - } - return gaussfac * sum - gaussadd; } static void -spectralsynth(float ** const x, - unsigned int const n, - double const h) { +spectralsynth(double ** const aP, + unsigned int const n, + double const h, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Spectrally synthesized fractal motion in two dimensions. This algorithm is given under the name SpectralSynthesisFM2D on page 108 of Peitgen & Saupe. -----------------------------------------------------------------------------*/ - unsigned bl; + unsigned int const bl = ((((unsigned long) n) * n) + 1) * 2; + int i, j, i0, j0, nsize[3]; double rad, phase, rcos, rsin; - float *a; + double * a; + + MALLOCARRAY(a, bl); - bl = ((((unsigned long) n) * n) + 1) * 2 * sizeof(float); - a = (float *) calloc(bl, 1); - if (a == (float *) 0) { - pm_error("Cannot allocate %d x %d result array (% d bytes).", + if (!a) { + pm_error("Cannot allocate %u x %u result array (%u doubles).", n, n, bl); } - *x = a; + for (i = 0; i < bl; ++i) + a[i] = 0.0; /* initial value */ for (i = 0; i <= n / 2; i++) { for (j = 0; j <= n / 2; j++) { - phase = 2 * M_PI * ((rand() & 0x7FFF) / arand); + phase = randPhase(randStP); if (i != 0 || j != 0) { - rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(); + rad = pow( (double) (i*i + j*j), - (h + 1) / 2) * pm_gaussrand(randStP); } else { rad = 0; } @@ -416,8 +412,8 @@ spectralsynth(float ** const x, Imag(a, n / 2, n / 2) = 0; for (i = 1; i <= n / 2 - 1; i++) { for (j = 1; j <= n / 2 - 1; j++) { - phase = 2 * M_PI * ((rand() & 0x7FFF) / arand); - rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(); + phase = randPhase(randStP); + rad = pow((double) (i * i + j * j), -(h + 1) / 2) * pm_gaussrand(randStP); rcos = rad * cos(phase); rsin = rad * sin(phase); Real(a, i, n - j) = rcos; @@ -430,6 +426,8 @@ spectralsynth(float ** const x, nsize[0] = 0; nsize[1] = nsize[2] = n; /* Dimension of frequency domain array */ fourn(a, nsize, 2, -1); /* Take inverse 2D Fourier transform */ + + *aP = a; } @@ -469,22 +467,22 @@ temprgb(double const temp, static void -etoile(pixel * const pix) { +etoile(pixel * const pix, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Set a pixel in the starry sky. -----------------------------------------------------------------------------*/ - if ((rand() % 1000) < starfraction) { -#define StarQuality 0.5 /* Brightness distribution exponent */ -#define StarIntensity 8 /* Brightness scale factor */ -#define StarTintExp 0.5 /* Tint distribution exponent */ - double v = StarIntensity * pow(1 / (1 - Cast(0, 0.9999)), - (double) StarQuality), - temp, - r, g, b; - - if (v > 255) { - v = 255; - } + if ((pm_rand(randStP) % 1000) < starfraction) { + double const starQuality = 0.5; + /* Brightness distribution exponent */ + double const starIntensity = 8; + /* Brightness scale factor */ + double const starTintExp = 0.5; + /* Tint distribution exponent */ + double const v = + MIN(255.0, + starIntensity * pow(1 / (1 - cast(0, 0.9999, randStP)), + (double) starQuality)); /* We make a special case for star color of zero in order to prevent floating point roundoff which would otherwise @@ -493,13 +491,17 @@ etoile(pixel * const pix) { 256 shades in the image. */ if (starcolor == 0) { - int vi = v; + pixval const vi = v; PPM_ASSIGN(*pix, vi, vi, vi); } else { + double temp; + double r, g, b; + temp = 5500 + starcolor * - pow(1 / (1 - Cast(0, 0.9999)), StarTintExp) * - ((rand() & 7) ? -1 : 1); + pow(1 / (1 - cast(0, 0.9999, randStP)), starTintExp) * + ((pm_rand(randStP) & 7) ? -1 : 1); + /* Constrain temperature to a reasonable value: >= 2600K (S Cephei/R Andromedae), <= 28,000 (Spica). */ temp = MAX(2600, MIN(28000, temp)); @@ -535,9 +537,9 @@ atSat(double const x, static unsigned char * -makeCp(float * const a, - unsigned int const n, - pixval const maxval) { +makeCp(const double * const a, + unsigned int const n, + pixval const maxval) { /* Prescale the grid points into intensities. */ @@ -550,7 +552,7 @@ makeCp(float * const a, if (cp == NULL) pm_error("Unable to allocate %u bytes for cp array", n); - ap = cp; + ap = cp; /* initial value */ { unsigned int i; for (i = 0; i < n; i++) { @@ -565,17 +567,18 @@ makeCp(float * const a, static void -createPlanetStuff(bool const clouds, - float * const a, - unsigned int const n, - double ** const uP, - double ** const u1P, - unsigned int ** const bxfP, - unsigned int ** const bxcP, - unsigned char ** const cpP, - Vector * const sunvecP, - unsigned int const cols, - pixval const maxval) { +createPlanetStuff(bool const clouds, + const double * const a, + unsigned int const n, + double ** const uP, + double ** const u1P, + unsigned int ** const bxfP, + unsigned int ** const bxcP, + unsigned char ** const cpP, + Vector * const sunvecP, + unsigned int const cols, + pixval const maxval, + struct pm_randSt * const randStP) { double *u, *u1; unsigned int *bxf, *bxc; @@ -585,8 +588,8 @@ createPlanetStuff(bool const clouds, /* Compute incident light direction vector. */ - shang = hourspec ? hourangle : Cast(0, 2 * M_PI); - siang = inclspec ? inclangle : Cast(-M_PI * 0.12, M_PI * 0.12); + shang = hourspec ? hourangle : randPhase(randStP); + siang = inclspec ? inclangle : cast(-M_PI * 0.12, M_PI * 0.12, randStP); sunvecP->x = sin(shang) * cos(siang); sunvecP->y = sin(siang); @@ -594,7 +597,7 @@ createPlanetStuff(bool const clouds, /* Allow only 25% of random pictures to be crescents */ - if (!hourspec && ((rand() % 100) < 75)) { + if (!hourspec && ((pm_rand(randStP) % 100) < 75)) { flipped = (sunvecP->z < 0); sunvecP->z = fabs(sunvecP->z); } else @@ -634,7 +637,7 @@ createPlanetStuff(bool const clouds, pm_error("Cannot allocate %u element interpolation tables.", cols); { unsigned int j; - for (j = 0; j < cols; j++) { + for (j = 0; j < cols; ++j) { double const bx = (n - 1) * uprj(j, cols); bxf[j] = floor(bx); @@ -651,8 +654,9 @@ createPlanetStuff(bool const clouds, static void -generateStarrySkyRow(pixel * const pixels, - unsigned int const cols) { +generateStarrySkyRow(pixel * const pixels, + unsigned int const cols, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Generate a starry sky. Note that no FFT is performed; the output is generated directly from a power law @@ -660,8 +664,8 @@ generateStarrySkyRow(pixel * const pixels, -----------------------------------------------------------------------------*/ unsigned int j; - for (j = 0; j < cols; j++) - etoile(pixels + j); + for (j = 0; j < cols; ++j) + etoile(pixels + j, randStP); } @@ -867,21 +871,22 @@ limbDarken(int * const irP, static void -generatePlanetRow(pixel * const pixelrow, - unsigned int const row, - unsigned int const rows, - unsigned int const cols, - double const t, - double const t1, - double * const u, - double * const u1, - unsigned char * const cp, - unsigned int * const bxc, - unsigned int * const bxf, - int const byc, - int const byf, - Vector const sunvec, - pixval const maxval) { +generatePlanetRow(pixel * const pixelrow, + unsigned int const row, + unsigned int const rows, + unsigned int const cols, + double const t, + double const t1, + double * const u, + double * const u1, + unsigned char * const cp, + unsigned int * const bxc, + unsigned int * const bxf, + int const byc, + int const byf, + Vector const sunvec, + pixval const maxval, + struct pm_randSt * const randStP) { unsigned int const StarClose = 2; @@ -924,24 +929,25 @@ generatePlanetRow(pixel * const pixelrow, /* Left stars */ for (col = 0; (int)col < (int)(cols/2 - (lcos + StarClose)); ++col) - etoile(&pixelrow[col]); + etoile(&pixelrow[col], randStP); /* Right stars */ for (col = cols/2 + (lcos + StarClose); col < cols; ++col) - etoile(&pixelrow[col]); + etoile(&pixelrow[col], randStP); } static void -genplanet(bool const stars, - bool const clouds, - float * const a, - unsigned int const cols, - unsigned int const rows, - unsigned int const n, - unsigned int const rseed) { +genplanet(bool const stars, + bool const clouds, + const double * const a, + unsigned int const cols, + unsigned int const rows, + unsigned int const n, + unsigned int const rseed, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Generate planet from elevation array. @@ -971,13 +977,13 @@ genplanet(bool const stars, clouds ? "clouds" : "planet", rseed, fracdim, powscale, meshsize); createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, - cols, maxval); + cols, maxval, randStP); } pixelrow = ppm_allocrow(cols); for (row = 0; row < rows; ++row) { if (stars) - generateStarrySkyRow(pixelrow, cols); + generateStarrySkyRow(pixelrow, cols, randStP); else { double const by = (n - 1) * uprj(row, rows); int const byf = floor(by) * n; @@ -993,7 +999,8 @@ genplanet(bool const stars, generatePlanetRow(pixelrow, row, rows, cols, t, t1, u, u1, cp, bxc, bxf, byc, byf, sunvec, - maxval); + maxval, + randStP); } ppm_writeppmrow(stdout, pixelrow, cols, maxval, FALSE); } @@ -1010,9 +1017,9 @@ genplanet(bool const stars, static void -applyPowerLawScaling(float * const a, - int const meshsize, - double const powscale) { +applyPowerLawScaling(double * const a, + int const meshsize, + double const powscale) { /* Apply power law scaling if non-unity scale is requested. */ @@ -1023,7 +1030,7 @@ applyPowerLawScaling(float * const a, for (j = 0; j < meshsize; j++) { double const r = Real(a, i, j); if (r > 0) - Real(a, i, j) = pow(r, powscale); + Real(a, i, j) = MIN(hugeVal, pow(r, powscale)); } } } @@ -1032,10 +1039,10 @@ applyPowerLawScaling(float * const a, static void -computeExtremeReal(const float * const a, - int const meshsize, - double * const rminP, - double * const rmaxP) { +computeExtremeReal(const double * const a, + int const meshsize, + double * const rminP, + double * const rmaxP) { /* Compute extrema for autoscaling. */ @@ -1061,8 +1068,8 @@ computeExtremeReal(const float * const a, static void -replaceWithSpread(float * const a, - int const meshsize) { +replaceWithSpread(double * const a, + int const meshsize) { /*---------------------------------------------------------------------------- Replace the real part of each element of the 'a' array with a measure of how far the real is from the middle; sort of a standard @@ -1096,17 +1103,19 @@ planet(unsigned int const cols, /*---------------------------------------------------------------------------- Make a planet. -----------------------------------------------------------------------------*/ - float * a; + double * a; bool error; + struct pm_randSt randSt; - initgauss(rseed); + pm_randinit(&randSt); + pm_srand(&randSt, rseed); if (stars) { a = NULL; error = FALSE; } else { - spectralsynth(&a, meshsize, 3.0 - fracdim); - if (a == NULL) { + spectralsynth(&a, meshsize, 3.0 - fracdim, &randSt); + if (!a) { error = TRUE; } else { applyPowerLawScaling(a, meshsize, powscale); @@ -1117,7 +1126,7 @@ planet(unsigned int const cols, } } if (!error) - genplanet(stars, clouds, a, cols, rows, meshsize, rseed); + genplanet(stars, clouds, a, cols, rows, meshsize, rseed, &randSt); if (a != NULL) free(a); @@ -1159,7 +1168,8 @@ main(int argc, const char ** argv) { cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1); rows = cmdline.height; - success = planet(cols, rows, cmdline.night, cmdline.clouds, cmdline.seed); + success = planet(cols, rows, cmdline.night, + cmdline.clouds, cmdline.seed); exit(success ? 0 : 1); } diff --git a/generator/ppmmake.c b/generator/ppmmake.c index 7bac9601..b1de7b52 100644 --- a/generator/ppmmake.c +++ b/generator/ppmmake.c @@ -31,11 +31,11 @@ static void parseCommandLine(int argc, char ** argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- - Convert program invocation arguments (argc,argv) into a format the + 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 + Note that some string information we return as *cmdlineP is in the storage argv[] points to. -----------------------------------------------------------------------------*/ optEntry * option_def; diff --git a/generator/ppmpat.c b/generator/ppmpat.c index 908c200f..2f71914e 100644 --- a/generator/ppmpat.c +++ b/generator/ppmpat.c @@ -14,7 +14,6 @@ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ /* get M_PI in math.h */ #define _BSD_SOURCE /* Make sure strdup() is in <string.h> */ -#define SPIROGRAPHS 0 /* Spirograph to be added soon */ #include <assert.h> #include <math.h> @@ -23,8 +22,9 @@ #include "pm_c_util.h" #include "mallocvar.h" -#include "shhopt.h" #include "nstring.h" +#include "rand.h" +#include "shhopt.h" #include "ppm.h" #include "ppmdraw.h" @@ -39,12 +39,10 @@ typedef enum { PAT_POLES, PAT_SQUIG, PAT_CAMO, - PAT_ANTICAMO, - PAT_SPIRO1, - PAT_SPIRO2, - PAT_SPIRO3 + PAT_ANTICAMO } Pattern; + typedef struct { /*---------------------------------------------------------------------------- An ordered list of colors with a cursor. @@ -60,16 +58,79 @@ struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - Pattern basePattern; - unsigned int width; - unsigned int height; - unsigned int colorSpec; - ColorTable colorTable; - unsigned int randomseed; - unsigned int randomseedSpec; + Pattern basePattern; + unsigned int width; + unsigned int height; + unsigned int colorSpec; + ColorTable colorTable; + unsigned int randomseed; + unsigned int randomseedSpec; + ppmd_drawproc * drawProc; }; + +static pixel +averageTwoColors(pixel const p1, + pixel const p2) { + + pixel p; + + PPM_ASSIGN(p, + (PPM_GETR(p1) + PPM_GETR(p2)) / 2, + (PPM_GETG(p1) + PPM_GETG(p2)) / 2, + (PPM_GETB(p1) + PPM_GETB(p2)) / 2); + + return p; +} + + + +static ppmd_drawproc average_drawproc; + +static void +average_drawproc(pixel ** const pixels, + int const cols, + int const rows, + pixval const maxval, + int const col, + int const row, + const void * const clientdata) { +/*---------------------------------------------------------------------------- + Reset the pixel's color to the average of the original color and the color + indicated by * clientdata. +-----------------------------------------------------------------------------*/ + + if (col >= 0 && col < cols && row >= 0 && row < rows) + pixels[row][col] = + averageTwoColors(pixels[row][col], *((const pixel*) clientdata)); +} + + + +static ppmd_drawproc checkerboard_drawproc; + +static void +checkerboard_drawproc(pixel ** const pixels, + int const cols, + int const rows, + pixval const maxval, + int const col, + int const row, + const void * const clientdata) { +/*---------------------------------------------------------------------------- + If col and row are both even or both odd, do nothing. + If one is even and the other is odd, set the pixel's color to that indicated + by * clientdata. +-----------------------------------------------------------------------------*/ + if (col >= 0 && col < cols && row >= 0 && + row < rows && row % 2 != col % 2) + + pixels[row][col] = *((const pixel*) clientdata); +} + + + static void validateColorCount(Pattern const basePattern, unsigned int const colorCount) { @@ -80,7 +141,6 @@ validateColorCount(Pattern const basePattern, switch (basePattern) { case PAT_GINGHAM2: case PAT_ARGYLE1: - case PAT_SPIRO1: if (colorCount != 2) pm_error("Wrong number of colors: %u. " "2 colors are required for the specified pattern.", @@ -112,8 +172,6 @@ validateColorCount(Pattern const basePattern, colorCount); break; - case PAT_SPIRO2: - case PAT_SPIRO3: default: pm_error("INTERNAL ERROR."); } @@ -188,9 +246,7 @@ parseCommandLine(int argc, const char ** argv, unsigned int squig; unsigned int camo; unsigned int anticamo; - unsigned int spiro1; - unsigned int spiro2; - unsigned int spiro3; + unsigned int meshSpec; MALLOCARRAY_NOFAIL(option_def, 100); @@ -208,9 +264,9 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "tartan", OPT_FLAG, NULL, &tartan, 0); OPTENT3(0, "argyle1", OPT_FLAG, NULL, - &argyle1, 0); + &argyle1, 0); OPTENT3(0, "argyle2", OPT_FLAG, NULL, - &argyle2, 0); + &argyle2, 0); OPTENT3(0, "poles", OPT_FLAG, NULL, &poles, 0); OPTENT3(0, "squig", OPT_FLAG, NULL, @@ -219,20 +275,12 @@ parseCommandLine(int argc, const char ** argv, &camo, 0); OPTENT3(0, "anticamo", OPT_FLAG, NULL, &anticamo, 0); -#if SPIROGRAPHS != 0 - OPTENT3(0, "spiro1", OPT_FLAG, NULL, - &spiro1, 0); - OPTENT3(0, "spiro2", OPT_FLAG, NULL, - &spiro1, 0); - OPTENT3(0, "spiro3", OPT_FLAG, NULL, - &spiro1, 0); -#else - spiro1 = spiro2 = spiro3 = 0; -#endif OPTENT3(0, "color", OPT_STRINGLIST, &colorText, &cmdlineP->colorSpec, 0); OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, &cmdlineP->randomseedSpec, 0); + OPTENT3(0, "mesh", OPT_FLAG, NULL, + &meshSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -246,8 +294,7 @@ parseCommandLine(int argc, const char ** argv, gingham2 + gingham3 + madras + tartan + argyle1 + argyle2 + poles + squig + - camo + anticamo + - spiro1 + spiro2 + spiro3; + camo + anticamo; if (basePatternCount < 1) pm_error("You must specify a base pattern option such as -gingham2"); @@ -275,12 +322,6 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->basePattern = PAT_CAMO; else if (anticamo) cmdlineP->basePattern = PAT_ANTICAMO; - else if (spiro1) - cmdlineP->basePattern = PAT_SPIRO1; - else if (spiro2) - cmdlineP->basePattern = PAT_SPIRO2; - else if (spiro3) - cmdlineP->basePattern = PAT_SPIRO3; else assert(false); /* Every possibility is accounted for */ } @@ -291,12 +332,20 @@ parseCommandLine(int argc, const char ** argv, } else cmdlineP->colorTable.count = 0; + if (meshSpec) { + if (gingham2 + gingham3 + madras + tartan > 0) + cmdlineP->drawProc = &checkerboard_drawproc; + else + pm_message("-mesh ignored (no effect with specified pattern)"); + } else + cmdlineP->drawProc = &average_drawproc; + if (argc-1 != 2) pm_error("You must specify 2 non-option arguments: width and height " "in pixels. You specified %u", argc-1); else { - cmdlineP->width = atoi(argv[1]); - cmdlineP->height = atoi(argv[2]); + cmdlineP->width = pm_parse_width(argv[1]); + cmdlineP->height = pm_parse_height(argv[2]); if (cmdlineP->width < 1) pm_error("Width must be at least 1 pixel"); @@ -339,14 +388,15 @@ validateComputableDimensions(unsigned int const cols, static pixel -randomColor(pixval const maxval) { +randomColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; PPM_ASSIGN(p, - rand() % (maxval + 1), - rand() % (maxval + 1), - rand() % (maxval + 1) + pm_rand(randStP) % (maxval + 1), + pm_rand(randStP) % (maxval + 1), + pm_rand(randStP) % (maxval + 1) ); return p; @@ -354,15 +404,18 @@ randomColor(pixval const maxval) { -#define DARK_THRESH 0.25 +static double const DARK_THRESH = 0.25; + + static pixel -randomBrightColor(pixval const maxval) { +randomBrightColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; do { - p = randomColor(maxval); + p = randomColor(randStP, maxval); } while (PPM_LUMIN(p) <= maxval * DARK_THRESH); return p; @@ -371,12 +424,13 @@ randomBrightColor(pixval const maxval) { static pixel -randomDarkColor(pixval const maxval) { +randomDarkColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; do { - p = randomColor(maxval); + p = randomColor(randStP, maxval); } while (PPM_LUMIN(p) > maxval * DARK_THRESH); return p; @@ -384,40 +438,6 @@ randomDarkColor(pixval const maxval) { -static pixel -averageTwoColors(pixel const p1, - pixel const p2) { - - pixel p; - - PPM_ASSIGN(p, - (PPM_GETR(p1) + PPM_GETR(p2)) / 2, - (PPM_GETG(p1) + PPM_GETG(p2)) / 2, - (PPM_GETB(p1) + PPM_GETB(p2)) / 2); - - return p; -} - - - -static ppmd_drawproc average_drawproc; - -static void -average_drawproc(pixel ** const pixels, - int const cols, - int const rows, - pixval const maxval, - int const col, - int const row, - const void * const clientdata) { - - if (col >= 0 && col < cols && row >= 0 && row < rows) - pixels[row][col] = - averageTwoColors(pixels[row][col], *((const pixel*) clientdata)); -} - - - static void nextColor(ColorTable * const colorTableP) { /*---------------------------------------------------------------------------- @@ -448,7 +468,8 @@ nextColorBg(ColorTable * const colorTableP) { static pixel -randomAnticamoColor(pixval const maxval) { +randomAnticamoColor(struct pm_randSt * const randStP, + pixval const maxval) { int v1, v2, v3; pixel p; @@ -457,37 +478,49 @@ randomAnticamoColor(pixval const maxval) { v2 = (maxval + 1) / 2; v3 = 3 * v1; - switch (rand() % 15) { + switch (pm_rand(randStP) % 15) { case 0: case 1: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2, + pm_rand(randStP) % v2); break; case 2: case 3: - PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2); break; case 4: case 5: - PPM_ASSIGN(p, rand() % v2, rand() % v2, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3); break; case 6: case 7: case 8: - PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v1 + v3); break; case 9: case 10: case 11: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3); break; case 12: case 13: case 14: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v1 + v3, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2); break; } @@ -497,7 +530,8 @@ randomAnticamoColor(pixval const maxval) { static pixel -randomCamoColor(pixval const maxval) { +randomCamoColor(struct pm_randSt * const randStP, + pixval const maxval) { int const v1 = (maxval + 1 ) / 8; int const v2 = (maxval + 1 ) / 4; @@ -505,31 +539,39 @@ randomCamoColor(pixval const maxval) { pixel p; - switch (rand() % 10) { + switch (pm_rand(randStP) % 10) { case 0: case 1: case 2: /* light brown */ - PPM_ASSIGN(p, rand() % v3 + v3, rand() % v3 + v2, rand() % v3 + v2); + PPM_ASSIGN(p, pm_rand(randStP) % v3 + v3, + pm_rand(randStP) % v3 + v2, + pm_rand(randStP) % v3 + v2); break; case 3: case 4: case 5: /* dark green */ - PPM_ASSIGN(p, rand() % v2, rand() % v2 + 3 * v1, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v2 + 3 * v1, + pm_rand(randStP) % v2); break; case 6: case 7: /* brown */ - PPM_ASSIGN(p, rand() % v2 + v2, rand() % v2, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2 + v2, + pm_rand(randStP) % v2, + pm_rand(randStP) % v2); break; case 8: case 9: /* dark brown */ - PPM_ASSIGN(p, rand() % v1 + v1, rand() % v1, rand() % v1); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v1, + pm_rand(randStP) % v1, + pm_rand(randStP) % v1); break; } @@ -539,28 +581,30 @@ randomCamoColor(pixval const maxval) { static float -rnduni(void) { - return rand() % 32767 / 32767.0; +rnduni(struct pm_randSt * const randStP) { + + return pm_rand(randStP) % 32767 / 32767.0; } static void -clearBackgroundCamo(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - ColorTable * const colorTableP, - bool const antiflag) { +clearBackgroundCamo(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + bool const antiflag) { pixel color; if (colorTableP->count > 0) { color = colorTableP->color[0]; } else if (antiflag) - color = randomAnticamoColor(maxval); + color = randomAnticamoColor(randStP, maxval); else - color = randomCamoColor(maxval); + color = randomCamoColor(randStP, maxval); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC, @@ -570,13 +614,14 @@ clearBackgroundCamo(pixel ** const pixels, static void -camoFill(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - struct fillobj * const fh, - ColorTable * const colorTableP, - bool const antiflag) { +camoFill(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + struct fillobj * const fh, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + bool const antiflag) { pixel color; @@ -585,9 +630,9 @@ camoFill(pixel ** const pixels, color = colorTableP->color[colorTableP->index]; nextColorBg(colorTableP); } else if (antiflag) - color = randomAnticamoColor(maxval); + color = randomAnticamoColor(randStP, maxval); else - color = randomCamoColor(maxval); + color = randomCamoColor(randStP, maxval); ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color); } @@ -608,25 +653,29 @@ camoFill(pixel ** const pixels, static void -computeXsYs(int * const xs, - int * const ys, - unsigned int const cols, - unsigned int const rows, - unsigned int const pointCt) { - - unsigned int const cx = rand() % cols; - unsigned int const cy = rand() % rows; - double const a = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + - MIN_ELLIPSE_FACTOR; - double const b = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + - MIN_ELLIPSE_FACTOR; - double const theta = rnduni() * 2.0 * M_PI; +computeXsYs(int * const xs, + int * const ys, + unsigned int const cols, + unsigned int const rows, + unsigned int const pointCt, + struct pm_randSt * const randStP) { + + unsigned int const cx = pm_rand(randStP) % cols; + unsigned int const cy = pm_rand(randStP) % rows; + double const a = rnduni(randStP) * + (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + + MIN_ELLIPSE_FACTOR; + double const b = rnduni(randStP) * + (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + + MIN_ELLIPSE_FACTOR; + double const theta = rnduni(randStP) * 2.0 * M_PI; unsigned int p; for (p = 0; p < pointCt; ++p) { - double const c = rnduni() * (MAX_POINT_FACTOR - MIN_POINT_FACTOR) + - MIN_POINT_FACTOR; + double const c = rnduni(randStP) * + (MAX_POINT_FACTOR - MIN_POINT_FACTOR) + + MIN_POINT_FACTOR; double const tx = a * sin(p * 2.0 * M_PI / pointCt); double const ty = b * cos(p * 2.0 * M_PI / pointCt); double const tang = atan2(ty, tx) + theta; @@ -638,18 +687,20 @@ computeXsYs(int * const xs, static void -camo(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval, - bool const antiflag) { +camo(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval, + bool const antiflag) { unsigned int const n = (rows * cols) / SQR(BLOBRAD) * 5; unsigned int i; - clearBackgroundCamo(pixels, cols, rows, maxval, colorTableP, antiflag); + clearBackgroundCamo(pixels, cols, rows, maxval, + colorTableP, randStP, antiflag); if (colorTableP->count > 0) { assert(colorTableP->count > 1); @@ -658,13 +709,13 @@ camo(pixel ** const pixels, for (i = 0; i < n; ++i) { unsigned int const pointCt = - rand() % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS; + pm_rand(randStP) % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS; int xs[MAX_POINTS], ys[MAX_POINTS]; int x0, y0; struct fillobj * fh; - computeXsYs(xs, ys, cols, rows, pointCt); + computeXsYs(xs, ys, cols, rows, pointCt, randStP); x0 = (xs[0] + xs[pointCt - 1]) / 2; y0 = (ys[0] + ys[pointCt - 1]) / 2; @@ -675,7 +726,8 @@ camo(pixel ** const pixels, pixels, cols, rows, maxval, x0, y0, pointCt, xs, ys, x0, y0, ppmd_fill_drawproc, fh); - camoFill(pixels, cols, rows, maxval, fh, colorTableP, antiflag); + camoFill(pixels, cols, rows, maxval, fh, + colorTableP, randStP, antiflag); ppmd_fill_destroy(fh); } @@ -688,17 +740,21 @@ camo(pixel ** const pixels, -----------------------------------------------------------------------------*/ static void -gingham2(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +gingham2(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + ppmd_drawproc * const drawproc, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const forecolor = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); unsigned int const colso2 = cols / 2; unsigned int const rowso2 = rows / 2; @@ -712,29 +768,34 @@ gingham2(pixel ** const pixels, /* Woof. */ ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, 0, cols, rowso2, average_drawproc, + pixels, cols, rows, maxval, 0, 0, cols, rowso2, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rowso2, cols, rows - rowso2, - average_drawproc, &forecolor); + drawproc, &forecolor); } static void -gingham3(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +gingham3(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + ppmd_drawproc * const drawproc, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const colso4 = cols / 4; unsigned int const rowso4 = rows / 4; @@ -754,35 +815,40 @@ gingham3(pixel ** const pixels, /* Woof. */ ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, 0, cols, rowso4, average_drawproc, + pixels, cols, rows, maxval, 0, 0, cols, rowso4, drawproc, &backcolor); ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, average_drawproc, + pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 2 * rowso4, cols, rowso4, - average_drawproc, &fore2color); + drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 3 * rowso4, cols, rows - rowso4, - average_drawproc, &fore1color); + drawproc, &fore1color); } static void -madras(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +madras(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + ppmd_drawproc * const drawproc, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const cols2 = cols * 2 / 44; unsigned int const rows2 = rows * 2 / 44; unsigned int const cols3 = cols * 3 / 44; @@ -846,72 +912,77 @@ madras(pixel ** const pixels, /* Woof. */ ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, 0, cols, rows2, average_drawproc, + pixels, cols, rows, maxval, 0, 0, cols, rows2, drawproc, &backcolor); ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, rows2, cols, rows3, average_drawproc, + pixels, cols, rows, maxval, 0, rows2, cols, rows3, drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows2 + rows3, cols, rows2, - average_drawproc, &backcolor); + drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 2 * rows2 + rows3, cols, rows2, - average_drawproc, &fore1color); + drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 3 * rows2 + rows3, cols, rows2, - average_drawproc, &backcolor); + drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 4 * rows2 + rows3, cols, rows6a, - average_drawproc, &fore2color); + drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 4 * rows2 + rows3 + rows6a, cols, rows2, - average_drawproc, &backcolor); + drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 5 * rows2 + rows3 + rows6a, cols, rows3, - average_drawproc, &fore1color); + drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 5 * rows2 + 2 * rows3 + rows6a, cols, - rows2, average_drawproc, &backcolor); + rows2, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 6 * rows2 + 2 * rows3 + rows6a, cols, - rows3, average_drawproc, &fore1color); + rows3, drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 6 * rows2 + 3 * rows3 + rows6a, cols, - rows2, average_drawproc, &backcolor); + rows2, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a, cols, - rows6b, average_drawproc, &fore2color); + rows6b, drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a + rows6b, - cols, rows2, average_drawproc, &backcolor); + cols, rows2, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 8 * rows2 + 3 * rows3 + rows6a + rows6b, - cols, rows2, average_drawproc, &fore1color); + cols, rows2, drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 9 * rows2 + 3 * rows3 + rows6a + rows6b, - cols, rows2, average_drawproc, &backcolor); + cols, rows2, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 10 * rows2 + 3 * rows3 + rows6a + rows6b, - cols, rows3, average_drawproc, &fore2color); + cols, rows3, drawproc, &fore2color); } static void -tartan(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +tartan(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + ppmd_drawproc * const drawproc, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const cols1 = cols / 22; unsigned int const rows1 = rows / 22; unsigned int const cols3 = cols * 3 / 22; @@ -951,29 +1022,29 @@ tartan(pixel ** const pixels, /* Woof. */ ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, 0, cols, rows5a, average_drawproc, + pixels, cols, rows, maxval, 0, 0, cols, rows5a, drawproc, &backcolor); ppmd_filledrectangle( - pixels, cols, rows, maxval, 0, rows5a, cols, rows1, average_drawproc, + pixels, cols, rows, maxval, 0, rows5a, cols, rows1, drawproc, &fore1color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows5a + rows1, cols, rows5b, - average_drawproc, &backcolor); + drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows10 + rows1, cols, rows3, - average_drawproc, &fore2color); + drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows10 + rows1 + rows3, cols, rows1, - average_drawproc, &backcolor); + drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + rows3, cols, rows3, - average_drawproc, &fore2color); + drawproc, &fore2color); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + 2 * rows3, cols, - rows1, average_drawproc, &backcolor); + rows1, drawproc, &backcolor); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, rows10 + 3 * rows1 + 2 * rows3, cols, - rows3, average_drawproc, &fore2color); + rows3, drawproc, &fore2color); } @@ -1013,14 +1084,15 @@ argyle(pixel ** const pixels, unsigned int const cols, unsigned int const rows, ColorTable const colorTable, + struct pm_randSt * const randStP, pixval const maxval, bool const stripes) { bool const colorSpec = (colorTable.count > 0); pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + colorTable.color[0] : randomDarkColor(randStP, maxval); pixel const forecolor = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : randomBrightColor(randStP, maxval); /* Fill canvas with background to start */ ppmd_filledrectangle( @@ -1032,7 +1104,8 @@ argyle(pixel ** const pixels, if (stripes) { /* Connect corners with thin stripes */ pixel const stripecolor = - colorSpec ? colorTable.color[2] : randomBrightColor(maxval); + colorSpec ? colorTable.color[2] : + randomBrightColor(randStP, maxval); ppmd_line(pixels, cols, rows, maxval, 0, 0, cols-1, rows-1, PPMD_NULLDRAWPROC, (char *) &stripecolor); @@ -1054,27 +1127,28 @@ argyle(pixel ** const pixels, static void -placeAndColorPolesRandomly(int * const xs, - int * const ys, - pixel * const colors, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - ColorTable * const colorTableP, - unsigned int const poleCt) { +placeAndColorPolesRandomly(int * const xs, + int * const ys, + pixel * const colors, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + unsigned int const poleCt) { unsigned int i; for (i = 0; i < poleCt; ++i) { - xs[i] = rand() % cols; - ys[i] = rand() % rows; + xs[i] = pm_rand(randStP) % cols; + ys[i] = pm_rand(randStP) % rows; if (colorTableP->count > 0) { colors[i] = colorTableP->color[colorTableP->index]; nextColor(colorTableP); } else - colors[i] = randomBrightColor(maxval); + colors[i] = randomBrightColor(randStP, maxval); } } @@ -1104,11 +1178,12 @@ assignInterpolatedColor(pixel * const resultP, static void -poles(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval) { +poles(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval) { unsigned int const poleCt = MAX(2, MIN(MAXPOLES, cols * rows / 30000)); @@ -1117,7 +1192,7 @@ poles(pixel ** const pixels, unsigned int row; placeAndColorPolesRandomly(xs, ys, colors, cols, rows, maxval, - colorTableP, poleCt); + colorTableP, randStP, poleCt); /* Interpolate points */ @@ -1236,11 +1311,12 @@ sqRainbowCircleDrawproc(pixel ** const pixels, static void -chooseSqPoleColors(ColorTable * const colorTableP, - pixval const maxval, - pixel * const color1P, - pixel * const color2P, - pixel * const color3P) { +chooseSqPoleColors(ColorTable * const colorTableP, + pixval const maxval, + pixel * const color1P, + pixel * const color2P, + pixel * const color3P, + struct pm_randSt * const randStP) { if (colorTableP->count > 0) { *color1P = colorTableP->color[colorTableP->index]; @@ -1250,19 +1326,20 @@ chooseSqPoleColors(ColorTable * const colorTableP, *color3P = colorTableP->color[colorTableP->index]; nextColor(colorTableP); } else { - *color1P = randomBrightColor(maxval); - *color2P = randomBrightColor(maxval); - *color3P = randomBrightColor(maxval); + *color1P = randomBrightColor(randStP, maxval); + *color2P = randomBrightColor(randStP, maxval); + *color3P = randomBrightColor(randStP, maxval); } } static void -sqAssignColors(unsigned int const circlecount, - pixval const maxval, - ColorTable * const colorTableP, - pixel * const colors) { +sqAssignColors(unsigned int const circlecount, + pixval const maxval, + ColorTable * const colorTableP, + pixel * const colors, + struct pm_randSt * const randStP) { float const cco3 = (circlecount - 1) / 3.0; @@ -1271,7 +1348,7 @@ sqAssignColors(unsigned int const circlecount, pixel rc3; unsigned int i; - chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3); + chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3, randStP); for (i = 0; i < circlecount; ++i) { if (i < cco3) { @@ -1333,24 +1410,25 @@ clearBackgroundSquig(pixel ** const pixels, static void -chooseWrapAroundPoint(unsigned int const cols, - unsigned int const rows, - ppmd_point * const pFirstP, - ppmd_point * const pLastP, - ppmd_point * const p0P, - ppmd_point * const p1P, - ppmd_point * const p2P, - ppmd_point * const p3P) { - - switch (rand() % 4) { +chooseWrapAroundPoint(unsigned int const cols, + unsigned int const rows, + ppmd_point * const pFirstP, + ppmd_point * const pLastP, + ppmd_point * const p0P, + ppmd_point * const p1P, + ppmd_point * const p2P, + ppmd_point * const p3P, + struct pm_randSt * const randStP) { + + switch (pm_rand(randStP) % 4) { case 0: - p1P->x = rand() % cols; + p1P->x = pm_rand(randStP) % cols; p1P->y = 0; if (p1P->x < cols / 2) - pFirstP->x = rand() % (p1P->x * 2 + 1); + pFirstP->x = pm_rand(randStP) % (p1P->x * 2 + 1); else - pFirstP->x = cols - 1 - rand() % ((cols - p1P->x) * 2); - pFirstP->y = rand() % rows; + pFirstP->x = cols - 1 - pm_rand(randStP) % ((cols - p1P->x) * 2); + pFirstP->y = pm_rand(randStP) % rows; p2P->x = p1P->x; p2P->y = rows - 1; pLastP->x = 2 * p2P->x - pFirstP->x; @@ -1362,13 +1440,13 @@ chooseWrapAroundPoint(unsigned int const cols, break; case 1: - p2P->x = rand() % cols; + p2P->x = pm_rand(randStP) % cols; p2P->y = 0; if (p2P->x < cols / 2) - pLastP->x = rand() % (p2P->x * 2 + 1); + pLastP->x = pm_rand(randStP) % (p2P->x * 2 + 1); else - pLastP->x = cols - 1 - rand() % ((cols - p2P->x) * 2); - pLastP->y = rand() % rows; + pLastP->x = cols - 1 - pm_rand(randStP) % ((cols - p2P->x) * 2); + pLastP->y = pm_rand(randStP) % rows; p1P->x = p2P->x; p1P->y = rows - 1; pFirstP->x = 2 * p1P->x - pLastP->x; @@ -1381,12 +1459,12 @@ chooseWrapAroundPoint(unsigned int const cols, case 2: p1P->x = 0; - p1P->y = rand() % rows; - pFirstP->x = rand() % cols; + p1P->y = pm_rand(randStP) % rows; + pFirstP->x = pm_rand(randStP) % cols; if (p1P->y < rows / 2) - pFirstP->y = rand() % (p1P->y * 2 + 1); + pFirstP->y = pm_rand(randStP) % (p1P->y * 2 + 1); else - pFirstP->y = rows - 1 - rand() % ((rows - p1P->y) * 2); + pFirstP->y = rows - 1 - pm_rand(randStP) % ((rows - p1P->y) * 2); p2P->x = cols - 1; p2P->y = p1P->y; pLastP->x = p2P->x - pFirstP->x; @@ -1399,12 +1477,12 @@ chooseWrapAroundPoint(unsigned int const cols, case 3: p2P->x = 0; - p2P->y = rand() % rows; - pLastP->x = rand() % cols; + p2P->y = pm_rand(randStP) % rows; + pLastP->x = pm_rand(randStP) % cols; if (p2P->y < rows / 2) - pLastP->y = rand() % (p2P->y * 2 + 1); + pLastP->y = pm_rand(randStP) % (p2P->y * 2 + 1); else - pLastP->y = rows - 1 - rand() % ((rows - p2P->y) * 2); + pLastP->y = rows - 1 - pm_rand(randStP) % ((rows - p2P->y) * 2); p1P->x = cols - 1; p1P->y = p2P->y; pFirstP->x = p1P->x - pLastP->x; @@ -1420,11 +1498,12 @@ chooseWrapAroundPoint(unsigned int const cols, static void -squig(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval) { +squig(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval) { int i; @@ -1453,10 +1532,11 @@ squig(pixel ** const pixels, ppmd_circlep(pixels, cols, rows, maxval, ppmd_makePoint(0, 0), radius, sqMeasureCircleDrawproc, &sqClientData); - sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color); + sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color, + randStP); chooseWrapAroundPoint(cols, rows, &c[0], &c[SQ_POINTS-1], - &p0, &p1, &p2, &p3); + &p0, &p1, &p2, &p3, randStP); { /* Do the middle points */ @@ -1466,8 +1546,8 @@ squig(pixel ** const pixels, /* validateSquigAspect() assures that cols - 2 * radius, rows -2 * radius are positive */ - c[j].x = (rand() % (cols - 2 * radius)) + radius; - c[j].y = (rand() % (rows - 2 * radius)) + radius; + c[j].x = (pm_rand(randStP) % (cols - 2 * radius)) + radius; + c[j].y = (pm_rand(randStP) % (rows - 2 * radius)) + radius; } } @@ -1490,6 +1570,7 @@ main(int argc, const char ** argv) { struct CmdlineInfo cmdline; pixel ** pixels; + struct pm_randSt randSt; pm_proginit(&argc, argv); @@ -1497,65 +1578,68 @@ main(int argc, const char ** argv) { validateComputableDimensions(cmdline.width, cmdline.height); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); pixels = ppm_allocarray(cmdline.width, cmdline.height); switch (cmdline.basePattern) { case PAT_GINGHAM2: gingham2(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL); break; case PAT_GINGHAM3: gingham3(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL); break; case PAT_MADRAS: madras(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL); break; case PAT_TARTAN: tartan(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL); break; case PAT_ARGYLE1: argyle(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL, FALSE); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL, FALSE); break; case PAT_ARGYLE2: argyle(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL, TRUE); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL, TRUE); break; case PAT_POLES: poles(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_SQUIG: squig(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_CAMO: camo(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL, 0); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 0); break; case PAT_ANTICAMO: camo(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL, 1); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 1); break; default: pm_error("can't happen!"); } + pm_randterm(&randSt); + ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL, 0); diff --git a/generator/ppmrainbow b/generator/ppmrainbow index e8a329ff..68d519a0 100755 --- a/generator/ppmrainbow +++ b/generator/ppmrainbow @@ -26,6 +26,19 @@ exec perl -w -x -S -- "$0" "$@" use strict; use Getopt::Long; use File::Temp; +use IO::Handle; + + + +sub pm_message($) { + STDERR->print("ppmrainbow: $_[0]\n"); +} + +sub pm_error($) { + pm_message($_[0]); + exit(1); +} + my ($FALSE, $TRUE) = (0,1); @@ -46,15 +59,6 @@ sub doVersionHack($) { -sub fatal($) { - my ($msg) = @_; - - print(STDERR "ppmrainbow: $msg\n"); - exit(1); -} - - - ############################################################################## # # MAINLINE @@ -79,14 +83,14 @@ GetOptions("width=i" => \$Twid, "verbose!" => \$verbose); if ($Twid < 1 || $Thgt < 1) { - fatal("invalid width and/or height"); + pm_error("invalid width and/or height"); } my $verboseCommand = $verbose ? "set -x;" : ""; if (@ARGV < 1) { - fatal("You must specify at least one color as an argument"); + pm_error("You must specify at least one color as an argument"); } elsif (@ARGV < 2 && ! $repeat) { - fatal("With the -norepeat option, you must specify at least two colors " . + pm_error("With the -norepeat option, you must specify at least two colors " . "as arguments."); } @@ -115,15 +119,18 @@ while (@colorlist >= 2) { my $rc = system("$verboseCommand pgmramp -lr $w $Thgt | " . "pgmtoppm \"$colorlist[0]-$colorlist[1]\" >$outfile"); if ($rc != 0) { - fatal("pgmramp|pgmtoppm pipe failed."); + pm_error("pgmramp|pgmtoppm pipe failed."); } $widthRemaining -= $w; $n++; shift @colorlist; } -0 == system qq{$verboseCommand pnmcat -lr @outlist} - or exit 1; +my $termStat = + system("$verboseCommand pamcat -leftright @outlist"); +if ($termStat != 0) { + exit 1; +} exit 0; diff --git a/generator/ppmrough.c b/generator/ppmrough.c index c87a0364..d9f1bb65 100644 --- a/generator/ppmrough.c +++ b/generator/ppmrough.c @@ -16,11 +16,10 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" #include "ppm.h" -static pixel** PIX; -static pixval BG_RED, BG_GREEN, BG_BLUE; struct CmdlineInfo { @@ -28,9 +27,12 @@ struct CmdlineInfo { in a form easy for the program to use. */ unsigned int left, right, top, bottom; - unsigned int width, height, var; - const char * bg_rgb; - const char * fg_rgb; + unsigned int leftSpec, rightSpec, topSpec, bottomSpec; + unsigned int width; + unsigned int height; + unsigned int var; + const char * bg; /* Null if not specified */ + const char * fg; /* Null if not specified */ unsigned int randomseed; unsigned int randomseedSpec; unsigned int verbose; @@ -42,6 +44,8 @@ static void parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { + unsigned int widthSpec, heightSpec, bgSpec, fgSpec, varSpec; + optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ optStruct3 opt; @@ -51,28 +55,30 @@ parseCommandLine(int argc, const char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, NULL, 0); - OPTENT3(0, "height", OPT_UINT, &cmdlineP->height, NULL, 0); - OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, NULL, 0); - OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, NULL, 0); - OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, NULL, 0); - OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, NULL, 0); - OPTENT3(0, "bg", OPT_STRING, &cmdlineP->bg_rgb, NULL, 0); - OPTENT3(0, "fg", OPT_STRING, &cmdlineP->fg_rgb, NULL, 0); - OPTENT3(0, "var", OPT_UINT, &cmdlineP->var, NULL, 0); + OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, + &widthSpec, 0); + OPTENT3(0, "height", OPT_UINT, &cmdlineP->height, + &heightSpec, 0); + OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, + &cmdlineP->leftSpec, 0); + OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, + &cmdlineP->rightSpec, 0); + OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, + &cmdlineP->topSpec, 0); + OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, + &cmdlineP->bottomSpec, 0); + OPTENT3(0, "bg", OPT_STRING, &cmdlineP->bg, + &bgSpec, 0); + OPTENT3(0, "fg", OPT_STRING, &cmdlineP->fg, + &fgSpec, 0); + OPTENT3(0, "var", OPT_UINT, &cmdlineP->var, + &varSpec, 0); OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, &cmdlineP->randomseedSpec, 0); OPTENT3(0, "init", OPT_UINT, &cmdlineP->randomseed, &cmdlineP->randomseedSpec, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - - /* Set the defaults */ - cmdlineP->width = 100; - cmdlineP->height = 100; - cmdlineP->left = cmdlineP->right = cmdlineP->top = cmdlineP->bottom = -1; - cmdlineP->bg_rgb = NULL; - cmdlineP->fg_rgb = NULL; - cmdlineP->var = 10; + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -80,6 +86,26 @@ parseCommandLine(int argc, const char ** argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + if (!widthSpec) + cmdlineP->width = 100; + if (!heightSpec) + cmdlineP->height = 100; + if (!bgSpec) + cmdlineP->bg = NULL; + if (!fgSpec) + cmdlineP->fg = NULL; + if (!varSpec) + cmdlineP->var = 10; + + if (cmdlineP->topSpec && cmdlineP->top > cmdlineP->height) + pm_error("-top value too large. Max is %u", cmdlineP->height); + if (cmdlineP->bottomSpec && cmdlineP->bottom > cmdlineP->height) + pm_error("-bottom value too large. Max is %u", cmdlineP->height); + if (cmdlineP->leftSpec && cmdlineP->left > cmdlineP->width) + pm_error("-left value too large. Max is %u", cmdlineP->width); + if (cmdlineP->rightSpec && cmdlineP->right > cmdlineP->width) + pm_error("-right value too large. Max is %u", cmdlineP->width); + if (argc-1 != 0) pm_error("There are no arguments. You specified %d.", argc-1); @@ -88,240 +114,353 @@ parseCommandLine(int argc, const char ** argv, -static void -procLeft(int const r1, - int const r2, - int const c1, - int const c2, - unsigned int const var) { +static int +mean(int const a, + int const b) { - int cm, rm, c; + return (a + b) / 2; +} - if (r1 + 1 == r2) return; - rm = (r1 + r2) >> 1; - cm = (c1 + c2) >> 1; - cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); - for (c = 0; c < cm; c++) - PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE); - procLeft(r1, rm, c1, cm, var); - procLeft(rm, r2, cm, c2, var); +static void +reportParameters(struct CmdlineInfo const cmdline, + pixel const bgcolor, + pixel const fgcolor) { + + pm_message("width is %d, height is %d, variance is %d.", + cmdline.width, cmdline.height, cmdline.var); + if (cmdline.leftSpec) + pm_message("ragged left border is required"); + if (cmdline.rightSpec) + pm_message("ragged right border is required"); + if (cmdline.topSpec) + pm_message("ragged top border is required"); + if (cmdline.bottomSpec) + pm_message("ragged bottom border is required"); + pm_message("background is %s", + ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1)); + pm_message("foreground is %s", + ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1)); + if (cmdline.randomseedSpec) + pm_message("pm_rand() initialized with seed %u", + cmdline.randomseed); } static void -procRight(int const r1, - int const r2, - int const c1, - int const c2, - unsigned int const width, - unsigned int const var) { +makeAllForegroundColor(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + pixel const fgcolor) { - int cm, rm, c; + pixval const r = PPM_GETR(fgcolor); + pixval const g = PPM_GETG(fgcolor); + pixval const b = PPM_GETB(fgcolor); - if (r1 + 1 == r2) return; - rm = (r1 + r2) >> 1; - cm = (c1 + c2) >> 1; - cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); + unsigned int row; - for (c = cm; c < width; c++) - PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE); + for (row = 0; row < rows; ++row) { + unsigned int col; - procRight(r1, rm, c1, cm, width, var); - procRight(rm, r2, cm, c2, width, var); + for (col = 0; col < cols; ++col) + PPM_ASSIGN(pixels[row][col], r, g, b); + } } static void -procTop(int const c1, - int const c2, - int const r1, - int const r2, - unsigned int const var) { +procLeft(pixel ** const pixels, + int const r1, + int const r2, + int const c1, + int const c2, + unsigned int const width, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (r1 + 1 != r2) { + int const rm = mean(r1, r2); + int const cm = mean(c1, c2) + + (int)floor(((float)pm_drand(randStP) - 0.5) * var + 0.5); + + unsigned int c; + + for (c = 0; c < MIN(width, MAX(0, cm)); ++c) + pixels[rm][c] = bgcolor; + + procLeft(pixels, r1, rm, c1, cm, width, var, bgcolor, randStP); + procLeft(pixels, rm, r2, cm, c2, width, var, bgcolor, randStP); + } +} - int rm, cm, r; - if (c1 + 1 == c2) return; - cm = (c1 + c2) >> 1; - rm = (r1 + r2) >> 1; - rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); - for (r = 0; r < rm; r++) - PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE); +static void +procRight(pixel ** const pixels, + int const r1, + int const r2, + int const c1, + int const c2, + unsigned int const width, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (r1 + 1 != r2) { + int const rm = mean(r1, r2); + int const cm = mean(c1, c2) + + (int)floor(((float)pm_drand(randStP) - 0.5) * var + 0.5); + + unsigned int c; + + for (c = MAX(0, cm); c < width; ++c) + pixels[rm][c] = bgcolor; + + procRight(pixels, r1, rm, c1, cm, width, var, bgcolor, randStP); + procRight(pixels, rm, r2, cm, c2, width, var, bgcolor, randStP); + } +} - procTop(c1, cm, r1, rm, var); - procTop(cm, c2, rm, r2, var); + + +static void +procTop(pixel ** const pixels, + int const c1, + int const c2, + int const r1, + int const r2, + unsigned int const height, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (c1 + 1 != c2) { + int const cm = mean(c1, c2); + int const rm = mean(r1, r2) + + (int)floor(((float)pm_drand(randStP) - 0.5) * var + 0.5); + + unsigned int r; + + for (r = 0; r < MIN(height, MAX(0, rm)); ++r) + pixels[r][cm] = bgcolor; + + procTop(pixels, c1, cm, r1, rm, height, var, bgcolor, randStP); + procTop(pixels, cm, c2, rm, r2, height, var, bgcolor, randStP); + } } static void -procBottom(int const c1, - int const c2, - int const r1, - int const r2, - unsigned int const height, - unsigned int const var) { +procBottom(pixel ** const pixels, + int const c1, + int const c2, + int const r1, + int const r2, + unsigned int const height, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (c1 + 1 != c2) { + int const cm = mean(c1, c2); + int const rm = mean(r1, r2) + + (int)floor(((float)pm_drand(randStP) - 0.5) * var + 0.5); + + unsigned int r; + + for (r = MAX(0, rm); r < height; ++r) + pixels[r][cm] = bgcolor; + + procBottom(pixels, c1, cm, r1, rm, height, var, bgcolor, randStP); + procBottom(pixels, cm, c2, rm, r2, height, var, bgcolor, randStP); + } +} - int rm, cm, r; - if (c1 + 1 == c2) return; - cm = (c1 + c2) >> 1; - rm = (r1 + r2) >> 1; - rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); - for (r = rm; r < height; r++) - PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE); +static void +makeRaggedLeftBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const leftSpec, + unsigned int const left, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (leftSpec) { + int const leftC1 = left; + int const leftC2 = left; + int const leftR1 = 0; + int const leftR2 = rows - 1; + + unsigned int col; - procBottom(c1, cm, r1, rm, height, var); - procBottom(cm, c2, rm, r2, height, var); + for (col = 0; col < leftC1; ++col) + pixels[leftR1][col] = bgcolor; + for (col = 0; col < leftC2; ++col) + pixels[leftR2][col] = bgcolor; + + procLeft(pixels, leftR1, leftR2, leftC1, leftC2, cols, var, + bgcolor, randStP); + } } -int -main(int argc, const char * argv[]) { +static void +makeRaggedRightBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const rightSpec, + unsigned int const right, + unsigned int const width, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (rightSpec) { + int const rightC1 = cols - right - 1; + int const rightC2 = cols - right - 1; + int const rightR1 = 0; + int const rightR2 = rows - 1; - struct CmdlineInfo cmdline; - pixel bgcolor, fgcolor; - pixval fg_red, fg_green, fg_blue; - int rows, cols, row; - int left, right, top, bottom; + unsigned int col; - pm_proginit(&argc, argv); + for (col = rightC1; col < cols; ++col) + pixels[rightR1][col] = bgcolor; + for (col = rightC2; col < cols; ++col) + pixels[rightR2][col] = bgcolor; - parseCommandLine(argc, argv, &cmdline); + procRight(pixels, rightR1, rightR2, rightC1, rightC2, width, var, + bgcolor, randStP); + } +} - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - cols = cmdline.width; - rows = cmdline.height; - left = cmdline.left; - right = cmdline.right; - top = cmdline.top; - bottom = cmdline.bottom; - if (cmdline.bg_rgb) - bgcolor = ppm_parsecolor(cmdline.bg_rgb, PPM_MAXMAXVAL); - else - PPM_ASSIGN(bgcolor, 0, 0, 0); - BG_RED = PPM_GETR(bgcolor); - BG_GREEN = PPM_GETG(bgcolor); - BG_BLUE = PPM_GETB(bgcolor); +static void +makeRaggedTopBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const topSpec, + unsigned int const top, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (topSpec) { + unsigned int const topR1 = top; + unsigned int const topR2 = top; + unsigned int const topC1 = 0; + unsigned int const topC2 = cols - 1; - if (cmdline.fg_rgb) - fgcolor = ppm_parsecolor(cmdline.fg_rgb, PPM_MAXMAXVAL); - else - PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL); - fg_red = PPM_GETR(fgcolor); - fg_green = PPM_GETG(fgcolor); - fg_blue = PPM_GETB(fgcolor); - - if (cmdline.verbose) { - pm_message("width is %d, height is %d, variance is %d.", - cols, rows, cmdline.var); - if (left >= 0) - pm_message("ragged left border is required"); - if (right >= 0) - pm_message("ragged right border is required"); - if (top >= 0) - pm_message("ragged top border is required"); - if (bottom >= 0) - pm_message("ragged bottom border is required"); - pm_message("background is %s", - ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1)); - pm_message("foreground is %s", - ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1)); - if (cmdline.randomseedSpec) - pm_message("srand() initialized with seed %u", cmdline.randomseed); - } + unsigned int row; - /* Allocate memory for the whole pixmap */ - PIX = ppm_allocarray(cols, rows); + for (row = 0; row < topR1; ++row) + pixels[row][topC1] = bgcolor; + for (row = 0; row < topR2; ++row) + pixels[row][topC2] = bgcolor; - /* First, set all pixel to foreground color */ - for (row = 0; row < rows; row++) { - unsigned int col; - for (col = 0; col < cols; ++col) - PPM_ASSIGN(PIX[row][col], fg_red, fg_green, fg_blue); + procTop(pixels, topC1, topC2, topR1, topR2, rows, + var, bgcolor, randStP); } - /* Make a ragged left border */ - if (left >= 0) { - int const left_c1 = left; - int const left_c2 = left; - int const left_r1 = 0; - int const left_r2 = rows - 1; +} - unsigned int col; - for (col = 0; col < left_c1; ++col) - PPM_ASSIGN(PIX[left_r1][col], BG_RED, BG_GREEN, BG_BLUE); - for (col = 0; col < left_c2; ++col) - PPM_ASSIGN(PIX[left_r2][col], BG_RED, BG_GREEN, BG_BLUE); - procLeft(left_r1, left_r2, left_c1, left_c2, cmdline.var); +static void +makeRaggedBottomBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const bottomSpec, + unsigned int const bottom, + unsigned int const height, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (bottomSpec) { + unsigned int const bottomR1 = rows - bottom - 1; + unsigned int const bottomR2 = rows - bottom - 1; + unsigned int const bottomC1 = 0; + unsigned int const bottomC2 = cols - 1; + + unsigned int row; + + for (row = bottomR1; row < rows; ++row) + pixels[row][bottomC1] = bgcolor; + for (row = bottomR2; row < rows; ++row) + pixels[row][bottomC2] = bgcolor; + + procBottom(pixels, bottomC1, bottomC2, bottomR1, bottomR2, + height, var, bgcolor, randStP); } +} - /* Make a ragged right border */ - if (right >= 0) { - int const right_c1 = cols - right - 1; - int const right_c2 = cols - right - 1; - int const right_r1 = 0; - int const right_r2 = rows - 1; - unsigned int col; - for (col = right_c1; col < cols; col++) - PPM_ASSIGN(PIX[right_r1][col], BG_RED, BG_GREEN, BG_BLUE); - for (col = right_c2; col < cols; col++) - PPM_ASSIGN(PIX[right_r2][col], BG_RED, BG_GREEN, BG_BLUE); +int +main(int argc, const char ** const argv) { - procRight(right_r1, right_r2, right_c1, right_c2, - cmdline.width, cmdline.var); - } + struct CmdlineInfo cmdline; + pixel bgcolor, fgcolor; + struct pm_randSt randSt; + static pixel** pixels; - /* Make a ragged top border */ - if (top >= 0) { - int const top_r1 = top; - int const top_r2 = top; - int const top_c1 = 0; - int const top_c2 = cols - 1; + pm_proginit(&argc, argv); - unsigned int row; + parseCommandLine(argc, argv, &cmdline); - for (row = 0; row < top_r1; ++row) - PPM_ASSIGN(PIX[row][top_c1], BG_RED, BG_GREEN, BG_BLUE); - for (row = 0; row < top_r2; ++row) - PPM_ASSIGN(PIX[row][top_c2], BG_RED, BG_GREEN, BG_BLUE); + pm_randinit(&randSt); + pm_srand(&randSt, + cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - procTop(top_c1, top_c2, top_r1, top_r2, cmdline.var); - } + if (cmdline.bg) + bgcolor = ppm_parsecolor(cmdline.bg, PPM_MAXMAXVAL); + else + PPM_ASSIGN(bgcolor, 0, 0, 0); + + if (cmdline.fg) + fgcolor = ppm_parsecolor(cmdline.fg, PPM_MAXMAXVAL); + else + PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL); - /* Make a ragged bottom border */ - if (bottom >= 0) { - int const bottom_r1 = rows - bottom - 1; - int const bottom_r2 = rows - bottom - 1; - int const bottom_c1 = 0; - int const bottom_c2 = cols - 1; + if (cmdline.verbose) + reportParameters(cmdline, bgcolor, fgcolor); - unsigned int row; + pixels = ppm_allocarray(cmdline.width, cmdline.height); - for (row = bottom_r1; row < rows; ++row) - PPM_ASSIGN(PIX[row][bottom_c1], BG_RED, BG_GREEN, BG_BLUE); - for (row = bottom_r2; row < rows; ++row) - PPM_ASSIGN(PIX[row][bottom_c2], BG_RED, BG_GREEN, BG_BLUE); + makeAllForegroundColor(pixels, cmdline.height, cmdline.width, fgcolor); - procBottom(bottom_c1, bottom_c2, bottom_r1, bottom_r2, - cmdline.height, cmdline.var); - } + makeRaggedLeftBorder(pixels, cmdline.height, cmdline.width, + cmdline.leftSpec, cmdline.left, + cmdline.var, bgcolor, &randSt); + + makeRaggedRightBorder(pixels, cmdline.height, cmdline.width, + cmdline.rightSpec, cmdline.right, + cmdline.width, cmdline.var, bgcolor, &randSt); + + makeRaggedTopBorder(pixels, cmdline.height, cmdline.width, + cmdline.topSpec, cmdline.top, + cmdline.var, bgcolor, &randSt); + + makeRaggedBottomBorder(pixels, cmdline.height, cmdline.width, + cmdline.bottomSpec, cmdline.bottom, + cmdline.height, cmdline.var, bgcolor, &randSt); + + pm_randterm(&randSt); /* Write pixmap */ - ppm_writeppm(stdout, PIX, cols, rows, PPM_MAXMAXVAL, 0); + ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height, + PPM_MAXMAXVAL, 0); - ppm_freearray(PIX, rows); + ppm_freearray(pixels, cmdline.height); pm_close(stdout); @@ -329,4 +468,3 @@ main(int argc, const char * argv[]) { } - |