diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-09-27 21:44:29 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-09-27 21:44:29 +0000 |
commit | 43939e66b1d4eeb2f3799c124f3598756755005a (patch) | |
tree | 15733092de55d52421a6ea02f5a43d5f8ff24393 /editor/specialty | |
parent | 49f4336c9bba33650573ba780b70bc501b38643e (diff) | |
download | netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.gz netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.xz netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.zip |
Rebase Stable series to current Advanced: 10.47.04
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@995 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor/specialty')
-rw-r--r-- | editor/specialty/Makefile | 55 | ||||
-rw-r--r-- | editor/specialty/pamdeinterlace.c | 133 | ||||
-rw-r--r-- | editor/specialty/pammixinterlace.c | 345 | ||||
-rw-r--r-- | editor/specialty/pamoil.c | 137 | ||||
-rw-r--r-- | editor/specialty/pampop9.c | 108 | ||||
-rw-r--r-- | editor/specialty/pbmlife.c | 114 | ||||
-rw-r--r-- | editor/specialty/pgmabel.c | 316 | ||||
-rw-r--r-- | editor/specialty/pgmbentley.c | 74 | ||||
-rw-r--r-- | editor/specialty/pgmmorphconv.c | 253 | ||||
-rw-r--r-- | editor/specialty/pnmindex.c | 640 | ||||
-rw-r--r-- | editor/specialty/ppm3d.c | 308 | ||||
-rw-r--r-- | editor/specialty/ppmglobe.c | 173 | ||||
-rw-r--r-- | editor/specialty/ppmntsc.c | 501 | ||||
-rw-r--r-- | editor/specialty/ppmrelief.c | 90 | ||||
-rw-r--r-- | editor/specialty/ppmshift.c | 132 | ||||
-rw-r--r-- | editor/specialty/ppmspread.c | 117 | ||||
-rw-r--r-- | editor/specialty/ppmtv.c | 105 |
17 files changed, 3601 insertions, 0 deletions
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/specialty/pamdeinterlace.c b/editor/specialty/pamdeinterlace.c new file mode 100644 index 00000000..f158fbac --- /dev/null +++ b/editor/specialty/pamdeinterlace.c @@ -0,0 +1,133 @@ +/****************************************************************************** + pamdeinterlace +******************************************************************************* + De-interlace an image, i.e. select every 2nd row. + + By Bryan Henderson, San Jose, CA 2001.11.11. + + Contributed to the public domain. +******************************************************************************/ + +#include "pm_c_util.h" +#include "pam.h" +#include "shhopt.h" +#include "mallocvar.h" + +enum evenodd {EVEN, ODD}; + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char *inputFilespec; /* Filespecs of input files */ + enum evenodd rowsToTake; +}; + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo *cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optStruct3 opt; /* set by OPTENT3 */ + optEntry *option_def; + unsigned int option_def_index; + + unsigned int takeeven, takeodd; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "takeeven", OPT_FLAG, NULL, &takeeven, 0); + OPTENT3(0, "takeodd", OPT_FLAG, NULL, &takeodd, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (takeeven && takeodd) + pm_error("You cannot specify both -takeeven and -takeodd options."); + + if (takeodd) + cmdlineP->rowsToTake = ODD; + else + cmdlineP->rowsToTake = EVEN; + + if (argc-1 < 1) + cmdlineP->inputFilespec = "-"; + else if (argc-1 == 1) + cmdlineP->inputFilespec = argv[1]; + else + pm_error("You specified too many arguments (%d). The only " + "argument is the optional input file specification.", + argc-1); +} + + + + + +int +main(int argc, char *argv[]) { + + FILE * ifP; + tuple * tuplerow; /* Row from input image */ + unsigned int row; + struct cmdlineInfo cmdline; + struct pam inpam; + struct pam outpam; + + pnm_init( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + tuplerow = pnm_allocpamrow(&inpam); + + outpam = inpam; /* Initial value -- most fields should be same */ + outpam.file = stdout; + if (inpam.height % 2 == 0) + outpam.height = inpam.height / 2; + else { + if (cmdline.rowsToTake == ODD) + outpam.height = inpam.height / 2; + else + outpam.height = inpam.height / 2 + 1; + } + + pnm_writepaminit(&outpam); + + { + unsigned int modulusToTake; + /* The row number mod 2 of the rows that are supposed to go into + the output. + */ + + switch (cmdline.rowsToTake) { + case EVEN: modulusToTake = 0; break; + case ODD: modulusToTake = 1; break; + default: pm_error("INTERNAL ERROR: invalid rowsToTake"); + } + + /* Read input and write out rows extracted from it */ + for (row = 0; row < inpam.height; row++) { + pnm_readpamrow(&inpam, tuplerow); + if (row % 2 == modulusToTake) + pnm_writepamrow(&outpam, tuplerow); + } + } + pnm_freepamrow(tuplerow); + pm_close(inpam.file); + pm_close(outpam.file); + + return 0; +} + diff --git a/editor/specialty/pammixinterlace.c b/editor/specialty/pammixinterlace.c new file mode 100644 index 00000000..9f98b406 --- /dev/null +++ b/editor/specialty/pammixinterlace.c @@ -0,0 +1,345 @@ +/****************************************************************************** + pammixinterlace +******************************************************************************* + De-interlace an image by merging adjacent rows. + + Copyright (C) 2007 Bruce Guenter, FutureQuest, Inc. + + 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 _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */ + +#include <string.h> + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "shhopt.h" +#include "pam.h" + + + +static sample +clamp(sample const val, + sample const maxval) { + + return val < 0 ? 0 : val > maxval ? maxval : val; +} + + + +static bool +distant(long const above, + long const mid, + long const below) { + + return abs(mid - (above + below) / 2) > abs(above - below); +} + + + +static void +filterLinearBlend(tuple * const outputrow, + tuple ** const tuplerowWindow, + unsigned int const width, + unsigned int const depth, + bool const adaptive, + sample const maxval) { + + unsigned int col; + + for (col = 0; col < width; ++col) { + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + long const above = tuplerowWindow[0][col][plane]; + long const mid = tuplerowWindow[1][col][plane]; + long const below = tuplerowWindow[2][col][plane]; + + sample out; + + if (!adaptive || distant(above, mid, below)) + out = (above + mid * 2 + below) / 4; + else + out = mid; + + outputrow[col][plane] = out; + } + } +} + + + +static void +filterFfmpeg(tuple * const outputrow, + tuple ** const tuplerowWindow, + unsigned int const width, + unsigned int const depth, + bool const adaptive, + sample const maxval) { + + unsigned int col; + + for (col = 0; col < width; ++col) { + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + long const above = tuplerowWindow[1][col][plane]; + long const mid = tuplerowWindow[2][col][plane]; + long const below = tuplerowWindow[3][col][plane]; + + sample out; + + if (!adaptive || distant(above, mid, below)) { + long const a = (- (long)tuplerowWindow[0][col][plane] + + above * 4 + + mid * 2 + + below * 4 + - (long)tuplerowWindow[4][col][plane]) / 8; + out = clamp(a, maxval); + } else + out = mid; + + outputrow[col][plane] = out; + } + } +} + + + +static void +filterFIR(tuple * const outputrow, + tuple ** const tuplerowWindow, + unsigned int const width, + unsigned int const depth, + bool const adaptive, + sample const maxval) { + + unsigned int col; + + for (col = 0; col < width; ++col) { + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + + long const above = tuplerowWindow[1][col][plane]; + long const mid = tuplerowWindow[2][col][plane]; + long const below = tuplerowWindow[3][col][plane]; + + sample out; + + if (!adaptive || distant(above, mid, below)) { + long const a = (- (long)tuplerowWindow[0][col][plane] + + above * 2 + + mid * 6 + + below * 2 + - (long)tuplerowWindow[4][col][plane]) / 8; + out = clamp(a, maxval); + } else + out = mid; + + outputrow[col][plane] = out; + } + } +} + + + +struct filter { + const char * name; /* The command-line name of the filter */ + unsigned int rows; /* The number of rows the filter operates on */ + void (*filter)(tuple *, tuple **, + unsigned int width, unsigned int depth, + bool adaptive, sample maxval); +}; + +static struct filter filters[] = { + { "fir", 5, filterFIR }, /* FIR is cleanest and default filter */ + { "ffmpeg", 5, filterFfmpeg }, + { "linear", 3, filterLinearBlend }, +}; + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Names of input files */ + struct filter * filterP; + unsigned int adaptive; +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optStruct3 opt; /* set by OPTENT3 */ + optEntry * option_def; + unsigned int option_def_index; + const char * filterName; + unsigned int filterSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "filter", OPT_STRING, &filterName, &filterSpec, 0); + OPTENT3(0, "adaptive", OPT_FLAG, NULL, &cmdlineP->adaptive, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!filterSpec) + cmdlineP->filterP = &filters[0]; + else { + unsigned int i; + cmdlineP->filterP = NULL; + for (i = 0; i < sizeof filters / sizeof(struct filter); ++i) { + if (strcaseeq(filterName, filters[i].name)) { + cmdlineP->filterP = &filters[i]; + break; + } + } + if (!cmdlineP->filterP) + pm_error("The filter name '%s' is not known.", filterName); + } + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("You specified too many arguments (%d). The only " + "argument is the optional input file specification.", + argc-1); +} + + + +static void +allocateRowWindowBuffer(struct pam * const pamP, + tuple ** const tuplerowWindow, + unsigned int const rows) { + + unsigned int row; + + for (row = 0; row < rows; ++row) + tuplerowWindow[row] = pnm_allocpamrow(pamP); +} + + + +static void +freeRowWindowBuffer(tuple ** const tuplerowWindow, + unsigned int const rows) { + + unsigned int row; + + for (row = 0; row < rows; ++row) + pnm_freepamrow(tuplerowWindow[row]); +} + + + +static void +slideWindowDown(tuple ** const tuplerowWindow, + unsigned int const rows) { +/*---------------------------------------------------------------------------- + Slide the rows-line tuple row window tuplerowWindow[] down one by moving + pointers. +-----------------------------------------------------------------------------*/ + tuple * const oldrow0 = tuplerowWindow[0]; + + unsigned int i; + + for (i = 0; i < rows-1; ++i) + tuplerowWindow[i] = tuplerowWindow[i+1]; + + tuplerowWindow[i] = oldrow0; +} + + + +int +main(int argc, char *argv[]) { + + FILE * ifP; + struct cmdlineInfo cmdline; + struct pam inpam; + struct pam outpam; + tuple * tuplerowWindow[5]; + tuple * outputrow; + unsigned int rows; + + pnm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + rows = cmdline.filterP->rows; + + ifP = pm_openr(cmdline.inputFileName); + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + outpam = inpam; /* Initial value -- most fields should be same */ + outpam.file = stdout; + + pnm_writepaminit(&outpam); + + allocateRowWindowBuffer(&inpam, tuplerowWindow, rows); + outputrow = pnm_allocpamrow(&outpam); + + if (inpam.height < rows) { + unsigned int row; + pm_message("WARNING: Image height less than %d. No mixing done.", + rows); + for (row = 0; row < inpam.height; ++row) { + pnm_readpamrow(&inpam, tuplerowWindow[0]); + pnm_writepamrow(&outpam, tuplerowWindow[0]); + } + } else { + unsigned int row; + + for (row = 0; row < rows-1; ++row) + pnm_readpamrow(&inpam, tuplerowWindow[row]); + + /* Pass through first unfilterable rows */ + for (row = 0; row < rows/2; ++row) + pnm_writepamrow(&outpam, tuplerowWindow[row]); + + for (row = rows / 2 + 1; row < inpam.height - rows / 2 + 1; ++row) { + pnm_readpamrow(&inpam, tuplerowWindow[rows-1]); + cmdline.filterP->filter(outputrow, tuplerowWindow, + inpam.width, inpam.depth, + cmdline.adaptive, inpam.maxval); + pnm_writepamrow(&outpam, outputrow); + + slideWindowDown(tuplerowWindow, rows); + } + + /* Pass through last rows */ + for (row = rows/2; row < rows-1; ++row) + pnm_writepamrow(&outpam, tuplerowWindow[row]); + } + + freeRowWindowBuffer(tuplerowWindow, rows); + pnm_freepamrow(outputrow); + pm_close(inpam.file); + pm_close(outpam.file); + + return 0; +} diff --git a/editor/specialty/pamoil.c b/editor/specialty/pamoil.c new file mode 100644 index 00000000..6cb8d3ac --- /dev/null +++ b/editor/specialty/pamoil.c @@ -0,0 +1,137 @@ +/* pgmoil.c - read a portable pixmap and turn into an oil painting +** +** Copyright (C) 1990 by Wilson Bent (whb@hoh-2.att.com) +** Shamelessly butchered into a color version by Chris Sheppard +** 2001 +** +** 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "pam.h" +#include "mallocvar.h" + +static void +convertRow(struct pam const inpam, tuple ** const tuples, + tuple * const tuplerow, int const row, int const smearFactor, + int * const hist) { + + int sample; + for (sample = 0; sample < inpam.depth; sample++) { + int col; + for (col = 0; col < inpam.width; ++col) { + int i; + int drow; + int modalval; + /* The sample value that occurs most often in the neighborhood + of the pixel being examined + */ + + /* Compute hist[] - frequencies, in the neighborhood, of each + sample value + */ + for (i = 0; i <= inpam.maxval; ++i) hist[i] = 0; + + for (drow = row - smearFactor; drow <= row + smearFactor; ++drow) { + if (drow >= 0 && drow < inpam.height) { + int dcol; + for (dcol = col - smearFactor; + dcol <= col + smearFactor; + ++dcol) { + if ( dcol >= 0 && dcol < inpam.width ) + ++hist[tuples[drow][dcol][sample]]; + } + } + } + { + /* Compute modalval */ + int sampleval; + int maxfreq; + + maxfreq = 0; + modalval = 0; + + for (sampleval = 0; sampleval <= inpam.maxval; ++sampleval) { + if (hist[sampleval] > maxfreq) { + maxfreq = hist[sampleval]; + modalval = sampleval; + } + } + } + tuplerow[col][sample] = modalval; + } + } +} + + + +int +main(int argc, char *argv[] ) { + struct pam inpam, outpam; + FILE* ifp; + tuple ** tuples; + tuple * tuplerow; + int * hist; + /* A buffer for the convertRow subroutine to use */ + int argn; + int row; + int smearFactor; + const char* const usage = "[-n <n>] [ppmfile]"; + + ppm_init( &argc, argv ); + + argn = 1; + smearFactor = 3; /* DEFAULT VALUE */ + + /* Check for options. */ + if ( argn < argc && argv[argn][0] == '-' ) { + if ( argv[argn][1] == 'n' ) { + ++argn; + if ( argn == argc || sscanf(argv[argn], "%d", &smearFactor) != 1 ) + pm_usage( usage ); + } else + pm_usage( usage ); + ++argn; + } + if ( argn < argc ) { + ifp = pm_openr( argv[argn] ); + ++argn; + } else + ifp = stdin; + + if ( argn != argc ) + pm_usage( usage ); + + tuples = pnm_readpam(ifp, &inpam, PAM_STRUCT_SIZE(tuple_type)); + pm_close(ifp); + + MALLOCARRAY(hist, inpam.maxval + 1); + if (hist == NULL) + pm_error("Unable to allocate memory for histogram."); + + outpam = inpam; outpam.file = stdout; + + pnm_writepaminit(&outpam); + + tuplerow = pnm_allocpamrow(&inpam); + + for (row = 0; row < inpam.height; ++row) { + convertRow(inpam, tuples, tuplerow, row, smearFactor, hist); + pnm_writepamrow(&outpam, tuplerow); + } + + pnm_freepamrow(tuplerow); + free(hist); + pnm_freepamarray(tuples, &inpam); + + pm_close(stdout); + exit(0); +} + diff --git a/editor/specialty/pampop9.c b/editor/specialty/pampop9.c new file mode 100644 index 00000000..d6c61e4f --- /dev/null +++ b/editor/specialty/pampop9.c @@ -0,0 +1,108 @@ +/* + * + * (c) Robert Tinsley, 2003 (http://www.thepoacher.net/contact) + * + * Released under the GPL (http://www.fsf.org/licenses/gpl.txt) + * + * + * CHANGES + * + * v1.00 2003-02-28 Original version + * + * v1.10 2003-03-02 + * + changed to use pam_* routines rather than ppm_* + * + changed to use pm_* rather than fopen()/fclose() + * + renamed from ppmgrid to pampup9 + * + wrote a man-page (actually, html) + * + * Changes by Bryan Henderson for inclusion in the Netpbm package (fully + * exploiting Netpbm library). Renamed to Pampop9. March 2003. + * + */ + +#include <stdio.h> +#include <stdlib.h> /* atoi() */ + +#include "pam.h" + +static const char * const copyright = + "(c) Robert Tinsley 2003 (http://www.thepoacher.net/contact)"; + +static const char *usagestr = "pnmfile|- xtiles ytiles xdelta ydelta"; + +int main(int argc, char *argv[]) +{ + const char *filename = "-"; + int xtiles, ytiles, xdelta, ydelta; + FILE *fp; + + struct pam spam, dpam; + tuple **spix, *dpix; + int xtilesize, ytilesize, sx, sy, dx, dy, p; + + + + pnm_init(&argc, argv); + + if (argc-1 != 5) { + pm_error("Wrong number of arguments. Program requires 5 arguments; " + "you supplied %d. Usage: %s", argc-1, usagestr); + } + + filename = argv[1]; + xtiles = atoi(argv[2]); + ytiles = atoi(argv[3]); + xdelta = atoi(argv[4]); + ydelta = atoi(argv[5]); + + if (filename == NULL || *filename == '\0' + || xtiles <= 0 || ytiles <= 0 || xdelta < 0 || ydelta < 0) + pm_error("invalid argument"); + + /* read src pam */ + + fp = pm_openr(filename); + + spix = pnm_readpam(fp, &spam, PAM_STRUCT_SIZE(tuple_type)); + + pm_close(fp); + + /* init dst pam */ + + xtilesize = spam.width - (xtiles - 1) * xdelta; + ytilesize = spam.height - (ytiles - 1) * ydelta; + + if (xtilesize <= 0) + pm_error("xtilesize must be positive. You specified %d", xtilesize); + if (ytilesize <= 0) + pm_error("ytilesize must be positive. You specified %d", ytilesize); + + dpam = spam; + dpam.file = stdout; + dpam.width = xtiles * xtilesize; + dpam.height = ytiles * ytilesize; + + dpix = pnm_allocpamrow(&dpam); + + pnm_writepaminit(&dpam); + + /* generate dst pam */ + + for (dy = 0; dy < dpam.height; dy++) { + sy = ((int) (dy / ytilesize)) * ydelta + (dy % ytilesize); + for (dx = 0; dx < dpam.width; dx++) { + sx = ((int) (dx / xtilesize)) * xdelta + (dx % xtilesize); + for (p = 0; p < spam.depth; ++p) { + dpix[dx][p] = spix[sy][sx][p]; + } + } + pnm_writepamrow(&dpam, dpix); + } + + /* all done */ + + pnm_freepamarray(spix, &spam); + pnm_freepamrow(dpix); + + exit(EXIT_SUCCESS); +} diff --git a/editor/specialty/pbmlife.c b/editor/specialty/pbmlife.c new file mode 100644 index 00000000..be34cc69 --- /dev/null +++ b/editor/specialty/pbmlife.c @@ -0,0 +1,114 @@ +/* pbmlife.c - read a portable bitmap and apply Conway's rules of Life to it +** +** Copyright (C) 1988,1 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. +*/ + +#include "pbm.h" + +int +main( argc, argv ) +int argc; +char* argv[]; + { + FILE* ifp; + bit* prevrow; + bit* thisrow; + bit* nextrow; + bit* temprow; + register bit* newrow; + int rows, cols, row; + register int col, count; + int format; + + + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[pbmfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + pbm_readpbminit( ifp, &cols, &rows, &format ); + prevrow = pbm_allocrow( cols ); + thisrow = pbm_allocrow( cols ); + nextrow = pbm_allocrow( cols ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + newrow = pbm_allocrow( cols ); + + pbm_readpbmrow( ifp, nextrow, cols, format ); + + for ( row = 0; row < rows; ++row ) + { + temprow = prevrow; + prevrow = thisrow; + thisrow = nextrow; + nextrow = temprow; + if ( row < rows - 1 ) + pbm_readpbmrow( ifp, nextrow, cols, format ); + + for ( col = 0; col < cols; ++col ) + { + /* Check the neighborhood, with an unrolled double loop. */ + count = 0; + if ( row > 0 ) + { + /* upper left */ + if ( col > 0 && prevrow[col - 1] == PBM_WHITE ) + ++count; + /* upper center */ + if ( prevrow[col] == PBM_WHITE ) + ++count; + /* upper right */ + if ( col < cols - 1 && prevrow[col + 1] == PBM_WHITE ) + ++count; + } + /* left */ + if ( col > 0 && thisrow[col - 1] == PBM_WHITE ) + ++count; + /* right */ + if ( col < cols - 1 && thisrow[col + 1] == PBM_WHITE ) + ++count; + if ( row < rows - 1 ) + { + /* lower left */ + if ( col > 0 && nextrow[col - 1] == PBM_WHITE ) + ++count; + /* lower center */ + if ( nextrow[col] == PBM_WHITE ) + ++count; + /* lower right */ + if ( col < cols - 1 && nextrow[col + 1] == PBM_WHITE ) + ++count; + } + + /* And compute the new value. */ + if ( thisrow[col] == PBM_WHITE ) + if ( count == 2 || count == 3 ) + newrow[col] = PBM_WHITE; + else + newrow[col] = PBM_BLACK; + else + if ( count == 3 ) + newrow[col] = PBM_WHITE; + else + newrow[col] = PBM_BLACK; + } + pbm_writepbmrow( stdout, newrow, cols, 0 ); + } + + pm_close( ifp ); + pm_close( stdout ); + + exit( 0 ); + } diff --git a/editor/specialty/pgmabel.c b/editor/specialty/pgmabel.c new file mode 100644 index 00000000..4914c4be --- /dev/null +++ b/editor/specialty/pgmabel.c @@ -0,0 +1,316 @@ +/* pgmabel.c - read a portable graymap and making the deconvolution +** +** Deconvolution of an axial-symmetric image of an rotation symmetrical +** process by solving the linear equation system with y-Axis as +** symmetry-line +** +** Copyright (C) 1997-2006 by German Aerospace Research establishment +** +** Author: Volker Schmidt +** lefti@voyager.boerde.de +** +** 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. +** +** $HISTORY: +** +** 24 Jan 2002 : 001.009 : some optimzization +** 22 Jan 2002 : 001.008 : some stupid calculations changed +** 08 Aug 2001 : 001.007 : new usage (netpbm-conform) +** 27 Jul 1998 : 001.006 : First try of error correction +** 26 Mar 1998 : 001.005 : Calculating the dl's before transformation +** 06 Feb 1998 : 001.004 : Include of a logo in the upper left edge +** 26 Nov 1997 : 001.003 : Some bug fixes and reading only lines +** 25 Nov 1997 : 001.002 : include of pixsize for getting scale invariant +** 03 Sep 1997 : 001.001 : only define for PID2 +** 03 Sep 1997 : 001.000 : First public release +** 21 Aug 1997 : 000.909 : Recalculate the streching-factor +** 20 Aug 1997 : 000.908 : -left and -right for calculating only one side +** 20 Aug 1997 : 000.906 : correction of divisor, include of -factor +** 15 Aug 1997 : 000.905 : Include of -help and -axis +*/ + +static const char* const version="$VER: pgmabel 1.009 (24 Jan 2002)"; + +#include <math.h> +#include <stdlib.h> /* for calloc */ +#include "pgm.h" +#include "mallocvar.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 */ + +/* ---------------------------------------------------------------------------- +** procedure for calculating the sum of the calculated surfaces with the +** weight of the surface +** n <- index of end point of the summation +** N <- width of the calculated row +** xr <- array of the calculated elements of the row +** adl <- pre-calculated surface coefficient for each segment +*/ +static double +Sum ( int n, double *xr, int N, double *adl) +{ + int k; + double result=0.0; + + if (n==0) return(0.0); /* outer ring is 0 per definition */ + for (k=0 ; k<=(n-1) ; k++) + { + result += xr[k] * ( adl[k*N+n] - adl[(k+1)*N+n]); +/* result += xr[k] * ( dr(k,n+0.5,N) - dr(k+1,n+0.5,N)); */ + } + return(result); +} + +/* ---------------------------------------------------------------------------- +** procedure for calculating the surface coefficient for the Integration +** R, N <- indizes of the coefficient +** r <- radial position of the center of the surface +*/ +static double +dr ( int R, double r, int N) +{ + double a; + double b; + a=(double) N-R ; + b=(double) N-r ; + return(sqrt(a*a-b*b)); +} + +/* ---------------------------------------------------------------------------- +** procedure for making the Abel integration for deconvolution of the image +** y <-> array with values for deconvolution and results +** N <- width of the array +** adl <- array with pre-calculated weighting factors +*/ +static void +abel ( float *y, int N, double *adl) +{ + register int n; + double *rho, *rhop; /* results and new index */ + float *yp; /* new indizes for the y-array */ + + MALLOCARRAY(rho, N); + if( !rho ) + pm_error( "out of memory" ); + rhop = rho; + yp = y; + + for (n=0 ; n<N ; n++) + { + *(rhop++) = ((*yp++) - Sum(n,rho,N,adl))/(adl[n*N+n]); +/* *(rhop++) = ((*yp++) - Sum(n,rho,N))/(dr(n,n+0.5,N)); old version */ + if ( *rhop < 0.0 ) *rhop = 0.0; /* error correction ! */ +/* if (n > 2) rhop[n-1] = (rho[n-2]+rho[n-1]+rho[n])/3.0; stabilization*/ + } + for (n=0 ; n<N ; n++) + { + if (( n>=1 )&&( n<N-1 )) + (*y++) = ((rho[n-1]*0.5+rho[n]+rho[n+1]*0.5)/2.0);/*1D median filter*/ + else (*y++) = rho[n]; + } + free(rho); +} + +/* ---------------------------------------------------------------------------- +** printing a help message if Option -h(elp) is chosen +*/ +static void +help() +{ + pm_message("-----------------------------------------------------------------"); + pm_message("| pgmabel |"); + pm_message("| make a deconvolution with vertical axis as symmetry-line |"); + pm_message("| usage: |"); + pm_message("| pgmabel [-help] [-axis N] [-factor N] [-left|-right] |"); + pm_message("| [-pixsize] [-verbose] [pgmfile] |"); + pm_message("| axis : horizontal position of the axis |"); + pm_message("| factor : user defines stretch-factor for the gray levels |"); + pm_message("| pixsize : size of one pixel in mm (default = 0.1) |"); + pm_message("| left : calculating only the left (or right) side |"); + pm_message("| verbose : output of useful data |"); + pm_message("| pgmfile : Name of a pgmfile (optional) |"); + pm_message("| |"); + pm_message("| for further information please contact the manpage |"); + pm_message("-----------------------------------------------------------------"); + pm_message("%s",version); /* telling the version */ + exit(-1); /* retur-code for no result */ +} + + + + + +/* ---------------------------------------------------------------------------- +** main program +*/ +int main( argc, argv ) + int argc; + char* argv[]; +{ + FILE* ifp; + gray maxval; /* maximum gray-level */ + gray* grayorig; + gray* grayrow; /* one line in the image */ + int argn, rows, cols, row, format; + int col, midcol=0, temp, tc; + float *trow; /* temporary row for deconvolution */ + float l_div, r_div, fac=1.0, cfac=4.0; /* factor for scaling gray-level */ + float pixsize=0.1; + /* no verbose, calculating both sides */ + int verb = FALSE, left = TRUE, right = TRUE; + int nologo = FALSE; + const char* const usage = "[-help] [-axis N] [-factor N] [-pixsize N] [-left|-right] [-verbose] [pgmfile]"; + + pgm_init( &argc, argv ); + argn = 1; + + /* Check for flags. */ + while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) + { + if ( pm_keymatch( argv[argn], "-help", 1 ) ) help(); + else if ( pm_keymatch( argv[argn], "-axis", 1 ) ) + { + ++argn; + if ( argn == argc || sscanf( argv[argn], "%i", &midcol ) !=1 ) + pm_usage( usage ); + } + else if ( pm_keymatch( argv[argn], "-factor", 1 ) ) + { + ++argn; + if ( argn == argc || sscanf( argv[argn], "%f", &fac ) !=1 ) + pm_usage( usage ); + } + else if ( pm_keymatch( argv[argn], "-pixsize", 1 ) ) + { + ++argn; + if ( argn == argc || sscanf( argv[argn], "%f", &pixsize ) !=1 ) + pm_usage( usage ); + } + else if ( pm_keymatch( argv[argn], "-verbose", 1 ) ) + { + verb = TRUE; + } + else if ( pm_keymatch( argv[argn], "-left", 1 ) ) + { + if ( left ) right = FALSE; + else pm_usage( usage ); + } + else if ( pm_keymatch( argv[argn], "-right", 1 ) ) + { + if ( right ) left = FALSE; + else pm_usage( usage ); + } + else if ( pm_keymatch( argv[argn], "-nologo", 4 ) ) + { + nologo = TRUE; + } + else + pm_usage( usage ); + ++ argn; + } + if ( argn < argc ) + { + ifp = pm_openr( argv[argn] ); /* open the picture */ + ++argn; + } + else + ifp = stdin; /* or reading from STDIN */ + if ( argn != argc ) + pm_usage( usage ); + + pgm_readpgminit( ifp, &cols, &rows, &maxval, &format ); /* read picture */ + pgm_writepgminit( stdout, cols, rows, maxval, 0 ); /* write the header */ + grayorig = pgm_allocrow(cols); + grayrow = pgm_allocrow( cols ); /* allocate a row */ + + if (midcol == 0) midcol = cols/2; /* if no axis set take the center */ + if (left ) l_div = (float)(PID2*pixsize)/(cfac*fac); + else l_div=1.0; /* weighting the left side */ + if (right) r_div = (float)(PID2*pixsize)/(cfac*fac); + else r_div=1.0; /* weighting the right side */ + + if (verb) + { + pm_message("%s",version); + pm_message("Calculating a portable graymap with %i rows and %i cols",rows,cols); + pm_message(" resuming a pixelsize of %f mm",pixsize); + if ( !right ) pm_message(" only the left side!"); + if ( !left ) pm_message(" only the right side!"); + pm_message(" axis = %i, stretching factor = %f",midcol,cfac*fac); + if ( left ) pm_message(" left side weighting = %f",l_div); + if ( right ) pm_message(" right side weighting = %f",r_div); + } + + /* allocating the memory for the arrays aldl and ardl */ + aldl = calloc ( midcol*midcol, sizeof(double)); + if( !aldl ) + pm_error( "out of memory" ); + ardl = calloc ( (cols-midcol)*(cols-midcol), sizeof(double)); + if( !ardl ) + pm_error( "out of memory" ); + + MALLOCARRAY(trow, cols); + if( !trow ) + pm_error( "out of memory" ); + + /* now precalculating the weighting-factors for the abel-transformation */ + for (col = 0; col < midcol; ++col) /* factors for left side */ + { + for (tc = 0; tc < midcol; ++tc) aldl[col*midcol+tc] = dr(col,tc+0.5,midcol); + } + for (col = 0; col < (cols-midcol); ++col) /* factors for right side */ + { + for (tc = 0; tc < (cols-midcol); ++tc) + ardl[col*(cols-midcol)+tc] = dr(col,tc+0.5,cols-midcol); + } + + /* abel-transformation for each row splitted in right and left side */ + for ( row = 0; row < rows ; ++row ) + { + pgm_readpgmrow( ifp, grayorig, cols, maxval, format ); + for ( col = 0; col < midcol; ++col) /* left side */ + { + trow[col] = (float) (grayorig[col]); + } + if (left ) abel(trow, midcol, aldl); /* deconvolution */ + for ( col = 0; col < midcol; ++col) /* writing left side */ + { + temp = (int)(trow[col]/l_div); + grayrow[col] = (temp>0?temp:0); + } + for ( col = midcol; col < cols; ++col ) /* right side */ + { + trow[cols-col-1] = (float) (grayorig[col]); + } + if ( right ) abel(trow,(cols-midcol),ardl); /* deconvolution */ + for ( col = midcol; col < cols; ++col) /* writing right side */ + { + temp = (int)(trow[cols-col-1]/r_div); + temp = (temp>0?temp:0); + grayrow[col] = temp; + } + pgm_writepgmrow( stdout, grayrow, cols, maxval, 0 ); /* saving row */ + } + pm_close( ifp ); + pm_close( stdout ); /* closing output */ + free( trow ); /* deconvolution is done, clear memory */ + pgm_freerow( grayorig ); + pgm_freerow( grayrow ); + free(aldl); + free(ardl); /* all used memory freed (i hope) */ + exit( 0 ); /* end of procedure */ +} + diff --git a/editor/specialty/pgmbentley.c b/editor/specialty/pgmbentley.c new file mode 100644 index 00000000..aed92074 --- /dev/null +++ b/editor/specialty/pgmbentley.c @@ -0,0 +1,74 @@ +/* pgmbentley.c - read a portable graymap and smear it according to brightness +** +** Copyright (C) 1990 by Wilson Bent (whb@hoh-2.att.com) +** +** 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 <stdio.h> + +#include "pm_c_util.h" +#include "pgm.h" + + +static unsigned int const N = 4; + + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + int rows, cols; + gray maxval; + gray ** gin; + gray ** gout; + unsigned int row; + const char * inputFileName; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFileName = "-"; + else { + inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("There are no options and only one argument. " + "You specified %u", argc-1); + } + ifP = pm_openr(inputFileName); + + gin = pgm_readpgm(ifP, &cols, &rows, &maxval); + + pm_close(ifP); + + gout = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) + gout[row][col] = 0; + } + + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) { + unsigned int const brow = MIN(rows-1, row + gin[row][col] / N); + + gout[brow][col] = gin[row][col]; + } + } + + pgm_writepgm(stdout, gout, cols, rows, maxval, 0); + + pm_close(stdout); + pgm_freearray(gout, rows); + + return 0; +} diff --git a/editor/specialty/pgmmorphconv.c b/editor/specialty/pgmmorphconv.c new file mode 100644 index 00000000..abc4e718 --- /dev/null +++ b/editor/specialty/pgmmorphconv.c @@ -0,0 +1,253 @@ +/* pgmmorphconv.c - morphological convolutions on a graymap: dilation and +** erosion +** +** Copyright (C) 2000 by Luuk van Dijk/Mind over Matter +** +** Based on +** pnmconvol.c - general MxN convolution on a portable anymap +** +** 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. +*/ + +#include "pm_c_util.h" +#include "pgm.h" + + +/************************************************************ + * Dilate + ************************************************************/ + +static int +dilate( bit** template, int trowso2, int tcolso2, + gray** in_image, gray** out_image, + int rows, int cols ){ + + int c, r, tc, tr; + int templatecount; + gray source; + + 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 ){ + + 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 ){ + 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 */ + + return templatecount; + +} /* dilate */ + + + +/************************************************************ + * Erode: same as dilate except !!!! + ************************************************************/ + +static int +erode( bit** template, int trowso2, int tcolso2, + gray** in_image, gray** out_image, + int rows, int cols ){ + + int c, r, tc, tr; + int templatecount; + gray source; + + 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 + */ + + templatecount=0; + + for( tr=-trowso2; tr<=trowso2; ++tr ){ + for( tc=-tcolso2; tc<=tcolso2; ++tc ){ + + 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 ){ + + source = in_image[r+tr][c+tc]; + out_image[r][c] = MIN(source, out_image[r][c]); + + } /* for c */ + } /* for r */ + + + + } /* for tr */ + } /* for tc */ + + return templatecount; + +} /* erode */ + + + +/************************************************************ + * Main + ************************************************************/ + + +int main( int argc, char* argv[] ){ + + int argn; + char operation; + const char* usage = "-dilate|-erode|-open|-close <templatefile> [pgmfile]"; + + FILE* tifp; /* template */ + int tcols, trows; + int tcolso2, trowso2; + bit** template; + + + FILE* ifp; /* input image */ + int cols, rows; + gray maxval; + + gray** in_image; + gray** out_image; + + int templatecount=0; + + pgm_init( &argc, argv ); + + /* + * parse arguments + */ + + ifp = stdin; + operation = 'd'; + + 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. + */ + + template = pbm_readpbm( tifp, &tcols, &trows ); + pm_close( tifp ); + + if( tcols % 2 != 1 || trows % 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 */ + tcolso2 = tcols / 2; /* template coords run from -tcols/2 .. 0 .. +tcols/2 */ + trowso2 = trows / 2; + +#if 0 + fprintf(stderr, "template: %d x %d\n", trows, tcols); + fprintf(stderr, "half: %d x %d\n", trowso2, tcolso2); +#endif + + /* + * Read in the image + */ + + in_image = pgm_readpgm( ifp, &cols, &rows, &maxval); + + if( cols < tcols || rows < trows ) + pm_error("the image is smaller than the convolution matrix" ); + +#if 0 + fprintf(stderr, "image: %d x %d (%d)\n", rows, cols, maxval); +#endif + + /* + * Allocate output buffer and initialize with min or max value + */ + + out_image = pgm_allocarray( cols, rows ); + + 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 ); + } + + 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 */ + diff --git a/editor/specialty/pnmindex.c b/editor/specialty/pnmindex.c new file mode 100644 index 00000000..ca1da18c --- /dev/null +++ b/editor/specialty/pnmindex.c @@ -0,0 +1,640 @@ +/*============================================================================ + pnmindex +============================================================================== + + build a visual index of a bunch of PNM images + + This used to be a C shell program, and then a BASH program. Neither + were portable enough, and the program is too complex for either of + those languages anyway, so now it's in C. + + By Bryan Henderson 2005.04.24. + + Contributed to the public domain by its author. + +============================================================================*/ + +#define _BSD_SOURCE /* Make sure strdup is in string.h */ + +#include <assert.h> +#include <unistd.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/stat.h> + + +#include "pm_config.h" +#include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "nstring.h" +#include "pnm.h" + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int inputFileCount; + const char ** inputFileName; + unsigned int size; + unsigned int across; + unsigned int colors; + unsigned int black; + unsigned int noquant; + const char * title; + unsigned int verbose; +}; + +static bool verbose; + + + +static void PM_GNU_PRINTF_ATTR(1,2) +systemf(const char * const fmt, + ...) { + + va_list varargs; + + size_t dryRunLen; + + va_start(varargs, fmt); + + vsnprintfN(NULL, 0, fmt, varargs, &dryRunLen); + + va_end(varargs); + + if (dryRunLen + 1 < dryRunLen) + /* arithmetic overflow */ + pm_error("Command way too long"); + else { + size_t const allocSize = dryRunLen + 1; + char * shellCommand; + shellCommand = malloc(allocSize); + if (shellCommand == NULL) + pm_error("Can't get storage for %u-character command", + allocSize); + else { + va_list varargs; + size_t realLen; + int rc; + + va_start(varargs, fmt); + + vsnprintfN(shellCommand, allocSize, fmt, varargs, &realLen); + + assert(realLen == dryRunLen); + va_end(varargs); + + if (verbose) + pm_message("shell cmd: %s", shellCommand); + + rc = system(shellCommand); + if (rc != 0) + pm_error("shell command '%s' failed. rc %d", + shellCommand, rc); + + strfree(shellCommand); + } + } +} + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo * const cmdlineP) { + + unsigned int option_def_index; + optEntry *option_def; + /* Instructions to optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int quant; + unsigned int sizeSpec, colorsSpec, acrossSpec, titleSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "black", OPT_FLAG, NULL, + &cmdlineP->black, 0); + OPTENT3(0, "noquant", OPT_FLAG, NULL, + &cmdlineP->noquant, 0); + OPTENT3(0, "quant", OPT_FLAG, NULL, + &quant, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "size", OPT_UINT, &cmdlineP->size, + &sizeSpec, 0); + OPTENT3(0, "colors", OPT_UINT, &cmdlineP->colors, + &colorsSpec, 0); + OPTENT3(0, "across", OPT_UINT, &cmdlineP->across, + &acrossSpec, 0); + OPTENT3(0, "title", OPT_STRING, &cmdlineP->title, + &titleSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + + if (quant && cmdlineP->noquant) + pm_error("You can't specify both -quant and -noquat"); + + if (!colorsSpec) + cmdlineP->colors = 256; + + if (!sizeSpec) + cmdlineP->size = 100; + + if (!acrossSpec) + cmdlineP->across = 6; + + if (!titleSpec) + cmdlineP->title = NULL; + + if (colorsSpec && cmdlineP->noquant) + pm_error("-colors doesn't make any sense with -noquant"); + + if (argc-1 < 1) + pm_error("You must name at least one file that contains an image " + "to go into the index"); + + cmdlineP->inputFileCount = argc-1; + + MALLOCARRAY_NOFAIL(cmdlineP->inputFileName, cmdlineP->inputFileCount); + + { + unsigned int i; + for (i = 0; i < cmdlineP->inputFileCount; ++i) { + cmdlineP->inputFileName[i] = strdup(argv[i+1]); + if (cmdlineP->inputFileName[i] == NULL) + pm_error("Unable to allocate memory for a file name"); + } + } +} + + + +static void +freeCmdline(struct cmdlineInfo const cmdline) { + + unsigned int i; + + for (i = 0; i < cmdline.inputFileCount; ++i) + strfree(cmdline.inputFileName[i]); + + free(cmdline.inputFileName); + +} + + + +static void +makeTempDir(const char ** const tempDirP) { + + const char * const tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"; + + const char * mytmpdir; + int rc; + + asprintfN(&mytmpdir, "%s/pnmindex_%d", tmpdir, getpid()); + + rc = pm_mkdir(mytmpdir, 0700); + if (rc != 0) + pm_error("Unable to create temporary file directory '%s'. mkdir() " + "fails with errno %d (%s)", + mytmpdir, errno, strerror(errno)); + + *tempDirP = mytmpdir; +} + + + +static void +removeTempDir(const char * const tempDir) { + + int rc; + + rc = rmdir(tempDir); + if (rc != 0) + pm_error("Failed to remove temporary file directory '%s'. " + "rmdir() fails with errno %d (%s)", + tempDir, errno, strerror(errno)); +} + + +static const char * +rowFileName(const char * const dirName, + unsigned int const row) { + + const char * fileName; + + asprintfN(&fileName, "%s/pi.%u", dirName, row); + + return fileName; +} + + + +static void +makeTitle(const char * const title, + unsigned int const rowNumber, + bool const blackBackground, + const char * const tempDir) { + + const char * const invertStage = blackBackground ? "| pnminvert " : ""; + + const char * fileName; + + fileName = rowFileName(tempDir, rowNumber); + + /* This quoting is not adequate. We really should do this without + a shell at all. + */ + systemf("pbmtext \"%s\" " + "%s" + "> %s", + title, invertStage, fileName); + + strfree(fileName); +} + + + +static void +copyImage(const char * const inputFileName, + const char * const outputFileName) { + + systemf("cat %s > %s", inputFileName, outputFileName); +} + + + +static void +copyScaleQuantImage(const char * const inputFileName, + const char * const outputFileName, + int const format, + unsigned int const size, + unsigned int const quant, + unsigned int const colors) { + + const char * scaleCommand; + + switch (PNM_FORMAT_TYPE(format)) { + case PBM_TYPE: + asprintfN(&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); + break; + + case PPM_TYPE: + if (quant) + asprintfN(&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); + break; + default: + pm_error("Unrecognized Netpbm format: %d", format); + } + + systemf("%s", scaleCommand); + + strfree(scaleCommand); +} + + + +static int +formatTypeMax(int const typeA, + int const typeB) { + + if (typeA == PPM_TYPE || typeB == PPM_TYPE) + return PPM_TYPE; + else if (typeA == PGM_TYPE || typeB == PGM_TYPE) + return PGM_TYPE; + else + return PBM_TYPE; +} + + + +static const char * +thumbnailFileName(const char * const dirName, + unsigned int const row, + unsigned int const col) { + + const char * fileName; + + asprintfN(&fileName, "%s/pi.%u.%u", dirName, row, col); + + return fileName; +} + + + +static const char * +thumbnailFileList(const char * const dirName, + unsigned int const row, + unsigned int const cols) { + + unsigned int const maxListSize = 4096; + + char * list; + unsigned int col; + + list = malloc(maxListSize); + if (list == NULL) + pm_error("Unable to allocate %u bytes for file list", maxListSize); + + list[0] = '\0'; + + for (col = 0; col < cols; ++col) { + const char * const fileName = thumbnailFileName(dirName, row, col); + + if (strlen(list) + strlen(fileName) + 1 > maxListSize - 1) + pm_error("File name list too long for this program to handle."); + else { + strcat(list, " "); + strcat(list, fileName); + } + strfree(fileName); + } + + return list; +} + + + +static void +makeImageFile(const char * const thumbnailFileName, + const char * const inputFileName, + bool const blackBackground, + const char * const outputFileName) { + + const char * const blackWhiteOpt = blackBackground ? "-black" : "-white"; + const char * const invertStage = blackBackground ? "| pnminvert " : ""; + + systemf("pbmtext \"%s\" " + "%s" + "| pnmcat %s -topbottom %s - " + "> %s", + inputFileName, invertStage, blackWhiteOpt, + thumbnailFileName, outputFileName); +} + + + +static void +makeThumbnail(const char * const inputFileName, + unsigned int const size, + bool const black, + bool const quant, + unsigned int const colors, + const char * const tempDir, + unsigned int const row, + unsigned int const col, + int * const formatP) { + + FILE * ifP; + int imageCols, imageRows, format; + xelval maxval; + const char * tmpfile; + const char * fileName; + + ifP = pm_openr(inputFileName); + pnm_readpnminit(ifP, &imageCols, &imageRows, &maxval, &format); + pm_close(ifP); + + asprintfN(&tmpfile, "%s/pi.tmp", tempDir); + + if (imageCols < size && imageRows < size) + copyImage(inputFileName, tmpfile); + else + copyScaleQuantImage(inputFileName, tmpfile, format, + size, quant, colors); + + fileName = thumbnailFileName(tempDir, row, col); + + makeImageFile(tmpfile, inputFileName, black, fileName); + + unlink(tmpfile); + + strfree(fileName); + strfree(tmpfile); + + *formatP = format; +} + + + +static void +unlinkThumbnailFiles(const char * const dirName, + unsigned int const row, + unsigned int const cols) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + const char * const fileName = thumbnailFileName(dirName, row, col); + + unlink(fileName); + + strfree(fileName); + } +} + + + +static void +unlinkRowFiles(const char * const dirName, + unsigned int const rows) { + + unsigned int row; + + for (row = 0; row < rows; ++row) { + const char * const fileName = rowFileName(dirName, row); + + unlink(fileName); + + strfree(fileName); + } +} + + + +static void +combineIntoRowAndDelete(unsigned int const row, + unsigned int const cols, + int const maxFormatType, + bool const blackBackground, + bool const quant, + unsigned int const colors, + const char * const tempDir) { + + const char * const blackWhiteOpt = blackBackground ? "-black" : "-white"; + + const char * fileName; + const char * quantStage; + const char * fileList; + + fileName = rowFileName(tempDir, row); + + unlink(fileName); + + if (maxFormatType == PPM_TYPE && quant) + asprintfN(&quantStage, "| pnmquant -quiet %u ", colors); + else + quantStage = strdup(""); + + fileList = thumbnailFileList(tempDir, row, cols); + + systemf("pnmcat %s -leftright -jbottom %s " + "%s" + ">%s", + blackWhiteOpt, fileList, quantStage, fileName); + + strfree(fileList); + strfree(quantStage); + strfree(fileName); + + unlinkThumbnailFiles(tempDir, row, cols); +} + + + +static const char * +rowFileList(const char * const dirName, + unsigned int const rows) { + + unsigned int const maxListSize = 4096; + + unsigned int row; + char * list; + + list = malloc(maxListSize); + if (list == NULL) + pm_error("Unable to allocate %u bytes for file list", maxListSize); + + list[0] = '\0'; + + for (row = 0; row < rows; ++row) { + const char * const fileName = rowFileName(dirName, row); + + if (strlen(list) + strlen(fileName) + 1 > maxListSize - 1) + pm_error("File name list too long for this program to handle."); + + else { + strcat(list, " "); + strcat(list, fileName); + } + strfree(fileName); + } + + return list; +} + + + +static void +writeRowsAndDelete(unsigned int const rows, + int const maxFormatType, + bool const blackBackground, + bool const quant, + unsigned int const colors, + const char * const tempDir) { + + const char * const blackWhiteOpt = blackBackground ? "-black" : "-white"; + + const char * quantStage; + const char * fileList; + + if (maxFormatType == PPM_TYPE && quant) + asprintfN(&quantStage, "| pnmquant -quiet %u ", colors); + else + quantStage = strdup(""); + + fileList = rowFileList(tempDir, rows); + + systemf("pnmcat %s -topbottom %s %s", + blackWhiteOpt, fileList, quantStage); + + strfree(fileList); + strfree(quantStage); + + unlinkRowFiles(tempDir, rows); +} + + + +int +main(int argc, char *argv[]) { + struct cmdlineInfo cmdline; + const char * tempDir; + int maxFormatType; + unsigned int colsInRow; + unsigned int rowsDone; + unsigned int i; + + pnm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + makeTempDir(&tempDir); + + maxFormatType = PBM_TYPE; + colsInRow = 0; + rowsDone = 0; + + if (cmdline.title) + makeTitle(cmdline.title, rowsDone++, cmdline.black, tempDir); + + for (i = 0; i < cmdline.inputFileCount; ++i) { + const char * const inputFileName = cmdline.inputFileName[i]; + + int format; + + makeThumbnail(inputFileName, cmdline.size, cmdline.black, + !cmdline.noquant, cmdline.colors, tempDir, + rowsDone, colsInRow, &format); + + maxFormatType = formatTypeMax(maxFormatType, PNM_FORMAT_TYPE(format)); + + ++colsInRow; + if (colsInRow >= cmdline.across || i == cmdline.inputFileCount-1) { + combineIntoRowAndDelete( + rowsDone, colsInRow, maxFormatType, + cmdline.black, !cmdline.noquant, cmdline.colors, + tempDir); + ++rowsDone; + colsInRow = 0; + } + } + + writeRowsAndDelete(rowsDone, maxFormatType, cmdline.black, + !cmdline.noquant, cmdline.colors, tempDir); + + removeTempDir(tempDir); + + freeCmdline(cmdline); + + pm_close(stdout); + + return 0; +} diff --git a/editor/specialty/ppm3d.c b/editor/specialty/ppm3d.c new file mode 100644 index 00000000..d9ada365 --- /dev/null +++ b/editor/specialty/ppm3d.c @@ -0,0 +1,308 @@ +/*============================================================================= + ppmto3d +=============================================================================== + This program converts two PPM images into an anaglyph stereogram image PPM. + (for viewing with red/blue 3D glasses). + +=============================================================================*/ + +#include <assert.h> + +#include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "ppm.h" +#include "lum.h" + + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * leftInputFileName; /* '-' if stdin */ + const char * rghtInputFileName; /* '-' if stdin */ + int offset; + unsigned int color; +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + unsigned int offsetSpec; + const char * offsetArg; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "color", OPT_FLAG, NULL, + &cmdlineP->color, 0); + OPTENT3(0, "offset", OPT_INT, &cmdlineP->offset, + &offsetSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 2) + pm_error("You must specify at least two arguments: left and right " + "input file names. You specified %u", argc-1); + else { + cmdlineP->leftInputFileName = argv[1]; + cmdlineP->rghtInputFileName = argv[2]; + + if (argc-1 > 2) { + offsetArg = argv[3]; + + if (argc-1 > 3) + pm_error("Program takes at most 3 arguments: left and " + "right input file names and offset. " + "You specified %u", argc-1); + } else + offsetArg = NULL; + } + + if (offsetArg && offsetSpec) + pm_error("You cannot specify both -offset and the offset " + "argument (i.e. with -offset, there is at most " + "two arguments: left and right input file names"); + else if (!offsetArg && !offsetSpec) + cmdlineP->offset = 0; + else if (offsetArg) + cmdlineP->offset = atoi(offsetArg); +} + + + +static void +computeGrayscaleRow(const pixel * const inputRow, + gray * const outputRow, + pixval const maxval, + unsigned int const cols) { + + if (maxval <= 255) { + unsigned int col; + /* Use fast approximation to 0.299 r + 0.587 g + 0.114 b. */ + for (col = 0; col < cols; ++col) + outputRow[col] = ppm_fastlumin(inputRow[col]); + } else { + unsigned int col; + /* Can't use fast approximation, so fall back on floats. */ + for (col = 0; col < cols; ++col) + outputRow[col] = PPM_LUMIN(inputRow[col]) + 0.5; + } +} + + + +static void +compute3dRowMono(gray * const lGrayrow, + gray * const rGrayrow, + pixel * const pixelrow, + unsigned int const cols, + int const offset) { + + unsigned int col; + gray * lgP; + gray * rgP; + pixel * pP; + + assert(abs(offset) <= cols); + + for (col = 0, pP = pixelrow, lgP = lGrayrow, rgP = rGrayrow; + col < cols + offset; + ++col) { + + if ((int)col < offset/2) + ++lgP; + else if ((int)col < offset) { + PPM_ASSIGN(*pP, 0, *lgP, *lgP); + ++lgP; + ++pP; + } else if (col < cols) { + PPM_ASSIGN(*pP, *rgP, *lgP, *lgP); + ++lgP; + ++rgP; + ++pP; + } else if (col < cols + offset/2) { + PPM_ASSIGN(*pP, *rgP, 0, 0); + ++rgP; + ++pP; + } else { + assert(col < cols + offset); + ++rgP; + } + } +} + + + +static void +compute3dRowColor(pixel * const lPixelrow, + pixel * const rPixelrow, + pixel * const pixelrow, + unsigned int const cols, + unsigned int const offset) { + + unsigned int col; + pixel * lP; + pixel * rP; + pixel * pP; + + assert(abs(offset) <= cols); + + for (col = 0, pP = pixelrow, lP = lPixelrow, rP = rPixelrow; + col < cols + offset; + ++col) { + + if ((int)col < offset/2) + ++lP; + else if ((int)col < offset) { + PPM_ASSIGN(*pP, 0, PPM_GETG(*lP), PPM_GETB(*lP)); + ++lP; + ++pP; + } else if (col < cols) { + PPM_ASSIGN(*pP, PPM_GETR(*rP), PPM_GETG(*lP), PPM_GETB(*lP)); + ++lP; + ++rP; + ++pP; + } else if (col < cols + offset/2) { + PPM_ASSIGN(*pP, PPM_GETR(*rP), 0, 0); + ++rP; + ++pP; + } else { + assert(col < cols + offset); + ++rP; + } + } +} + + + +static void +write3dRaster(FILE * const ofP, + FILE * const lIfP, + FILE * const rIfP, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + int const lFormat, + int const rFormat, + int const offset, + bool const color) { + + pixel * lPixelrow; + gray * lGrayrow; + pixel * rPixelrow; + gray * rGrayrow; + pixel * pixelrow; + + unsigned int row; + + assert(abs(offset) < cols); + + lPixelrow = ppm_allocrow (cols); + lGrayrow = pgm_allocrow (cols); + rPixelrow = ppm_allocrow (cols); + rGrayrow = pgm_allocrow (cols); + pixelrow = ppm_allocrow (cols); + + for (row = 0; row < rows; ++row) { + ppm_readppmrow(lIfP, lPixelrow, cols, maxval, lFormat); + ppm_readppmrow(rIfP, rPixelrow, cols, maxval, rFormat); + + computeGrayscaleRow(lPixelrow, lGrayrow, maxval, cols); + computeGrayscaleRow(rPixelrow, rGrayrow, maxval, cols); + + if (color) + compute3dRowColor(lPixelrow, rPixelrow, pixelrow, cols, offset); + else + compute3dRowMono(lGrayrow, rGrayrow, pixelrow, cols, offset); + + ppm_writeppmrow(ofP, pixelrow, cols, maxval, 0); + } + + ppm_freerow(pixelrow); + pgm_freerow(rGrayrow); + ppm_freerow(rPixelrow); + pgm_freerow(lGrayrow); + ppm_freerow(lPixelrow); +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + FILE * lIfP; + FILE * rIfP; + + int cols, rows; + pixval maxval; + + int lRows, lCols; + int lFormat; + pixval lMaxval; + + int rRows, rCols; + int rFormat; + pixval rMaxval; + + ppm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + lIfP = pm_openr(cmdline.leftInputFileName); + rIfP = pm_openr(cmdline.rghtInputFileName); + + ppm_readppminit(lIfP, &lCols, &lRows, &lMaxval, &lFormat); + ppm_readppminit(rIfP, &rCols, &rRows, &rMaxval, &rFormat); + + if ((lCols != rCols) || (lRows != rRows) || + (lMaxval != rMaxval) || + (PPM_FORMAT_TYPE(lFormat) != PPM_FORMAT_TYPE(rFormat))) + pm_error ("Pictures are not of same size and format"); + + cols = lCols; + rows = lRows; + maxval = lMaxval; + + if (abs(cmdline.offset) >= cols) + pm_error("Magnitude of -offset (%u columns) is not less than " + "width of images " + "(%u columns)", abs(cmdline.offset), cols); + + ppm_writeppminit(stdout, cols, rows, maxval, 0); + + write3dRaster(stdout, lIfP, rIfP, cols, rows, maxval, + lFormat, rFormat, cmdline.offset, cmdline.color); + + pm_close(lIfP); + pm_close(rIfP); + pm_close(stdout); + + return 0; +} + diff --git a/editor/specialty/ppmglobe.c b/editor/specialty/ppmglobe.c new file mode 100644 index 00000000..82fae5fb --- /dev/null +++ b/editor/specialty/ppmglobe.c @@ -0,0 +1,173 @@ +/* + * This code written 2003 + * by Max Gensthaler <Max@Gensthaler.de> + * Distributed under the Gnu Public License (GPL) + * + * Gensthaler called it 'ppmglobemap'. + * + * Translations of comments and C dialect by Bryan Henderson May 2003. + */ + + +#define _XOPEN_SOURCE /* get M_PI in math.h */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <math.h> + +#include "pm_c_util.h" +#include "ppm.h" +#include "colorname.h" +#include "shhopt.h" +#include "mallocvar.h" + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Filename of input files */ + unsigned int stripcount; + const char * background; + unsigned int closeok; +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int backgroundSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "background", OPT_STRING, &cmdlineP->background, + &backgroundSpec, 0); + OPTENT3(0, "closeok", OPT_FLAG, NULL, + &cmdlineP->closeok, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!backgroundSpec) + cmdlineP->background = NULL; + + if (argc - 1 < 1) + pm_error("You must specify at least one argument: the strip count"); + else { + int const stripcount = atoi(argv[1]); + if (stripcount <= 0) + pm_error("The strip count must be positive. You specified %d", + stripcount); + + cmdlineP->stripcount = stripcount; + + if (argc-1 < 2) + cmdlineP->inputFileName = "-"; + else + cmdlineP->inputFileName = argv[2]; + + if (argc - 1 > 2) + pm_error("There are at most two arguments: strip count " + "and input file name. " + "You specified %u", argc-1); + } +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + pixel ** srcPixels; + pixel ** dstPixels; + int srcCols, srcRows; + unsigned int dstCols, dstRows; + pixval srcMaxval, dstMaxval; + unsigned int stripWidth; + /* Width in pixels of each strip. In the output image, this means + the rectangular strip in which the lens-shaped foreground strip + is placed.. + */ + unsigned int row; + pixel backgroundColor; + + ppm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + srcPixels = ppm_readppm(ifP, &srcCols, &srcRows, &srcMaxval); + + pm_close(ifP); + + stripWidth = srcCols / cmdline.stripcount; + + if (stripWidth < 1) + pm_error("You asked for %u strips, but the image is only " + "%u pixels wide, so that is impossible.", + cmdline.stripcount, srcCols); + + dstCols = stripWidth * cmdline.stripcount; + dstRows = srcRows; + dstMaxval = srcMaxval; + + if (cmdline.background == NULL) + PPM_ASSIGN(backgroundColor, 0, 0, 0); + else + pm_parse_dictionary_name(cmdline.background, + dstMaxval, cmdline.closeok, + &backgroundColor); + + dstPixels = ppm_allocarray(dstCols, dstRows); + + for (row = 0; row < dstRows; ++row) { + double const factor = sin(M_PI * row / dstRows); + /* Amount by which we squeeze the foreground image of each + strip in this row. + */ + int const stripBorder = (int)((stripWidth*(1.0-factor)/2.0) + 0.5); + /* Distance from the edge (either one) of a strip to the + foreground image within that strip -- i.e. number of pixels + of background color, which User will cut out with scissors + after he prints the image. + */ + unsigned int dstCol; + + for (dstCol = 0; dstCol < dstCols; ++dstCol) { + if (dstCol % stripWidth < stripBorder + || dstCol % stripWidth >= stripWidth - stripBorder) + dstPixels[row][dstCol] = backgroundColor; + else { + unsigned int const leftEdge = + (dstCol / stripWidth) * stripWidth; + unsigned int const srcCol = leftEdge + + (int)((dstCol % stripWidth - stripBorder) / factor + 0.5); + dstPixels[row][dstCol] = srcPixels[row][srcCol]; + } + } + } + + ppm_writeppm(stdout, dstPixels, dstCols, dstRows, dstMaxval, 0); + + return 0; +} diff --git a/editor/specialty/ppmntsc.c b/editor/specialty/ppmntsc.c new file mode 100644 index 00000000..ae3bcfe9 --- /dev/null +++ b/editor/specialty/ppmntsc.c @@ -0,0 +1,501 @@ +/* This is ppmntsc.c, a program to adjust saturation values in an image + so they are legal for NTSC or PAL. + + It is derived from the program rlelegal.c, dated June 5, 1995, + which is described below and propagates that program's copyright. + The derivation was done by Bryan Henderson on 2000.04.21 to convert + it from operating on the RLE format to operating on the PPM format + and to rewrite it in a cleaner style, taking advantage of modern C + compiler technology. +*/ + + +/* + * This software is copyrighted as noted below. It may be freely copied, + * modified, and redistributed, provided that the copyright notice is + * preserved on all copies. + * + * There is no warranty or other guarantee of fitness for this software, + * it is provided solely "as is". Bug reports or fixes may be sent + * to the author, who may or may not act on them as he desires. + * + * You may not include this software in a program or other software product + * without supplying the source, or without informing the end-user that the + * source is available for no extra charge. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + */ + +/* + * rlelegal.c - Make RGB colors legal in the YIQ or YUV color systems. + * + * Author: Wes Barris + * Minnesota Supercomputer Center, Inc. + * Date: Fri Oct 15, 1993 + * @Copyright, Research Equipment Inc., d/b/a Minnesota Supercomputer + * Center, Inc., 1993 + + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include <stdio.h> +#include <math.h> +#include <string.h> + +#include "pm_c_util.h" +#include "ppm.h" +#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 */ + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFilename; + unsigned int verbose; + unsigned int debug; + unsigned int pal; + enum {ALL, LEGAL_ONLY, ILLEGAL_ONLY, CORRECTED_ONLY} output; +}; + + + + +static void +rgbtoyiq(const int r, const int g, const int b, + double * const y_p, + double * const i_p, + double * const q_p) { + + *y_p = .299*(r/255.0) + .587*(g/255.0) + .114*(b/255.0); + *i_p = .596*(r/255.0) - .274*(g/255.0) - .322*(b/255.0); + *q_p = .211*(r/255.0) - .523*(g/255.0) + .312*(b/255.0); +} + + + +static void +yiqtorgb(const double y, const double i, const double q, + int * const r_p, int * const g_p, int * const b_p) { + *r_p = 255.0*(1.00*y + .9562*i + .6214*q); + *g_p = 255.0*(1.00*y - .2727*i - .6468*q); + *b_p = 255.0*(1.00*y -1.1037*i +1.7006*q); +} + + + +static void +rgbtoyuv(const int r, const int g, const int b, + double * const y_p, + double * const u_p, + double * const v_p) { + *y_p = .299*(r/255.0) + .587*(g/255.0) + .114*(b/255.0); + *u_p = -.147*(r/255.0) - .289*(g/255.0) + .437*(b/255.0); + *v_p = .615*(r/255.0) - .515*(g/255.0) - .100*(b/255.0); +} + + + +static void +yuvtorgb(const double y, const double u, const double v, + int * const r_p, int * const g_p, int * const b_p) { + + *r_p = 255.0*(1.00*y + .0000*u +1.1398*v); + *g_p = 255.0*(1.00*y - .3938*u - .5805*v); + *b_p = 255.0*(1.00*y +2.0279*u + .0000*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 + ) { + + double sat_old, sat_new; + /* + * 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; + } else { + *y_new_p = y; + *i_new_p = i; + *q_new_p = q; + *action_p = ALREADY_LEGAL; + } + return; +} + + + +static void +make_legal_yuv(const double y, const double u, const double v, + double * const y_new_p, + double * const u_new_p, + double * const v_new_p, + enum legalize * const action_p + ) { + + double sat_old, sat_new; + /* + * U and V are legs of a right triangle. Saturation is the hypotenuse. + */ + sat_old = sqrt(u*u + v*v); + if (y+sat_old >= 1.334) { + const double diff = 0.5*((y+sat_old) - 1.334); + *y_new_p = y - diff; + sat_new = 1.333 - *y_new_p; + *u_new_p = u*(sat_new/sat_old); + *v_new_p = v*(sat_new/sat_old); + *action_p = LOWER_SAT; + } else if (y-sat_old <= -0.339) { + const double diff = 0.5*((sat_old-y) - 0.339); + *y_new_p = y + diff; + sat_new = 0.338 + *y_new_p; + *u_new_p = u*(sat_new/sat_old); + *v_new_p = v*(sat_new/sat_old); + *action_p = RAISE_SAT; + } else { + *u_new_p = u; + *v_new_p = v; + *action_p = ALREADY_LEGAL; + } + return; +} + + + +static void +make_legal_yiq_i(const int r_in, const int g_in, const int b_in, + int * const r_out_p, + int * const g_out_p, + int * const b_out_p, + enum legalize * const action_p + ) { + + double y, i, q; + double y_new, i_new, q_new; + /* + * 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); + if (*action_p != ALREADY_LEGAL) + /* + * Given the new I and Q, compute new RGB values. + */ + yiqtorgb(y_new, i_new, q_new, r_out_p, g_out_p, b_out_p); + else { + *r_out_p = r_in; + *g_out_p = g_in; + *b_out_p = b_in; + } + return; +} + + + +static void +make_legal_yuv_i(const int r_in, const int g_in, const int b_in, + int * const r_out_p, + int * const g_out_p, + int * const b_out_p, + enum legalize * const action_p + ){ + + double y, u, v; + double y_new, u_new, v_new; + /* + * Convert to YUV and compute the new saturation. + */ + rgbtoyuv(r_in, g_in, b_in, &y, &u, &v); + make_legal_yuv(y, u, v, &y_new, &u_new, &v_new, action_p); + if (*action_p != ALREADY_LEGAL) + /* + * Given the new U and V, compute new RGB values. + */ + yuvtorgb(y_new, u_new, v_new, r_out_p, g_out_p, b_out_p); + else { + *r_out_p = r_in; + *g_out_p = g_in; + *b_out_p = b_in; + } + return; +} + + + +static void +make_legal_yiq_b(const pixel input, + pixel * const output_p, + enum legalize * const action_p) { + + + int ir_in, ig_in, ib_in; + int ir_out, ig_out, ib_out; + + ir_in = (int)PPM_GETR(input); + ig_in = (int)PPM_GETG(input); + ib_in = (int)PPM_GETB(input); + + make_legal_yiq_i(ir_in, ig_in, ib_in, &ir_out, &ig_out, &ib_out, action_p); + + PPM_ASSIGN(*output_p, ir_out, ig_out, ib_out); + + return; +} + + + +static void +make_legal_yuv_b(const pixel input, + pixel * const output_p, + enum legalize * const action_p) { + + int ir_in, ig_in, ib_in; + int ir_out, ig_out, ib_out; + + ir_in = (int)PPM_GETR(input); + ig_in = (int)PPM_GETG(input); + ib_in = (int)PPM_GETB(input); + make_legal_yuv_i(ir_in, ig_in, ib_in, &ir_out, &ig_out, &ib_out, action_p); + + PPM_ASSIGN(*output_p, ir_out, ig_out, ib_out); + + return; +} + + + +static void +report_mapping(const pixel old_pixel, const pixel new_pixel) { +/*---------------------------------------------------------------------------- + Assuming old_pixel and new_pixel 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) + ); + + last_changed_pixel = old_pixel; + first_time = FALSE; + } +} + + + +static void +convert_one_image(FILE * const ifp, struct cmdlineInfo const cmdline, + bool * const eofP, + int * const hicountP, 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); + { + 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 black; + /* A constant - black pixel */ + + PPM_ASSIGN(black, 0, 0, 0); + + PPM_ASSIGN(last_illegal_pixel, 0, 0, 0); /* initial value */ + { + int row; + + *hicountP = 0; *locountP = 0; /* initial values */ + + for (row = 0; row < rows; ++row) { + int col; + ppm_readppmrow(ifp, input_row, cols, maxval, format); + for (col = 0; col < cols; ++col) { + pixel corrected; + /* Corrected or would-be corrected value for pixel */ + enum legalize action; + /* What action was used to make pixel legal */ + if (cmdline.pal) + make_legal_yuv_b(input_row[col], + &corrected, + &action); + else + make_legal_yiq_b(input_row[col], + &corrected, + &action); + + if (action == LOWER_SAT) + (*hicountP)++; + if (action == RAISE_SAT) + (*locountP)++; + if (cmdline.debug) report_mapping(input_row[col], + corrected); + switch (cmdline.output) { + case ALL: + output_row[col] = corrected; + break; + case LEGAL_ONLY: + output_row[col] = (action == ALREADY_LEGAL) ? + input_row[col] : black; + break; + case ILLEGAL_ONLY: + output_row[col] = (action != ALREADY_LEGAL) ? + input_row[col] : black; + break; + case CORRECTED_ONLY: + output_row[col] = (action != ALREADY_LEGAL) ? + corrected : black; + break; + } + } + ppm_writeppmrow(stdout, output_row, cols, maxval, FALSE); + } + } + ppm_freerow(output_row); + ppm_freerow(input_row); + } +} + + +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) { + + struct cmdlineInfo cmdline; + FILE * ifP; + int total_hicount, total_locount; + int image_count; + + bool eof; + + ppm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilename); + + image_count = 0; /* initial value */ + total_hicount = 0; /* initial value */ + total_locount = 0; /* initial value */ + + eof = FALSE; + while (!eof) { + int hicount, locount; + convert_one_image(ifP, cmdline, &eof, &hicount, &locount); + image_count++; + total_hicount += hicount; + total_locount += 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_close(ifP); + + return 0; +} diff --git a/editor/specialty/ppmrelief.c b/editor/specialty/ppmrelief.c new file mode 100644 index 00000000..5e0669c3 --- /dev/null +++ b/editor/specialty/ppmrelief.c @@ -0,0 +1,90 @@ +/* ppmrelief.c - generate a relief map of a portable pixmap +** +** Copyright (C) 1990 by Wilson H. Bent, Jr. +** +** 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 <stdio.h> +#include "ppm.h" + +int +main(int argc, char * argv[]) { + + FILE* ifp; + pixel** inputbuf; + pixel* outputrow; + int argn, rows, cols, format, row; + register int col; + pixval maxval, mv2; + const char* const usage = "[ppmfile]"; + + ppm_init( &argc, argv ); + + argn = 1; + + if ( argn != argc ) { + ifp = pm_openr( argv[argn] ); + ++argn; + } else + ifp = stdin; + + if ( argn != argc ) + pm_usage( usage ); + + ppm_readppminit( ifp, &cols, &rows, &maxval, &format ); + mv2 = maxval / 2; + + /* Allocate space for 3 input rows, plus an output row. */ + inputbuf = ppm_allocarray( cols, 3 ); + outputrow = ppm_allocrow( cols ); + + 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 ); + + /* Write out the first row, all zeros. */ + for ( col = 0; col < cols; ++col ) + PPM_ASSIGN( outputrow[col], 0, 0, 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. + */ + 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 = PPM_GETR( inputbuf[rowa][col] ) + + ( mv2 - PPM_GETR( inputbuf[rowb][col + 2] ) ); + g = PPM_GETG( inputbuf[rowa][col] ) + + ( mv2 - PPM_GETG( inputbuf[rowb][col + 2] ) ); + b = PPM_GETB( inputbuf[rowa][col] ) + + ( mv2 - PPM_GETB( inputbuf[rowb][col + 2] ) ); + PPM_ASSIGN( outputrow[col + 1], r, g, b ); + } + 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 ); + + pm_close( ifp ); + pm_close( stdout ); + + exit( 0 ); +} diff --git a/editor/specialty/ppmshift.c b/editor/specialty/ppmshift.c new file mode 100644 index 00000000..a765daa5 --- /dev/null +++ b/editor/specialty/ppmshift.c @@ -0,0 +1,132 @@ + +/*********************************************************************/ +/* ppmshift - shift lines of a picture left or right by x pixels */ +/* Frank Neumann, October 1993 */ +/* V1.1 16.11.1993 */ +/* */ +/* version history: */ +/* V1.0 11.10.1993 first version */ +/* V1.1 16.11.1993 Rewritten to be NetPBM.programming conforming */ +/*********************************************************************/ + +#include "ppm.h" + +/**************************/ +/* start of main function */ +/**************************/ +int +main(int argc, + char * argv[]) { + + FILE * ifP; + unsigned int row; + int argn, rows, cols, format; + pixel * srcrow; + pixel * destrow; + pixval maxval; + int shift, nowshift; + int shiftArg; + + const char * const usage = "shift [ppmfile]\n shift: maximum number of pixels to shift a line by\n"; + + /* parse in 'default' parameters */ + ppm_init(&argc, argv); + + argn = 1; + + /* parse in shift number */ + if (argn == argc) + pm_usage(usage); + if (sscanf(argv[argn], "%d", &shiftArg) != 1) + pm_usage(usage); + if (shiftArg < 0) + pm_error("shift factor must be 0 or more"); + ++argn; + + /* parse in filename (if present, stdin otherwise) */ + if (argn != argc) + { + ifP = pm_openr(argv[argn]); + ++argn; + } + else + ifP = stdin; + + if (argn != argc) + pm_usage(usage); + + /* read first data from file */ + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); + + if (shiftArg > cols) { + shift = cols; + pm_message("shift amount is larger than picture width - reset to %d", + shift); + } else + shift = shiftArg; + + srcrow = ppm_allocrow(cols); + + destrow = ppm_allocrow(cols); + + ppm_writeppminit(stdout, cols, rows, maxval, 0); + + srand(pm_randseed()); + + /** now do the shifting **/ + /* the range by which a line is shifted lays in the range from */ + /* -shift/2 .. +shift/2 pixels; however, within this range it is */ + /* randomly chosen */ + for (row = 0; row < rows; ++row) { + pixel * pP; + pixel * pP2; + + if (shift != 0) + nowshift = (rand() % (shift+1)) - ((shift+1) / 2); + else + nowshift = 0; + + ppm_readppmrow(ifP, srcrow, cols, maxval, format); + + pP = &srcrow[0]; + pP2 = &destrow[0]; + + /* if the shift value is less than zero, we take the original + pixel line and copy it into the destination line translated + to the left by x pixels. The empty pixels on the right end + of the destination line are filled up with the pixel that + is the right-most in the original pixel line. + */ + if (nowshift < 0) { + unsigned int col; + pP += abs(nowshift); + for (col = 0; col < cols; ++col) { + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + ++pP2; + if (col < (cols + nowshift) - 1) + ++pP; + } + } else { + unsigned int col; + /* The shift value is 0 or positive, so fill the first + <nowshift> pixels of the destination line with the + first pixel from the source line, and copy the rest of + the source line to the dest line + */ + for (col = 0; col < cols; ++col) { + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + ++pP2; + if (col >= nowshift) + ++pP; + } + } + + ppm_writeppmrow(stdout, destrow, cols, maxval, 0); + } + + pm_close(ifP); + ppm_freerow(srcrow); + ppm_freerow(destrow); + + return 0; +} diff --git a/editor/specialty/ppmspread.c b/editor/specialty/ppmspread.c new file mode 100644 index 00000000..6753f4fe --- /dev/null +++ b/editor/specialty/ppmspread.c @@ -0,0 +1,117 @@ +/*********************************************************************/ +/* ppmspread - randomly displace a PPM's pixels by a certain amount */ +/* Frank Neumann, October 1993 */ +/* V1.1 16.11.1993 */ +/* */ +/* version history: */ +/* V1.0 12.10.1993 first version */ +/* V1.1 16.11.1993 Rewritten to be NetPBM.programming conforming */ +/*********************************************************************/ + +#include <string.h> + +#include "ppm.h" + + + +int +main(int argc, + char * argv[]) { + + FILE * ifP; + int argn, rows, cols; + unsigned int row; + pixel ** destarray, ** srcarray; + pixel * pP; + pixel * pP2; + pixval maxval; + pixval r1, g1, b1; + int amount; + const char * const usage = "amount [ppmfile]\n amount: # of pixels to displace a pixel by at most\n"; + + /* parse in 'default' parameters */ + ppm_init(&argc, argv); + + argn = 1; + + /* parse in amount & seed */ + if (argn == argc) + pm_usage(usage); + if (sscanf(argv[argn], "%d", &amount) != 1) + pm_usage(usage); + if (amount < 0) + pm_error("amount should be a positive number"); + ++argn; + + /* parse in filename (if present, stdin otherwise) */ + if (argn != argc) + { + ifP = pm_openr(argv[argn]); + ++argn; + } + else + ifP = stdin; + + if (argn != argc) + pm_usage(usage); + + srcarray = ppm_readppm(ifP, &cols, &rows, &maxval); + + destarray = ppm_allocarray(cols, rows); + + /* clear out the buffer */ + for (row = 0; row < rows; ++row) + memset(destarray[row], 0, cols * sizeof(pixel)); + + srand(pm_randseed()); + + /* start displacing pixels */ + for (row = 0; row < rows; ++row) { + unsigned int col; + pP = &srcarray[row][0]; + + for (col = 0; col < cols; ++col) { + int const xdis = (rand() % (amount+1)) - ((amount+1) / 2); + int const ydis = (rand() % (amount+1)) - ((amount+1) / 2); + + int const xnew = col + xdis; + int const ynew = row + ydis; + + /* only set the displaced pixel if it's within the bounds + of the image + */ + if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) { + /* displacing a pixel is accomplished by swapping it + with another pixel in its vicinity - so, first + store other pixel's RGB + */ + pP2 = &srcarray[ynew][xnew]; + r1 = PPM_GETR(*pP2); + g1 = PPM_GETG(*pP2); + b1 = PPM_GETB(*pP2); + /* set second pixel to new value */ + pP2 = &destarray[ynew][xnew]; + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + + /* now, set first pixel to (old) value of second */ + pP2 = &destarray[row][col]; + PPM_ASSIGN(*pP2, r1, g1, b1); + } else { + /* displaced pixel is out of bounds; leave the old + pixel there + */ + pP2 = &destarray[row][col]; + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + } + ++pP; + } + } + + ppm_writeppm(stdout, destarray, cols, rows, maxval, 0); + + pm_close(ifP); + ppm_freearray(srcarray, rows); + ppm_freearray(destarray, rows); + + return 0; +} diff --git a/editor/specialty/ppmtv.c b/editor/specialty/ppmtv.c new file mode 100644 index 00000000..da25102a --- /dev/null +++ b/editor/specialty/ppmtv.c @@ -0,0 +1,105 @@ + +/*********************************************************************/ +/* ppmtv - make a 'look-alike ntsc' picture from a PPM file */ +/* Frank Neumann, October 1993 */ +/* V1.1 16.11.1993 */ +/* */ +/* version history: */ +/* V1.0 12.10.1993 first version */ +/* V1.1 16.11.1993 Rewritten to be NetPBM.programming conforming */ +/*********************************************************************/ + +#include "ppm.h" + +/**************************/ +/* start of main function */ +/**************************/ +int main(argc, argv) +int argc; +char *argv[]; +{ + FILE* ifp; + int argn, rows, cols, format, i = 0, j = 0; + pixel *srcrow, *destrow; + pixel *pP = NULL, *pP2 = NULL; + pixval maxval; + double dimfactor; + long longfactor; + const char * const usage = "dimfactor [ppmfile]\n dimfactor: 0.0 = total blackness, 1.0 = original picture\n"; + + /* parse in 'default' parameters */ + ppm_init(&argc, argv); + + argn = 1; + + /* parse in dim factor */ + if (argn == argc) + pm_usage(usage); + if (sscanf(argv[argn], "%lf", &dimfactor) != 1) + pm_usage(usage); + if (dimfactor < 0.0 || dimfactor > 1.0) + pm_error("dim factor must be in the range from 0.0 to 1.0 "); + ++argn; + + /* parse in filename (if present, stdin otherwise) */ + if (argn != argc) + { + ifp = pm_openr(argv[argn]); + ++argn; + } + else + ifp = stdin; + + if (argn != argc) + pm_usage(usage); + + /* read first data from file */ + ppm_readppminit(ifp, &cols, &rows, &maxval, &format); + + /* no error checking required here, ppmlib does it all for us */ + srcrow = ppm_allocrow(cols); + + longfactor = (long)(dimfactor * 65536); + + /* allocate a row of pixel data for the new pixels */ + destrow = ppm_allocrow(cols); + + ppm_writeppminit(stdout, cols, rows, maxval, 0); + + /** now do the ntsc'ing (actually very similar to ppmdim) **/ + for (i = 0; i < rows; i++) + { + ppm_readppmrow(ifp, srcrow, cols, maxval, format); + + pP = srcrow; + pP2 = destrow; + + for (j = 0; j < cols; j++) + { + /* every alternating row is left in unchanged condition */ + if (i & 1) + { + PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP)); + } + /* and the other lines are dimmed to the specified factor */ + else + { + PPM_ASSIGN(*pP2, (PPM_GETR(*pP) * longfactor) >> 16, + (PPM_GETG(*pP) * longfactor) >> 16, + (PPM_GETB(*pP) * longfactor) >> 16); + } + pP++; + pP2++; + } + + /* write out one line of graphic data */ + ppm_writeppmrow(stdout, destrow, cols, maxval, 0); + } + + pm_close(ifp); + ppm_freerow(srcrow); + ppm_freerow(destrow); + + exit(0); +} + |