diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2019-06-28 23:07:55 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2019-06-28 23:07:55 +0000 |
commit | 11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32 (patch) | |
tree | 7c40f096dd973943ef563ec87b2a68d8205db4fb /editor/specialty | |
parent | 89c6ec14eb7514630aea5abc4b90b51d1473d33a (diff) | |
download | netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.tar.gz netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.tar.xz netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.zip |
Promote Stable to Super_stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@3640 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor/specialty')
-rw-r--r-- | editor/specialty/Makefile | 2 | ||||
-rw-r--r-- | editor/specialty/pamdeinterlace.c | 2 | ||||
-rw-r--r-- | editor/specialty/pammixinterlace.c | 2 | ||||
-rw-r--r-- | editor/specialty/pampaintspill.c | 500 | ||||
-rw-r--r-- | editor/specialty/pgmabel.c | 6 | ||||
-rw-r--r-- | editor/specialty/pgmmorphconv.c | 520 | ||||
-rw-r--r-- | editor/specialty/pnmindex.c | 81 | ||||
-rw-r--r-- | editor/specialty/pnmmercator.c | 430 | ||||
-rw-r--r-- | editor/specialty/ppm3d.c | 4 | ||||
-rw-r--r-- | editor/specialty/ppmglobe.c | 4 | ||||
-rw-r--r-- | editor/specialty/ppmntsc.c | 311 | ||||
-rw-r--r-- | editor/specialty/ppmrelief.c | 112 |
12 files changed, 1547 insertions, 427 deletions
diff --git a/editor/specialty/Makefile b/editor/specialty/Makefile index 76befbb4..427c2c8f 100644 --- a/editor/specialty/Makefile +++ b/editor/specialty/Makefile @@ -11,11 +11,13 @@ PORTBINARIES = pamdeinterlace \ pammixinterlace \ pamoil \ pampop9 \ + pampaintspill \ pbmlife \ pgmabel \ pgmbentley \ pgmmorphconv \ pnmindex \ + pnmmercator \ ppm3d \ ppmglobe \ ppmntsc \ diff --git a/editor/specialty/pamdeinterlace.c b/editor/specialty/pamdeinterlace.c index 7c6b123c..d6f6aee1 100644 --- a/editor/specialty/pamdeinterlace.c +++ b/editor/specialty/pamdeinterlace.c @@ -47,7 +47,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); diff --git a/editor/specialty/pammixinterlace.c b/editor/specialty/pammixinterlace.c index 9f98b406..7410a8f1 100644 --- a/editor/specialty/pammixinterlace.c +++ b/editor/specialty/pammixinterlace.c @@ -200,7 +200,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!filterSpec) diff --git a/editor/specialty/pampaintspill.c b/editor/specialty/pampaintspill.c new file mode 100644 index 00000000..745c9b68 --- /dev/null +++ b/editor/specialty/pampaintspill.c @@ -0,0 +1,500 @@ +/* ---------------------------------------------------------------------- + * + * Bleed colors from non-background colors into the background + * + * By Scott Pakin <scott+pbm@pakin.org> + * + * ---------------------------------------------------------------------- + * + * Copyright (C) 2010 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 + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * ---------------------------------------------------------------------- + */ + +/* + This program contains code to work with Openmp, so that it can process + multiple columns at once, using multiple threads on multiple CPU cores, + and thus take less elapsed time to run. + + But that code is dead in a normal Netpbm build, as it does not use the + required compiler options or link with the required library in any + conventional environment we know of. One can exploit this code with a + modified build, e.g. with CADD and LADD make variables. + + 10.04.14 +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <time.h> + +#include "mallocvar.h" +#include "nstring.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; + /* Minimum number of progress updates to output */ + + +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 */ + const char * bgcolor; + unsigned int wrap; + unsigned int all; + float power; + unsigned int downsample; +}; + +struct coords { + /* This structure represents an (x,y) coordinate within an image and + the color at that coordinate. */ + unsigned int x; + unsigned int y; + tuple color; +}; + +typedef double distFunc_t(const struct coords * const p0, + const struct coords * const p1, + unsigned int const width, + unsigned int const height); + /* Distance function */ + + + +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; + unsigned int bgcolorSpec, powerSpec, downsampleSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + option_def_index = 0; /* Incremented by OPTENTRY */ + + 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, + &powerSpec, 0); + OPTENT3(0, "downsample", OPT_UINT, &cmdlineP->downsample, + &downsampleSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = 0; + opt.allowNegNum = 1; + + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 ); + + if (!bgcolorSpec) + cmdlineP->bgcolor = NULL; + + if (!powerSpec) + cmdlineP->power = -2.0; + + if (!downsampleSpec) + cmdlineP->downsample = 0; + + if (argc-1 < 1) + cmdlineP->inputFilename = "-"; + else { + cmdlineP->inputFilename = argv[1]; + if (argc-1 > 1) + pm_error("Too many arguments: %u. The only argument is the " + "optional input file name", argc-1); + } +} + + +static bool +tupleEqualColor(const struct pam * const pamP, + tuple const comparand, + tuple const comparator) { +/*---------------------------------------------------------------------------- + Report whether two tuples have equal color, regardless of alpha. +----------------------------------------------------------------------------*/ + unsigned int const nColorPlanes = pamP->depth >= 3 ? 3 : 1; + + unsigned int plane; + + for (plane = 0; plane < nColorPlanes; ++plane) + if (comparand[plane] != comparator[plane]) + return false; + + return true; +} + + + +struct paintSourceSet { + struct coords * list; /* malloc'ed */ + /* The list of places in the image from which paint comes */ + unsigned int size; + /* Number of entries in sources[] */ + unsigned int alloc; + /* Number of slots for entries of allocated memory */ +}; + + + +static void +setPaintSourceColors(struct pam * const pamP, + tuple ** const tuples, + struct paintSourceSet const paintSources) { +/*---------------------------------------------------------------------------- + Set the 'color' member of each source in 'paintSources'. + + Set it to the color of the source pixel in tuples[][], indicated by + 'paintSources'. + + Malloc memory to store these colors -- a contiguous block of memory for all + of them. +-----------------------------------------------------------------------------*/ + struct pam pamPaint; + /* numPaintSources-wide PAM for use by pnm_allocpamrow() */ + tuple * paintColor; + /* Points to storage for the color tuples */ + unsigned int i; + + pamPaint = *pamP; + pamPaint.width = paintSources.size; + paintColor = pnm_allocpamrow(&pamPaint); + + for (i = 0; i < paintSources.size; ++i) { + struct coords * const thisSourceP = &paintSources.list[i]; + + thisSourceP->color = paintColor[i]; + pnm_assigntuple(pamP, thisSourceP->color, + tuples[thisSourceP->y][thisSourceP->x]); + } +} + + + +static void +addPaintSource(unsigned int const row, + unsigned int const col, + struct paintSourceSet * const paintSourcesP) { + + if (paintSourcesP->size == paintSourcesP->alloc) { + paintSourcesP->alloc += 1024; + REALLOCARRAY(paintSourcesP->list, paintSourcesP->alloc); + if (!paintSourcesP->list) + pm_error("Out of memory"); + } + paintSourcesP->list[paintSourcesP->size].x = col; + paintSourcesP->list[paintSourcesP->size].y = row; + ++paintSourcesP->size; +} + + + +static void +locatePaintSources(struct pam * const pamP, + tuple ** const tuples, + tuple const bgColor, + unsigned int const downsample, + struct paintSourceSet * const paintSourcesP) { +/*-------------------------------------------------------------------- + Construct a list of all pixel coordinates in the input image that + represent a non-background color. + ----------------------------------------------------------------------*/ + struct paintSourceSet paintSources; + int row; /* signed so it works with Openmp */ + + paintSources.list = NULL; + paintSources.size = 0; + paintSources.alloc = 0; + + #pragma omp parallel for + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + if (!tupleEqualColor(pamP, tuples[row][col], bgColor)) + #pragma omp critical (addPaintSource) + addPaintSource(row, col, &paintSources); + } + } + + 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) { + unsigned int i; + + srand(time(NULL)); + + for (i = 0; i < downsample; ++i) { + unsigned int const swapIdx = + i + rand() % (paintSources.size - i); + struct coords const swapVal = paintSources.list[i]; + + paintSources.list[i] = paintSources.list[swapIdx]; + paintSources.list[swapIdx] = swapVal; + } + paintSources.size = downsample; + } + + setPaintSourceColors(pamP, tuples, paintSources); + + *paintSourcesP = paintSources; +} + + + +static distFunc_t euclideanDistanceSqr; + +static double +euclideanDistanceSqr(const struct coords * const p0, + const struct coords * const p1, + unsigned int const width, + unsigned int const height) { +/*---------------------------------------------------------------------------- + Return the square of the Euclidian distance between p0 and p1. +-----------------------------------------------------------------------------*/ + double const deltax = (double) (int) (p1->x - p0->x); + double const deltay = (double) (int) (p1->y - p0->y); + + return SQR(deltax) + SQR(deltay); +} + + + +static distFunc_t euclideanDistanceTorusSqr; + +static double +euclideanDistanceTorusSqr(const struct coords * const p0, + const struct coords * const p1, + unsigned int const width, + unsigned int const height) { +/*---------------------------------------------------------------------------- + Return the square of the Euclidian 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. +-----------------------------------------------------------------------------*/ + struct coords p0Adj, p1Adj; + + if (p1->x >= p0->x + width / 2) { + p0Adj.x = p0->x + width; + p1Adj.x = p1->x; + } else if (p0->x >= p1->x + width / 2) { + p0Adj.x = p0->x; + p1Adj.x = p1->x + width; + } else { + p0Adj.x = p0->x; + p1Adj.x = p1->x; + } + if (p1->y >= p0->y + height / 2) { + p0Adj.y = p0->y + height; + p1Adj.y = p1->y; + } else if (p0->y >= p1->y + height / 2) { + p0Adj.y = p0->y; + p1Adj.y = p1->y + height; + } else { + p0Adj.y = p0->y; + p1Adj.y = p1->y; + } + + return euclideanDistanceSqr(&p0Adj, &p1Adj, 0, 0); +} + + + +static void +reportProgress(unsigned int const rowsComplete, + unsigned int const height) { + + static time_t prevOutputTime = 0; + time_t now; /* Current time in seconds */ + + if (prevOutputTime == 0) + prevOutputTime = time(NULL); + + /* Output our progress only every timeUpdateDelta seconds. */ + now = time(NULL); + if (prevOutputTime) { + if (now - prevOutputTime >= timeUpdateDelta + || rowsComplete % (height/minUpdates) == 0) { + pm_message("%5.1f%% complete", + rowsComplete * 100.0 / height); + prevOutputTime = now; + } + } else + prevOutputTime = now; +} + + + +static void +spillOnePixel(struct pam * const pamP, + struct coords const target, + struct paintSourceSet const paintSources, + distFunc_t * const distFunc, + double const distPower, + tuple const outTuple, + double * const newColor) { + + unsigned int plane; + unsigned int ps; + double totalWeight; + + for (plane = 0; plane < pamP->depth; ++plane) + newColor[plane] = 0.0; + 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); + + 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); + + unsigned int plane; + + for (plane = 0; plane < pamP->depth; ++plane) + newColor[plane] += weight * source.color[plane]; + + totalWeight += weight; + } + } + for (plane = 0; plane < pamP->depth; ++plane) + outTuple[plane] = (sample) (newColor[plane] / totalWeight); +} + + + +static void +produceOutputImage(struct pam * const pamP, + tuple ** const intuples, + tuple const bgColor, + struct paintSourceSet const paintSources, + distFunc_t * const distFunc, + double const distPower, + bool const all, + tuple *** const outtuplesP) { +/*-------------------------------------------------------------------- + Color each background pixel (or, if allPixels is 1, all pixels) + using a fraction of each paint source as determined by its distance + to the background pixel. +----------------------------------------------------------------------*/ + int row; /* signed so it works with Openmp */ + unsigned int rowsComplete; + tuple ** outtuples; + + outtuples = pnm_allocpamarray(pamP); + + rowsComplete = 0; + #pragma omp parallel for + for (row = 0; row < pamP->height; ++row) { + struct coords target; + double * newColor; + + MALLOCARRAY(newColor, pamP->depth); + + target.y = row; + for (target.x = 0; target.x < pamP->width; ++target.x) { + tuple const targetTuple = intuples[target.y][target.x]; + tuple const outputTuple = outtuples[target.y][target.x]; + + if (all || tupleEqualColor(pamP, targetTuple, bgColor)) + spillOnePixel(pamP, target, paintSources, distFunc, distPower, + outputTuple, newColor); + else + pnm_assigntuple(pamP, outputTuple, targetTuple); + } + #pragma omp critical (rowTally) + reportProgress(++rowsComplete, pamP->height); + + free(newColor); + } + *outtuplesP = outtuples; +} + + + +int +main(int argc, const char *argv[]) { + FILE * ifP; + struct cmdlineInfo cmdline; /* Command-line parameters */ + tuple bgColor; /* Input image's background color */ + struct paintSourceSet paintSources; + /* The set of paint-source indexes into 'tuples' */ + distFunc_t * distFunc; /* The distance function */ + struct pam inPam; + struct pam outPam; + tuple ** inTuples; + tuple ** outTuples; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilename); + + inTuples = pnm_readpam(ifP, &inPam, PAM_STRUCT_SIZE(allocation_depth)); + + pm_close(ifP); + + distFunc = cmdline.wrap ? euclideanDistanceTorusSqr : euclideanDistanceSqr; + + if (cmdline.bgcolor) + bgColor = pnm_parsecolor(cmdline.bgcolor, inPam.maxval) ; + else + bgColor = pnm_backgroundtuple(&inPam, inTuples); + + pm_message("Treating %s as the background color", + pnm_colorname(&inPam, bgColor, PAM_COLORNAME_HEXOK)); + + locatePaintSources(&inPam, inTuples, bgColor, cmdline.downsample, + &paintSources); + + produceOutputImage(&inPam, inTuples, bgColor, paintSources, distFunc, + cmdline.power, cmdline.all, &outTuples); + + outPam = inPam; + outPam.file = stdout; + pnm_writepam(&outPam, outTuples); + + pnm_freepamarray(outTuples, &inPam); + pnm_freepamarray(inTuples, &outPam); + + return 0; +} diff --git a/editor/specialty/pgmabel.c b/editor/specialty/pgmabel.c index 4914c4be..1764c5d7 100644 --- a/editor/specialty/pgmabel.c +++ b/editor/specialty/pgmabel.c @@ -38,15 +38,15 @@ static const char* const version="$VER: pgmabel 1.009 (24 Jan 2002)"; #include <math.h> #include <stdlib.h> /* for calloc */ -#include "pgm.h" + +#include "pm_c_util.h" #include "mallocvar.h" +#include "pgm.h" #ifndef PID2 /* PI/2 (on AMIGA always defined) */ #define PID2 1.57079632679489661923 #endif -#define TRUE 1 -#define FALSE 0 /* some global variables */ static double *aldl, *ardl; /* pointer for weighting factors */ diff --git a/editor/specialty/pgmmorphconv.c b/editor/specialty/pgmmorphconv.c index abc4e718..2ba2d62d 100644 --- a/editor/specialty/pgmmorphconv.c +++ b/editor/specialty/pgmmorphconv.c @@ -17,237 +17,403 @@ */ #include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" #include "pgm.h" -/************************************************************ - * Dilate - ************************************************************/ -static int -dilate( bit** template, int trowso2, int tcolso2, - gray** in_image, gray** out_image, - int rows, int cols ){ +enum Operation { ERODE, DILATE, OPEN, CLOSE, GRADIENT }; + + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + const char * templateFileName; /* File name of template file */ - int c, r, tc, tr; - int templatecount; - gray source; + enum Operation operation; +}; - for( c=0; c<cols; ++c) - for( r=0; r<rows; ++r ) - out_image[r][c] = 0; /* only difference with erode is here and below */ - - /* - * for each non-black pixel of the template - * add in to out - */ - templatecount=0; - for( tr=-trowso2; tr<=trowso2; ++tr ){ - for( tc=-tcolso2; tc<=tcolso2; ++tc ){ +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; + unsigned int erode, dilate, open, close, gradient; - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; + MALLOCARRAY_NOFAIL(option_def, 100); - ++templatecount; + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "erode", OPT_FLAG, NULL, &erode, 0); + OPTENT3(0, "dilate", OPT_FLAG, NULL, &dilate, 0); + OPTENT3(0, "open", OPT_FLAG, NULL, &open, 0); + OPTENT3(0, "close", OPT_FLAG, NULL, &close, 0); + OPTENT3(0, "gradient", OPT_FLAG, NULL, &gradient, 0); - for( r= ((tr>0)?0:-tr) ; r< ((tr>0)?(rows-tr):rows) ; ++r ){ - for( c= ((tc>0)?0:-tc) ; c< ((tc>0)?(cols-tc):cols) ; ++c ){ - source = in_image[r+tr][c+tc]; - out_image[r][c] = MAX(source, out_image[r][c]); - } /* for c */ - } /* for r */ - } /* for tr */ - } /* for tc */ + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ - return templatecount; + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ -} /* dilate */ + if (erode + dilate + open + close + gradient > 1) + pm_error("You may specify at most one of -erode, -dilate, " + "-open, -close, or -gradient"); + if (erode) + cmdlineP->operation = ERODE; + else if (dilate) + cmdlineP->operation = DILATE; + else if (open) + cmdlineP->operation = OPEN; + else if (close) + cmdlineP->operation = CLOSE; + else if (gradient) + cmdlineP->operation = GRADIENT; + else + cmdlineP->operation = DILATE; + + if (argc-1 < 1) + pm_error("You must specify the template file name as an argument"); + else { + cmdlineP->templateFileName = argv[1]; + + 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 template file name and the input file name", + argc-1); + } + } +} + + + +static void +readTemplateMatrix(const char * const fileName, + bit *** const templateP, + unsigned int * const rowsP, + unsigned int * const colsP) { +/*---------------------------------------------------------------------------- + Read in the template matrix. +-----------------------------------------------------------------------------*/ + FILE * templateFileP; + int cols, rows; + + templateFileP = pm_openr(fileName); + + *templateP = pbm_readpbm(templateFileP, &cols, &rows); + + pm_close(templateFileP); + + if (cols % 2 != 1 || rows % 2 != 1) + pm_error("the template matrix must have an odd number of " + "rows and columns" ); + + /* the reason is that we want the middle pixel to be the origin */ + *rowsP = rows; + *colsP = cols; +} + + + +static void +setAllPixel(gray ** const image, + unsigned int const rows, + unsigned int const cols, + gray const value) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + unsigned int row; + for (row = 0; row < rows; ++row) + image[row][col] = value; + } +} + + + +static void +dilate(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + unsigned int templateCount; + int tr; + + setAllPixel(outImage, rows, cols, 0); + + /* for each non-black pixel of the template add in to out */ + + for (tr = -trowso2, templateCount = 0; tr <= trowso2; ++tr) { + int tc; + for (tc = -tcolso2; tc <= tcolso2; ++tc) { + int r; + if (template[trowso2+tr][tcolso2+tc] != PBM_BLACK) { + ++templateCount; + + for (r = ((tr > 0) ? 0 : -tr); + r < ((tr > 0) ? (rows-tr) : rows); + ++r) { + int c; + for (c = ((tc > 0) ? 0 : -tc); + c < ((tc > 0) ? (cols-tc) : cols); + ++c) { + gray const source = inImage[r+tr][c+tc]; + outImage[r][c] = MAX(source, outImage[r][c]); + } + } + } + } + } + *templateCountP = templateCount; +} + + + +static void +erode(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + unsigned int templateCount; + int tr; + + setAllPixel(outImage, rows, cols, PGM_MAXMAXVAL); + + /* For each non-black pixel of the template add in to out */ + + for (tr = -trowso2, templateCount = 0; tr <= trowso2; ++tr) { + int tc; + for (tc = -tcolso2; tc <= tcolso2; ++tc) { + if (template[trowso2+tr][tcolso2+tc] != PBM_BLACK) { + int r; + ++templateCount; + + for (r = ((tr > 0) ? 0 : -tr); + r < ((tr > 0) ? (rows-tr) : rows); + ++r){ + int c; + + for (c = ((tc > 0) ? 0 : -tc); + c < ((tc > 0) ? (cols-tc) : cols); + ++c) { + + gray const source = inImage[r+tr][c+tc]; + outImage[r][c] = MIN(source, outImage[r][c]); + + } + } + } + } + } + *templateCountP = templateCount; +} -/************************************************************ - * Erode: same as dilate except !!!! - ************************************************************/ -static int -erode( bit** template, int trowso2, int tcolso2, - gray** in_image, gray** out_image, - int rows, int cols ){ +static void +openMorph(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { - int c, r, tc, tr; - int templatecount; - gray source; + gray ** erodedImage; + unsigned int erodedTemplateCount; - for( c=0; c<cols; ++c) - for( r=0; r<rows; ++r ) - out_image[r][c] = PGM_MAXMAXVAL; /* !!!! */ - - /* - * for each non-black pixel of the template - * add in to out - */ + erodedImage = pgm_allocarray(cols, rows); + + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, &erodedTemplateCount); - templatecount=0; + dilate(template, trowso2, tcolso2, + erodedImage, outputImage, rows, cols, templateCountP); - for( tr=-trowso2; tr<=trowso2; ++tr ){ - for( tc=-tcolso2; tc<=tcolso2; ++tc ){ + pgm_freearray(erodedImage, rows); +} - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; - ++templatecount; - for( r= ((tr>0)?0:-tr) ; r< ((tr>0)?(rows-tr):rows) ; ++r ){ - for( c= ((tc>0)?0:-tc) ; c< ((tc>0)?(cols-tc):cols) ; ++c ){ +static void +closeMorph(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { - source = in_image[r+tr][c+tc]; - out_image[r][c] = MIN(source, out_image[r][c]); - - } /* for c */ - } /* for r */ + gray ** dilatedImage; + unsigned int dilatedTemplateCount; + dilatedImage = pgm_allocarray(cols, rows); + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); - } /* for tr */ - } /* for tc */ + erode(template, trowso2, tcolso2, + dilatedImage, outputImage, rows, cols, templateCountP); - return templatecount; + pgm_freearray(dilatedImage, rows); +} -} /* erode */ +static void +subtract(gray ** const subtrahendImage, + gray ** const subtractorImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols ) { -/************************************************************ - * Main - ************************************************************/ + /* (I call the minuend the subtrahend and the subtrahend the subtractor, + to be consistent with other arithmetic terminology). + */ + unsigned int c; -int main( int argc, char* argv[] ){ + for (c = 0; c < cols; ++c) { + unsigned int r; + for (r = 0; r < rows; ++r) + outImage[r][c] = subtrahendImage[r][c] - subtractorImage[r][c]; + } +} - int argn; - char operation; - const char* usage = "-dilate|-erode|-open|-close <templatefile> [pgmfile]"; - FILE* tifp; /* template */ - int tcols, trows; - int tcolso2, trowso2; - bit** template; +static void +gradient(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { - FILE* ifp; /* input image */ - int cols, rows; - gray maxval; + gray ** dilatedImage; + gray ** erodedImage; + unsigned int dilatedTemplateCount; + + dilatedImage = pgm_allocarray(cols, rows); + erodedImage = pgm_allocarray(cols, rows); - gray** in_image; - gray** out_image; + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); - int templatecount=0; + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, templateCountP); - pgm_init( &argc, argv ); + subtract(dilatedImage, erodedImage, outputImage, rows, cols); - /* - * parse arguments - */ - - ifp = stdin; - operation = 'd'; + pgm_freearray(erodedImage, rows ); + pgm_freearray(dilatedImage, rows ); +} - argn=1; - - if( argn == argc ) pm_usage( usage ); - - if( pm_keymatch( argv[argn], "-erode", 2 )) { operation='e'; argn++; } - else - if( pm_keymatch( argv[argn], "-dilate", 2 )) { operation='d'; argn++; } - else - if( pm_keymatch( argv[argn], "-open", 2 )) { operation='o'; argn++; } - else - if( pm_keymatch( argv[argn], "-close", 2 )) { operation='c'; argn++; } - - if( argn == argc ) pm_usage( usage ); - - tifp = pm_openr( argv[argn++] ); - - if( argn != argc ) ifp = pm_openr( argv[argn++] ); - if( argn != argc ) pm_usage( usage ); - - /* - * Read in the template matrix. - */ +int +main(int argc, const char ** argv) { - template = pbm_readpbm( tifp, &tcols, &trows ); - pm_close( tifp ); + struct CmdlineInfo cmdline; + FILE * ifP; + bit ** template; + unsigned int templateCols, templateRows; + int cols, rows; + gray maxval; + gray ** inputImage; + gray ** outputImage; + unsigned int templateCount; - if( tcols % 2 != 1 || trows % 2 != 1 ) - pm_error("the template matrix must have an odd number of " - "rows and columns" ); + pm_proginit(&argc, argv); - /* the reason is that we want the middle pixel to be the origin */ - tcolso2 = tcols / 2; /* template coords run from -tcols/2 .. 0 .. +tcols/2 */ - trowso2 = trows / 2; + parseCommandLine(argc, argv, &cmdline); -#if 0 - fprintf(stderr, "template: %d x %d\n", trows, tcols); - fprintf(stderr, "half: %d x %d\n", trowso2, tcolso2); -#endif + ifP = pm_openr(cmdline.inputFileName); - /* - * Read in the image - */ - - in_image = pgm_readpgm( ifp, &cols, &rows, &maxval); + readTemplateMatrix(cmdline.templateFileName, + &template, &templateRows, &templateCols); - if( cols < tcols || rows < trows ) - pm_error("the image is smaller than the convolution matrix" ); + /* Template coords run from -templateCols/2 .. 0 .. + templateCols/2 */ -#if 0 - fprintf(stderr, "image: %d x %d (%d)\n", rows, cols, maxval); -#endif - - /* - * Allocate output buffer and initialize with min or max value - */ + inputImage = pgm_readpgm(ifP, &cols, &rows, &maxval); - out_image = pgm_allocarray( cols, rows ); + if (cols < templateCols || rows < templateRows) + pm_error("the image is smaller than the convolution matrix" ); - if( operation == 'd' ){ - templatecount = dilate(template, trowso2, tcolso2, - in_image, out_image, rows, cols); - } - else if( operation == 'e' ){ - templatecount = erode(template, trowso2, tcolso2, - in_image, out_image, rows, cols); - } - else if( operation == 'o' ){ - gray ** eroded_image; - eroded_image = pgm_allocarray( cols, rows ); - templatecount = erode(template, trowso2, tcolso2, - in_image, eroded_image, rows, cols); - templatecount = dilate(template, trowso2, tcolso2, - eroded_image, out_image, rows, cols); - pgm_freearray( eroded_image, rows ); - } - else if( operation == 'c' ){ - gray ** dilated_image; - dilated_image = pgm_allocarray( cols, rows ); - templatecount = dilate(template, trowso2, tcolso2, - in_image, dilated_image, rows, cols); - templatecount = erode(template, trowso2, tcolso2, - dilated_image, out_image, rows, cols); - pgm_freearray( dilated_image, rows ); - } + outputImage = pgm_allocarray(cols, rows); - if(templatecount == 0 ) pm_error( "The template was empty!" ); - - pgm_writepgm( stdout, out_image, cols, rows, maxval, 1 ); - - pgm_freearray( out_image, rows ); - pgm_freearray( in_image, rows ); - pm_close( ifp ); - - exit( 0 ); - -} /* main */ + switch (cmdline.operation) { + case DILATE: + dilate(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case ERODE: + erode(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case OPEN: + openMorph(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case CLOSE: + closeMorph(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case GRADIENT: + gradient(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + } + + if (templateCount == 0) + pm_error( "The template was empty!" ); + + pgm_writepgm(stdout, outputImage, cols, rows, maxval, 0); + + pgm_freearray(outputImage, rows); + pgm_freearray(inputImage, rows); + pm_close(ifP); + + return 0; +} diff --git a/editor/specialty/pnmindex.c b/editor/specialty/pnmindex.c index ca1da18c..4ec9edaa 100644 --- a/editor/specialty/pnmindex.c +++ b/editor/specialty/pnmindex.c @@ -14,6 +14,7 @@ ============================================================================*/ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup is in string.h */ #include <assert.h> @@ -59,7 +60,7 @@ systemf(const char * const fmt, va_start(varargs, fmt); - vsnprintfN(NULL, 0, fmt, varargs, &dryRunLen); + pm_vsnprintf(NULL, 0, fmt, varargs, &dryRunLen); va_end(varargs); @@ -72,7 +73,7 @@ systemf(const char * const fmt, shellCommand = malloc(allocSize); if (shellCommand == NULL) pm_error("Can't get storage for %u-character command", - allocSize); + (unsigned)allocSize); else { va_list varargs; size_t realLen; @@ -80,7 +81,7 @@ systemf(const char * const fmt, va_start(varargs, fmt); - vsnprintfN(shellCommand, allocSize, fmt, varargs, &realLen); + pm_vsnprintf(shellCommand, allocSize, fmt, varargs, &realLen); assert(realLen == dryRunLen); va_end(varargs); @@ -93,7 +94,7 @@ systemf(const char * const fmt, pm_error("shell command '%s' failed. rc %d", shellCommand, rc); - strfree(shellCommand); + pm_strfree(shellCommand); } } } @@ -106,7 +107,7 @@ parseCommandLine(int argc, char ** argv, unsigned int option_def_index; optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -137,7 +138,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (quant && cmdlineP->noquant) @@ -184,7 +185,7 @@ freeCmdline(struct cmdlineInfo const cmdline) { unsigned int i; for (i = 0; i < cmdline.inputFileCount; ++i) - strfree(cmdline.inputFileName[i]); + pm_strfree(cmdline.inputFileName[i]); free(cmdline.inputFileName); @@ -200,7 +201,7 @@ makeTempDir(const char ** const tempDirP) { const char * mytmpdir; int rc; - asprintfN(&mytmpdir, "%s/pnmindex_%d", tmpdir, getpid()); + pm_asprintf(&mytmpdir, "%s/pnmindex_%d", tmpdir, getpid()); rc = pm_mkdir(mytmpdir, 0700); if (rc != 0) @@ -232,7 +233,7 @@ rowFileName(const char * const dirName, const char * fileName; - asprintfN(&fileName, "%s/pi.%u", dirName, row); + pm_asprintf(&fileName, "%s/pi.%u", dirName, row); return fileName; } @@ -259,7 +260,7 @@ makeTitle(const char * const title, "> %s", title, invertStage, fileName); - strfree(fileName); + pm_strfree(fileName); } @@ -285,28 +286,28 @@ copyScaleQuantImage(const char * const inputFileName, switch (PNM_FORMAT_TYPE(format)) { case PBM_TYPE: - asprintfN(&scaleCommand, - "pamscale -quiet -xysize %u %u %s " - "| pgmtopbm > %s", - size, size, inputFileName, outputFileName); + pm_asprintf(&scaleCommand, + "pamscale -quiet -xysize %u %u %s " + "| pgmtopbm > %s", + size, size, inputFileName, outputFileName); break; case PGM_TYPE: - asprintfN(&scaleCommand, - "pamscale -quiet -xysize %u %u %s >%s", - size, size, inputFileName, outputFileName); + pm_asprintf(&scaleCommand, + "pamscale -quiet -xysize %u %u %s >%s", + size, size, inputFileName, outputFileName); break; case PPM_TYPE: if (quant) - asprintfN(&scaleCommand, - "pamscale -quiet -xysize %u %u %s " - "| pnmquant -quiet %u > %s", - size, size, inputFileName, colors, outputFileName); + pm_asprintf(&scaleCommand, + "pamscale -quiet -xysize %u %u %s " + "| pnmquant -quiet %u > %s", + size, size, inputFileName, colors, outputFileName); else - asprintfN(&scaleCommand, - "pamscale -quiet -xysize %u %u %s >%s", - size, size, inputFileName, outputFileName); + pm_asprintf(&scaleCommand, + "pamscale -quiet -xysize %u %u %s >%s", + size, size, inputFileName, outputFileName); break; default: pm_error("Unrecognized Netpbm format: %d", format); @@ -314,7 +315,7 @@ copyScaleQuantImage(const char * const inputFileName, systemf("%s", scaleCommand); - strfree(scaleCommand); + pm_strfree(scaleCommand); } @@ -340,7 +341,7 @@ thumbnailFileName(const char * const dirName, const char * fileName; - asprintfN(&fileName, "%s/pi.%u.%u", dirName, row, col); + pm_asprintf(&fileName, "%s/pi.%u.%u", dirName, row, col); return fileName; } @@ -372,7 +373,7 @@ thumbnailFileList(const char * const dirName, strcat(list, " "); strcat(list, fileName); } - strfree(fileName); + pm_strfree(fileName); } return list; @@ -420,7 +421,7 @@ makeThumbnail(const char * const inputFileName, pnm_readpnminit(ifP, &imageCols, &imageRows, &maxval, &format); pm_close(ifP); - asprintfN(&tmpfile, "%s/pi.tmp", tempDir); + pm_asprintf(&tmpfile, "%s/pi.tmp", tempDir); if (imageCols < size && imageRows < size) copyImage(inputFileName, tmpfile); @@ -434,8 +435,8 @@ makeThumbnail(const char * const inputFileName, unlink(tmpfile); - strfree(fileName); - strfree(tmpfile); + pm_strfree(fileName); + pm_strfree(tmpfile); *formatP = format; } @@ -454,7 +455,7 @@ unlinkThumbnailFiles(const char * const dirName, unlink(fileName); - strfree(fileName); + pm_strfree(fileName); } } @@ -471,7 +472,7 @@ unlinkRowFiles(const char * const dirName, unlink(fileName); - strfree(fileName); + pm_strfree(fileName); } } @@ -497,7 +498,7 @@ combineIntoRowAndDelete(unsigned int const row, unlink(fileName); if (maxFormatType == PPM_TYPE && quant) - asprintfN(&quantStage, "| pnmquant -quiet %u ", colors); + pm_asprintf(&quantStage, "| pnmquant -quiet %u ", colors); else quantStage = strdup(""); @@ -508,9 +509,9 @@ combineIntoRowAndDelete(unsigned int const row, ">%s", blackWhiteOpt, fileList, quantStage, fileName); - strfree(fileList); - strfree(quantStage); - strfree(fileName); + pm_strfree(fileList); + pm_strfree(quantStage); + pm_strfree(fileName); unlinkThumbnailFiles(tempDir, row, cols); } @@ -542,7 +543,7 @@ rowFileList(const char * const dirName, strcat(list, " "); strcat(list, fileName); } - strfree(fileName); + pm_strfree(fileName); } return list; @@ -564,7 +565,7 @@ writeRowsAndDelete(unsigned int const rows, const char * fileList; if (maxFormatType == PPM_TYPE && quant) - asprintfN(&quantStage, "| pnmquant -quiet %u ", colors); + pm_asprintf(&quantStage, "| pnmquant -quiet %u ", colors); else quantStage = strdup(""); @@ -573,8 +574,8 @@ writeRowsAndDelete(unsigned int const rows, systemf("pnmcat %s -topbottom %s %s", blackWhiteOpt, fileList, quantStage); - strfree(fileList); - strfree(quantStage); + pm_strfree(fileList); + pm_strfree(quantStage); unlinkRowFiles(tempDir, rows); } diff --git a/editor/specialty/pnmmercator.c b/editor/specialty/pnmmercator.c new file mode 100644 index 00000000..cd9ff19b --- /dev/null +++ b/editor/specialty/pnmmercator.c @@ -0,0 +1,430 @@ +/* pammercator.c - convert a map in PNM image format from 360x180 degrees +** to Mercator projection or vice versa +** +** This program borrowed a lot of code from PnmScale which again was derived +** from PpmScale. +** +** Copyright (C) 2009 by Willem van Schaik <willem@schaik.com> +** Copyright (C) 1989, 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +*/ + +#define _XOPEN_SOURCE /* Make sure M_PI is in <math.h> */ +#include <math.h> +#include <string.h> + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" +#include "pnm.h" + +/* The pnm library allows us to code this program without branching cases for + PGM and PPM, but we do the branch anyway to speed up processing of PGM + images. +*/ + + + +struct cmdlineInfo +{ + /* + All the information the user supplied in the command line, + in a form easy for the program to use. + */ + + const char * input_filespec; /* Filespecs of input files */ + const char * inputFileName; /* Filespec of input file */ + unsigned int inverse; /* from Mercator to Degrees */ + unsigned int nomix; + unsigned int verbose; + unsigned int vverbose; +}; + + + +static void +parseCommandLine(int argc, + const char ** argv, + struct cmdlineInfo * const cmdlineP ) { + + optEntry * option_def; + optStruct3 opt; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "inverse", OPT_FLAG, NULL, &cmdlineP->inverse, 0); + OPTENT3(0, "nomix", OPT_FLAG, NULL, &cmdlineP->nomix, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "vverbose", OPT_FLAG, NULL, &cmdlineP->vverbose, 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 */ + + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 ); + + /* Only parameter allowed is optional filespec */ + if (argc-1 < 1) + cmdlineP->input_filespec = "-"; + else + cmdlineP->input_filespec = argv[1]; +} + + + +static void +computeOutputDimensions(const struct cmdlineInfo cmdline, + const int rows, const int cols, + int * newrowsP, int * newcolsP) +{ + *newcolsP = cols; + if (!cmdline.inverse) + *newrowsP = 2 * rows; + else + *newrowsP = rows / 2; + + if (*newcolsP < 1) *newcolsP = 1; + if (*newrowsP < 1) *newrowsP = 1; + + if (cmdline.verbose) { + if (!cmdline.inverse) + pm_message("Creating Mercator map, new size is %dx%d", + *newcolsP, *newrowsP); + else + pm_message("Creating Degrees map, new size is %dx%d", + *newcolsP, *newrowsP); + } +} + + + +static void +transformWithMixing(FILE * const ifP, + int const cols, int const rows, + xelval const maxval, int const format, + int const newcols, int const newrows, + xelval const newmaxval, int const newformat, + bool const inverse, + bool const verbose, bool const vverbose) +{ + /* + Transform the map image on input file 'ifP' (which is described by + 'cols', 'rows', 'format', and 'maxval') to a Mercator projection + and write the result to standard output as format 'newformat' and + with maxval 'newmaxval'. + + We'll blend colors from subsequent rows in the output pixels. + */ + + xel* oddxelrow; /* an input row */ + xel* evenxelrow; + xel* newxelrow; /* the output row */ + + int row; + double fRow; + int rowInXelrow; + int inputRow; + int col; + + double fFract; + double fLatRad; + double fLatMerc; + + oddxelrow = pnm_allocrow(cols); + evenxelrow = pnm_allocrow(cols); + rowInXelrow = 0; + + newxelrow = pnm_allocrow(newcols); + + for (row = 0; row < newrows; ++row) { + + fRow = (double)row + 0.5; /* center on half the pixel */ + if (!inverse) { + /* the result is mercator, calculate back to degrees */ + fLatMerc = 2.0 * M_PI * (fRow / (double)newrows - 0.5); + /* merc goes from -pi to +pi */ + fLatRad = 2.0 * (atan(exp(fLatMerc)) - M_PI / 4.0); + fRow = ((fLatRad / M_PI) + 0.5) * (double)rows; + /* lat goes from -pi/2 to +pi/2 */ + } else { + /* the result is in degrees, calculate back to mercator */ + fLatRad = M_PI * (fRow / (double)newrows - 0.5); + /* lat goes from -pi/2 to +pi/2 */ + fLatMerc = log(tan((M_PI / 4.0 + fLatRad / 2.0))); + fRow = ((fLatMerc / M_PI / 2.0) + 0.5) * (double)rows; + /* merc goes from -pi to +pi */ + } + fRow -= 0.5; + + inputRow = (int) floor(fRow); + if (inputRow < 0) + inputRow = 0; + if (inputRow > rows - 1) + inputRow = rows - 1; + + /* calculate the fraction */ + fFract = 1.0 - ((fRow) - (double) inputRow); + + if (vverbose) { + if (!inverse) { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) +#else + #ifdef DBG_MIDDLE + if ((row > (newrows/2 - 10)) && (row < (newrows/2 + 10))) + #else + if (row % 20 == 0) + #endif +#endif + pm_message("outputRow=%d latMerc=%f latRad=%f inputRow=%d " + "fRow=%f fFract=%f", + row, fLatMerc, fLatRad, inputRow, fRow, fFract); + } else { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) +#else + #ifdef DBG_MIDDLE + if ((row > (newrows/2 - 10)) && (row < (newrows/2 + 10))) + #else + if (row % 10 == 0) + #endif +#endif + pm_message("outputRow=%d latRad=%f latMerc=%f inputRow=%d" + "fRow=%f fFract=%f", + row, fLatRad, fLatMerc, inputRow, fRow, fFract); + } + } + + while ((rowInXelrow <= inputRow + 1) && + (rowInXelrow < rows)) { + /* we need to read one row ahead */ + if (rowInXelrow % 2 == 0) { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) + pm_message("read even row - rowInXelrow=%d inputRow=%d", + rowInXelrow, inputRow); +#endif + pnm_readpnmrow(ifP, evenxelrow, cols, newmaxval, format); + } else { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) + pm_message("read odd row - rowInXelrow=%d inputRow=%d", + rowInXelrow, inputRow); +#endif + pnm_readpnmrow(ifP, oddxelrow, cols, newmaxval, format); + } + ++rowInXelrow; + } + + for (col = 0; col < newcols; ++col) { + if (inputRow == 0) + newxelrow[col] = evenxelrow[col]; + else if (inputRow == rows - 1) + newxelrow[col] = oddxelrow[col]; + else if (inputRow % 2 == 0) { + /* the even row is the low one, the odd the high one */ + newxelrow[col].r = fFract * evenxelrow[col].r + + (1.0 - fFract) * oddxelrow[col].r; + newxelrow[col].g = fFract * evenxelrow[col].g + + (1.0 - fFract) * oddxelrow[col].g; + newxelrow[col].b = fFract * evenxelrow[col].b + + (1.0 - fFract) * oddxelrow[col].b; + } else { + newxelrow[col].r = fFract * oddxelrow[col].r + + (1.0 - fFract) * evenxelrow[col].r; + newxelrow[col].g = fFract * oddxelrow[col].g + + (1.0 - fFract) * evenxelrow[col].g; + newxelrow[col].b = fFract * oddxelrow[col].b + + (1.0 - fFract) * evenxelrow[col].b; + } + } + + pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0 ); + } + + pnm_freerow(oddxelrow); + pnm_freerow(evenxelrow); + pnm_freerow(newxelrow); +} + + + +static void +transformNoneMixing(FILE * const ifP, + int const cols, int const rows, + xelval const maxval, int const format, + int const newcols, int const newrows, + xelval const newmaxval, int const newformat, + bool const inverse, + bool const verbose, bool const vverbose) +{ + /* + Transform the map image on input file 'ifP' (which is described by + 'cols', 'rows', 'format', and 'maxval') to a Mercator projection and + write the result to standard output as format 'newformat' and with + maxval 'newmaxval'. + + Don't mix colors from different input pixels together in the output + pixels. Each output pixel is an exact copy of some corresponding + input pixel. + */ + + xel* xelrow; /* an input row */ + xel* newxelrow; /* the output row */ + + int row; + double fRow; + int rowInXelrow; + int inputRow; + int col; + + double fLatRad; + double fLatMerc; + + xelrow = pnm_allocrow(cols); + rowInXelrow = 0; + + newxelrow = pnm_allocrow(newcols); + + for (row = 0; row < newrows; ++row) { + + fRow = (double)row + 0.5; /* center on half the pixel */ + if (!inverse) { + /* the result is mercator, calculate back to degrees */ + fLatMerc = 2.0 * M_PI * (fRow / (double)newrows - 0.5); + /* merc goes from -pi to +pi */ + fLatRad = 2.0 * (atan(exp(fLatMerc)) - M_PI / 4.0); + fRow = ((fLatRad / M_PI) + 0.5) * (double)rows; + /* lat goes from -pi/2 to +pi/2 */ + } else { + /* the result is in degrees, calculate back to mercator */ + fLatRad = M_PI * (fRow / (double)newrows - 0.5); + /* lat goes from -pi/2 to +pi/2 */ + fLatMerc = log(tan((M_PI / 4.0 + fLatRad / 2.0))); + fRow = ((fLatMerc / M_PI / 2.0) + 0.5) * (double)rows; + /* merc goes from -pi to +pi */ + } + /* fRow -= 0.5; */ /* it's weird that this isn't needed */ + + inputRow = (int) floor(fRow); + if (inputRow < 0) + inputRow = 0; + if (inputRow > rows - 1) + inputRow = rows - 1; + + if (vverbose) { + if (!inverse) { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) +#else + #ifdef DBG_MIDDLE + if ((row > (newrows/2 - 10)) && (row < (newrows/2 + 10))) + #else + if (row % 20 == 0) + #endif +#endif + pm_message("outputRow=%d latMerc=%f latRad=%f inputRow=%d" + "fRow=%f", + row, fLatMerc, fLatRad, inputRow, fRow); + } else { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) +#else + #ifdef DBG_MIDDLE + if ((row > (newrows/2 - 10)) && (row < (newrows/2 + 10))) + #else + if (row % 10 == 0) + #endif +#endif + pm_message("outputRow=%d latRad=%f latMerc=%f inputRow=%d" + "fRow=%f", + row, fLatRad, fLatMerc, inputRow, fRow); + } + } + + while ((rowInXelrow <= inputRow) && (rowInXelrow < rows)) { +#ifdef DBG_EDGES + if ((row < 10) || (row > (newrows - 10))) + pm_message("read row - rowInXelrow=%d inputRow=%d", + rowInXelrow, inputRow); +#endif + pnm_readpnmrow(ifP, xelrow, cols, newmaxval, format); + ++rowInXelrow; + } + for (col = 0; col < newcols; ++col) { + newxelrow[col] = xelrow[col]; + } + + pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0 ); + } + + pnm_freerow(xelrow); + pnm_freerow(newxelrow); +} + + + +int +main(int argc, const char ** argv ) +{ + struct cmdlineInfo cmdline; + FILE* ifP; + int rows, cols, format, newformat, newrows, newcols; + xelval maxval, newmaxval; + bool verbose; + + pm_proginit( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose || cmdline.vverbose; + + ifP = pm_openr(cmdline.input_filespec); + + pnm_readpnminit( ifP, &cols, &rows, &maxval, &format ); + + /* Promote PBM file to PGM. */ + if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) { + newformat = PGM_TYPE; + newmaxval = PGM_MAXMAXVAL; + pm_message( "promoting from PBM to PGM" ); + } else { + newformat = format; + newmaxval = maxval; + } + + computeOutputDimensions(cmdline, rows, cols, &newrows, &newcols); + + pnm_writepnminit(stdout, newcols, newrows, newmaxval, newformat, 0); + + if (cmdline.nomix) { + if (verbose) + pm_message("Transforming map without mixing/blending colors"); + transformNoneMixing(ifP, cols, rows, maxval, format, + newcols, newrows, newmaxval, newformat, + cmdline.inverse, verbose, cmdline.vverbose); + } else { + if (verbose) + pm_message("Transforming map while using intermediate colors"); + transformWithMixing(ifP, cols, rows, maxval, format, + newcols, newrows, newmaxval, newformat, + cmdline.inverse, verbose, cmdline.vverbose); + } + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/editor/specialty/ppm3d.c b/editor/specialty/ppm3d.c index d9ada365..a6faa341 100644 --- a/editor/specialty/ppm3d.c +++ b/editor/specialty/ppm3d.c @@ -42,7 +42,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -62,7 +62,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 < 2) diff --git a/editor/specialty/ppmglobe.c b/editor/specialty/ppmglobe.c index 82fae5fb..92e22746 100644 --- a/editor/specialty/ppmglobe.c +++ b/editor/specialty/ppmglobe.c @@ -42,7 +42,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -62,7 +62,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!backgroundSpec) diff --git a/editor/specialty/ppmntsc.c b/editor/specialty/ppmntsc.c index ae3bcfe9..a721b891 100644 --- a/editor/specialty/ppmntsc.c +++ b/editor/specialty/ppmntsc.c @@ -51,9 +51,6 @@ #include "mallocvar.h" #include "shhopt.h" -#define TRUE 1 -#define FALSE 0 - enum legalize {RAISE_SAT, LOWER_SAT, ALREADY_LEGAL}; /* The actions that make a legal pixel */ @@ -70,6 +67,61 @@ struct cmdlineInfo { +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that many of the strings that this function returns in the + *cmdlineP structure are actually in the supplied argv array. And + sometimes, one of these strings is actually just a suffix of an entry + in argv! +-----------------------------------------------------------------------------*/ + optStruct3 opt; + optEntry *option_def; + /* Instructions to OptParseOptions on how to parse our options. + */ + unsigned int option_def_index; + unsigned int legalonly, illegalonly, correctedonly; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3('v', "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3('V', "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); + OPTENT3('p', "pal", OPT_FLAG, NULL, &cmdlineP->pal, 0); + OPTENT3('l', "legalonly", OPT_FLAG, NULL, &legalonly, 0); + OPTENT3('i', "illegalonly", OPT_FLAG, NULL, &illegalonly, 0); + OPTENT3('c', "correctedonly", OPT_FLAG, NULL, &correctedonly, 0); + + opt.opt_table = option_def; + opt.short_allowed = true; + opt.allowNegNum = false; + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + + if (argc - 1 == 0) + cmdlineP->inputFilename = "-"; /* he wants stdin */ + else if (argc - 1 == 1) + cmdlineP->inputFilename = argv[1]; + else + pm_error("Too many arguments. The only arguments accepted " + "are the mask color and optional input file specification"); + + if (legalonly + illegalonly + correctedonly > 1) + pm_error("--legalonly, --illegalonly, and --correctedonly are " + "conflicting options. Specify at most one of these."); + + if (legalonly) + cmdlineP->output = LEGAL_ONLY; + else if (illegalonly) + cmdlineP->output = ILLEGAL_ONLY; + else if (correctedonly) + cmdlineP->output = CORRECTED_ONLY; + else + cmdlineP->output = ALL; +} + + static void rgbtoyiq(const int r, const int g, const int b, @@ -118,39 +170,39 @@ yuvtorgb(const double y, const double u, const double v, static void -make_legal_yiq(const double y, const double i, const double q, - double * const y_new_p, - double * const i_new_p, - double * const q_new_p, - enum legalize * const action_p - ) { +makeLegalYiq(double const y, + double const i, + double const q, + double * const yNewP, + double * const iNewP, + double * const qNewP, + enum legalize * const actionP) { - double sat_old, sat_new; + double satOld, satNew; /* * I and Q are legs of a right triangle. Saturation is the hypotenuse. */ - sat_old = sqrt(i*i + q*q); - if (y+sat_old > 1.0) { - const double diff = 0.5*((y+sat_old) - 1.0); - *y_new_p = y - diff; - sat_new = 1.0 - *y_new_p; - *i_new_p = i*(sat_new/sat_old); - *q_new_p = q*(sat_new/sat_old); - *action_p = LOWER_SAT; - } else if (y-sat_old <= -0.251) { - const double diff = 0.5*((sat_old-y) - 0.251); - *y_new_p = y + diff; - sat_new = 0.250 + *y_new_p; - *i_new_p = i*(sat_new/sat_old); - *q_new_p = q*(sat_new/sat_old); - *action_p = RAISE_SAT; + satOld = sqrt(SQR(i) + SQR(q)); + if (y+satOld > 1.0) { + const double diff = 0.5*((y + satOld) - 1.0); + *yNewP = y - diff; + satNew = 1.0 - *yNewP; + *iNewP = i * (satNew/satOld); + *qNewP = q * (satNew/satOld); + *actionP = LOWER_SAT; + } else if (y - satOld <= -0.251) { + const double diff = 0.5*((satOld - y) - 0.251); + *yNewP = y + diff; + satNew = 0.250 + *yNewP; + *iNewP = i * (satNew/satOld); + *qNewP = q * (satNew/satOld); + *actionP = RAISE_SAT; } else { - *y_new_p = y; - *i_new_p = i; - *q_new_p = q; - *action_p = ALREADY_LEGAL; + *yNewP = y; + *iNewP = i; + *qNewP = q; + *actionP = ALREADY_LEGAL; } - return; } @@ -206,7 +258,7 @@ make_legal_yiq_i(const int r_in, const int g_in, const int b_in, * Convert to YIQ and compute the new saturation. */ rgbtoyiq(r_in, g_in, b_in, &y, &i, &q); - make_legal_yiq(y, i, q, &y_new, &i_new, &q_new, action_p); + makeLegalYiq(y, i, q, &y_new, &i_new, &q_new, action_p); if (*action_p != ALREADY_LEGAL) /* * Given the new I and Q, compute new RGB values. @@ -295,204 +347,155 @@ make_legal_yuv_b(const pixel input, static void -report_mapping(const pixel old_pixel, const pixel new_pixel) { +reportMapping(pixel const oldPixel, + pixel const newPixel) { /*---------------------------------------------------------------------------- - Assuming old_pixel and new_pixel are input and output pixels, + Assuming oldPixel and newPixel are input and output pixels, tell the user that we changed a pixel to make it legal, if in fact we did and it isn't the same change that we just reported. -----------------------------------------------------------------------------*/ - static pixel last_changed_pixel; - static int first_time = TRUE; - - if (!PPM_EQUAL(old_pixel, new_pixel) && - (first_time || PPM_EQUAL(old_pixel, last_changed_pixel))) { - pm_message("Mapping %d %d %d -> %d %d %d\n", - PPM_GETR(old_pixel), - PPM_GETG(old_pixel), - PPM_GETB(old_pixel), - PPM_GETR(new_pixel), - PPM_GETG(new_pixel), - PPM_GETB(new_pixel) + static pixel lastChangedPixel; + static bool firstTime = true; + + if (!PPM_EQUAL(oldPixel, newPixel) && + (firstTime || PPM_EQUAL(oldPixel, lastChangedPixel))) { + pm_message("Mapping %u %u %u -> %u %u %u\n", + PPM_GETR(oldPixel), + PPM_GETG(oldPixel), + PPM_GETB(oldPixel), + PPM_GETR(newPixel), + PPM_GETG(newPixel), + PPM_GETB(newPixel) ); - last_changed_pixel = old_pixel; - first_time = FALSE; + lastChangedPixel = oldPixel; + firstTime = false; } } static void -convert_one_image(FILE * const ifp, struct cmdlineInfo const cmdline, - bool * const eofP, - int * const hicountP, int * const locountP) { +convertOneImage(FILE * const ifP, + struct cmdlineInfo const cmdline, + unsigned int * const hiCountP, + unsigned int * const loCountP) { /* Parameters of input image: */ int rows, cols; pixval maxval; int format; - ppm_readppminit(ifp, &cols, &rows, &maxval, &format); - ppm_writeppminit(stdout, cols, rows, maxval, FALSE); + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); + ppm_writeppminit(stdout, cols, rows, maxval, 0); { - pixel* const input_row = ppm_allocrow(cols); - pixel* const output_row = ppm_allocrow(cols); - pixel last_illegal_pixel; - /* Value of the illegal pixel we most recently processed */ + pixel * const inputRow = ppm_allocrow(cols); + pixel * const outputRow = ppm_allocrow(cols); + + pixel lastIllegalPixel; + /* Value of the illegal pixel we most recently processed */ pixel black; - /* A constant - black pixel */ + /* A constant - black pixel */ PPM_ASSIGN(black, 0, 0, 0); - PPM_ASSIGN(last_illegal_pixel, 0, 0, 0); /* initial value */ + PPM_ASSIGN(lastIllegalPixel, 0, 0, 0); /* initial value */ { - int row; + unsigned int row; - *hicountP = 0; *locountP = 0; /* initial values */ + *hiCountP = 0; *loCountP = 0; /* initial values */ for (row = 0; row < rows; ++row) { - int col; - ppm_readppmrow(ifp, input_row, cols, maxval, format); + unsigned int col; + ppm_readppmrow(ifP, inputRow, cols, maxval, format); for (col = 0; col < cols; ++col) { pixel corrected; - /* Corrected or would-be corrected value for pixel */ + /* Corrected or would-be corrected value for pixel */ enum legalize action; - /* What action was used to make pixel legal */ + /* What action was used to make pixel legal */ if (cmdline.pal) - make_legal_yuv_b(input_row[col], + make_legal_yuv_b(inputRow[col], &corrected, &action); else - make_legal_yiq_b(input_row[col], + make_legal_yiq_b(inputRow[col], &corrected, &action); if (action == LOWER_SAT) - (*hicountP)++; + ++*hiCountP; if (action == RAISE_SAT) - (*locountP)++; - if (cmdline.debug) report_mapping(input_row[col], - corrected); + ++*loCountP; + if (cmdline.debug) + reportMapping(inputRow[col], corrected); switch (cmdline.output) { case ALL: - output_row[col] = corrected; + outputRow[col] = corrected; break; case LEGAL_ONLY: - output_row[col] = (action == ALREADY_LEGAL) ? - input_row[col] : black; + outputRow[col] = (action == ALREADY_LEGAL) ? + inputRow[col] : black; break; case ILLEGAL_ONLY: - output_row[col] = (action != ALREADY_LEGAL) ? - input_row[col] : black; + outputRow[col] = (action != ALREADY_LEGAL) ? + inputRow[col] : black; break; case CORRECTED_ONLY: - output_row[col] = (action != ALREADY_LEGAL) ? + outputRow[col] = (action != ALREADY_LEGAL) ? corrected : black; break; } } - ppm_writeppmrow(stdout, output_row, cols, maxval, FALSE); + ppm_writeppmrow(stdout, outputRow, cols, maxval, 0); } } - ppm_freerow(output_row); - ppm_freerow(input_row); + ppm_freerow(outputRow); + ppm_freerow(inputRow); } } -static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { -/*---------------------------------------------------------------------------- - Note that many of the strings that this function returns in the - *cmdlineP structure are actually in the supplied argv array. And - sometimes, one of these strings is actually just a suffix of an entry - in argv! ------------------------------------------------------------------------------*/ - optStruct3 opt; - optEntry *option_def; - /* Instructions to OptParseOptions on how to parse our options. - */ - unsigned int option_def_index; - unsigned int legalonly, illegalonly, correctedonly; - - MALLOCARRAY(option_def, 100); - - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3('v', "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - OPTENT3('V', "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); - OPTENT3('p', "pal", OPT_FLAG, NULL, &cmdlineP->pal, 0); - OPTENT3('l', "legalonly", OPT_FLAG, NULL, &legalonly, 0); - OPTENT3('i', "illegalonly", OPT_FLAG, NULL, &illegalonly, 0); - OPTENT3('c', "correctedonly", OPT_FLAG, NULL, &correctedonly, 0); - - opt.opt_table = option_def; - opt.short_allowed = TRUE; - opt.allowNegNum = FALSE; - - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); - - if (argc - 1 == 0) - cmdlineP->inputFilename = "-"; /* he wants stdin */ - else if (argc - 1 == 1) - cmdlineP->inputFilename = argv[1]; - else - pm_error("Too many arguments. The only arguments accepted " - "are the mask color and optional input file specification"); - - if (legalonly + illegalonly + correctedonly > 1) - pm_error("--legalonly, --illegalonly, and --correctedonly are " - "conflicting options. Specify at most one of these."); - - if (legalonly) - cmdlineP->output = LEGAL_ONLY; - else if (illegalonly) - cmdlineP->output = ILLEGAL_ONLY; - else if (correctedonly) - cmdlineP->output = CORRECTED_ONLY; - else - cmdlineP->output = ALL; -} - - int -main(int argc, char **argv) { +main(int argc, const char **argv) { struct cmdlineInfo cmdline; FILE * ifP; - int total_hicount, total_locount; - int image_count; + unsigned int totalHiCount, totalLoCount; + unsigned int imageCount; - bool eof; + int eof; - ppm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilename); + + imageCount = 0; /* initial value */ + totalHiCount = 0; /* initial value */ + totalLoCount = 0; /* initial value */ - image_count = 0; /* initial value */ - total_hicount = 0; /* initial value */ - total_locount = 0; /* initial value */ - - eof = FALSE; + eof = false; while (!eof) { - int hicount, locount; - convert_one_image(ifP, cmdline, &eof, &hicount, &locount); - image_count++; - total_hicount += hicount; - total_locount += locount; + unsigned int hiCount, loCount; + + convertOneImage(ifP, cmdline, &hiCount, &loCount); + + ++imageCount; + totalHiCount += hiCount; + totalLoCount += loCount; + ppm_nextimage(ifP, &eof); } if (cmdline.verbose) { - pm_message("%d images processed.", image_count); - pm_message("%d pixels were above the saturation limit.", - total_hicount); - pm_message("%d pixels were below the saturation limit.", - total_locount); + pm_message("%u images processed.", imageCount); + pm_message("%u pixels were above the saturation limit.", + totalHiCount); + pm_message("%u pixels were below the saturation limit.", + totalLoCount); } pm_close(ifP); diff --git a/editor/specialty/ppmrelief.c b/editor/specialty/ppmrelief.c index 1c408aec..14a6d0a8 100644 --- a/editor/specialty/ppmrelief.c +++ b/editor/specialty/ppmrelief.c @@ -1,4 +1,4 @@ -/* ppmrelief.c - generate a relief map of a portable pixmap +/* ppmrelief.c - generate a relief map of a PPM image ** ** Copyright (C) 1990 by Wilson H. Bent, Jr. ** @@ -11,86 +11,104 @@ */ #include <stdio.h> + #include "pm_c_util.h" #include "ppm.h" + + +static pixval +clip(int const p, + pixval const maxval) { + + return MAX(0, MIN(maxval, p)); +} + + + int -main(int argc, char * argv[]) { - - FILE* ifp; - pixel** inputbuf; - pixel* outputrow; - int argn, rows, cols, format, row; - register int col; - pixval maxval, mv2; +main(int argc, const char * argv[]) { + + FILE * ifP; + pixel ** inputbuf; + pixel * outputrow; + int argn, format, rows, cols; + unsigned int row, col; + pixval maxval; const char* const usage = "[ppmfile]"; - ppm_init( &argc, argv ); + pm_proginit(&argc, argv); argn = 1; if ( argn != argc ) { - ifp = pm_openr( argv[argn] ); + ifP = pm_openr( argv[argn] ); ++argn; } else - ifp = stdin; + ifP = stdin; if ( argn != argc ) pm_usage( usage ); - - ppm_readppminit( ifp, &cols, &rows, &maxval, &format ); + + ppm_readppminit(ifP, &cols, &rows, &maxval, &format ); if (cols < 3 || rows < 3 ) pm_error("Input image too small: %u x %u. Must be at least 3x3", cols, rows); - mv2 = maxval / 2; - /* Allocate space for 3 input rows, plus an output row. */ - inputbuf = ppm_allocarray( cols, 3 ); - outputrow = ppm_allocrow( cols ); + inputbuf = ppm_allocarray(cols, 3); + outputrow = ppm_allocrow(cols); - ppm_writeppminit( stdout, cols, rows, maxval, 0 ); + ppm_writeppminit(stdout, cols, rows, maxval, 0); /* Read in the first two rows. */ - ppm_readppmrow( ifp, inputbuf[0], cols, maxval, format ); - ppm_readppmrow( ifp, inputbuf[1], cols, maxval, format ); + ppm_readppmrow(ifP, inputbuf[0], cols, maxval, format); + ppm_readppmrow(ifP, inputbuf[1], cols, maxval, format); /* Write out the first row, all zeros. */ - for ( col = 0; col < cols; ++col ) + for (col = 0; col < cols; ++col) PPM_ASSIGN( outputrow[col], 0, 0, 0 ); - ppm_writeppmrow( stdout, outputrow, cols, maxval, 0 ); + + ppm_writeppmrow(stdout, outputrow, cols, maxval, 0); /* Now the rest of the image - read in the 3rd row of inputbuf, - ** and convolve with the first row into the output buffer. + and convolve with the first row into the output buffer. */ - for ( row = 2 ; row < rows; ++row ) { - pixval r, g, b; - int rowa, rowb; - - rowa = row % 3; - rowb = (row + 2) % 3; - ppm_readppmrow( ifp, inputbuf[rowa], cols, maxval, format ); - - for ( col = 0; col < cols - 2; ++col ) { - r = MAX(0, MIN(maxval, PPM_GETR( inputbuf[rowa][col] ) + - ( mv2 - PPM_GETR( inputbuf[rowb][col + 2] ) ))); - g = MAX(0, MIN(maxval, PPM_GETG( inputbuf[rowa][col] ) + - ( mv2 - PPM_GETG( inputbuf[rowb][col + 2] ) ))); - b = MAX(0, MIN(maxval, PPM_GETB( inputbuf[rowa][col] ) + - ( mv2 - PPM_GETB( inputbuf[rowb][col + 2] ) ))); - PPM_ASSIGN( outputrow[col + 1], r, g, b ); + for (row = 2 ; row < rows; ++row) { + pixval const mv2 = maxval / 2; + unsigned int const rowa = row % 3; + unsigned int const rowb = (rowa + 2) % 3; + + ppm_readppmrow(ifP, inputbuf[rowa], cols, maxval, format); + + for (col = 0; col < cols - 2; ++col) { + pixel const inputA = inputbuf[rowa][col]; + pixel const inputB = inputbuf[rowb][col + 2]; + + pixval const r = + clip(PPM_GETR(inputA) + (mv2 - PPM_GETR(inputB)), maxval); + pixval const g = + clip(PPM_GETG(inputA) + (mv2 - PPM_GETG(inputB)), maxval); + pixval const b = + clip(PPM_GETB(inputA) + (mv2 - PPM_GETB(inputB)), maxval); + + PPM_ASSIGN(outputrow[col + 1], r, g, b); } - ppm_writeppmrow( stdout, outputrow, cols, maxval, 0 ); + ppm_writeppmrow(stdout, outputrow, cols, maxval, 0); } /* And write the last row, zeros again. */ - for ( col = 0; col < cols; ++col ) - PPM_ASSIGN( outputrow[col], 0, 0, 0 ); - ppm_writeppmrow( stdout, outputrow, cols, maxval, 0 ); + for (col = 0; col < cols; ++col) + PPM_ASSIGN(outputrow[col], 0, 0, 0); + + ppm_writeppmrow(stdout, outputrow, cols, maxval, 0); + + ppm_freerow(outputrow); + ppm_freearray(inputbuf, 3); - pm_close( ifp ); - pm_close( stdout ); + pm_close(ifP); + pm_close(stdout); - exit( 0 ); + return 0; } |