home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2133 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  11.5 KB

  1. From: bert@let.rug.nl (Bert Bos)
  2. Newsgroups: alt.sources
  3. Subject: pgmcolor - convert portable gray map to false-color
  4. Message-ID: <1381@gufalet.let.rug.nl>
  5. Date: 21 Nov 90 19:16:58 GMT
  6.  
  7. I needed a utility to convert numbers to colors, but I couldn't find
  8. it among the PBM programs. Therefore I decided to make one myself.
  9.  
  10. pgmcolor reads a PGM file and outputs a PPM file, using the gray
  11. values as indices into a palette which is itself a PPM file. pgmcolor
  12. can be used to make false-color images. I use it to assign colors to
  13. level sets of Mandelbrot and Julia fractals. It is also possible to
  14. convert a gray image from a scanner to colors, if there where not too
  15. maany colors in the original.
  16.  
  17. A Makefile and a manual are included. You need to have the pbmplus
  18. package (specifically the libraries).
  19.  
  20. ----- CUT HERE -----------------------------------------------------------
  21. # This is a shell archive.  Remove anything before this line,
  22. # then unpack it by saving it in a file and typing "sh file".
  23. #
  24. # Wrapped by Bert Bos <bert@gufal03> on Tue Nov 20 19:41:08 1990
  25. #
  26. # This archive contains:
  27. #    README        pgmcolor.1    pgmcolor.c    Makefile    
  28. #
  29.  
  30. LANG=""; export LANG
  31. PATH=/bin:/usr/bin:$PATH; export PATH
  32.  
  33. echo x - README
  34. cat >README <<'@EOF'
  35. pgmcolor converts a portable gray map to a portable pixmap, using a
  36. palette (which is itself a PPM file). pgmcolor can be used to make
  37. false-color images. I use it to assign colors to level sets of
  38. Mandelbrot and Julia fractals. It is also possible to convert a gray
  39. image from a scanner to colors (but choosing convincing colors is not
  40. a sinecure).
  41.  
  42. A Makefile and a manual are included. You need to have the pbmplus
  43. package to compile this. The program is called with:
  44.  
  45.     pgmcolor [-v] [-a] palettefile [pgmfile]
  46.  
  47. Copyright by Bert Bos <bert@let.rug.nl>.
  48. @EOF
  49.  
  50. chmod 644 README
  51.  
  52. echo x - pgmcolor.1
  53. cat >pgmcolor.1 <<'@EOF'
  54. .TH pgmcolor 1 "20 November 1990"
  55. .SH NAME
  56. pgmcolor - create false color image from a portable graymap
  57. .SH SYNOPSIS
  58. pgmcolor [-v] [-a] palette [pgmfile]
  59. .SH DESCRIPTION
  60. Reads a portable graymap as input and a portable pixmap as palette.
  61. The different gray values are replaced by pixel values from the
  62. palette, from darkest to lightest.  Normally, the darkest gray is
  63. replaced by the first color in the palette file, the next gray by the
  64. next color, etc. If there are more pixel values than actual gray
  65. levels, the last pixels are discarded.  If there are insufficient
  66. pixel values, they are applied cyclicly.
  67.  
  68. The -a (absolute) option forces the first pixel to be assigned to gray
  69. level 0, the next to gray level 1, etc., regardless of the actual
  70. existence of that gray level in the input.
  71.  
  72. The -v (verbose) flag reports the number of gray levels and the number
  73. of pixel values in the input and the palette, respectively.
  74.  
  75. An example palette might look like this:
  76.  
  77. .nf
  78.     P3
  79.     # Palette for 16 yellowish colors
  80.     16 1
  81.     15
  82.     0 0 0    1 1 0    3 2 0    5 3 0    7 4 0
  83.     9 5 0    11 6 0   13 7 0   15 8 1   15 9 3
  84.     15 10 5  15 11 7  15 12 9  15 13 11 15 14 13
  85.     15 15 15
  86. .fi
  87.  
  88. You can use pgmhist(1) to see how many gray levels a PGM file has.
  89. .SH "SEE ALSO"
  90. pgmhist(1), pgm(5), ppm(5)
  91. .SH AUTHOR
  92. Copyright (C) 1990 by Bert Bos <bert@let.rug.nl>.
  93.  
  94. Permission to use, copy, modify, and distribute this software and its
  95. documentation for any purpose and without fee is hereby granted, provided
  96. that the above copyright notice appear in all copies and that both that
  97. copyright notice and this permission notice appear in supporting
  98. documentation.  This software is provided "as is" without express or
  99. implied warranty.
  100. @EOF
  101.  
  102. chmod 644 pgmcolor.1
  103.  
  104. echo x - pgmcolor.c
  105. cat >pgmcolor.c <<'@EOF'
  106. /* 
  107.   pgmcolor -- Make a false color image from a portable gray map
  108.   Copyright: Bert Bos <bert@let.rug.nl>
  109.   Date: 19 Nov 1990
  110.  
  111.   Usage: pgmcolor [-v] [-a] palette [pgmfile]
  112.  
  113. The palette file is a PPM file. It should contain a number of RGB
  114. values.  Pgmcolor assigns the first pixel's color to the darkest gray
  115. and the next pixels color to the next darkest gray. If there are more
  116. grays than pixels in the palette file, the colors will be applied
  117. cyclicly If there are more RGB values than gray values, the
  118. superfluous RGB colors will be ignored.
  119.  
  120. The -v option (verbose) will display some statistics on this.
  121.  
  122. If the -a option is specified, the colors in the palette will be
  123. assigned to graylevels 0, 1, 2, etc. regardless of the existence of
  124. this levels in the PGM file.
  125.  
  126. */
  127.  
  128. #include <stdio.h>
  129. #include <pgm.h>
  130. #include <ppm.h>
  131.  
  132. #define TRUE 1
  133. #define FALSE 0
  134. #define NULL 0
  135.  
  136. #define Bool int
  137.  
  138. static Bool verbose = FALSE;
  139. static Bool absolute = FALSE;
  140. static char *paletteName = (char *) NULL;
  141. static char *infileName = (char *) NULL;
  142. static char *progName = (char *) NULL;
  143.  
  144.  
  145. /* usage -- Print usage message and exit */
  146. void usage()
  147. {
  148.   fprintf(stderr, "Usage: %s [-v] [-a] palette [pgm-file]\n", progName);
  149.   exit(1);
  150. }
  151.  
  152.  
  153. /* arguments -- interpret command line arguments */
  154. void arguments(argc, argv)
  155.      int argc;
  156.      char **argv;
  157. {
  158.   char **p, *arg;
  159.   int i = 0;
  160.  
  161.   p = argv;
  162.   while (i < argc) {            /* Loop over arguments */
  163.     arg = *p;
  164.     if (*arg == '-') {            /* It's an option */
  165.       arg++;                /* Skip '-' */
  166.       while (*arg) {            /* Loop over all letters in option */
  167.     switch (*arg) {
  168.     case 'v':            /* -v verbose */
  169.       verbose = TRUE;
  170.       break;
  171.     case 'a':            /* -a absolute */
  172.       absolute = TRUE;
  173.       break;
  174.     default:
  175.       usage();            /* Unknown option */
  176.     }
  177.     arg++;                /* Next letter */
  178.       }
  179.     }
  180.     else if (! progName) {        /* It's the program's own name */
  181.       progName = arg;
  182.     }
  183.     else if (! paletteName) {        /* It's the palette's name */
  184.       paletteName = arg;
  185.     }
  186.     else if (! infileName) {        /* It's the input file's name */
  187.       infileName = arg;
  188.     }
  189.     else                /* Too many arguments */
  190.       usage();
  191.     p++;                /* Next argument */
  192.     i++;
  193.   }
  194.   if (! paletteName)            /* Too few arguments */
  195.     usage();
  196. }
  197.  
  198.  
  199. /* doAbsolute -- replace each gray level by corresponding pixel value */
  200. void doAbsolute(infile, palette)
  201.      FILE *infile, *palette;
  202. {
  203.   pixel **colors;            /* Holds palette */
  204.   int colsP, rowsP;            /* For palette file */
  205.   pixval maxvalP;            /* For palette file */
  206.   int colsG, rowsG, formatG;        /* For PGM file */
  207.   gray maxvalG;                /* For PGM file */
  208.   gray *grayrow;            /* Holds successive rows of pgm file */
  209.   pixel *newrow;            /* Holds successive rows of output */
  210.   int row, col;                /* Temporary variables */
  211.  
  212.   /* Read colors and header of pgm input file, then write output header */
  213.   colors = ppm_readppm(palette, &colsP, &rowsP, &maxvalP);
  214.   fclose(palette);
  215.   if (! colors) {
  216.     fprintf(stderr, "%s: out of memory\n", progName);
  217.     exit(-1);
  218.   }
  219.   pgm_readpgminit(infile, &colsG, &rowsG, &maxvalG, &formatG);
  220.   ppm_writeppminit(stdout, colsG, rowsG, maxvalP);
  221.  
  222.   if (verbose) {
  223.     fprintf(stderr, "%s is a %dx%d PGM file with %d gray levels.\n",
  224.         infileName?infileName:"standard input", colsG, rowsG, maxvalG);
  225.     fprintf(stderr, "%s defines %d colors", paletteName, colsP * rowsP);
  226.     if (maxvalG + 1 < colsP * rowsP)
  227.       fprintf(stderr, ", last %d will be ignored.\n", colsP*rowsP-maxvalG-1);
  228.     else if (maxvalG + 1 > colsP * rowsP)
  229.       fprintf(stderr, ", colors will be used cyclicly\n");
  230.     else
  231.       fprintf(stderr, " exactly\n");
  232.   }
  233.     
  234.   /* Loop over rows of PGM file */
  235.   newrow = ppm_allocrow(colsG);
  236.   for (row = 0; row < rowsG; row++) {
  237.     pgm_readpgmrow(infile, grayrow, colsG, maxvalG, formatG);
  238.     for (col = 0; col < colsG; col++)
  239.       newrow[col] = (*colors)[(int) grayrow[col] % (colsP * rowsP)];
  240.     ppm_writeppmrow(stdout, newrow, colsG, maxvalP);
  241.   }
  242.  
  243.   /* Close input */
  244.   fclose(infile);
  245. }
  246.  
  247.  
  248. /* doRelative -- replace only existing graylevels with pixel values */
  249. void doRelative(infile, palette)
  250.      FILE *infile, *palette;
  251. {
  252.   pixel **colors, *cmap;        /* Hold palette & color map */
  253.   int colsP, rowsP;            /* For palette file */
  254.   pixval maxvalP;            /* For palette file */
  255.   gray **graymap;            /* Holds PGM file */
  256.   int colsG, rowsG;            /* For PGM file */
  257.   gray maxvalG;                /* For PGM file */
  258.   pixel *newrow;            /* Holds successive rows of output */
  259.   int *hist, count;            /* Histogram */
  260.   int row, col, i, j;            /* Temporary variables */
  261.  
  262.   /* Read colors and gray map */
  263.   colors = ppm_readppm(palette, &colsP, &rowsP, &maxvalP);
  264.   fclose(palette);
  265.   graymap = pgm_readpgm(infile, &colsG, &rowsG, &maxvalG);
  266.   fclose(infile);
  267.   if (! colors || ! graymap) {
  268.     fprintf(stderr, "%s: out of memory\n", progName);
  269.     exit(-1);
  270.   }
  271.  
  272.   /* Build histogram of PGM file */
  273.   hist = (int *) malloc((maxvalG + 1)*sizeof(int));
  274.   cmap = ppm_allocrow(maxvalG);
  275.   newrow = ppm_allocrow(colsG);
  276.   if (! hist || ! cmap || ! newrow) {
  277.     fprintf(stderr, "%s: out of memory\n", progName);
  278.     exit(-1);
  279.   }
  280.   for (i = 0; i <= maxvalG; i++)
  281.     hist[i] = 0;
  282.   for (row = 0; row < rowsG; row++)
  283.     for (col = 0; col < colsG; col++)
  284.       hist[(int) graymap[row][col]]++;
  285.   
  286.   /* Now put a pixel value in cmap next to each nonzero hist[i] */
  287.   count = 0;
  288.   for (i = 0; i <= maxvalG; i++)
  289.     if (hist[i]) {
  290.       cmap[i] = (*colors)[count % (colsP * rowsP)];
  291.       count++;
  292.     }
  293.   
  294.   if (verbose) {
  295.     if (infileName)
  296.       fprintf(stderr, "%s is a %dx%d PGM file with %d gray levels out of %d\n",
  297.           infileName, colsG, rowsG, count, maxvalG);
  298.     else
  299.       fprintf(stderr, "standard input is a %dx%d PGM file with %d gray levels out of %d\n",
  300.           colsG, rowsG, count, maxvalG);
  301.     fprintf(stderr, "%s defines %d colors", paletteName, colsP * rowsP);
  302.     if (count < colsP * rowsP)
  303.       fprintf(stderr, "; last %d will be ignored.\n", colsP * rowsP - count);
  304.     else if (count > colsP * rowsP)
  305.       fprintf(stderr, "; colors will be used cyclicly\n");
  306.     else
  307.       fprintf(stderr, " exactly\n");
  308.   }
  309.  
  310.   /* Write out a PPM file of the same size as the PGM file */
  311.   ppm_writeppminit(stdout, colsG, rowsG, maxvalP);
  312.   for (row = 0; row < rowsG; row++) {
  313.     for (col = 0; col <colsG; col++)
  314.       newrow[col] = cmap[(int) graymap[row][col]];
  315.     ppm_writeppmrow(stdout, newrow, colsG, maxvalP);
  316.   }
  317. }
  318.  
  319.  
  320. /* main -- main routine of pgmcolor */
  321. int main(argc, argv)
  322. {
  323.   FILE *infile, *palette;
  324.  
  325.   /* get command line arguments */
  326.   arguments(argc, argv);
  327.  
  328.   /* Read palette and PGM input file */
  329.   if (!(palette = fopen(paletteName, "r"))) {
  330.     fprintf(stderr, "%s: cannot open %s\n", progName, paletteName);
  331.     return 1;
  332.   }
  333.   if (! infileName)
  334.     infile = stdin;
  335.   else if (!(infile = fopen(infileName, "r"))) {
  336.     fprintf(stderr, "%s: cannot open %s\n", progName, infileName);
  337.     return 1;
  338.   }
  339.  
  340.   /* Now call the appropriate routine */
  341.   if (absolute)
  342.     doAbsolute(infile, palette);
  343.   else
  344.     doRelative(infile, palette);
  345.  
  346.   /* Exit */
  347.   return 0;
  348. }
  349. @EOF
  350.  
  351. chmod 644 pgmcolor.c
  352.  
  353. echo x - Makefile
  354. cat >Makefile <<'@EOF'
  355. #  Makefile for pgmcolor
  356. #  Copyright Bert Bos, 1990
  357.  
  358. #  pgmcolor needs the three pbm libraries: libpbm, libpgm and libppm
  359. #  The following three macros comtain the directories where they can be found:
  360. PBMDIR=../pbm
  361. PGMDIR=../pgm
  362. PPMDIR=../ppm
  363.  
  364. #  The files pgm.h and ppm.h are also needed, if they are not in the same
  365. #  directories as their respective libraries, the following macro needs to
  366. #  be changed:
  367. INC=-I $(PPMDIR) -I $(PGMDIR) -I $(PBMDIR)
  368.  
  369. #  Choose your compiler and compiler flags:
  370. CC=gcc
  371. CFLAGS=-O $(INC)
  372.  
  373. LDFLAGS=-L $(PPMDIR) -L $(PGMDIR) -L $(PBMDIR) -lppm -lpgm -lpbm
  374.  
  375. # The single rule to make pgmcolor:
  376.  
  377. pgmcolor:
  378. @EOF
  379.  
  380. chmod 644 Makefile
  381.  
  382. exit 0
  383. ----- CUT HERE -----------------------------------------------------------
  384. -- 
  385.   "Always remember, however, that there's     Bert Bos (bert@let.rug.nl)
  386.    usually a simpler and better way to do     Alfa-informatica
  387.    something than the first way that pops     RijksUniversiteit Groningen
  388.    into your head." (D.E. Knuth, TeXbook)     Groningen, The Netherlands
  389.