home *** CD-ROM | disk | FTP | other *** search
- From: bert@let.rug.nl (Bert Bos)
- Newsgroups: alt.sources
- Subject: pgmcolor - convert portable gray map to false-color
- Message-ID: <1381@gufalet.let.rug.nl>
- Date: 21 Nov 90 19:16:58 GMT
-
- I needed a utility to convert numbers to colors, but I couldn't find
- it among the PBM programs. Therefore I decided to make one myself.
-
- pgmcolor reads a PGM file and outputs a PPM file, using the gray
- values as indices into a palette which is itself a PPM file. pgmcolor
- can be used to make false-color images. I use it to assign colors to
- level sets of Mandelbrot and Julia fractals. It is also possible to
- convert a gray image from a scanner to colors, if there where not too
- maany colors in the original.
-
- A Makefile and a manual are included. You need to have the pbmplus
- package (specifically the libraries).
-
- ----- CUT HERE -----------------------------------------------------------
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- #
- # Wrapped by Bert Bos <bert@gufal03> on Tue Nov 20 19:41:08 1990
- #
- # This archive contains:
- # README pgmcolor.1 pgmcolor.c Makefile
- #
-
- LANG=""; export LANG
- PATH=/bin:/usr/bin:$PATH; export PATH
-
- echo x - README
- cat >README <<'@EOF'
- pgmcolor converts a portable gray map to a portable pixmap, using a
- palette (which is itself a PPM file). pgmcolor can be used to make
- false-color images. I use it to assign colors to level sets of
- Mandelbrot and Julia fractals. It is also possible to convert a gray
- image from a scanner to colors (but choosing convincing colors is not
- a sinecure).
-
- A Makefile and a manual are included. You need to have the pbmplus
- package to compile this. The program is called with:
-
- pgmcolor [-v] [-a] palettefile [pgmfile]
-
- Copyright by Bert Bos <bert@let.rug.nl>.
- @EOF
-
- chmod 644 README
-
- echo x - pgmcolor.1
- cat >pgmcolor.1 <<'@EOF'
- .TH pgmcolor 1 "20 November 1990"
- .SH NAME
- pgmcolor - create false color image from a portable graymap
- .SH SYNOPSIS
- pgmcolor [-v] [-a] palette [pgmfile]
- .SH DESCRIPTION
- Reads a portable graymap as input and a portable pixmap as palette.
- The different gray values are replaced by pixel values from the
- palette, from darkest to lightest. Normally, the darkest gray is
- replaced by the first color in the palette file, the next gray by the
- next color, etc. If there are more pixel values than actual gray
- levels, the last pixels are discarded. If there are insufficient
- pixel values, they are applied cyclicly.
-
- The -a (absolute) option forces the first pixel to be assigned to gray
- level 0, the next to gray level 1, etc., regardless of the actual
- existence of that gray level in the input.
-
- The -v (verbose) flag reports the number of gray levels and the number
- of pixel values in the input and the palette, respectively.
-
- An example palette might look like this:
-
- .nf
- P3
- # Palette for 16 yellowish colors
- 16 1
- 15
- 0 0 0 1 1 0 3 2 0 5 3 0 7 4 0
- 9 5 0 11 6 0 13 7 0 15 8 1 15 9 3
- 15 10 5 15 11 7 15 12 9 15 13 11 15 14 13
- 15 15 15
- .fi
-
- You can use pgmhist(1) to see how many gray levels a PGM file has.
- .SH "SEE ALSO"
- pgmhist(1), pgm(5), ppm(5)
- .SH AUTHOR
- Copyright (C) 1990 by Bert Bos <bert@let.rug.nl>.
-
- 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.
- @EOF
-
- chmod 644 pgmcolor.1
-
- echo x - pgmcolor.c
- cat >pgmcolor.c <<'@EOF'
- /*
- pgmcolor -- Make a false color image from a portable gray map
- Copyright: Bert Bos <bert@let.rug.nl>
- Date: 19 Nov 1990
-
- Usage: pgmcolor [-v] [-a] palette [pgmfile]
-
- The palette file is a PPM file. It should contain a number of RGB
- values. Pgmcolor assigns the first pixel's color to the darkest gray
- and the next pixels color to the next darkest gray. If there are more
- grays than pixels in the palette file, the colors will be applied
- cyclicly If there are more RGB values than gray values, the
- superfluous RGB colors will be ignored.
-
- The -v option (verbose) will display some statistics on this.
-
- If the -a option is specified, the colors in the palette will be
- assigned to graylevels 0, 1, 2, etc. regardless of the existence of
- this levels in the PGM file.
-
- */
-
- #include <stdio.h>
- #include <pgm.h>
- #include <ppm.h>
-
- #define TRUE 1
- #define FALSE 0
- #define NULL 0
-
- #define Bool int
-
- static Bool verbose = FALSE;
- static Bool absolute = FALSE;
- static char *paletteName = (char *) NULL;
- static char *infileName = (char *) NULL;
- static char *progName = (char *) NULL;
-
-
- /* usage -- Print usage message and exit */
- void usage()
- {
- fprintf(stderr, "Usage: %s [-v] [-a] palette [pgm-file]\n", progName);
- exit(1);
- }
-
-
- /* arguments -- interpret command line arguments */
- void arguments(argc, argv)
- int argc;
- char **argv;
- {
- char **p, *arg;
- int i = 0;
-
- p = argv;
- while (i < argc) { /* Loop over arguments */
- arg = *p;
- if (*arg == '-') { /* It's an option */
- arg++; /* Skip '-' */
- while (*arg) { /* Loop over all letters in option */
- switch (*arg) {
- case 'v': /* -v verbose */
- verbose = TRUE;
- break;
- case 'a': /* -a absolute */
- absolute = TRUE;
- break;
- default:
- usage(); /* Unknown option */
- }
- arg++; /* Next letter */
- }
- }
- else if (! progName) { /* It's the program's own name */
- progName = arg;
- }
- else if (! paletteName) { /* It's the palette's name */
- paletteName = arg;
- }
- else if (! infileName) { /* It's the input file's name */
- infileName = arg;
- }
- else /* Too many arguments */
- usage();
- p++; /* Next argument */
- i++;
- }
- if (! paletteName) /* Too few arguments */
- usage();
- }
-
-
- /* doAbsolute -- replace each gray level by corresponding pixel value */
- void doAbsolute(infile, palette)
- FILE *infile, *palette;
- {
- pixel **colors; /* Holds palette */
- int colsP, rowsP; /* For palette file */
- pixval maxvalP; /* For palette file */
- int colsG, rowsG, formatG; /* For PGM file */
- gray maxvalG; /* For PGM file */
- gray *grayrow; /* Holds successive rows of pgm file */
- pixel *newrow; /* Holds successive rows of output */
- int row, col; /* Temporary variables */
-
- /* Read colors and header of pgm input file, then write output header */
- colors = ppm_readppm(palette, &colsP, &rowsP, &maxvalP);
- fclose(palette);
- if (! colors) {
- fprintf(stderr, "%s: out of memory\n", progName);
- exit(-1);
- }
- pgm_readpgminit(infile, &colsG, &rowsG, &maxvalG, &formatG);
- ppm_writeppminit(stdout, colsG, rowsG, maxvalP);
-
- if (verbose) {
- fprintf(stderr, "%s is a %dx%d PGM file with %d gray levels.\n",
- infileName?infileName:"standard input", colsG, rowsG, maxvalG);
- fprintf(stderr, "%s defines %d colors", paletteName, colsP * rowsP);
- if (maxvalG + 1 < colsP * rowsP)
- fprintf(stderr, ", last %d will be ignored.\n", colsP*rowsP-maxvalG-1);
- else if (maxvalG + 1 > colsP * rowsP)
- fprintf(stderr, ", colors will be used cyclicly\n");
- else
- fprintf(stderr, " exactly\n");
- }
-
- /* Loop over rows of PGM file */
- newrow = ppm_allocrow(colsG);
- for (row = 0; row < rowsG; row++) {
- pgm_readpgmrow(infile, grayrow, colsG, maxvalG, formatG);
- for (col = 0; col < colsG; col++)
- newrow[col] = (*colors)[(int) grayrow[col] % (colsP * rowsP)];
- ppm_writeppmrow(stdout, newrow, colsG, maxvalP);
- }
-
- /* Close input */
- fclose(infile);
- }
-
-
- /* doRelative -- replace only existing graylevels with pixel values */
- void doRelative(infile, palette)
- FILE *infile, *palette;
- {
- pixel **colors, *cmap; /* Hold palette & color map */
- int colsP, rowsP; /* For palette file */
- pixval maxvalP; /* For palette file */
- gray **graymap; /* Holds PGM file */
- int colsG, rowsG; /* For PGM file */
- gray maxvalG; /* For PGM file */
- pixel *newrow; /* Holds successive rows of output */
- int *hist, count; /* Histogram */
- int row, col, i, j; /* Temporary variables */
-
- /* Read colors and gray map */
- colors = ppm_readppm(palette, &colsP, &rowsP, &maxvalP);
- fclose(palette);
- graymap = pgm_readpgm(infile, &colsG, &rowsG, &maxvalG);
- fclose(infile);
- if (! colors || ! graymap) {
- fprintf(stderr, "%s: out of memory\n", progName);
- exit(-1);
- }
-
- /* Build histogram of PGM file */
- hist = (int *) malloc((maxvalG + 1)*sizeof(int));
- cmap = ppm_allocrow(maxvalG);
- newrow = ppm_allocrow(colsG);
- if (! hist || ! cmap || ! newrow) {
- fprintf(stderr, "%s: out of memory\n", progName);
- exit(-1);
- }
- for (i = 0; i <= maxvalG; i++)
- hist[i] = 0;
- for (row = 0; row < rowsG; row++)
- for (col = 0; col < colsG; col++)
- hist[(int) graymap[row][col]]++;
-
- /* Now put a pixel value in cmap next to each nonzero hist[i] */
- count = 0;
- for (i = 0; i <= maxvalG; i++)
- if (hist[i]) {
- cmap[i] = (*colors)[count % (colsP * rowsP)];
- count++;
- }
-
- if (verbose) {
- if (infileName)
- fprintf(stderr, "%s is a %dx%d PGM file with %d gray levels out of %d\n",
- infileName, colsG, rowsG, count, maxvalG);
- else
- fprintf(stderr, "standard input is a %dx%d PGM file with %d gray levels out of %d\n",
- colsG, rowsG, count, maxvalG);
- fprintf(stderr, "%s defines %d colors", paletteName, colsP * rowsP);
- if (count < colsP * rowsP)
- fprintf(stderr, "; last %d will be ignored.\n", colsP * rowsP - count);
- else if (count > colsP * rowsP)
- fprintf(stderr, "; colors will be used cyclicly\n");
- else
- fprintf(stderr, " exactly\n");
- }
-
- /* Write out a PPM file of the same size as the PGM file */
- ppm_writeppminit(stdout, colsG, rowsG, maxvalP);
- for (row = 0; row < rowsG; row++) {
- for (col = 0; col <colsG; col++)
- newrow[col] = cmap[(int) graymap[row][col]];
- ppm_writeppmrow(stdout, newrow, colsG, maxvalP);
- }
- }
-
-
- /* main -- main routine of pgmcolor */
- int main(argc, argv)
- {
- FILE *infile, *palette;
-
- /* get command line arguments */
- arguments(argc, argv);
-
- /* Read palette and PGM input file */
- if (!(palette = fopen(paletteName, "r"))) {
- fprintf(stderr, "%s: cannot open %s\n", progName, paletteName);
- return 1;
- }
- if (! infileName)
- infile = stdin;
- else if (!(infile = fopen(infileName, "r"))) {
- fprintf(stderr, "%s: cannot open %s\n", progName, infileName);
- return 1;
- }
-
- /* Now call the appropriate routine */
- if (absolute)
- doAbsolute(infile, palette);
- else
- doRelative(infile, palette);
-
- /* Exit */
- return 0;
- }
- @EOF
-
- chmod 644 pgmcolor.c
-
- echo x - Makefile
- cat >Makefile <<'@EOF'
- # Makefile for pgmcolor
- # Copyright Bert Bos, 1990
-
- # pgmcolor needs the three pbm libraries: libpbm, libpgm and libppm
- # The following three macros comtain the directories where they can be found:
- PBMDIR=../pbm
- PGMDIR=../pgm
- PPMDIR=../ppm
-
- # The files pgm.h and ppm.h are also needed, if they are not in the same
- # directories as their respective libraries, the following macro needs to
- # be changed:
- INC=-I $(PPMDIR) -I $(PGMDIR) -I $(PBMDIR)
-
- # Choose your compiler and compiler flags:
- CC=gcc
- CFLAGS=-O $(INC)
-
- LDFLAGS=-L $(PPMDIR) -L $(PGMDIR) -L $(PBMDIR) -lppm -lpgm -lpbm
-
- # The single rule to make pgmcolor:
-
- pgmcolor:
- @EOF
-
- chmod 644 Makefile
-
- exit 0
- ----- CUT HERE -----------------------------------------------------------
- --
- "Always remember, however, that there's Bert Bos (bert@let.rug.nl)
- usually a simpler and better way to do Alfa-informatica
- something than the first way that pops RijksUniversiteit Groningen
- into your head." (D.E. Knuth, TeXbook) Groningen, The Netherlands
-