home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / sources / 3100 < prev    next >
Encoding:
Text File  |  1993-01-28  |  11.2 KB  |  348 lines

  1. Newsgroups: alt.sources
  2. 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
  3. From: strombrg@uceng.uc.edu (Dan Stromberg)
  4. Subject: ppmdist - for computer generated color images on mono devices
  5. Message-ID: <C1HBz0.AKA@uceng.uc.edu>
  6. Organization: University of Cincinnati
  7. Date: Tue, 26 Jan 1993 21:06:36 GMT
  8. Lines: 338
  9.  
  10. This is ppmdist, something I wrote in response to a user's frustration
  11. with repeatedly using xv's palette editor, to get colors mapped into
  12. something that would show up distinctly on a B/W printer.  The man
  13. page gives more information.
  14.  
  15. You'll want pbmplus and ANSI C (or an ANSI->K&R filter) to compile.
  16.  
  17. If there's something already out there that does this, I imagine
  18. people will let me know about it.  :)  Here goes...
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  Makefile ppmcmap.h ppmdist.1 ppmdist.c
  28. # Wrapped by strombrg@cicada.occ.uc.edu on Tue Jan 26 15:53:11 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'Makefile'\"
  32. else
  33. echo shar: Extracting \"'Makefile'\" \(172 characters\)
  34. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  35. XCFLAGS=-O6 -s
  36. X
  37. Xppmdist: ppmdist.o
  38. X    gcc.rt $(CFLAGS) -o ppmdist ppmdist.o -lppm -lpgm -lpbm
  39. X
  40. Xppmdist.o: ppmdist.c
  41. X    gcc.rt -c $(CFLAGS) ppmdist.c 
  42. X
  43. Xclean:
  44. X    rm -f ppmdist *.o
  45. END_OF_FILE
  46. if test 172 -ne `wc -c <'Makefile'`; then
  47.     echo shar: \"'Makefile'\" unpacked with wrong size!
  48. fi
  49. # end of 'Makefile'
  50. fi
  51. if test -f 'ppmcmap.h' -a "${1}" != "-c" ; then 
  52.   echo shar: Will not clobber existing file \"'ppmcmap.h'\"
  53. else
  54. echo shar: Extracting \"'ppmcmap.h'\" \(1375 characters\)
  55. sed "s/^X//" >'ppmcmap.h' <<'END_OF_FILE'
  56. X/* ppmcmap.h - header file for colormap routines in libppm
  57. X*/
  58. X
  59. X/* Color histogram stuff. */
  60. X
  61. Xtypedef struct colorhist_item* colorhist_vector;
  62. Xstruct colorhist_item
  63. X    {
  64. X    pixel color;
  65. X    int value;
  66. X    };
  67. X
  68. Xtypedef struct colorhist_list_item* colorhist_list;
  69. Xstruct colorhist_list_item
  70. X    {
  71. X    struct colorhist_item ch;
  72. X    colorhist_list next;
  73. X    };
  74. X
  75. Xcolorhist_vector ppm_computecolorhist ARGS(( pixel** pixels, int cols, int rows, int maxcolors, int* colorsP ));
  76. X/* Returns a colorhist *colorsP long (with space allocated for maxcolors. */
  77. X
  78. Xvoid ppm_addtocolorhist ARGS(( colorhist_vector chv, int* colorsP, int maxcolors, pixel* colorP, int value, int position ));
  79. X
  80. Xvoid ppm_freecolorhist ARGS(( colorhist_vector chv ));
  81. X
  82. X
  83. X/* Color hash table stuff. */
  84. X
  85. Xtypedef colorhist_list* colorhash_table;
  86. X
  87. Xcolorhash_table ppm_computecolorhash ARGS(( pixel** pixels, int cols, int rows, int maxcolors, int* colorsP ));
  88. X
  89. Xint
  90. Xppm_lookupcolor ARGS(( colorhash_table cht, pixel* colorP ));
  91. X
  92. Xcolorhist_vector ppm_colorhashtocolorhist ARGS(( colorhash_table cht, int maxcolors ));
  93. Xcolorhash_table ppm_colorhisttocolorhash ARGS(( colorhist_vector chv, int colors ));
  94. X
  95. Xint ppm_addtocolorhash ARGS(( colorhash_table cht, pixel* colorP, int value ));
  96. X/* Returns -1 on failure. */
  97. X
  98. Xcolorhash_table ppm_alloccolorhash ARGS(( void ));
  99. X
  100. Xvoid ppm_freecolorhash ARGS(( colorhash_table cht ));
  101. END_OF_FILE
  102. if test 1375 -ne `wc -c <'ppmcmap.h'`; then
  103.     echo shar: \"'ppmcmap.h'\" unpacked with wrong size!
  104. fi
  105. # end of 'ppmcmap.h'
  106. fi
  107. if test -f 'ppmdist.1' -a "${1}" != "-c" ; then 
  108.   echo shar: Will not clobber existing file \"'ppmdist.1'\"
  109. else
  110. echo shar: Extracting \"'ppmdist.1'\" \(1722 characters\)
  111. sed "s/^X//" >'ppmdist.1' <<'END_OF_FILE'
  112. X.TH ppmdist 1 "22 July 1992"
  113. X.IX ppmdist
  114. X.SH NAME
  115. Xppmdist - simplistic grayscale assignment for machine generated, color images
  116. X.SH SYNOPSIS
  117. X.B ppmdist
  118. X.RB [ -intensity | -frequency ]
  119. X.RI [ ppmfile ]
  120. X.SH DESCRIPTION
  121. XReads a portable pixmap as input, performs a simplistic grayscale
  122. Xassignment intended for use with grayscale or bitmap printers.
  123. X
  124. XOften conversion from ppm to pgm will yield an image with contrast too
  125. Xlow for good printer output.  The program maximizes contrast between
  126. Xthe gray levels output.
  127. X
  128. XA ppm input of n colors is read, and a pgm of n gray levels is written.
  129. XThe gray levels take on the values 0..n-1, while maxval takes on n-1.
  130. X
  131. XThe mapping from color to stepped grayscale can be performed in order
  132. Xof input pixel intensity, or input pixel frequency (number of repetitions).
  133. X.SH OPTIONS
  134. X.TP 14
  135. X.TP 14
  136. X.BI -frequency
  137. XSort input colors by the number of times a color appears in the input,
  138. Xbefore mapping to evenly distributed graylevels of output.
  139. X.BI -intensity
  140. XSort input colors by their grayscale intensity, before mapping to evenly
  141. Xdistributed graylevels of output.  This is the default.
  142. X.SH BUGS
  143. XHelpful only for images with a very small number of colors.
  144. XPerhaps should have been an option to ppmtopgm(1).
  145. X.SH "SEE ALSO"
  146. Xppmtopgm(1), ppmhist(1), ppm(5)
  147. X.SH AUTHOR
  148. XCopyright (C) 1993 by Dan Stromberg.
  149. X.\" Permission to use, copy, modify, and distribute this software and its
  150. X.\" documentation for any purpose and without fee is hereby granted, provided
  151. X.\" that the above copyright notice appear in all copies and that both that
  152. X.\" copyright notice and this permission notice appear in supporting
  153. X.\" documentation.  This software is provided "as is" without express or
  154. X.\" implied warranty.
  155. END_OF_FILE
  156. if test 1722 -ne `wc -c <'ppmdist.1'`; then
  157.     echo shar: \"'ppmdist.1'\" unpacked with wrong size!
  158. fi
  159. # end of 'ppmdist.1'
  160. fi
  161. if test -f 'ppmdist.c' -a "${1}" != "-c" ; then 
  162.   echo shar: Will not clobber existing file \"'ppmdist.c'\"
  163. else
  164. echo shar: Extracting \"'ppmdist.c'\" \(5112 characters\)
  165. sed "s/^X//" >'ppmdist.c' <<'END_OF_FILE'
  166. X#include <pnm.h>
  167. X#include <pgm.h>
  168. X#include "ppmcmap.h"
  169. X
  170. X/*
  171. X * Yep, this is ANSI C alright... It was developed on something that doesn't
  172. X * do K&R very well.
  173. X */
  174. X
  175. X/*
  176. X * Yep, it's a very simple algorithm, but it was something I wanted to have
  177. X * available.
  178. X */
  179. X
  180. Xstruct colorToGrayEntry {
  181. X    pixel           color;
  182. X    gray            gray;
  183. X    int             frequency;
  184. X};
  185. X
  186. X/*
  187. X * BUG: This number was chosen pretty arbitrarily.  The program is * probably
  188. X * only useful for a very small numbers of colors - and that's * not only
  189. X * because of the O(n) search that's used.  The idea lends * itself primarily
  190. X * to low color (read: simple, machine generated) images.
  191. X */
  192. X#define MAXCOLORS 255
  193. X
  194. Xvoid            main(int argc, char *argv[]);
  195. Xgray            newGrayValue(pixel * pixel, struct colorToGrayEntry * colorToGrayMap, int colors);
  196. Xint             cmpColorToGrayEntryByIntensity(void *entry1, void *entry2);
  197. Xint             cmpColorToGrayEntryByFrequency(void *entry1, void *entry2);
  198. X
  199. Xvoid
  200. Xmain(int argc, char *argv[])
  201. X{
  202. X    FILE           *ifp;
  203. X    int             col, cols, row, rows, color, colors, argn;
  204. X    int             frequency;
  205. X    pixval          maxval;
  206. X    pixel         **pixels;
  207. X    pixel          *pP;
  208. X    colorhist_vector hist;
  209. X    gray           *grayrow;
  210. X    gray           *gP;
  211. X    struct colorToGrayEntry *colorToGrayMap;
  212. X
  213. X    ppm_init(&argc, argv);
  214. X
  215. X    argn = 1;
  216. X    /* Default is to sort colors by intensity */
  217. X    frequency = 0;
  218. X
  219. X    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  220. X        if (pm_keymatch(argv[argn], "-frequency", 2))
  221. X            frequency = 1;
  222. X        else if (pm_keymatch(argv[argn], "-intensity", 2))
  223. X            frequency = 0;
  224. X        else
  225. X            pm_usage( "[-frequency|-intensity] [ppmfile]" );
  226. X        ++argn;
  227. X    }
  228. X
  229. X    if (argn < argc) {
  230. X        ifp = pm_openr(argv[argn]);
  231. X        ++argn;
  232. X    } else
  233. X        ifp = stdin;
  234. X
  235. X    pixels = ppm_readppm(ifp, &cols, &rows, &maxval);
  236. X    pm_close(ifp);
  237. X    /* all done with the input file - it's entirely in memory */
  238. X
  239. X    /*
  240. X     * Compute a histogram of the colors in the input.  This is good for
  241. X     * both frequency, and indirectly the intensity, of a color.
  242. X     */
  243. X    hist = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
  244. X
  245. X    if (hist == (colorhist_vector) 0)
  246. X        /*
  247. X         * BUG: This perhaps should use an exponential backoff, in
  248. X         * the number of colors, until success - cf ppmquant's
  249. X         * approach.  The results are then more what's expected, but
  250. X         * not necessarily very useful.
  251. X         */
  252. X        pm_error("Too many colors - Try reducing with ppmquant");
  253. X
  254. X    /* copy the colors into another structure for sorting */
  255. X    colorToGrayMap = (struct colorToGrayEntry *)
  256. X        malloc(sizeof(struct colorToGrayEntry) * colors);
  257. X    for (color = 0; color < colors; color++) {
  258. X        colorToGrayMap[color].color = hist[color].color;
  259. X        colorToGrayMap[color].frequency = hist[color].value;
  260. X        /*
  261. X         * This next is derivable, of course, but it's far faster to
  262. X         * store it precomputed.  This can be skipped, when sorting
  263. X         * by frequency - but again, for a small number of colors
  264. X         * it's a small matter.
  265. X         */
  266. X        colorToGrayMap[color].gray = PPM_LUMIN(hist[color].color);
  267. X    }
  268. X
  269. X    /*
  270. X     * sort by intensity - sorting by frequency (in the histogram) is
  271. X     * worth considering as a future addition.
  272. X     */
  273. X    if (frequency)
  274. X        qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
  275. X                cmpColorToGrayEntryByFrequency);
  276. X    else
  277. X        qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
  278. X                cmpColorToGrayEntryByIntensity);
  279. X
  280. X    /*
  281. X     * create mapping between the n colors in input, to n evenly spaced
  282. X     * grey-scale intensities.  This is done by overwriting the neatly
  283. X     * formed gray values corresponding to the input-colors, with a new
  284. X     * set of evenly spaced gray values.  Since maxval can be changed on
  285. X     * a lark, we just use gray levels 0..colors-1, and adjust maxval
  286. X     * accordingly
  287. X     */
  288. X    maxval = colors - 1;
  289. X    for (color = 0; color < colors; color++)
  290. X        colorToGrayMap[color].gray = color;
  291. X
  292. X    /* write pgm file, mapping colors to intensities */
  293. X    pgm_writepgminit(stdout, cols, rows, maxval, 0);
  294. X
  295. X    grayrow = pgm_allocrow(cols);
  296. X
  297. X    for (row = 0; row < rows; row++) {
  298. X        for (col = 0, pP = pixels[row], gP = grayrow; col < cols;
  299. X             col++, pP++, gP++)
  300. X            *gP = newGrayValue(pP, colorToGrayMap, colors);
  301. X        pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
  302. X    }
  303. X
  304. X    pm_close(stdout);
  305. X
  306. X    exit(0);
  307. X}
  308. X
  309. Xgray
  310. XnewGrayValue(pixel * pixel, struct colorToGrayEntry * colorToGrayMap,
  311. X         int colors)
  312. X{
  313. X    int             color;
  314. X    /*
  315. X     * Allowing this to be O(n), since the program is intended for small
  316. X     * n.  Later, perhaps sort by color (r, then g, then b) and bsearch.
  317. X     */
  318. X    for (color = 0; color < colors; color++) {
  319. X        if (PPM_EQUAL(*pixel, colorToGrayMap[color].color))
  320. X            return colorToGrayMap[color].gray;
  321. X    }
  322. X    pm_error("This should never happen - contact the maintainer");
  323. X}
  324. X
  325. Xint
  326. XcmpColorToGrayEntryByIntensity(entry1, entry2)
  327. X    void           *entry1, *entry2;
  328. X{
  329. X    return ((struct colorToGrayEntry *) entry1)->gray -
  330. X        ((struct colorToGrayEntry *) entry2)->gray;
  331. X}
  332. X
  333. Xint
  334. XcmpColorToGrayEntryByFrequency(entry1, entry2)
  335. X    void           *entry1, *entry2;
  336. X{
  337. X    return ((struct colorToGrayEntry *) entry1)->frequency -
  338. X        ((struct colorToGrayEntry *) entry2)->frequency;
  339. X}
  340. END_OF_FILE
  341. if test 5112 -ne `wc -c <'ppmdist.c'`; then
  342.     echo shar: \"'ppmdist.c'\" unpacked with wrong size!
  343. fi
  344. # end of 'ppmdist.c'
  345. fi
  346. echo shar: End of shell archive.
  347. exit 0
  348.