home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: alt.sources
- Path: sparky!uunet!ferkel.ucsb.edu!taco!rock!stanford.edu!agate!spool.mu.edu!news.cs.indiana.edu!babbage.ece.uc.edu!uceng.uc.edu!strombrg
- From: strombrg@uceng.uc.edu (Dan Stromberg)
- Subject: ppmdist - for computer generated color images on mono devices
- Message-ID: <C1HBz0.AKA@uceng.uc.edu>
- Organization: University of Cincinnati
- Date: Tue, 26 Jan 1993 21:06:36 GMT
- Lines: 338
-
- This is ppmdist, something I wrote in response to a user's frustration
- with repeatedly using xv's palette editor, to get colors mapped into
- something that would show up distinctly on a B/W printer. The man
- page gives more information.
-
- You'll want pbmplus and ANSI C (or an ANSI->K&R filter) to compile.
-
- If there's something already out there that does this, I imagine
- people will let me know about it. :) Here goes...
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: Makefile ppmcmap.h ppmdist.1 ppmdist.c
- # Wrapped by strombrg@cicada.occ.uc.edu on Tue Jan 26 15:53:11 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(172 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- XCFLAGS=-O6 -s
- X
- Xppmdist: ppmdist.o
- X gcc.rt $(CFLAGS) -o ppmdist ppmdist.o -lppm -lpgm -lpbm
- X
- Xppmdist.o: ppmdist.c
- X gcc.rt -c $(CFLAGS) ppmdist.c
- X
- Xclean:
- X rm -f ppmdist *.o
- END_OF_FILE
- if test 172 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'ppmcmap.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ppmcmap.h'\"
- else
- echo shar: Extracting \"'ppmcmap.h'\" \(1375 characters\)
- sed "s/^X//" >'ppmcmap.h' <<'END_OF_FILE'
- X/* ppmcmap.h - header file for colormap routines in libppm
- X*/
- X
- X/* Color histogram stuff. */
- X
- Xtypedef struct colorhist_item* colorhist_vector;
- Xstruct colorhist_item
- X {
- X pixel color;
- X int value;
- X };
- X
- Xtypedef struct colorhist_list_item* colorhist_list;
- Xstruct colorhist_list_item
- X {
- X struct colorhist_item ch;
- X colorhist_list next;
- X };
- X
- Xcolorhist_vector ppm_computecolorhist ARGS(( pixel** pixels, int cols, int rows, int maxcolors, int* colorsP ));
- X/* Returns a colorhist *colorsP long (with space allocated for maxcolors. */
- X
- Xvoid ppm_addtocolorhist ARGS(( colorhist_vector chv, int* colorsP, int maxcolors, pixel* colorP, int value, int position ));
- X
- Xvoid ppm_freecolorhist ARGS(( colorhist_vector chv ));
- X
- X
- X/* Color hash table stuff. */
- X
- Xtypedef colorhist_list* colorhash_table;
- X
- Xcolorhash_table ppm_computecolorhash ARGS(( pixel** pixels, int cols, int rows, int maxcolors, int* colorsP ));
- X
- Xint
- Xppm_lookupcolor ARGS(( colorhash_table cht, pixel* colorP ));
- X
- Xcolorhist_vector ppm_colorhashtocolorhist ARGS(( colorhash_table cht, int maxcolors ));
- Xcolorhash_table ppm_colorhisttocolorhash ARGS(( colorhist_vector chv, int colors ));
- X
- Xint ppm_addtocolorhash ARGS(( colorhash_table cht, pixel* colorP, int value ));
- X/* Returns -1 on failure. */
- X
- Xcolorhash_table ppm_alloccolorhash ARGS(( void ));
- X
- Xvoid ppm_freecolorhash ARGS(( colorhash_table cht ));
- END_OF_FILE
- if test 1375 -ne `wc -c <'ppmcmap.h'`; then
- echo shar: \"'ppmcmap.h'\" unpacked with wrong size!
- fi
- # end of 'ppmcmap.h'
- fi
- if test -f 'ppmdist.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ppmdist.1'\"
- else
- echo shar: Extracting \"'ppmdist.1'\" \(1722 characters\)
- sed "s/^X//" >'ppmdist.1' <<'END_OF_FILE'
- X.TH ppmdist 1 "22 July 1992"
- X.IX ppmdist
- X.SH NAME
- Xppmdist - simplistic grayscale assignment for machine generated, color images
- X.SH SYNOPSIS
- X.B ppmdist
- X.RB [ -intensity | -frequency ]
- X.RI [ ppmfile ]
- X.SH DESCRIPTION
- XReads a portable pixmap as input, performs a simplistic grayscale
- Xassignment intended for use with grayscale or bitmap printers.
- X
- XOften conversion from ppm to pgm will yield an image with contrast too
- Xlow for good printer output. The program maximizes contrast between
- Xthe gray levels output.
- X
- XA ppm input of n colors is read, and a pgm of n gray levels is written.
- XThe gray levels take on the values 0..n-1, while maxval takes on n-1.
- X
- XThe mapping from color to stepped grayscale can be performed in order
- Xof input pixel intensity, or input pixel frequency (number of repetitions).
- X.SH OPTIONS
- X.TP 14
- X.TP 14
- X.BI -frequency
- XSort input colors by the number of times a color appears in the input,
- Xbefore mapping to evenly distributed graylevels of output.
- X.BI -intensity
- XSort input colors by their grayscale intensity, before mapping to evenly
- Xdistributed graylevels of output. This is the default.
- X.SH BUGS
- XHelpful only for images with a very small number of colors.
- XPerhaps should have been an option to ppmtopgm(1).
- X.SH "SEE ALSO"
- Xppmtopgm(1), ppmhist(1), ppm(5)
- X.SH AUTHOR
- XCopyright (C) 1993 by Dan Stromberg.
- X.\" Permission to use, copy, modify, and distribute this software and its
- X.\" documentation for any purpose and without fee is hereby granted, provided
- X.\" that the above copyright notice appear in all copies and that both that
- X.\" copyright notice and this permission notice appear in supporting
- X.\" documentation. This software is provided "as is" without express or
- X.\" implied warranty.
- END_OF_FILE
- if test 1722 -ne `wc -c <'ppmdist.1'`; then
- echo shar: \"'ppmdist.1'\" unpacked with wrong size!
- fi
- # end of 'ppmdist.1'
- fi
- if test -f 'ppmdist.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ppmdist.c'\"
- else
- echo shar: Extracting \"'ppmdist.c'\" \(5112 characters\)
- sed "s/^X//" >'ppmdist.c' <<'END_OF_FILE'
- X#include <pnm.h>
- X#include <pgm.h>
- X#include "ppmcmap.h"
- X
- X/*
- X * Yep, this is ANSI C alright... It was developed on something that doesn't
- X * do K&R very well.
- X */
- X
- X/*
- X * Yep, it's a very simple algorithm, but it was something I wanted to have
- X * available.
- X */
- X
- Xstruct colorToGrayEntry {
- X pixel color;
- X gray gray;
- X int frequency;
- X};
- X
- X/*
- X * BUG: This number was chosen pretty arbitrarily. The program is * probably
- X * only useful for a very small numbers of colors - and that's * not only
- X * because of the O(n) search that's used. The idea lends * itself primarily
- X * to low color (read: simple, machine generated) images.
- X */
- X#define MAXCOLORS 255
- X
- Xvoid main(int argc, char *argv[]);
- Xgray newGrayValue(pixel * pixel, struct colorToGrayEntry * colorToGrayMap, int colors);
- Xint cmpColorToGrayEntryByIntensity(void *entry1, void *entry2);
- Xint cmpColorToGrayEntryByFrequency(void *entry1, void *entry2);
- X
- Xvoid
- Xmain(int argc, char *argv[])
- X{
- X FILE *ifp;
- X int col, cols, row, rows, color, colors, argn;
- X int frequency;
- X pixval maxval;
- X pixel **pixels;
- X pixel *pP;
- X colorhist_vector hist;
- X gray *grayrow;
- X gray *gP;
- X struct colorToGrayEntry *colorToGrayMap;
- X
- X ppm_init(&argc, argv);
- X
- X argn = 1;
- X /* Default is to sort colors by intensity */
- X frequency = 0;
- X
- X while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
- X if (pm_keymatch(argv[argn], "-frequency", 2))
- X frequency = 1;
- X else if (pm_keymatch(argv[argn], "-intensity", 2))
- X frequency = 0;
- X else
- X pm_usage( "[-frequency|-intensity] [ppmfile]" );
- X ++argn;
- X }
- X
- X if (argn < argc) {
- X ifp = pm_openr(argv[argn]);
- X ++argn;
- X } else
- X ifp = stdin;
- X
- X pixels = ppm_readppm(ifp, &cols, &rows, &maxval);
- X pm_close(ifp);
- X /* all done with the input file - it's entirely in memory */
- X
- X /*
- X * Compute a histogram of the colors in the input. This is good for
- X * both frequency, and indirectly the intensity, of a color.
- X */
- X hist = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
- X
- X if (hist == (colorhist_vector) 0)
- X /*
- X * BUG: This perhaps should use an exponential backoff, in
- X * the number of colors, until success - cf ppmquant's
- X * approach. The results are then more what's expected, but
- X * not necessarily very useful.
- X */
- X pm_error("Too many colors - Try reducing with ppmquant");
- X
- X /* copy the colors into another structure for sorting */
- X colorToGrayMap = (struct colorToGrayEntry *)
- X malloc(sizeof(struct colorToGrayEntry) * colors);
- X for (color = 0; color < colors; color++) {
- X colorToGrayMap[color].color = hist[color].color;
- X colorToGrayMap[color].frequency = hist[color].value;
- X /*
- X * This next is derivable, of course, but it's far faster to
- X * store it precomputed. This can be skipped, when sorting
- X * by frequency - but again, for a small number of colors
- X * it's a small matter.
- X */
- X colorToGrayMap[color].gray = PPM_LUMIN(hist[color].color);
- X }
- X
- X /*
- X * sort by intensity - sorting by frequency (in the histogram) is
- X * worth considering as a future addition.
- X */
- X if (frequency)
- X qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
- X cmpColorToGrayEntryByFrequency);
- X else
- X qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
- X cmpColorToGrayEntryByIntensity);
- X
- X /*
- X * create mapping between the n colors in input, to n evenly spaced
- X * grey-scale intensities. This is done by overwriting the neatly
- X * formed gray values corresponding to the input-colors, with a new
- X * set of evenly spaced gray values. Since maxval can be changed on
- X * a lark, we just use gray levels 0..colors-1, and adjust maxval
- X * accordingly
- X */
- X maxval = colors - 1;
- X for (color = 0; color < colors; color++)
- X colorToGrayMap[color].gray = color;
- X
- X /* write pgm file, mapping colors to intensities */
- X pgm_writepgminit(stdout, cols, rows, maxval, 0);
- X
- X grayrow = pgm_allocrow(cols);
- X
- X for (row = 0; row < rows; row++) {
- X for (col = 0, pP = pixels[row], gP = grayrow; col < cols;
- X col++, pP++, gP++)
- X *gP = newGrayValue(pP, colorToGrayMap, colors);
- X pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
- X }
- X
- X pm_close(stdout);
- X
- X exit(0);
- X}
- X
- Xgray
- XnewGrayValue(pixel * pixel, struct colorToGrayEntry * colorToGrayMap,
- X int colors)
- X{
- X int color;
- X /*
- X * Allowing this to be O(n), since the program is intended for small
- X * n. Later, perhaps sort by color (r, then g, then b) and bsearch.
- X */
- X for (color = 0; color < colors; color++) {
- X if (PPM_EQUAL(*pixel, colorToGrayMap[color].color))
- X return colorToGrayMap[color].gray;
- X }
- X pm_error("This should never happen - contact the maintainer");
- X}
- X
- Xint
- XcmpColorToGrayEntryByIntensity(entry1, entry2)
- X void *entry1, *entry2;
- X{
- X return ((struct colorToGrayEntry *) entry1)->gray -
- X ((struct colorToGrayEntry *) entry2)->gray;
- X}
- X
- Xint
- XcmpColorToGrayEntryByFrequency(entry1, entry2)
- X void *entry1, *entry2;
- X{
- X return ((struct colorToGrayEntry *) entry1)->frequency -
- X ((struct colorToGrayEntry *) entry2)->frequency;
- X}
- END_OF_FILE
- if test 5112 -ne `wc -c <'ppmdist.c'`; then
- echo shar: \"'ppmdist.c'\" unpacked with wrong size!
- fi
- # end of 'ppmdist.c'
- fi
- echo shar: End of shell archive.
- exit 0
-