diff options
Diffstat (limited to 'editor/specialty')
-rw-r--r-- | editor/specialty/pampaintspill.c | 172 | ||||
-rw-r--r-- | editor/specialty/pampop9.c | 3 | ||||
-rw-r--r-- | editor/specialty/pgmabel.c | 18 | ||||
-rw-r--r-- | editor/specialty/pnmindex.c | 106 | ||||
-rw-r--r-- | editor/specialty/ppmshift.c | 235 | ||||
-rw-r--r-- | editor/specialty/ppmspread.c | 206 |
6 files changed, 483 insertions, 257 deletions
diff --git a/editor/specialty/pampaintspill.c b/editor/specialty/pampaintspill.c index eb1888f7..7490fcef 100644 --- a/editor/specialty/pampaintspill.c +++ b/editor/specialty/pampaintspill.c @@ -6,7 +6,7 @@ * * ---------------------------------------------------------------------- * - * Copyright (C) 2010 Scott Pakin <scott+pbm@pakin.org> + * Copyright (C) 2010-2021 Scott Pakin <scott+pbm@pakin.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,11 +45,11 @@ #include "mallocvar.h" #include "nstring.h" +#include "rand.h" #include "shhopt.h" #include "pam.h" #include "pammap.h" - static time_t const timeUpdateDelta = 30; /* Seconds between progress updates */ static int const minUpdates = 4; @@ -67,6 +67,10 @@ struct cmdlineInfo { unsigned int all; float power; unsigned int downsample; + unsigned int randomseedSpec; + unsigned int randomseed; + unsigned int nearSpec; + unsigned int near; }; struct coords { @@ -98,16 +102,20 @@ parseCommandLine(int argc, const char ** const argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* Incremented by OPTENTRY */ - OPTENT3(0, "bgcolor", OPT_STRING, &cmdlineP->bgcolor, + OPTENT3(0, "bgcolor", OPT_STRING, &cmdlineP->bgcolor, &bgcolorSpec, 0); OPTENT3(0, "wrap", OPT_FLAG, NULL, &cmdlineP->wrap, 0); OPTENT3(0, "all", OPT_FLAG, NULL, &cmdlineP->all, 0); - OPTENT3(0, "power", OPT_FLOAT, &cmdlineP->power, + OPTENT3(0, "power", OPT_FLOAT, &cmdlineP->power, &powerSpec, 0); - OPTENT3(0, "downsample", OPT_UINT, &cmdlineP->downsample, + OPTENT3(0, "downsample", OPT_UINT, &cmdlineP->downsample, &downsampleSpec, 0); + OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, + &cmdlineP->randomseedSpec, 0); + OPTENT3(0, "near", OPT_UINT, &cmdlineP->near, + &cmdlineP->nearSpec, 0); opt.opt_table = option_def; opt.short_allowed = 0; @@ -124,6 +132,11 @@ parseCommandLine(int argc, const char ** const argv, if (!downsampleSpec) cmdlineP->downsample = 0; + if (cmdlineP->nearSpec) { + if (cmdlineP->near == 0) + pm_error("The -near option requires a positive argument"); + } + if (argc-1 < 1) cmdlineP->inputFilename = "-"; else { @@ -223,7 +236,9 @@ locatePaintSources(struct pam * const pamP, tuple ** const tuples, tuple const bgColor, unsigned int const downsample, - struct paintSourceSet * const paintSourcesP) { + struct paintSourceSet * const paintSourcesP, + bool const randomseedSpec, + unsigned int const randomseed) { /*-------------------------------------------------------------------- Construct a list of all pixel coordinates in the input image that represent a non-background color. @@ -248,21 +263,24 @@ locatePaintSources(struct pam * const pamP, pm_message("Image contains %u background + %u non-background pixels", pamP->width * pamP->height - paintSources.size, paintSources.size); - + /* Reduce the number of paint sources to reduce execution time. */ if (downsample > 0 && downsample < paintSources.size) { + struct pm_randSt randSt; unsigned int i; - srand(pm_randseed()); + pm_randinit(&randSt); + pm_srand2(&randSt, randomseedSpec, randomseed); for (i = 0; i < downsample; ++i) { unsigned int const swapIdx = - i + rand() % (paintSources.size - i); + i + pm_rand(&randSt) % (paintSources.size - i); struct coords const swapVal = paintSources.list[i]; paintSources.list[i] = paintSources.list[swapIdx]; paintSources.list[swapIdx] = swapVal; } + pm_randterm(&randSt); paintSources.size = downsample; } @@ -281,7 +299,7 @@ euclideanDistanceSqr(const struct coords * const p0, unsigned int const width, unsigned int const height) { /*---------------------------------------------------------------------------- - Return the square of the Euclidian distance between p0 and p1. + Return the square of the Euclidean distance between p0 and p1. -----------------------------------------------------------------------------*/ double const deltax = (double) (int) (p1->x - p0->x); double const deltay = (double) (int) (p1->y - p0->y); @@ -299,7 +317,7 @@ euclideanDistanceTorusSqr(const struct coords * const p0, unsigned int const width, unsigned int const height) { /*---------------------------------------------------------------------------- - Return the square of the Euclidian distance between p0 and p1, assuming + Return the square of the Euclidean distance between p0 and p1, assuming it's a toroidal surface on which the top row curves around to meet the bottom and the left column to the right. -----------------------------------------------------------------------------*/ @@ -356,6 +374,70 @@ reportProgress(unsigned int const rowsComplete, +struct distanceList { + struct coords * sources; /* malloc'ed */ + /* The list of places in the image from which paint comes */ + double * distSqrs; /* malloc'ed */ + /* The list of squared distances from the current point */ + unsigned int size; + /* Number of entries in sources[] */ +}; + + + +static void +computeDistances(struct pam * const pamP, + struct coords const target, + struct paintSourceSet const paintSources, + distFunc_t * const distFunc, + bool const nearOnly, + unsigned int const numNear, + struct distanceList * const distancesP) { + + unsigned int ps; + + /* Acquire a list of all distances. */ + distancesP->size = 0; + for (ps = 0; ps < paintSources.size; ++ps) { + struct coords const source = paintSources.list[ps]; + double const distSqr = + (*distFunc)(&target, &source, + pamP->width, pamP->height); + distancesP->sources[distancesP->size] = source; + distancesP->distSqrs[distancesP->size] = distSqr; + ++distancesP->size; + } + + /* If requested, truncate the list to the smallest numNear distances. */ + if (nearOnly && numNear < distancesP->size) { + unsigned int i; + + /* Perform a partial sort -- just enough to identify the numNear + smallest distances. For performance reasons we assume that + numNear is much less than paintSources.size (say, less than + log2(paintSources.size)). + */ + for (i = 0; i < numNear; ++i) { + unsigned int j; + for (j = i + 1; j < distancesP->size; ++j) { + if (distancesP->distSqrs[i] > distancesP->distSqrs[j]) { + /* Swap elements i and j. */ + struct coords const src = distancesP->sources[i];; + double const dist2 = distancesP->distSqrs[i]; + + distancesP->sources[i] = distancesP->sources[j]; + distancesP->distSqrs[i] = distancesP->distSqrs[j]; + distancesP->sources[j] = src; + distancesP->distSqrs[j] = dist2; + } + } + } + distancesP->size = numNear; + } +} + + + static void spillOnePixel(struct pam * const pamP, struct coords const target, @@ -363,37 +445,38 @@ spillOnePixel(struct pam * const pamP, distFunc_t * const distFunc, double const distPower, tuple const outTuple, - double * const newColor) { + double * const newColor, + bool const nearOnly, + unsigned int const numNear, + struct distanceList * const distancesP) { unsigned int plane; - unsigned int ps; + unsigned int d; double totalWeight; for (plane = 0; plane < pamP->depth; ++plane) newColor[plane] = 0.0; + computeDistances(pamP, target, paintSources, distFunc, + nearOnly, numNear, distancesP); totalWeight = 0.0; - for (ps = 0; ps < paintSources.size; ++ps) { - struct coords const source = paintSources.list[ps]; - double const distSqr = - (*distFunc)(&target, &source, - pamP->width, pamP->height); + for (d = 0; d < distancesP->size; ++d) { + double const distSqr = distancesP->distSqrs[d]; + struct coords const source = distancesP->sources[d]; - if (distSqr > 0.0) { - /* We do special cases for some common cases with code - that is much faster than pow(). - */ - double const weight = - distPower == -2.0 ? 1.0 / distSqr : - distPower == -1.0 ? 1.0 / sqrt(distSqr): - pow(distSqr, distPower/2); + /* We do special cases for some common cases with code + that is much faster than pow(). + */ + double const weight = + distPower == -2.0 ? 1.0 / distSqr : + distPower == -1.0 ? 1.0 / sqrt(distSqr): + pow(distSqr, distPower/2); - unsigned int plane; + unsigned int plane; - for (plane = 0; plane < pamP->depth; ++plane) - newColor[plane] += weight * source.color[plane]; + for (plane = 0; plane < pamP->depth; ++plane) + newColor[plane] += weight * source.color[plane]; - totalWeight += weight; - } + totalWeight += weight; } for (plane = 0; plane < pamP->depth; ++plane) outTuple[plane] = (sample) (newColor[plane] / totalWeight); @@ -409,6 +492,8 @@ produceOutputImage(struct pam * const pamP, distFunc_t * const distFunc, double const distPower, bool const all, + bool const nearOnly, + unsigned int const numNear, tuple *** const outtuplesP) { /*-------------------------------------------------------------------- Color each background pixel (or, if allPixels is 1, all pixels) @@ -424,10 +509,14 @@ produceOutputImage(struct pam * const pamP, rowsComplete = 0; #pragma omp parallel for for (row = 0; row < pamP->height; ++row) { - struct coords target; - double * newColor; - + struct coords target; + double * newColor; /* malloc'ed */ + struct distanceList * distancesP; /* malloc'ed */ + MALLOCARRAY(newColor, pamP->depth); + MALLOCVAR_NOFAIL(distancesP); + MALLOCARRAY_NOFAIL(distancesP->sources, paintSources.size); + MALLOCARRAY_NOFAIL(distancesP->distSqrs, paintSources.size); target.y = row; for (target.x = 0; target.x < pamP->width; ++target.x) { @@ -436,13 +525,17 @@ produceOutputImage(struct pam * const pamP, if (all || tupleEqualColor(pamP, targetTuple, bgColor)) spillOnePixel(pamP, target, paintSources, distFunc, distPower, - outputTuple, newColor); + outputTuple, newColor, nearOnly, numNear, + distancesP); else pnm_assigntuple(pamP, outputTuple, targetTuple); } #pragma omp critical (rowTally) reportProgress(++rowsComplete, pamP->height); + free(distancesP->distSqrs); + free(distancesP->sources); + free(distancesP); free(newColor); } *outtuplesP = outtuples; @@ -484,10 +577,12 @@ main(int argc, const char *argv[]) { pnm_colorname(&inPam, bgColor, PAM_COLORNAME_HEXOK)); locatePaintSources(&inPam, inTuples, bgColor, cmdline.downsample, - &paintSources); + &paintSources, + cmdline.randomseedSpec, cmdline.randomseed); produceOutputImage(&inPam, inTuples, bgColor, paintSources, distFunc, - cmdline.power, cmdline.all, &outTuples); + cmdline.power, cmdline.all, + cmdline.nearSpec, cmdline.near, &outTuples); outPam = inPam; outPam.file = stdout; @@ -498,3 +593,6 @@ main(int argc, const char *argv[]) { return 0; } + + + diff --git a/editor/specialty/pampop9.c b/editor/specialty/pampop9.c index d6c61e4f..b92c7d6b 100644 --- a/editor/specialty/pampop9.c +++ b/editor/specialty/pampop9.c @@ -25,9 +25,6 @@ #include "pam.h" -static const char * const copyright = - "(c) Robert Tinsley 2003 (http://www.thepoacher.net/contact)"; - static const char *usagestr = "pnmfile|- xtiles ytiles xdelta ydelta"; int main(int argc, char *argv[]) diff --git a/editor/specialty/pgmabel.c b/editor/specialty/pgmabel.c index 0f4233ac..5badfd19 100644 --- a/editor/specialty/pgmabel.c +++ b/editor/specialty/pgmabel.c @@ -44,7 +44,7 @@ static const char* const version="$VER: pgmabel 1.009 (24 Jan 2002)"; #include "pgm.h" #ifndef PID2 /* PI/2 (on AMIGA always defined) */ -#define PID2 1.57079632679489661923 +#define PID2 1.57079632679489661923 #endif @@ -59,7 +59,7 @@ static double *aldl, *ardl; /* pointer for weighting factors */ ** xr <- array of the calculated elements of the row ** adl <- pre-calculated surface coefficient for each segment */ -static double +static double Sum ( int n, double *xr, int N, double *adl) { int k; @@ -79,7 +79,7 @@ Sum ( int n, double *xr, int N, double *adl) ** R, N <- indizes of the coefficient ** r <- radial position of the center of the surface */ -static double +static double dr ( int R, double r, int N) { double a; @@ -95,7 +95,7 @@ dr ( int R, double r, int N) ** N <- width of the array ** adl <- array with pre-calculated weighting factors */ -static void +static void abel ( float *y, int N, double *adl) { register int n; @@ -126,7 +126,7 @@ abel ( float *y, int N, double *adl) /* ---------------------------------------------------------------------------- ** printing a help message if Option -h(elp) is chosen */ -static void +static void help() { pm_message("-----------------------------------------------------------------"); @@ -142,7 +142,7 @@ help() pm_message("| verbose : output of useful data |"); pm_message("| pgmfile : Name of a pgmfile (optional) |"); pm_message("| |"); - pm_message("| for further information please contact the manpage |"); + pm_message("| for further information please contact the manpage |"); pm_message("-----------------------------------------------------------------"); pm_message("%s",version); /* telling the version */ exit(-1); /* retur-code for no result */ @@ -267,11 +267,11 @@ int main( argc, argv ) } for (col = 0; col < (cols-midcol); ++col) /* factors for right side */ { - for (tc = 0; tc < (cols-midcol); ++tc) + for (tc = 0; tc < (cols-midcol); ++tc) ardl[col*(cols-midcol)+tc] = dr(col,tc+0.5,cols-midcol); } - /* abel-transformation for each row splitted in right and left side */ + /* abel-transformation for each row split into right and left side */ for ( row = 0; row < rows ; ++row ) { pgm_readpgmrow( ifp, grayorig, cols, maxval, format ); @@ -308,3 +308,5 @@ int main( argc, argv ) exit( 0 ); /* end of procedure */ } + + diff --git a/editor/specialty/pnmindex.c b/editor/specialty/pnmindex.c index 438fe058..2b39e4ec 100644 --- a/editor/specialty/pnmindex.c +++ b/editor/specialty/pnmindex.c @@ -1,5 +1,5 @@ /*============================================================================ - pnmindex + pnmindex ============================================================================== build a visual index of a bunch of PNM images @@ -32,7 +32,7 @@ #include "nstring.h" #include "pnm.h" -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -56,11 +56,11 @@ systemf(const char * const fmt, ...) { va_list varargs; - + size_t dryRunLen; - + va_start(varargs, fmt); - + pm_vsnprintf(NULL, 0, fmt, varargs, &dryRunLen); va_end(varargs); @@ -83,7 +83,7 @@ systemf(const char * const fmt, va_start(varargs, fmt); pm_vsnprintf(shellCommand, allocSize, fmt, varargs, &realLen); - + assert(realLen == dryRunLen); va_end(varargs); @@ -94,12 +94,12 @@ systemf(const char * const fmt, if (rc != 0) pm_error("shell command '%s' failed. rc %d", shellCommand, rc); - + pm_strfree(shellCommand); } } } - + static const char * @@ -168,8 +168,8 @@ shellQuote(const char * const arg) { static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, char ** argv, + struct CmdlineInfo * const cmdlineP) { unsigned int option_def_index; optEntry *option_def; @@ -183,13 +183,13 @@ parseCommandLine(int argc, char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "black", OPT_FLAG, NULL, + OPTENT3(0, "black", OPT_FLAG, NULL, &cmdlineP->black, 0); - OPTENT3(0, "noquant", OPT_FLAG, NULL, + OPTENT3(0, "noquant", OPT_FLAG, NULL, &cmdlineP->noquant, 0); - OPTENT3(0, "quant", OPT_FLAG, NULL, + OPTENT3(0, "quant", OPT_FLAG, NULL, &quant, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "size", OPT_UINT, &cmdlineP->size, &sizeSpec, 0); @@ -202,7 +202,7 @@ parseCommandLine(int argc, char ** argv, opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = FALSE; + opt.allowNegNum = FALSE; pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ @@ -212,7 +212,7 @@ parseCommandLine(int argc, char ** argv, if (!colorsSpec) cmdlineP->colors = 256; - + if (!sizeSpec) cmdlineP->size = 100; @@ -246,7 +246,7 @@ parseCommandLine(int argc, char ** argv, static void -freeCmdline(struct cmdlineInfo const cmdline) { +freeCmdline(struct CmdlineInfo const cmdline) { unsigned int i; @@ -326,9 +326,9 @@ rowFileName(const char * const dirName, unsigned int const row) { const char * fileName; - + pm_asprintf(&fileName, "%s/pi.%u", dirName, row); - + return fileName; } @@ -368,7 +368,7 @@ copyImage(const char * const inputFileName, systemf("cat %s > %s", inputFileNmToken, outputFileName); pm_strfree(inputFileNmToken); -} +} @@ -386,26 +386,26 @@ copyScaleQuantImage(const char * const inputFileName, switch (PNM_FORMAT_TYPE(format)) { case PBM_TYPE: - pm_asprintf(&scaleCommand, + pm_asprintf(&scaleCommand, "pamscale -quiet -xysize %u %u %s " "| pgmtopbm > %s", size, size, inputFileNmToken, outputFileName); break; - + case PGM_TYPE: - pm_asprintf(&scaleCommand, + pm_asprintf(&scaleCommand, "pamscale -quiet -xysize %u %u %s >%s", size, size, inputFileNmToken, outputFileName); break; - + case PPM_TYPE: if (quant) - pm_asprintf(&scaleCommand, + pm_asprintf(&scaleCommand, "pamscale -quiet -xysize %u %u %s " "| pnmquant -quiet %u > %s", size, size, inputFileNmToken, colors, outputFileName); else - pm_asprintf(&scaleCommand, + pm_asprintf(&scaleCommand, "pamscale -quiet -xysize %u %u %s >%s", size, size, inputFileNmToken, outputFileName); break; @@ -426,7 +426,7 @@ formatTypeMax(int const typeA, int const typeB) { if (typeA == PPM_TYPE || typeB == PPM_TYPE) - return PPM_TYPE; + return PPM_TYPE; else if (typeA == PGM_TYPE || typeB == PGM_TYPE) return PGM_TYPE; else @@ -441,9 +441,9 @@ thumbnailFileName(const char * const dirName, unsigned int const col) { const char * fileName; - + pm_asprintf(&fileName, "%s/pi.%u.%u", dirName, row, col); - + return fileName; } @@ -464,7 +464,7 @@ thumbnailFileList(const char * const dirName, pm_error("Unable to allocate %u bytes for file list", maxListSize); list[0] = '\0'; - + for (col = 0; col < cols; ++col) { const char * const fileName = thumbnailFileName(dirName, row, col); @@ -487,19 +487,28 @@ makeImageFile(const char * const thumbnailFileName, const char * const inputFileName, bool const blackBackground, const char * const outputFileName) { +/*---------------------------------------------------------------------------- + Create one thumbnail image. It consists of the image in the file named + 'thumbnailFileName' with text of that name appended to the bottom. + Write the result to the file named 'outputFileName'. + + 'blackBackground' means give the image a black background where padding + is necessary and make the text white on black. If false, give the image + a white background instead. +-----------------------------------------------------------------------------*/ const char * const blackWhiteOpt = blackBackground ? "-black" : "-white"; const char * const invertStage = blackBackground ? "| pnminvert " : ""; const char * inputFileNmToken = shellQuote(inputFileName); systemf("pbmtext %s %s" - "| pnmcat %s -topbottom %s - " + "| pamcat %s -topbottom %s - " "> %s", inputFileNmToken, invertStage, blackWhiteOpt, thumbnailFileName, outputFileName); pm_strfree(inputFileNmToken); -} +} @@ -519,21 +528,21 @@ makeThumbnail(const char * const inputFileName, xelval maxval; const char * tmpfile; const char * fileName; - + ifP = pm_openr(inputFileName); pnm_readpnminit(ifP, &imageCols, &imageRows, &maxval, &format); pm_close(ifP); - + pm_asprintf(&tmpfile, "%s/pi.tmp", tempDir); if (imageCols < size && imageRows < size) copyImage(inputFileName, tmpfile); else - copyScaleQuantImage(inputFileName, tmpfile, format, + copyScaleQuantImage(inputFileName, tmpfile, format, size, quant, colors); fileName = thumbnailFileName(tempDir, row, col); - + makeImageFile(tmpfile, inputFileName, black, fileName); unlink(tmpfile); @@ -543,7 +552,7 @@ makeThumbnail(const char * const inputFileName, *formatP = format; } - + static void @@ -552,7 +561,7 @@ unlinkThumbnailFiles(const char * const dirName, unsigned int const cols) { unsigned int col; - + for (col = 0; col < cols; ++col) { const char * const fileName = thumbnailFileName(dirName, row, col); @@ -569,7 +578,7 @@ unlinkRowFiles(const char * const dirName, unsigned int const rows) { unsigned int row; - + for (row = 0; row < rows; ++row) { const char * const fileName = rowFileName(dirName, row); @@ -595,7 +604,7 @@ combineIntoRowAndDelete(unsigned int const row, const char * fileName; const char * quantStage; const char * fileList; - + fileName = rowFileName(tempDir, row); unlink(fileName); @@ -607,7 +616,7 @@ combineIntoRowAndDelete(unsigned int const row, fileList = thumbnailFileList(tempDir, row, cols); - systemf("pnmcat %s -leftright -jbottom %s " + systemf("pamcat %s -leftright -jbottom %s " "%s" ">%s", blackWhiteOpt, fileList, quantStage, fileName); @@ -641,7 +650,7 @@ rowFileList(const char * const dirName, if (strlen(list) + strlen(fileName) + 1 > maxListSize - 1) pm_error("File name list too long for this program to handle."); - + else { strcat(list, " "); strcat(list, fileName); @@ -666,7 +675,7 @@ writeRowsAndDelete(unsigned int const rows, const char * quantStage; const char * fileList; - + if (maxFormatType == PPM_TYPE && quant) pm_asprintf(&quantStage, "| pnmquant -quiet %u ", colors); else @@ -674,7 +683,7 @@ writeRowsAndDelete(unsigned int const rows, fileList = rowFileList(tempDir, rows); - systemf("pnmcat %s -topbottom %s %s", + systemf("pamcat %s -topbottom %s %s", blackWhiteOpt, fileList, quantStage); pm_strfree(fileList); @@ -687,7 +696,7 @@ writeRowsAndDelete(unsigned int const rows, int main(int argc, char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; const char * tempDir; int maxFormatType; unsigned int colsInRow; @@ -699,7 +708,7 @@ main(int argc, char *argv[]) { parseCommandLine(argc, argv, &cmdline); verbose = cmdline.verbose; - + makeTempDir(&tempDir); maxFormatType = PBM_TYPE; @@ -714,7 +723,7 @@ main(int argc, char *argv[]) { int format; - makeThumbnail(inputFileName, cmdline.size, cmdline.black, + makeThumbnail(inputFileName, cmdline.size, cmdline.black, !cmdline.noquant, cmdline.colors, tempDir, rowsDone, colsInRow, &format); @@ -742,3 +751,6 @@ main(int argc, char *argv[]) { return 0; } + + + diff --git a/editor/specialty/ppmshift.c b/editor/specialty/ppmshift.c index a765daa5..27cbb78c3 100644 --- a/editor/specialty/ppmshift.c +++ b/editor/specialty/ppmshift.c @@ -9,124 +9,183 @@ /* V1.1 16.11.1993 Rewritten to be NetPBM.programming conforming */ /*********************************************************************/ +#include <stdbool.h> + +#include "mallocvar.h" +#include "rand.h" +#include "shhopt.h" #include "ppm.h" -/**************************/ -/* start of main function */ -/**************************/ + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; + + unsigned int shift; + unsigned int seedSpec; + unsigned int seed; +}; + + + +static void +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. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY(option_def, 100); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We have no parms that are negative numbers */ + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "seed", OPT_UINT, &cmdlineP->seed, + &cmdlineP->seedSpec, 0); + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 1) + pm_error("You must specify the shift factor as an argument"); + else { + int const arg1 = atoi(argv[1]); + if (arg1 < 0) + pm_error("shift factor must be 0 or more"); + cmdlineP->shift = arg1; + + if (argc-1 < 2) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[2]; + + if (argc-1 > 2) + pm_error("Too many arguments (%u). " + "Shift factor and input file name are the only " + "possible arguments", argc-1); + } + } + free(option_def); +} + + + +static void +shiftRow(pixel * const srcrow, + unsigned int const cols, + unsigned int const shift, + pixel * const destrow, + struct pm_randSt * const randStP) { + + /* the range by which a line is shifted lays in the range from */ + /* -shift/2 .. +shift/2 pixels; however, within this range it is */ + /* randomly chosen */ + + pixel * pP; + pixel * pP2; + int nowshift; + + if (shift != 0) + nowshift = (pm_rand(randStP) % (shift+1)) - ((shift+1) / 2); + else + nowshift = 0; + + pP = &srcrow[0]; + pP2 = &destrow[0]; + + /* if the shift value is less than zero, we take the original + pixel line and copy it into the destination line translated + to the left by x pixels. The empty pixels on the right end + of the destination line are filled up with the pixel that + is the right-most in the original pixel line. + */ + if (nowshift < 0) { + unsigned int col; + pP += abs(nowshift); + for (col = 0; col < cols; ++col) { + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + ++pP2; + if (col < (cols + nowshift) - 1) + ++pP; + } + } else { + unsigned int col; + /* The shift value is 0 or positive, so fill the first + <nowshift> pixels of the destination line with the + first pixel from the source line, and copy the rest of + the source line to the dest line + */ + for (col = 0; col < cols; ++col) { + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + ++pP2; + if (col >= nowshift) + ++pP; + } + } +} + + + int -main(int argc, - char * argv[]) { +main(int argc, const char ** argv) { FILE * ifP; - unsigned int row; - int argn, rows, cols, format; + struct CmdlineInfo cmdline; + int rows, cols, format; + pixval maxval; pixel * srcrow; pixel * destrow; - pixval maxval; - int shift, nowshift; - int shiftArg; - - const char * const usage = "shift [ppmfile]\n shift: maximum number of pixels to shift a line by\n"; + unsigned int row; + unsigned int shift; + struct pm_randSt randSt; /* parse in 'default' parameters */ - ppm_init(&argc, argv); - - argn = 1; - - /* parse in shift number */ - if (argn == argc) - pm_usage(usage); - if (sscanf(argv[argn], "%d", &shiftArg) != 1) - pm_usage(usage); - if (shiftArg < 0) - pm_error("shift factor must be 0 or more"); - ++argn; - - /* parse in filename (if present, stdin otherwise) */ - if (argn != argc) - { - ifP = pm_openr(argv[argn]); - ++argn; - } - else - ifP = stdin; + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.seedSpec, cmdline.seed); - if (argn != argc) - pm_usage(usage); + ifP = pm_openr(cmdline.inputFileName); /* read first data from file */ ppm_readppminit(ifP, &cols, &rows, &maxval, &format); - if (shiftArg > cols) { + if (cmdline.shift > cols) { shift = cols; - pm_message("shift amount is larger than picture width - reset to %d", + pm_message("shift amount is larger than picture width - reset to %u", shift); } else - shift = shiftArg; - - srcrow = ppm_allocrow(cols); + shift = cmdline.shift; + srcrow = ppm_allocrow(cols); destrow = ppm_allocrow(cols); ppm_writeppminit(stdout, cols, rows, maxval, 0); - srand(pm_randseed()); - - /** now do the shifting **/ - /* the range by which a line is shifted lays in the range from */ - /* -shift/2 .. +shift/2 pixels; however, within this range it is */ - /* randomly chosen */ for (row = 0; row < rows; ++row) { - pixel * pP; - pixel * pP2; - - if (shift != 0) - nowshift = (rand() % (shift+1)) - ((shift+1) / 2); - else - nowshift = 0; - ppm_readppmrow(ifP, srcrow, cols, maxval, format); - pP = &srcrow[0]; - pP2 = &destrow[0]; - - /* if the shift value is less than zero, we take the original - pixel line and copy it into the destination line translated - to the left by x pixels. The empty pixels on the right end - of the destination line are filled up with the pixel that - is the right-most in the original pixel line. - */ - if (nowshift < 0) { - unsigned int col; - pP += abs(nowshift); - for (col = 0; col < cols; ++col) { - PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); - ++pP2; - if (col < (cols + nowshift) - 1) - ++pP; - } - } else { - unsigned int col; - /* The shift value is 0 or positive, so fill the first - <nowshift> pixels of the destination line with the - first pixel from the source line, and copy the rest of - the source line to the dest line - */ - for (col = 0; col < cols; ++col) { - PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); - ++pP2; - if (col >= nowshift) - ++pP; - } - } + shiftRow(srcrow, cols, shift, destrow, &randSt); ppm_writeppmrow(stdout, destrow, cols, maxval, 0); } - pm_close(ifP); - ppm_freerow(srcrow); ppm_freerow(destrow); + ppm_freerow(srcrow); + pm_close(ifP); + pm_randterm(&randSt); return 0; } diff --git a/editor/specialty/ppmspread.c b/editor/specialty/ppmspread.c index 6753f4fe..7b9558e3 100644 --- a/editor/specialty/ppmspread.c +++ b/editor/specialty/ppmspread.c @@ -10,102 +10,158 @@ #include <string.h> +#include "nstring.h" +#include "rand.h" +#include "shhopt.h" #include "ppm.h" +struct CmdlineInfo { + /* This structure represents all of the information the user + supplied in the command line but in a form that's easy for the + program to use. + */ + const char * inputFilename; /* '-' if stdin */ + unsigned int spread; + unsigned int randomseedSpec; + unsigned int randomseed; +}; + + + +static void +parseCommandLine(int argc, const char ** const argv, + struct CmdlineInfo * const cmdlineP ) { + + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options */ + optStruct3 opt; + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + option_def_index = 0; /* Incremented by OPTENTRY */ + + OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, + &cmdlineP->randomseedSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = 0; + opt.allowNegNum = 1; + + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 ); + + if (argc-1 < 1) + pm_error("You must specify the spread factor as an argument"); + else { + const char * error; + pm_string_to_uint(argv[1], &cmdlineP->spread, &error); + + if (error) + pm_error("Spread factor '%s' is not an unsigned integer. %s", + argv[1], error); + + if (argc-1 < 2) + cmdlineP->inputFilename = "-"; + else { + cmdlineP->inputFilename = argv[2]; + if (argc-1 >2) + pm_error("Too many arguments: %u. " + "The only possible arguments are " + "the spread factor and the optional input file name", + argc-1); + } + } +} + + + +static void +spreadRow(pixel ** const srcarray, + unsigned int const cols, + unsigned int const rows, + unsigned int const spread, + unsigned int const row, + pixel ** const destarray, + struct pm_randSt * const randStP) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + pixel const p = srcarray[row][col]; + + int const xdis = (pm_rand(randStP) % (spread + 1) ) + - ((spread + 1) / 2); + int const ydis = (pm_rand(randStP) % (spread + 1)) + - ((spread + 1) / 2); + + int const xnew = col + xdis; + int const ynew = row + ydis; + + /* only set the displaced pixel if it's within the bounds + of the image + */ + if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) { + /* Displacing a pixel is accomplished by swapping it + with another pixel in its vicinity. + */ + pixel const p2 = srcarray[ynew][xnew]; + /* Original value of second pixel */ + + /* Set second pixel to new value */ + PPM_ASSIGN(destarray[ynew][xnew], + PPM_GETR(p), PPM_GETG(p), PPM_GETB(p)); + + /* Set first pixel to (old) value of second */ + PPM_ASSIGN(destarray[row][col], + PPM_GETR(p2), PPM_GETG(p2), PPM_GETB(p2)); + } else { + /* Displaced pixel is out of bounds; leave the old pixel there. + */ + PPM_ASSIGN(destarray[row][col], + PPM_GETR(p), PPM_GETG(p), PPM_GETB(p)); + } + } +} + + int -main(int argc, - char * argv[]) { +main(int argc, + const char * argv[]) { + struct CmdlineInfo cmdline; FILE * ifP; - int argn, rows, cols; + int rows, cols; unsigned int row; - pixel ** destarray, ** srcarray; - pixel * pP; - pixel * pP2; + pixel ** destarray; + pixel ** srcarray; pixval maxval; - pixval r1, g1, b1; - int amount; - const char * const usage = "amount [ppmfile]\n amount: # of pixels to displace a pixel by at most\n"; - - /* parse in 'default' parameters */ - ppm_init(&argc, argv); - - argn = 1; - - /* parse in amount & seed */ - if (argn == argc) - pm_usage(usage); - if (sscanf(argv[argn], "%d", &amount) != 1) - pm_usage(usage); - if (amount < 0) - pm_error("amount should be a positive number"); - ++argn; - - /* parse in filename (if present, stdin otherwise) */ - if (argn != argc) - { - ifP = pm_openr(argv[argn]); - ++argn; - } - else - ifP = stdin; + struct pm_randSt randSt; - if (argn != argc) - pm_usage(usage); + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilename); srcarray = ppm_readppm(ifP, &cols, &rows, &maxval); destarray = ppm_allocarray(cols, rows); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + /* clear out the buffer */ for (row = 0; row < rows; ++row) memset(destarray[row], 0, cols * sizeof(pixel)); - srand(pm_randseed()); - - /* start displacing pixels */ + /* Displace pixels */ for (row = 0; row < rows; ++row) { - unsigned int col; - pP = &srcarray[row][0]; - - for (col = 0; col < cols; ++col) { - int const xdis = (rand() % (amount+1)) - ((amount+1) / 2); - int const ydis = (rand() % (amount+1)) - ((amount+1) / 2); + spreadRow(srcarray, cols, rows, cmdline.spread, row, + destarray, &randSt); - int const xnew = col + xdis; - int const ynew = row + ydis; - - /* only set the displaced pixel if it's within the bounds - of the image - */ - if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) { - /* displacing a pixel is accomplished by swapping it - with another pixel in its vicinity - so, first - store other pixel's RGB - */ - pP2 = &srcarray[ynew][xnew]; - r1 = PPM_GETR(*pP2); - g1 = PPM_GETG(*pP2); - b1 = PPM_GETB(*pP2); - /* set second pixel to new value */ - pP2 = &destarray[ynew][xnew]; - PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); - - /* now, set first pixel to (old) value of second */ - pP2 = &destarray[row][col]; - PPM_ASSIGN(*pP2, r1, g1, b1); - } else { - /* displaced pixel is out of bounds; leave the old - pixel there - */ - pP2 = &destarray[row][col]; - PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); - } - ++pP; - } } + pm_randterm(&randSt); ppm_writeppm(stdout, destarray, cols, rows, maxval, 0); @@ -115,3 +171,5 @@ main(int argc, return 0; } + + |