diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/Makefile | 42 | ||||
-rw-r--r-- | editor/pamcut.c | 5 | ||||
-rw-r--r-- | editor/pamenlarge.test | 2 | ||||
-rw-r--r-- | editor/pnmcrop.c | 246 | ||||
-rw-r--r-- | editor/pnmcut.c | 427 | ||||
-rw-r--r-- | editor/pnminvert.test | 2 | ||||
-rw-r--r-- | editor/pnmscale.c | 748 | ||||
-rw-r--r-- | editor/specialty/Makefile | 55 | ||||
-rw-r--r-- | editor/specialty/pamdeinterlace.c (renamed from editor/pamdeinterlace.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pammixinterlace.c (renamed from editor/pammixinterlace.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pamoil.c (renamed from editor/pamoil.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pampop9.c (renamed from editor/pampop9.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pbmlife.c (renamed from editor/pbmlife.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pgmabel.c (renamed from editor/pgmabel.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pgmbentley.c (renamed from editor/pgmbentley.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pgmmorphconv.c (renamed from editor/pgmmorphconv.c) | 0 | ||||
-rw-r--r-- | editor/specialty/pnmindex.c (renamed from editor/pnmindex.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppm3d.c (renamed from editor/ppm3d.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmglobe.c (renamed from editor/ppmglobe.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmntsc.c (renamed from editor/ppmntsc.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmrelief.c (renamed from editor/ppmrelief.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmshift.c (renamed from editor/ppmshift.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmspread.c (renamed from editor/ppmspread.c) | 0 | ||||
-rw-r--r-- | editor/specialty/ppmtv.c (renamed from editor/ppmtv.c) | 0 |
24 files changed, 224 insertions, 1303 deletions
diff --git a/editor/Makefile b/editor/Makefile index 842cf31a..784a75a4 100644 --- a/editor/Makefile +++ b/editor/Makefile @@ -7,6 +7,8 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk +SUBDIRS = specialty + # We tend to separate out the build targets so that we don't have # any more dependencies for a given target than it really needs. # That way, if there is a problem with a dependency, we can still @@ -15,24 +17,23 @@ include $(BUILDDIR)/config.mk # build. PORTBINARIES = pamaddnoise pambackground pamcomp pamcut \ - pamdeinterlace pamdice pamditherbw pamedge \ + pamdice pamditherbw pamedge \ pamenlarge \ - pamflip pamfunc pammasksharpen pammixinterlace \ - pamoil pamperspective pampop9 \ + pamflip pamfunc pammasksharpen \ + pamperspective \ pamscale pamstretch pamthreshold pamundice \ - pbmclean pbmlife pbmmask pbmpscale pbmreduce \ - pgmabel pgmbentley pgmdeshadow pgmenhance \ - pgmmedian pgmmorphconv \ - pnmalias pnmcat pnmcomp pnmconvol pnmcrop pnmcut \ + pbmclean pbmmask pbmpscale pbmreduce \ + pgmdeshadow pgmenhance \ + pgmmedian \ + pnmalias pnmcat pnmcomp pnmconvol pnmcrop \ pnmgamma \ - pnmhisteq pnmindex pnminvert pnmmontage \ + pnmhisteq pnminvert pnmmontage \ pnmnlfilt pnmnorm pnmpad pnmpaste \ pnmremap pnmrotate \ - pnmscale pnmscalefixed pnmshear pnmsmooth pnmstitch pnmtile \ - ppm3d ppmbrighten ppmchange ppmcolormask \ + pnmscalefixed pnmshear pnmsmooth pnmstitch pnmtile \ + ppmbrighten ppmchange ppmcolormask \ ppmdim ppmdist ppmdither ppmdraw \ - ppmflash ppmglobe ppmlabel ppmmix \ - ppmntsc ppmrelief ppmshift ppmspread ppmtv + ppmflash ppmlabel ppmmix \ # We don't include programs that have special library dependencies in the # merge scheme, because we don't want those dependencies to prevent us @@ -51,7 +52,7 @@ OBJECTS = $(BINARIES:%=%.o) MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) .PHONY: all -all: $(BINARIES) +all: $(BINARIES) $(SUBDIRS:%=%/all) include $(SRCDIR)/common.mk @@ -60,15 +61,10 @@ install.bin: install.bin.local .PHONY: install.bin.local install.bin.local: $(PKGDIR)/bin # Remember that $(SYMLINK) might just be a copy command. -# backward compatibility: program used to be named pnmnoraw # backward compatibility: program used to be pnminterp cd $(PKGDIR)/bin ; \ rm -f pnminterp; \ $(SYMLINK) pamstretch$(EXE) pnminterp -# pamoil replaced pgmoil in June 2001. - cd $(PKGDIR)/bin ; \ - rm -f pgmoil ; \ - $(SYMLINK) pamoil$(EXE) pgmoil # In March 2002, pnmnorm replaced ppmnorm and pgmnorm cd $(PKGDIR)/bin ; \ rm -f ppmnorm ; \ @@ -84,3 +80,13 @@ install.bin.local: $(PKGDIR)/bin cd $(PKGDIR)/bin ; \ rm -f pnmenlarge ; \ $(SYMLINK) pamenlarge$(EXE) pnmenlarge +# In March 2009, pamcut replaced pnmcut (but pamcut is much older -- pnmcut +# was obsoleted by pamcut long before this). + cd $(PKGDIR)/bin ; \ + rm -f pnmcut ; \ + $(SYMLINK) pamcut$(EXE) pnmcut +# In March 2009, pamscale replaced pnmscale (but pamscale is much older -- +# pnmscale was obsoleted by pamscale long before this). + cd $(PKGDIR)/bin ; \ + rm -f pnmscale ; \ + $(SYMLINK) pamscale$(EXE) pnmscale diff --git a/editor/pamcut.c b/editor/pamcut.c index ce63da7b..d2d6170c 100644 --- a/editor/pamcut.c +++ b/editor/pamcut.c @@ -563,7 +563,7 @@ extractRowsPBM(const struct pam * const inpamP, int row; unsigned int totalWidth; - assert(0 <= leftcol && leftcol <= rightcol && rightcol < inpamP->width); + assert(leftcol <= rightcol); assert(toprow <= bottomrow); if (leftcol > 0) { @@ -658,8 +658,7 @@ cutOneImage(FILE * const ifP, pnm_writepaminit(&outpam); - if (PNM_FORMAT_TYPE(outpam.format) == PBM_TYPE && - leftcol >= 0 && rightcol < inpam.width) + if (PNM_FORMAT_TYPE(outpam.format) == PBM_TYPE) extractRowsPBM(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); else extractRowsGen(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); diff --git a/editor/pamenlarge.test b/editor/pamenlarge.test index a2221d4d..7584af01 100644 --- a/editor/pamenlarge.test +++ b/editor/pamenlarge.test @@ -1,6 +1,6 @@ echo Test 1. Should print 3424505894 913236 ./pamenlarge 3 ../testimg.ppm | cksum -echo Test 2. Should print 2940246561 304422 +echo Test 2. Should print 4152147096 304422 ppmtopgm ../testimg.ppm | ./pamenlarge 3 | cksum echo Test 3. Should print 3342398172 297 ./pamenlarge 3 ../testgrid.pbm | cksum diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c index e9dcbe4a..c2e07805 100644 --- a/editor/pnmcrop.c +++ b/editor/pnmcrop.c @@ -40,7 +40,17 @@ static const char * const edgeName[] = { "bottom" }; +typedef struct { + unsigned int size[4]; +} borderSet; +typedef enum { + /* A position in a PNM image file stream */ + FILEPOS_BEG, + /* Immediately before the raster */ + FILEPOS_END + /* Immediately after the raster */ +} imageFilePos; struct cmdlineInfo { /* All the information the user supplied in the command line, @@ -155,6 +165,11 @@ typedef struct { } cropOp; +typedef struct { + cropOp op[4]; +} cropSet; + + static xel background3Corners(FILE * const ifP, @@ -223,8 +238,7 @@ computeBackground(FILE * const ifP, int const rows, xelval const maxval, int const format, - enum bg_choice const backgroundChoice, - bool const verbose) { + enum bg_choice const backgroundChoice) { /*---------------------------------------------------------------------------- Determine what color is the background color of the image in file *ifP, which is described by 'cols', 'rows', 'maxval', and 'format'. @@ -254,11 +268,6 @@ computeBackground(FILE * const ifP, break; } - if (verbose) { - pixel const backgroundPixel = pnm_xeltopixel(background, format); - pm_message("Background color is %s", - ppm_colorname(&backgroundPixel, maxval, TRUE /*hexok*/)); - } return(background); } @@ -271,9 +280,8 @@ findBordersInImage(FILE * const ifP, xelval const maxval, int const format, xel const backgroundColor, - bool const verbose, bool * const hasBordersP, - unsigned int * const borderSize) { + borderSet * const borderSizeP) { /*---------------------------------------------------------------------------- Find the left, right, top, and bottom borders in the image 'ifP'. Return their sizes in pixels as borderSize[n]. @@ -335,38 +343,58 @@ findBordersInImage(FILE * const ifP, else { *hasBordersP = TRUE; assert(right <= cols); assert(bottom <= rows); - borderSize[LEFT] = left - 0; - borderSize[RIGHT] = cols - right; - borderSize[TOP] = top - 0; - borderSize[BOTTOM] = rows - bottom; + borderSizeP->size[LEFT] = left - 0; + borderSizeP->size[RIGHT] = cols - right; + borderSizeP->size[TOP] = top - 0; + borderSizeP->size[BOTTOM] = rows - bottom; } } static void -findBordersInFile(unsigned int const icols, - unsigned int const irows, - FILE * const borderFileP, - xel const backgroundColor, - bool const verbose, - bool * const hasBordersP, - unsigned int * const borderSize) { - - int bcols; /* cols and rows in the borderfile */ - int brows; - xelval maxval; - int format; - - pnm_readpnminit(borderFileP, &bcols, &brows, &maxval, &format); +analyzeImage(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + enum bg_choice const backgroundReq, + imageFilePos const newFilePos, + xel * const backgroundColorP, + bool * const hasBordersP, + borderSet * const borderSizeP) { +/*---------------------------------------------------------------------------- + Analyze the PNM image on file stream *ifP to determine its borders + and the color of those borders (the assumed background color). - if (bcols != icols || brows != irows) - pm_error("Image file and border file differ in size: %ux%u %ux%u", - icols, irows, bcols, brows); - - findBordersInImage(borderFileP, bcols, brows, maxval, format, - backgroundColor, verbose, hasBordersP, borderSize); -} + Return as *backgroundColorP the background color. + + Return as *borderSizeP the set of border sizes (one for each of the + four edges). But iff there are no borders, don't return anything as + *borderSizeP and return *hasBordersP == false. + + Expect *ifP to be positioned right after the header and seekable. + Return with it positioned either before or after the raster, as + requested by 'newFilePos'. +-----------------------------------------------------------------------------*/ + pm_filepos rasterpos; + xel background; + + pm_tell2(ifP, &rasterpos, sizeof(rasterpos)); + + background = computeBackground(ifP, cols, rows, maxval, format, + backgroundReq); + + pm_seek2(ifP, &rasterpos, sizeof(rasterpos)); + + findBordersInImage(ifP, cols, rows, maxval, format, + background, hasBordersP, borderSizeP); + + if (newFilePos == FILEPOS_BEG) + pm_seek2(ifP, &rasterpos, sizeof(rasterpos)); + + *backgroundColorP = background; +} @@ -379,21 +407,22 @@ ending(unsigned int const n) { static void -reportCroppingParameters(cropOp const crop[]) { +reportCroppingParameters(cropSet const crop) { unsigned int i; for (i = 0; i < 4; ++i) { - if (crop[i].removeSize == 0 && crop[i].padSize == 0) + if (crop.op[i].removeSize == 0 && crop.op[i].padSize == 0) pm_message("Not cropping %s edge", edgeName[i]); else { - if (crop[i].padSize > 0) + if (crop.op[i].padSize > 0) pm_message("Adding %u pixel%s to the %s border", - crop[i].padSize, ending(crop[i].padSize), + crop.op[i].padSize, ending(crop.op[i].padSize), edgeName[i]); - if (crop[i].removeSize > 0) + if (crop.op[i].removeSize > 0) pm_message("Cropping %u pixel%s from the %s border", - crop[i].removeSize, ending(crop[i].removeSize), + crop.op[i].removeSize, + ending(crop.op[i].removeSize), edgeName[i]); } } @@ -467,7 +496,7 @@ writeCroppedNonPbm(FILE * const ifP, unsigned int const rows, xelval const maxval, int const format, - cropOp const crop[], + cropSet const crop, xel const backgroundColor, FILE * const ofP) { @@ -511,22 +540,23 @@ writeCroppedNonPbm(FILE * const ifP, */ unsigned int const foregroundCols = - cols - crop[LEFT].removeSize - crop[RIGHT].removeSize; + cols - crop.op[LEFT].removeSize - crop.op[RIGHT].removeSize; unsigned int const outputCols = - foregroundCols + crop[LEFT].padSize + crop[RIGHT].padSize; + foregroundCols + crop.op[LEFT].padSize + crop.op[RIGHT].padSize; unsigned int const foregroundRows = - rows - crop[TOP].removeSize - crop[BOTTOM].removeSize; + rows - crop.op[TOP].removeSize - crop.op[BOTTOM].removeSize; unsigned int const outputRows = - foregroundRows + crop[TOP].padSize + crop[BOTTOM].padSize; + foregroundRows + crop.op[TOP].padSize + crop.op[BOTTOM].padSize; unsigned int const foregroundLeft = - MAX(crop[LEFT].removeSize, crop[LEFT].padSize); + MAX(crop.op[LEFT].removeSize, crop.op[LEFT].padSize); /* Index into xelrow[] of leftmost pixel of foreground */ unsigned int const foregroundRight = foregroundLeft + foregroundCols; /* Index into xelrow[] just past rightmost pixel of foreground */ unsigned int const allocCols = - foregroundRight + MAX(crop[RIGHT].removeSize, crop[RIGHT].padSize); + foregroundRight + MAX(crop.op[RIGHT].removeSize, + crop.op[RIGHT].padSize); xel * xelrow; unsigned int i; @@ -535,33 +565,35 @@ writeCroppedNonPbm(FILE * const ifP, xelrow = pnm_allocrow(allocCols); - readOffBorderNonPbm(crop[TOP].removeSize, ifP, cols, maxval, format); + readOffBorderNonPbm(crop.op[TOP].removeSize, ifP, cols, maxval, format); - outputNewBorderNonPbm(crop[TOP].padSize, outputCols, backgroundColor, + outputNewBorderNonPbm(crop.op[TOP].padSize, outputCols, backgroundColor, ofP, maxval, format); /* Set left border pixels */ - fillRow(&xelrow[foregroundLeft - crop[LEFT].padSize], crop[LEFT].padSize, + fillRow(&xelrow[foregroundLeft - crop.op[LEFT].padSize], + crop.op[LEFT].padSize, backgroundColor); /* Set right border pixels */ - fillRow(&xelrow[foregroundRight], crop[RIGHT].padSize, backgroundColor); + fillRow(&xelrow[foregroundRight], crop.op[RIGHT].padSize, backgroundColor); /* Read and output foreground rows */ for (i = 0; i < foregroundRows; ++i) { /* Read foreground pixels */ - pnm_readpnmrow(ifP, &(xelrow[foregroundLeft - crop[LEFT].removeSize]), + pnm_readpnmrow(ifP, + &(xelrow[foregroundLeft - crop.op[LEFT].removeSize]), cols, maxval, format); pnm_writepnmrow(ofP, - &(xelrow[foregroundLeft - crop[LEFT].padSize]), + &(xelrow[foregroundLeft - crop.op[LEFT].padSize]), outputCols, maxval, format, 0); } - readOffBorderNonPbm(crop[BOTTOM].removeSize, ifP, cols, maxval, format); + readOffBorderNonPbm(crop.op[BOTTOM].removeSize, ifP, cols, maxval, format); - outputNewBorderNonPbm(crop[BOTTOM].padSize, outputCols, + outputNewBorderNonPbm(crop.op[BOTTOM].padSize, outputCols, backgroundColor, ofP, maxval, format); @@ -642,7 +674,7 @@ writeCroppedPBM(FILE * const ifP, unsigned int const cols, unsigned int const rows, int const format, - cropOp const crop[], + cropSet const crop, xel const backgroundColor, FILE * const ofP) { @@ -651,26 +683,28 @@ writeCroppedPBM(FILE * const ifP, */ unsigned int const foregroundCols = - cols - crop[LEFT].removeSize - crop[RIGHT].removeSize; + cols - crop.op[LEFT].removeSize - crop.op[RIGHT].removeSize; unsigned int const outputCols = - foregroundCols + crop[LEFT].padSize + crop[RIGHT].padSize; + foregroundCols + crop.op[LEFT].padSize + crop.op[RIGHT].padSize; unsigned int const foregroundRows = - rows - crop[TOP].removeSize - crop[BOTTOM].removeSize; + rows - crop.op[TOP].removeSize - crop.op[BOTTOM].removeSize; unsigned int const outputRows = - foregroundRows + crop[TOP].padSize + crop[BOTTOM].padSize; + foregroundRows + crop.op[TOP].padSize + crop.op[BOTTOM].padSize; unsigned int const foregroundLeft = - MAX(crop[LEFT].removeSize, crop[LEFT].padSize); + MAX(crop.op[LEFT].removeSize, crop.op[LEFT].padSize); unsigned int const foregroundRight = foregroundLeft + foregroundCols; unsigned int const allocCols = - foregroundRight + MAX(crop[RIGHT].removeSize, crop[RIGHT].padSize); + foregroundRight + + MAX(crop.op[RIGHT].removeSize, crop.op[RIGHT].padSize); unsigned int const backgroundBlackWhite = PNM_EQUAL(backgroundColor, pnm_whitexel(1, PBM_TYPE)) ? 0: 1; - unsigned int const readOffset = foregroundLeft - crop[LEFT].removeSize; - unsigned int const writeOffset = foregroundLeft - crop[LEFT].padSize; + unsigned int const readOffset = + foregroundLeft - crop.op[LEFT].removeSize; + unsigned int const writeOffset = foregroundLeft - crop.op[LEFT].padSize; unsigned int const lastWriteChar = writeOffset/8 + (outputCols-1)/8; unsigned char * bitrow; unsigned int i; @@ -679,9 +713,9 @@ writeCroppedPBM(FILE * const ifP, bitrow = pbm_allocrow_packed(allocCols); - readOffBorderPbm(crop[TOP].removeSize, ifP, cols, format); + readOffBorderPbm(crop.op[TOP].removeSize, ifP, cols, format); - outputNewBorderPbm(crop[TOP].padSize, outputCols, backgroundBlackWhite, + outputNewBorderPbm(crop.op[TOP].padSize, outputCols, backgroundBlackWhite, ofP); /* Prepare padding: left and/or right */ @@ -699,13 +733,14 @@ writeCroppedPBM(FILE * const ifP, distorted by pbm_writepbmrow_bitoffset() (No need to mend any left-side padding) */ - if (crop[RIGHT].padSize > 0) + if (crop.op[RIGHT].padSize > 0) bitrow[lastWriteChar] = backgroundBlackWhite * 0xff; } - readOffBorderPbm(crop[BOTTOM].removeSize, ifP, cols, format); + readOffBorderPbm(crop.op[BOTTOM].removeSize, ifP, cols, format); - outputNewBorderPbm(crop[BOTTOM].padSize, outputCols, backgroundBlackWhite, + outputNewBorderPbm(crop.op[BOTTOM].padSize, outputCols, + backgroundBlackWhite, ofP); pbm_freerow_packed(bitrow); @@ -715,23 +750,25 @@ writeCroppedPBM(FILE * const ifP, static void determineCrops(struct cmdlineInfo const cmdline, - unsigned int const oldBorderSize[], - cropOp * const cropArray) { + borderSet * const oldBorderSizeP, + cropSet * const cropP) { edgeLocation i; for (i = 0; i < 4; ++i) { if (cmdline.wantCrop[i]) { - if (oldBorderSize[i] > cmdline.margin) { - cropArray[i].removeSize = oldBorderSize[i] - cmdline.margin; - cropArray[i].padSize = 0; + if (oldBorderSizeP->size[i] > cmdline.margin) { + cropP->op[i].removeSize = + oldBorderSizeP->size[i] - cmdline.margin; + cropP->op[i].padSize = 0; } else { - cropArray[i].removeSize = 0; - cropArray[i].padSize = cmdline.margin - oldBorderSize[i]; + cropP->op[i].removeSize = 0; + cropP->op[i].padSize = + cmdline.margin - oldBorderSizeP->size[i]; } } else { - cropArray[i].removeSize = 0; - cropArray[i].padSize = 0; + cropP->op[i].removeSize = 0; + cropP->op[i].padSize = 0; } } } @@ -741,15 +778,15 @@ determineCrops(struct cmdlineInfo const cmdline, static void validateComputableSize(unsigned int const cols, unsigned int const rows, - cropOp const crop[]) { + cropSet const crop) { double const newcols = (double)cols + - (double)crop[LEFT].padSize + (double)crop[RIGHT].padSize; + (double)crop.op[LEFT].padSize + (double)crop.op[RIGHT].padSize; double const newrows = (double)rows + - (double)crop[TOP].padSize + (double)crop[BOTTOM].padSize; + (double)crop.op[TOP].padSize + (double)crop.op[BOTTOM].padSize; if (newcols > INT_MAX) pm_error("Output width too large: %.0f.", newcols); @@ -771,50 +808,48 @@ cropOneImage(struct cmdlineInfo const cmdline, (the file that tells us where the existing borders are in the input image). Leave *ifP and *bdfP positioned after the image. - *ifP is seekable; *bdfP may not be. + Both files are seekable. -----------------------------------------------------------------------------*/ - xelval maxval; - int format; - int rows, cols; /* dimensions of input image */ + xelval maxval, bmaxval; + int format, bformat; + int rows, cols, brows, bcols; bool hasBorders; - unsigned int oldBorder[4]; + borderSet oldBorder; /* The sizes of the borders in the input image */ - cropOp crop[4]; + cropSet crop; /* The crops we have to do on each side */ - xel background; - pm_filepos rasterpos; pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); - pm_tell2(ifP, &rasterpos, sizeof(rasterpos)); - - background = computeBackground(ifP, cols, rows, maxval, format, - cmdline.background, cmdline.verbose); + if (bdfP) + pnm_readpnminit(bdfP, &bcols, &brows, &bmaxval, &bformat); - if (cmdline.borderfile) { - findBordersInFile(cols, rows, bdfP, background, - cmdline.verbose, &hasBorders, oldBorder); - } else { - pm_seek2(ifP, &rasterpos, sizeof(rasterpos)); + if (bdfP) + analyzeImage(bdfP, bcols, brows, bmaxval, bformat, cmdline.background, + FILEPOS_END, + &background, &hasBorders, &oldBorder); + else + analyzeImage(ifP, cols, rows, maxval, format, cmdline.background, + FILEPOS_BEG, + &background, &hasBorders, &oldBorder); - findBordersInImage(ifP, cols, rows, maxval, format, - background, cmdline.verbose, &hasBorders, - oldBorder); + if (cmdline.verbose) { + pixel const backgroundPixel = pnm_xeltopixel(background, format); + pm_message("Background color is %s", + ppm_colorname(&backgroundPixel, maxval, TRUE /*hexok*/)); } if (!hasBorders) pm_error("The image is entirely background; " "there is nothing to crop."); - determineCrops(cmdline, oldBorder, crop); + determineCrops(cmdline, &oldBorder, &crop); validateComputableSize(cols, rows, crop); if (cmdline.verbose) reportCroppingParameters(crop); - pm_seek2(ifP, &rasterpos, sizeof(rasterpos)); - if (PNM_FORMAT_TYPE(format) == PBM_TYPE) writeCroppedPBM(ifP, cols, rows, format, crop, background, ofP); else @@ -832,7 +867,8 @@ main(int argc, const char *argv[]) { /* The program's regular input file. Could be a seekable copy of it in a temporary file. */ - FILE * bdfP; /* The borderfile; NULL if none. No seeks. */ + FILE * bdfP; + /* The border file. NULL if none. */ bool eof; /* no more images in input stream */ bool beof; /* no more images in borderfile stream */ diff --git a/editor/pnmcut.c b/editor/pnmcut.c deleted file mode 100644 index a21fcffb..00000000 --- a/editor/pnmcut.c +++ /dev/null @@ -1,427 +0,0 @@ - /* pnmcut.c - cut a rectangle out of a portable anymap -** -** Copyright (C) 1989 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. -*/ - -#include <limits.h> -#include "pnm.h" -#include "shhopt.h" - -#define UNSPEC INT_MAX - /* UNSPEC is the value we use for an argument that is not specified - by the user. Theoretically, the user could specify this value, - but we hope not. - */ - -struct cmdline_info { - /* 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 */ - - /* The following describe the rectangle the user wants to cut out. - the value UNSPEC for any of them indicates that value was not - specified. A negative value means relative to the far edge. - 'width' and 'height' are not negative. These specifications - do not necessarily describe a valid rectangle; they are just - what the user said. - */ - int left; - int right; - int top; - int bottom; - int width; - int height; - int pad; - - int verbose; -}; - - - -static xel black_xel; /* A black xel */ - - -static void -parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { -/*---------------------------------------------------------------------------- - Note that the file spec array we return is stored in the storage that - was passed to us as the argv array. ------------------------------------------------------------------------------*/ - optStruct *option_def = malloc(100*sizeof(optStruct)); - /* Instructions to OptParseOptions2 on how to parse our options. - */ - optStruct2 opt; - - unsigned int option_def_index; - - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENTRY(0, "left", OPT_INT, &cmdline_p->left, 0); - OPTENTRY(0, "right", OPT_INT, &cmdline_p->right, 0); - OPTENTRY(0, "top", OPT_INT, &cmdline_p->top, 0); - OPTENTRY(0, "bottom", OPT_INT, &cmdline_p->bottom, 0); - OPTENTRY(0, "width", OPT_INT, &cmdline_p->width, 0); - OPTENTRY(0, "height", OPT_INT, &cmdline_p->height, 0); - OPTENTRY(0, "pad", OPT_FLAG, &cmdline_p->pad, 0); - OPTENTRY(0, "verbose", OPT_FLAG, &cmdline_p->verbose, 0); - - /* Set the defaults */ - cmdline_p->left = UNSPEC; - cmdline_p->right = UNSPEC; - cmdline_p->top = UNSPEC; - cmdline_p->bottom = UNSPEC; - cmdline_p->width = UNSPEC; - cmdline_p->height = UNSPEC; - cmdline_p->pad = FALSE; - cmdline_p->verbose = FALSE; - - 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 */ - - optParseOptions2(&argc, argv, opt, 0); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ - - if (cmdline_p->width < 0) - pm_error("-width may not be negative."); - if (cmdline_p->height < 0) - pm_error("-height may not be negative."); - - if ((argc-1) != 0 && (argc-1) != 1 && (argc-1) != 4 && (argc-1) != 5) - pm_error("Wrong number of arguments. " - "Must be 0, 1, 4, or 5 arguments."); - - switch (argc-1) { - case 0: - cmdline_p->input_filespec = "-"; - break; - case 1: - cmdline_p->input_filespec = argv[1]; - break; - case 4: - case 5: { - int warg, harg; /* The "width" and "height" command line arguments */ - - if (sscanf(argv[1], "%d", &cmdline_p->left) != 1) - pm_error("Invalid number for left column argument"); - if (sscanf(argv[2], "%d", &cmdline_p->top) != 1) - pm_error("Invalid number for top row argument"); - if (sscanf(argv[3], "%d", &warg) != 1) - pm_error("Invalid number for width argument"); - if (sscanf(argv[4], "%d", &harg) != 1) - pm_error("Invalid number for height argument"); - - if (warg > 0) { - cmdline_p->width = warg; - cmdline_p->right = UNSPEC; - } else { - cmdline_p->width = UNSPEC; - cmdline_p->right = warg -1; - } - if (harg > 0) { - cmdline_p->height = harg; - cmdline_p->bottom = UNSPEC; - } else { - cmdline_p->height = UNSPEC; - cmdline_p->bottom = harg - 1; - } - - if (argc-1 == 4) - cmdline_p->input_filespec = "-"; - else - cmdline_p->input_filespec = argv[5]; - break; - } - } -} - - - -static void -compute_cut_bounds(const int cols, const int rows, - const int leftarg, const int rightarg, - const int toparg, const int bottomarg, - const int widtharg, const int heightarg, - int * const leftcol_p, int * const rightcol_p, - int * const toprow_p, int * const bottomrow_p) { -/*---------------------------------------------------------------------------- - From the values given on the command line 'leftarg', 'rightarg', - 'toparg', 'bottomarg', 'widtharg', and 'heightarg', determine what - rectangle the user wants cut out. - - Any of these arguments may be UNSPEC to indicate "not specified". - Any except 'widtharg' and 'heightarg' may be negative to indicate - relative to the far edge. 'widtharg' and 'heightarg' are positive. - - Return the location of the rectangle as *leftcol_p, *rightcol_p, - *toprow_p, and *bottomrow_p. ------------------------------------------------------------------------------*/ - - int leftcol, rightcol, toprow, bottomrow; - /* The left and right column numbers and top and bottom row numbers - specified by the user, except with negative values translated - into the actual values. - - Note that these may very well be negative themselves, such - as when the user says "column -10" and there are only 5 columns - in the image. - */ - - /* Translate negative column and row into real column and row */ - /* Exploit the fact that UNSPEC is a positive number */ - - if (leftarg >= 0) - leftcol = leftarg; - else - leftcol = cols + leftarg; - if (rightarg >= 0) - rightcol = rightarg; - else - rightcol = cols + rightarg; - if (toparg >= 0) - toprow = toparg; - else - toprow = rows + toparg; - if (bottomarg >= 0) - bottomrow = bottomarg; - else - bottomrow = rows + bottomarg; - - /* Sort out left, right, and width specifications */ - - if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) { - *leftcol_p = 0; - *rightcol_p = cols - 1; - } - if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) { - *leftcol_p = 0; - *rightcol_p = 0 + widtharg - 1; - } - if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) { - *leftcol_p = 0; - *rightcol_p = rightcol; - } - if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) { - *leftcol_p = rightcol - widtharg + 1; - *rightcol_p = rightcol; - } - if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) { - *leftcol_p = leftcol; - *rightcol_p = cols - 1; - } - if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) { - *leftcol_p = leftcol; - *rightcol_p = leftcol + widtharg - 1; - } - if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) { - *leftcol_p = leftcol; - *rightcol_p = rightcol; - } - if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) { - pm_error("You may not specify left, right, and width.\n" - "Choose at most two of these."); - } - - - /* Sort out top, bottom, and height specifications */ - - if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) { - *toprow_p = 0; - *bottomrow_p = rows - 1; - } - if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) { - *toprow_p = 0; - *bottomrow_p = 0 + heightarg - 1; - } - if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) { - *toprow_p = 0; - *bottomrow_p = bottomrow; - } - if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) { - *toprow_p = bottomrow - heightarg + 1; - *bottomrow_p = bottomrow; - } - if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) { - *toprow_p = toprow; - *bottomrow_p = rows - 1; - } - if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) { - *toprow_p = toprow; - *bottomrow_p = toprow + heightarg - 1; - } - if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) { - *toprow_p = toprow; - *bottomrow_p = bottomrow; - } - if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) { - pm_error("You may not specify top, bottom, and height.\n" - "Choose at most two of these."); - } - -} - - - -static void -reject_out_of_bounds(const int cols, const int rows, - const int leftcol, const int rightcol, - const int toprow, const int bottomrow) { - - /* Reject coordinates off the edge */ - - if (leftcol < 0) - pm_error("You have specified a left edge (%d) that is beyond\n" - "the left edge of the image (0)", leftcol); - if (rightcol > cols-1) - pm_error("You have specified a right edge (%d) that is beyond\n" - "the right edge of the image (%d)", rightcol, cols-1); - if (rightcol < 0) - pm_error("You have specified a right edge (%d) that is beyond\n" - "the left edge of the image (0)", rightcol); - if (rightcol > cols-1) - pm_error("You have specified a right edge (%d) that is beyond\n" - "the right edge of the image (%d)", rightcol, cols-1); - if (leftcol > rightcol) - pm_error("You have specified a left edge (%d) that is to the right\n" - "of the right edge you specified (%d)", - leftcol, rightcol); - - if (toprow < 0) - pm_error("You have specified a top edge (%d) that is above the top " - "edge of the image (0)", toprow); - if (bottomrow > rows-1) - pm_error("You have specified a bottom edge (%d) that is below the\n" - "bottom edge of the image (%d)", bottomrow, rows-1); - if (bottomrow < 0) - pm_error("You have specified a bottom edge (%d) that is above the\n" - "top edge of the image (0)", bottomrow); - if (bottomrow > rows-1) - pm_error("You have specified a bottom edge (%d) that is below the\n" - "bottom edge of the image (%d)", bottomrow, rows-1); - if (toprow > bottomrow) - pm_error("You have specified a top edge (%d) that is below\n" - "the bottom edge you specified (%d)", - toprow, bottomrow); -} - - - -static void -write_black_rows(FILE *outfile, const int rows, const int cols, - xel * const output_row, - const pixval maxval, const int format) { -/*---------------------------------------------------------------------------- - Write out to file 'outfile' 'rows' rows of 'cols' black xels each, - part of an image of format 'format' with maxval 'maxval'. - - Use *output_row as a buffer. It is at least 'cols' xels wide. ------------------------------------------------------------------------------*/ - int row; - for (row = 0; row < rows; row++) { - int col; - for (col = 0; col < cols; col++) output_row[col] = black_xel; - pnm_writepnmrow(outfile, output_row, cols, maxval, format, 0); - } -} - - - -int -main(int argc, char *argv[]) { - - FILE* ifp; - xel* xelrow; /* Row from input image */ - xel* output_row; /* Row of output image */ - xelval maxval; - int rows, cols, format, row; - int leftcol, rightcol, toprow, bottomrow; - int output_cols; /* Width of output image */ - struct cmdline_info cmdline; - - pnm_init( &argc, argv ); - - parse_command_line(argc, argv, &cmdline); - - ifp = pm_openr(cmdline.input_filespec); - - pnm_readpnminit(ifp, &cols, &rows, &maxval, &format); - xelrow = pnm_allocrow(cols); - - black_xel = pnm_blackxel(maxval, format); - - compute_cut_bounds(cols, rows, - cmdline.left, cmdline.right, - cmdline.top, cmdline.bottom, - cmdline.width, cmdline.height, - &leftcol, &rightcol, &toprow, &bottomrow); - - if (!cmdline.pad) - reject_out_of_bounds(cols, rows, leftcol, rightcol, toprow, bottomrow); - - if (cmdline.verbose) { - pm_message("Image goes from Row 0, Column 0 through Row %d, Column %d", - rows-1, cols-1); - pm_message("Cutting from Row %d, Column %d through Row %d Column %d", - toprow, leftcol, bottomrow, rightcol); - } - - output_cols = rightcol-leftcol+1; - output_row = pnm_allocrow(output_cols); - - pnm_writepnminit(stdout, output_cols, bottomrow-toprow+1, - maxval, format, 0 ); - - /* Implementation note: If speed is ever an issue, we can probably - speed up significantly the non-padding case by writing a special - case loop here for the case cmdline.pad == FALSE. - */ - - /* Write out top padding */ - write_black_rows(stdout, 0 - toprow, output_cols, output_row, - maxval, format); - - /* Read input and write out rows extracted from it */ - for (row = 0; row < rows; row++) { - pnm_readpnmrow(ifp, xelrow, cols, maxval, format); - if (row >= toprow && row <= bottomrow) { - int col; - /* Put in left padding */ - for (col = leftcol; col < 0; col++) { - output_row[col-leftcol] = black_xel; - } - /* Put in extracted columns */ - for (col = MAX(leftcol, 0); col <= MIN(rightcol, cols-1); col++) { - output_row[col-leftcol] = xelrow[col]; - } - /* Put in right padding */ - for (col = MAX(cols, leftcol); col <= rightcol; col++) { - output_row[col-leftcol] = black_xel; - } - pnm_writepnmrow(stdout, output_row, output_cols, - maxval, format, 0); - } - } - /* Note that we may be tempted just to quit after reaching the bottom - of the extracted image, but that would cause a broken pipe problem - for the process that's feeding us the image. - */ - /* Write out bottom padding */ - write_black_rows(stdout, bottomrow - (rows-1), output_cols, output_row, - maxval, format); - - pnm_freerow(output_row); - pnm_freerow(xelrow); - pm_close(ifp); - pm_close(stdout); - - exit( 0 ); -} - diff --git a/editor/pnminvert.test b/editor/pnminvert.test index 606e4e5c..5534f20d 100644 --- a/editor/pnminvert.test +++ b/editor/pnminvert.test @@ -2,7 +2,7 @@ echo Test 1. Should print 1240379484 41 ./pnminvert ../testgrid.pbm | cksum echo Test 2. Should print 1416115901 101484 ./pnminvert ../testimg.ppm | cksum -echo Test 3. Should print 4215652354 33838 +echo Test 3. Should print 2961441369 33838 ppmtopgm ../testimg.ppm | ./pnminvert | cksum echo Test 4. Should print 2595564405 14 pbmmake -w 7 7 | ./pnminvert | cksum diff --git a/editor/pnmscale.c b/editor/pnmscale.c deleted file mode 100644 index f75f440c..00000000 --- a/editor/pnmscale.c +++ /dev/null @@ -1,748 +0,0 @@ -/* pnmscale.c - read a portable anymap and scale it -** -** 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. -** -*/ - -/* - - DON'T ADD NEW FUNCTION TO THIS PROGRAM. ADD IT TO pamscale.c - INSTEAD. - -*/ - - -#include <math.h> -#include <string.h> - -#include "pnm.h" -#include "shhopt.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 cmdline_info { - /* 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 */ - unsigned int xsize; - unsigned int ysize; - float xscale; - float yscale; - unsigned int xbox; - unsigned int ybox; - unsigned int pixels; - unsigned int verbose; - unsigned int nomix; -}; - - -static void -parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { -/*---------------------------------------------------------------------------- - 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 = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. - */ - optStruct3 opt; - - unsigned int option_def_index; - unsigned int xysize; - int xsize, ysize, pixels; - int reduce; - float xscale, yscale, scale_parm; - - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "xsize", OPT_UINT, &xsize, NULL, 0); - OPTENT3(0, "width", OPT_UINT, &xsize, NULL, 0); - OPTENT3(0, "ysize", OPT_UINT, &ysize, NULL, 0); - OPTENT3(0, "height", OPT_UINT, &ysize, NULL, 0); - OPTENT3(0, "xscale", OPT_FLOAT, &xscale, NULL, 0); - OPTENT3(0, "yscale", OPT_FLOAT, &yscale, NULL, 0); - OPTENT3(0, "pixels", OPT_UINT, &pixels, NULL, 0); - OPTENT3(0, "reduce", OPT_UINT, &reduce, NULL, 0); - OPTENT3(0, "xysize", OPT_FLAG, NULL, &xysize, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdline_p->verbose, 0); - OPTENT3(0, "nomix", OPT_FLAG, NULL, &cmdline_p->nomix, 0); - - /* Set the defaults. -1 = unspecified */ - /* (Now that we're using ParseOptions3, we don't have to do this -1 - nonsense, but we don't want to risk screwing these complex - option compatibilities up, so we'll convert that later. - */ - xsize = -1; - ysize = -1; - xscale = -1.0; - yscale = -1.0; - pixels = -1; - reduce = -1; - - opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ - - if (xsize == 0) - pm_error("-xsize/width must be greater than zero."); - if (ysize == 0) - pm_error("-ysize/height must be greater than zero."); - if (xscale != -1.0 && xscale <= 0.0) - pm_error("-xscale must be greater than zero."); - if (yscale != -1.0 && yscale <= 0.0) - pm_error("-yscale must be greater than zero."); - if (reduce <= 0 && reduce != -1) - pm_error("-reduce must be greater than zero."); - - if (xsize != -1 && xscale != -1) - pm_error("Cannot specify both -xsize/width and -xscale."); - if (ysize != -1 && yscale != -1) - pm_error("Cannot specify both -ysize/height and -yscale."); - - if (xysize && - (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1 || - reduce != -1 || pixels != -1) ) - pm_error("Cannot specify -xysize with other dimension options."); - if (pixels != -1 && - (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1 || - reduce != -1) ) - pm_error("Cannot specify -pixels with other dimension options."); - if (reduce != -1 && - (xsize != -1 || xscale != -1 || ysize != -1 || yscale != -1) ) - pm_error("Cannot specify -reduce with other dimension options."); - - if (pixels == 0) - pm_error("-pixels must be greater than zero"); - - /* Get the program parameters */ - - if (xysize) { - /* parameters are xbox, ybox, and optional filespec */ - scale_parm = 0.0; - if (argc-1 < 2) - pm_error("You must supply at least two parameters with -xysize:\n " - "x and y dimensions of the bounding box."); - else if (argc-1 > 3) - pm_error("Too many arguments. With -xysize, you need 2 or 3 " - "arguments."); - else { - char * endptr; - cmdline_p->xbox = strtol(argv[1], &endptr, 10); - if (strlen(argv[1]) > 0 && *endptr != '\0') - pm_error("horizontal xysize not an integer: '%s'", argv[1]); - if (cmdline_p->xbox <= 0) - pm_error("horizontal size is not positive: %d", - cmdline_p->xbox); - - cmdline_p->ybox = strtol(argv[2], &endptr, 10); - if (strlen(argv[2]) > 0 && *endptr != '\0') - pm_error("vertical xysize not an integer: '%s'", argv[2]); - if (cmdline_p->ybox <= 0) - pm_error("vertical size is not positive: %d", - cmdline_p->ybox); - - if (argc-1 < 3) - cmdline_p->input_filespec = "-"; - else - cmdline_p->input_filespec = argv[3]; - } - } else { - cmdline_p->xbox = 0; - cmdline_p->ybox = 0; - - if (xsize == -1 && xscale == -1 && ysize == -1 && yscale == -1 - && pixels == -1 && reduce == -1) { - /* parameters are scale factor and optional filespec */ - if (argc-1 < 1) - pm_error("With no dimension options, you must supply at least " - "one parameter: \nthe scale factor."); - else { - scale_parm = atof(argv[1]); - - if (scale_parm == 0.0) - pm_error("The scale parameter %s is not " - "a positive number.", - argv[1]); - else { - if (argc-1 < 2) - cmdline_p->input_filespec = "-"; - else - cmdline_p->input_filespec = argv[2]; - } - } - } else { - /* Only parameter allowed is optional filespec */ - if (argc-1 < 1) - cmdline_p->input_filespec = "-"; - else - cmdline_p->input_filespec = argv[1]; - - if (reduce != -1) { - scale_parm = ((double) 1.0) / ((double) reduce); - pm_message("reducing by %d gives scale factor of %f.", - reduce, scale_parm); - } else - scale_parm = 0.0; - } - } - - cmdline_p->xsize = xsize == -1 ? 0 : xsize; - cmdline_p->ysize = ysize == -1 ? 0 : ysize; - cmdline_p->pixels = pixels == -1 ? 0 : pixels; - - if (scale_parm) { - cmdline_p->xscale = scale_parm; - cmdline_p->yscale = scale_parm; - } else { - cmdline_p->xscale = xscale == -1.0 ? 0.0 : xscale; - cmdline_p->yscale = yscale == -1.0 ? 0.0 : yscale; - } -} - - - -static void -compute_output_dimensions(const struct cmdline_info cmdline, - const int rows, const int cols, - int * newrowsP, int * newcolsP) { - - if (cmdline.pixels) { - if (rows * cols <= cmdline.pixels) { - *newrowsP = rows; - *newcolsP = cols; - } else { - const double scale = - sqrt( (float) cmdline.pixels / ((float) cols * (float) rows)); - *newrowsP = rows * scale; - *newcolsP = cols * scale; - } - } else if (cmdline.xbox) { - const double aspect_ratio = (float) cols / (float) rows; - const double box_aspect_ratio = - (float) cmdline.xbox / (float) cmdline.ybox; - - if (box_aspect_ratio > aspect_ratio) { - *newrowsP = cmdline.ybox; - *newcolsP = *newrowsP * aspect_ratio + 0.5; - } else { - *newcolsP = cmdline.xbox; - *newrowsP = *newcolsP / aspect_ratio + 0.5; - } - } else { - if (cmdline.xsize) - *newcolsP = cmdline.xsize; - else if (cmdline.xscale) - *newcolsP = cmdline.xscale * cols + .5; - else if (cmdline.ysize) - *newcolsP = cols * ((float) cmdline.ysize/rows) +.5; - else - *newcolsP = cols; - - if (cmdline.ysize) - *newrowsP = cmdline.ysize; - else if (cmdline.yscale) - *newrowsP = cmdline.yscale * rows +.5; - else if (cmdline.xsize) - *newrowsP = rows * ((float) cmdline.xsize/cols) +.5; - else - *newrowsP = rows; - } - - /* If the calculations above yielded (due to rounding) a zero - dimension, we fudge it up to 1. We do this rather than considering - it a specification error (and dying) because it's friendlier to - automated processes that work on arbitrary input. It saves them - having to check their numbers to avoid catastrophe. - */ - - if (*newcolsP < 1) *newcolsP = 1; - if (*newrowsP < 1) *newrowsP = 1; -} - - - -static void -horizontal_scale(const xel inputxelrow[], xel newxelrow[], - const int cols, const int newcols, const float xscale, - const int format, const xelval maxval, - float * const stretchP) { -/*---------------------------------------------------------------------------- - Take the input row inputxelrow[], which is 'cols' columns wide, and - scale it by a factor of 'xscale', to create - the output row newxelrow[], which is 'newcols' columns wide. - - 'format' and 'maxval' describe the Netpbm format of the both input and - output rows. ------------------------------------------------------------------------------*/ - float r, g, b; - float fraccoltofill, fraccolleft; - unsigned int col; - unsigned int newcol; - - newcol = 0; - fraccoltofill = 1.0; /* Output column is "empty" now */ - r = g = b = 0; /* initial value */ - for (col = 0; col < cols; ++col) { - /* Process one pixel from input ('inputxelrow') */ - fraccolleft = xscale; - /* Output all columns, if any, that can be filled using information - from this input column, in addition to what's already in the output - column. - */ - while (fraccolleft >= fraccoltofill) { - /* Generate one output pixel in 'newxelrow'. It will consist - of anything accumulated from prior input pixels in 'r','g', - and 'b', plus a fraction of the current input pixel. - */ - switch (PNM_FORMAT_TYPE(format)) { - case PPM_TYPE: - r += fraccoltofill * PPM_GETR(inputxelrow[col]); - g += fraccoltofill * PPM_GETG(inputxelrow[col]); - b += fraccoltofill * PPM_GETB(inputxelrow[col]); - PPM_ASSIGN( newxelrow[newcol], - MIN(maxval, (int) (r + 0.5)), - MIN(maxval, (int) (g + 0.5)), - MIN(maxval, (int) (b + 0.5)) - ); - break; - - default: - g += fraccoltofill * PNM_GET1(inputxelrow[col]); - PNM_ASSIGN1( newxelrow[newcol], MIN(maxval, (int) (g + 0.5))); - break; - } - fraccolleft -= fraccoltofill; - /* Set up to start filling next output column */ - newcol++; - fraccoltofill = 1.0; - r = g = b = 0.0; - } - /* There's not enough left in the current input pixel to fill up - a whole output column, so just accumulate the remainder of the - pixel into the current output column. - */ - if (fraccolleft > 0.0) { - switch (PNM_FORMAT_TYPE(format)) { - case PPM_TYPE: - r += fraccolleft * PPM_GETR(inputxelrow[col]); - g += fraccolleft * PPM_GETG(inputxelrow[col]); - b += fraccolleft * PPM_GETB(inputxelrow[col]); - break; - - default: - g += fraccolleft * PNM_GET1(inputxelrow[col]); - break; - } - fraccoltofill -= fraccolleft; - } - } - - if (newcol < newcols-1 || newcol > newcols) - pm_error("Internal error: last column filled is %d, but %d " - "is the rightmost output column.", - newcol, newcols-1); - - if (newcol < newcols ) { - /* We were still working on the last output column when we - ran out of input columns. This would be because of rounding - down, and we should be missing only a tiny fraction of that - last output column. - */ - - *stretchP = fraccoltofill; - - switch (PNM_FORMAT_TYPE(format)) { - case PPM_TYPE: - r += fraccoltofill * PPM_GETR(inputxelrow[cols-1]); - g += fraccoltofill * PPM_GETG(inputxelrow[cols-1]); - b += fraccoltofill * PPM_GETB(inputxelrow[cols-1]); - - PPM_ASSIGN(newxelrow[newcol], - MIN(maxval, (int) (r + 0.5)), - MIN(maxval, (int) (g + 0.5)), - MIN(maxval, (int) (b + 0.5)) - ); - break; - - default: - g += fraccoltofill * PNM_GET1(inputxelrow[cols-1]); - PNM_ASSIGN1( newxelrow[newcol], MIN(maxval, (int) (g + 0.5))); - break; - } - } else - *stretchP = 0; -} - - - -static void -zeroAccum(int const cols, int const format, - float rs[], float gs[], float bs[]) { - - int col; - - for ( col = 0; col < cols; ++col ) - rs[col] = gs[col] = bs[col] = 0.0; -} - - - -static void -accumOutputRow(xel * const xelrow, float const fraction, - float rs[], float gs[], float bs[], - int const cols, int const format) { -/*---------------------------------------------------------------------------- - Take 'fraction' times the color in row xelrow and add it to - rs/gs/bs. 'fraction' is less than 1.0. ------------------------------------------------------------------------------*/ - int col; - - switch ( PNM_FORMAT_TYPE(format) ) { - case PPM_TYPE: - for ( col = 0; col < cols; ++col ) { - rs[col] += fraction * PPM_GETR(xelrow[col]); - gs[col] += fraction * PPM_GETG(xelrow[col]); - bs[col] += fraction * PPM_GETB(xelrow[col]); - } - break; - - default: - for ( col = 0; col < cols; ++col) - gs[col] += fraction * PNM_GET1(xelrow[col]); - break; - } -} - - - -static void -makeRow(xel * const xelrow, float rs[], float gs[], float bs[], - int const cols, xelval const maxval, int const format) { -/*---------------------------------------------------------------------------- - Make an xel row at 'xelrow' with format 'format' and - maxval 'maxval' out of the color values in - rs[], gs[], and bs[]. ------------------------------------------------------------------------------*/ - int col; - - switch ( PNM_FORMAT_TYPE(format) ) { - case PPM_TYPE: - for ( col = 0; col < cols; ++col) { - PPM_ASSIGN(xelrow[col], - MIN(maxval, (int) (rs[col] + 0.5)), - MIN(maxval, (int) (gs[col] + 0.5)), - MIN(maxval, (int) (bs[col] + 0.5)) - ); - } - break; - - default: - for ( col = 0; col < cols; ++col ) { - PNM_ASSIGN1(xelrow[col], - MIN(maxval, (int) (gs[col] + 0.5))); - } - break; - } -} - - - -static void -scaleWithMixing(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, - float const xscale, float const yscale, - bool const verbose) { -/*---------------------------------------------------------------------------- - Scale the image on input file 'ifP' (which is described by - 'cols', 'rows', 'format', and 'maxval') by xscale horizontally and - yscale vertically and write the result to standard output as format - 'newformat' and with maxval 'newmaxval'. - - The input file is positioned past the header, to the beginning of the - raster. The output file is too. - - Mix colors from input rows together in the output rows. ------------------------------------------------------------------------------*/ - /* Here's how we think of the color mixing scaling operation: - - First, I'll describe scaling in one dimension. Assume we have - a one row image. A raster row is ordinarily a sequence of - discrete pixels which have no width and no distance between - them -- only a sequence. Instead, think of the raster row as a - bunch of pixels 1 unit wide adjacent to each other. For - example, we are going to scale a 100 pixel row to a 150 pixel - row. Imagine placing the input row right above the output row - and stretching it so it is the same size as the output row. It - still contains 100 pixels, but they are 1.5 units wide each. - Our goal is to make the output row look as much as possible - like the input row, while observing that a pixel can be only - one color. - - Output Pixel 0 is completely covered by Input Pixel 0, so we - make Output Pixel 0 the same color as Input Pixel 0. Output - Pixel 1 is covered half by Input Pixel 0 and half by Input - Pixel 1. So we make Output Pixel 1 a 50/50 mix of Input Pixels - 0 and 1. If you stand back far enough, input and output will - look the same. - - This works for all scale factors, both scaling up and scaling down. - - This program always stretches or squeezes the input row to be the - same length as the output row; The output row's pixels are always - 1 unit wide. - - The same thing works in the vertical direction. We think of - rows as stacked strips of 1 unit height. We conceptually - stretch the image vertically first (same process as above, but - in place of a single-color pixels, we have a vector of colors). - Then we take each row this vertical stretching generates and - stretch it horizontally. - */ - - xel* xelrow; /* An input row */ - xel* vertScaledRow; - /* An output row after vertical scaling, but before horizontal - scaling - */ - xel* newxelrow; - float rowsleft; - /* The number of rows of output that need to be formed from the - current input row (the one in xelrow[]), less the number that - have already been formed (either in the rs/gs/bs accumulators - or output to the file). This can be fractional because of the - way we define rows as having height. - */ - float fracrowtofill; - /* The fraction of the current output row (the one in vertScaledRow[]) - that hasn't yet been filled in from an input row. - */ - float *rs, *gs, *bs; - /* The red, green, and blue color intensities so far accumulated - from input rows for the current output row. - */ - int rowsread; - /* Number of rows of the input file that have been read */ - int row; - - xelrow = pnm_allocrow(cols); - vertScaledRow = pnm_allocrow(cols); - rs = (float*) pm_allocrow( cols, sizeof(float) ); - gs = (float*) pm_allocrow( cols, sizeof(float) ); - bs = (float*) pm_allocrow( cols, sizeof(float) ); - rowsread = 0; - rowsleft = 0.0; - zeroAccum(cols, format, rs, gs, bs); - fracrowtofill = 1.0; - - newxelrow = pnm_allocrow( newcols ); - - for ( row = 0; row < newrows; ++row ) { - /* First scale Y from xelrow[] into vertScaledRow[]. */ - - if ( newrows == rows ) { /* shortcut Y scaling if possible */ - pnm_readpnmrow( ifP, vertScaledRow, cols, newmaxval, format ); - } else { - while (fracrowtofill > 0) { - if (rowsleft <= 0.0) { - if (rowsread < rows) { - pnm_readpnmrow(ifP, xelrow, cols, newmaxval, format); - ++rowsread; - } else { - /* We need another input row to fill up this - output row, but there aren't any more. - That's because of rounding down on our - scaling arithmetic. So we go ahead with - the data from the last row we read, which - amounts to stretching out the last output - row. - */ - if (verbose) - pm_message("%f of bottom row stretched due to " - "arithmetic imprecision", - fracrowtofill); - } - rowsleft = yscale; - } - if (rowsleft < fracrowtofill) { - accumOutputRow(xelrow, rowsleft, rs, gs, bs, - cols, format); - fracrowtofill -= rowsleft; - rowsleft = 0.0; - } else { - accumOutputRow(xelrow, fracrowtofill, rs, gs, bs, - cols, format); - rowsleft = rowsleft - fracrowtofill; - fracrowtofill = 0.0; - } - } - makeRow(vertScaledRow, rs, gs, bs, cols, newmaxval, format); - zeroAccum(cols, format, rs, gs, bs); - fracrowtofill = 1.0; - } - - /* Now scale vertScaledRow horizontally into newxelrow and write - it out. - */ - - if (newcols == cols) /* shortcut X scaling if possible */ - pnm_writepnmrow(stdout, vertScaledRow, newcols, - newmaxval, newformat, 0); - else { - float stretch; - - horizontal_scale(vertScaledRow, newxelrow, cols, newcols, xscale, - format, newmaxval, &stretch); - - if (verbose && row == 0) - pm_message("%f of right column stretched due to " - "arithmetic imprecision", - stretch); - - pnm_writepnmrow(stdout, newxelrow, newcols, - newmaxval, newformat, 0 ); - } - } - pnm_freerow(newxelrow); - pnm_freerow(xelrow); - pnm_freerow(vertScaledRow); -} - - - -static void -scaleWithoutMixing(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, - float const xscale, float const yscale) { -/*---------------------------------------------------------------------------- - Scale the image on input file 'ifP' (which is described by - 'cols', 'rows', 'format', and 'maxval') by xscale horizontally and - yscale vertically and write the result to standard output as format - 'newformat' and with maxval 'newmaxval'. - - The input file is positioned past the header, to the beginning of the - raster. The output file is too. - - 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; - int row; - int rowInXelrow; - - xelrow = pnm_allocrow(cols); - rowInXelrow = -1; - - newxelrow = pnm_allocrow(newcols); - - for (row = 0; row < newrows; ++row) { - int col; - - int const inputRow = (int) (row / yscale); - - for (; rowInXelrow < inputRow; ++rowInXelrow) - pnm_readpnmrow(ifP, xelrow, cols, newmaxval, format); - - - for (col = 0; col < newcols; ++col) { - int const inputCol = (int) (col / xscale); - - newxelrow[col] = xelrow[inputCol]; - } - - pnm_writepnmrow(stdout, newxelrow, newcols, - newmaxval, newformat, 0 ); - } - pnm_freerow(xelrow); - pnm_freerow(newxelrow); -} - - - -int -main(int argc, char **argv ) { - - struct cmdline_info cmdline; - FILE* ifP; - int rows, cols, format, newformat, newrows, newcols; - xelval maxval, newmaxval; - float xscale, yscale; - - pnm_init( &argc, argv ); - - parse_command_line(argc, argv, &cmdline); - - ifP = pm_openr(cmdline.input_filespec); - - pnm_readpnminit( ifP, &cols, &rows, &maxval, &format ); - - /* Promote PBM files 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; - } - compute_output_dimensions(cmdline, rows, cols, &newrows, &newcols); - - /* We round the scale factor down so that we never fill up the - output while (a fractional pixel of) input remains unused. Instead, - we will run out of input while (a fractional pixel of) output is - unfilled -- which is easier for our algorithm to handle. - */ - xscale = (float) newcols / cols; - yscale = (float) newrows / rows; - - if (cmdline.verbose) { - pm_message("Scaling by %f horizontally to %d columns.", - xscale, newcols ); - pm_message("Scaling by %f vertically to %d rows.", - yscale, newrows); - } - - if (xscale * cols < newcols - 1 || - yscale * rows < newrows - 1) - pm_error("Arithmetic precision of this program is inadequate to " - "do the specified scaling. Use a smaller input image " - "or a slightly different scale factor."); - - pnm_writepnminit(stdout, newcols, newrows, newmaxval, newformat, 0); - - if (cmdline.nomix) - scaleWithoutMixing(ifP, cols, rows, maxval, format, - newcols, newrows, newmaxval, newformat, - xscale, yscale); - else - scaleWithMixing(ifP, cols, rows, maxval, format, - newcols, newrows, newmaxval, newformat, - xscale, yscale, cmdline.verbose); - - pm_close(ifP); - pm_close(stdout); - - exit(0); -} diff --git a/editor/specialty/Makefile b/editor/specialty/Makefile new file mode 100644 index 00000000..eda54882 --- /dev/null +++ b/editor/specialty/Makefile @@ -0,0 +1,55 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = editor/specialty +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/config.mk + +PORTBINARIES = pamdeinterlace \ + pammixinterlace \ + pamoil \ + pampop9 \ + pbmlife \ + pgmabel \ + pgmbentley \ + pgmmorphconv \ + pnmindex \ + ppm3d \ + ppmglobe \ + ppmntsc \ + ppmrelief \ + ppmshift \ + ppmspread \ + ppmtv \ + +# We don't include programs that have special library dependencies in the +# merge scheme, because we don't want those dependencies to prevent us +# from building all the other programs. + +NOMERGEBINARIES = +MERGEBINARIES = $(PORTBINARIES) + + +BINARIES = $(MERGEBINARIES) $(NOMERGEBINARIES) +SCRIPTS = + +OBJECTS = $(BINARIES:%=%.o) + +MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) + +.PHONY: all +all: $(BINARIES) + +include $(SRCDIR)/common.mk + +install.bin: install.bin.local + +.PHONY: install.bin.local +install.bin.local: $(PKGDIR)/bin +# Remember that $(SYMLINK) might just be a copy command. +# pamoil replaced pgmoil in June 2001. + cd $(PKGDIR)/bin ; \ + rm -f pgmoil ; \ + $(SYMLINK) pamoil$(EXE) pgmoil diff --git a/editor/pamdeinterlace.c b/editor/specialty/pamdeinterlace.c index 9ed1d8eb..9ed1d8eb 100644 --- a/editor/pamdeinterlace.c +++ b/editor/specialty/pamdeinterlace.c diff --git a/editor/pammixinterlace.c b/editor/specialty/pammixinterlace.c index f22563f6..f22563f6 100644 --- a/editor/pammixinterlace.c +++ b/editor/specialty/pammixinterlace.c diff --git a/editor/pamoil.c b/editor/specialty/pamoil.c index 6cb8d3ac..6cb8d3ac 100644 --- a/editor/pamoil.c +++ b/editor/specialty/pamoil.c diff --git a/editor/pampop9.c b/editor/specialty/pampop9.c index d6c61e4f..d6c61e4f 100644 --- a/editor/pampop9.c +++ b/editor/specialty/pampop9.c diff --git a/editor/pbmlife.c b/editor/specialty/pbmlife.c index be34cc69..be34cc69 100644 --- a/editor/pbmlife.c +++ b/editor/specialty/pbmlife.c diff --git a/editor/pgmabel.c b/editor/specialty/pgmabel.c index 4914c4be..4914c4be 100644 --- a/editor/pgmabel.c +++ b/editor/specialty/pgmabel.c diff --git a/editor/pgmbentley.c b/editor/specialty/pgmbentley.c index aed92074..aed92074 100644 --- a/editor/pgmbentley.c +++ b/editor/specialty/pgmbentley.c diff --git a/editor/pgmmorphconv.c b/editor/specialty/pgmmorphconv.c index abc4e718..abc4e718 100644 --- a/editor/pgmmorphconv.c +++ b/editor/specialty/pgmmorphconv.c diff --git a/editor/pnmindex.c b/editor/specialty/pnmindex.c index 7b405ef3..7b405ef3 100644 --- a/editor/pnmindex.c +++ b/editor/specialty/pnmindex.c diff --git a/editor/ppm3d.c b/editor/specialty/ppm3d.c index 6f317a0b..6f317a0b 100644 --- a/editor/ppm3d.c +++ b/editor/specialty/ppm3d.c diff --git a/editor/ppmglobe.c b/editor/specialty/ppmglobe.c index ee1a57c3..ee1a57c3 100644 --- a/editor/ppmglobe.c +++ b/editor/specialty/ppmglobe.c diff --git a/editor/ppmntsc.c b/editor/specialty/ppmntsc.c index b9f2ac2f..b9f2ac2f 100644 --- a/editor/ppmntsc.c +++ b/editor/specialty/ppmntsc.c diff --git a/editor/ppmrelief.c b/editor/specialty/ppmrelief.c index 5e0669c3..5e0669c3 100644 --- a/editor/ppmrelief.c +++ b/editor/specialty/ppmrelief.c diff --git a/editor/ppmshift.c b/editor/specialty/ppmshift.c index a765daa5..a765daa5 100644 --- a/editor/ppmshift.c +++ b/editor/specialty/ppmshift.c diff --git a/editor/ppmspread.c b/editor/specialty/ppmspread.c index 6753f4fe..6753f4fe 100644 --- a/editor/ppmspread.c +++ b/editor/specialty/ppmspread.c diff --git a/editor/ppmtv.c b/editor/specialty/ppmtv.c index da25102a..da25102a 100644 --- a/editor/ppmtv.c +++ b/editor/specialty/ppmtv.c |