This is rleldmap.c in view mode; [Download] [Up]
/* * 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. */ /* * rleldmap.c - Load a color map into an RLE file. * * Author: Spencer W. Thomas * Computer Science Dept. * University of Utah * Date: Thu Jul 10 1986 * Copyright (c) 1986, Spencer W. Thomas */ #include <stdio.h> #include <math.h> #include <rle.h> #ifdef USE_STDLIB_H #include <stdlib.h> #else #ifdef VOID_STAR extern void *malloc(); #else extern char *malloc(); #endif extern void free(); #endif /* USE_STDLIB_H */ /* Check for negative left shift problem (on 68000, at least) */ #if 2 << -1 == 0 #define NO_NEGATIVE_SHIFT #endif void get_rle_map(), linmap(), gammap(), filemap(), mfilemap(); void applymap(), shiftmap(); /***************************************************************** * TAG( main ) * * Usage: * rleldmap [-ab] [-n nchan length] [-s bits] [-l [factor]] [-g gamma] * [-{tf} file] [-m files ...] [-r rlefile] * [-o outputfile] [inputfile] * Terminology: * input map: A color map already in the input RLE file. * applied map: The color map specified by the arguments that will * be applied (loaded) to the input map, producing * the output map. * output map: Unless -a or -b is specified, this is equal to the * applied map. * map composition:The output map is applied_map[input_map] if -a * (after) is specified, or input_map[applied_map] * if -b (before). The maps being composed must either * have the same number of channels, or one of them must * have only one channel. If an entry in the map being * used as a subscript is larger than the length of the * map being subscripted, it remains unchanged. The * output map will be the same length as the subscript * map and will have the number of channels that is the * larger of the two. If the input map is used * as a subscript, it will be downshifted the correct * number of bits to serve as a subscript for the applied * map. This also applies to the applied map if it is * taken from an RLE file (-r option below). * nchan: Number of separate lookup tables (channels) making up * the color map. Default 3 (one for red, one for * green, and one for blue). * length: Number of entries in each channel of the map. Default * is 256 (8 bits). * bits: Size of each color map entry in bits. Default * log2 length. * range: Maximum value of a color map entry, equal to * 2^bits - 1. * Inputs: * -ab: Compose the applied map with the input map. * If the input file has no map, this flag has no effect. * * -n nchan length Gives the size of the applied map if it is not 3x256. * length should be a power of two and will be rounded * up if necessary. If applying the map, nchan must be * either 1 or equal to the number of channels in the * input map. * * -s bits Gives the size in bits of each color map entry. * * Note: exactly one of -l, -g, -t, -f, -F, or -r must be specified. * * -l factor Generate a linear applied map with entries equal to * range * max(1.0, factor*(n/(length-1))). Factor * defaults to 1.0. * * -g gamma Generate an applied map with the given gamma. The * nth entry (out of length) is * range * (n/(length-1))^gamma * * -t file Read color map entries from a file (t for table). * The values for each channel of a particular entry * follow each other in the file. (Thus, for an RGB * color map, the file would look like: * red0 green0 blue0 * red1 green1 blue1 * ... ... ... * Line breaks in the input file are irrelevant. * * -f file Reads the applied map from a file, with all the * entries for each channel following each other. Thus, * the input file would appear as * red0 red1 red2 ... * green0 green1 green2 ... * blue0 blue1 blue2 ... * As above, line breaks are irrelevant. * * -m files ... Read the color map for each channel from a separate * file. The number of files specified must equal the * number of channels in the applied map. [Note: the * list of files must be followed by another flag or * by the null flag -- to separate it from the inputfile. * * -r rlefile Read the color map from another RLE file. In this * case, the nchan, length and bits arguments will be * ignored. * * inputfile The input RLE file. Defaults to stdin. * Outputs: * -o outputfile The output RLE file. Defaults to stdout. * Assumptions: * As stated above. * Algorithm: * Compute the desired map, and either replace the input map with it * or compose the maps as specified above. Copy the image data from * the input file to the output file. If stdin is empty (no input at * all, an output RLE file with just a color map will be generated). */ void main( argc, argv ) int argc; char **argv; { int apply = 0, nflag = 0, nchan = 3, length = 256, range, lbits, sflag = 0, bits = 8, lflag = 0, gflag = 0, tflag = 0, mflag = 0, rflag = 0, oflag = 0, nmfiles = 0; int ochan, olength, olbits; /* output map parameters */ double factor = 1.0, gamma = 1.0; char * mapfname = NULL, ** mfnames = NULL, * rlefname = NULL, * outputfname = NULL, * inputfname = NULL; FILE *outfile = stdout; rle_map ** imap = NULL, ** omap, ** amap, ** allocmap(); rle_hdr in_hdr, out_hdr, rle_f_hdr; int rle_cnt, rle_err; if ( scanargs( argc, argv, "% ab%- n%-nchan!dlength!d s%-bits!d l%-factor%F g%-gamma!F \n\ \ttf%-file!s m%-files!*s r%-rlefile!s o%-outputfile!s inputfile%s", &apply, &nflag, &nchan, &length, &sflag, &bits, &lflag, &factor, &gflag, &gamma, &tflag, &mapfname, &mflag, &nmfiles, &mfnames, &rflag, &rlefname, &oflag, &outputfname, &inputfname ) == 0 ) exit( 1 ); /* bad arguments */ /* Check for exclusive flag use */ if ( (lflag != 0) + (gflag != 0) + (tflag != 0) + (mflag != 0) + (rflag != 0) != 1 ) { fprintf(stderr, "%s: Must specify exactly one of -l -g -t -f -m -r\n", cmd_name( argv ) ); exit(-1); } /* Compute color map parameters */ if ( rflag ) /* from RLE file? */ { if ( lflag ) fprintf(stderr, "%s: Nchan, length and bits ignored, values from rle file used\n", cmd_name( argv )); get_rle_map( &rle_f_hdr, rlefname ); lbits = rle_f_hdr.cmaplen; length = 1 << lbits; nchan = rle_f_hdr.ncmap; bits = 16; /* Just use the rle map */ amap = allocmap( length, nchan, rle_f_hdr.cmap ); } else { for ( lbits = 0; length > 1<<lbits; lbits++ ) ; /* Get log2 of length */ if ( length != 1 << lbits ) { fprintf( stderr, "%s: Length (%d) rounded up to power of 2 (%d)\n", cmd_name( argv ), length, 1 << lbits ); length = 1 << lbits; /* round length to power of 2 */ } /* Allocate space for the applied map */ amap = allocmap( nchan, length, NULL ); } range = (1 << bits) - 1; /* Compute the requested map */ if ( lflag ) linmap( factor, nchan, length, range, amap ); if ( gflag ) gammap( gamma, nchan, length, range, amap ); if ( tflag ) filemap( tflag, mapfname, nchan, length, amap ); if ( mflag ) mfilemap( mfnames, nchan, length, amap ); /* Open input file and verify header */ in_hdr.rle_file = rle_open_f(cmd_name( argv ), inputfname, "r"); for ( rle_cnt = 0; (rle_err = rle_get_setup( &in_hdr )) == RLE_SUCCESS || rle_err == RLE_EMPTY; rle_cnt++ ) { if ( rle_err == RLE_EMPTY ) { if ( rle_cnt == 0 ) apply = 0; /* can't apply to non-existant map */ else break; /* Build in_hdr for non-existant image (all zeros works fine) */ bzero( &in_hdr, sizeof in_hdr ); } /* If apply flag was given, check for compatibility of color maps */ if ( in_hdr.ncmap == 0 ) apply = 0; /* Can't apply to non-existent map */ if ( apply ) { if ( ! ( nchan == 1 || in_hdr.ncmap == 1 || nchan == in_hdr.ncmap ) ) { fprintf( stderr, "%s: Nchan (%d) and input color map (%d channels) are not compatible\n", cmd_name( argv ), nchan, in_hdr.ncmap ); exit(-1); } ochan = (nchan > in_hdr.ncmap) ? nchan : in_hdr.ncmap; if ( apply == 1 ) /* "before", omap[i] = imap[amap[i]] */ { olength = length; olbits = lbits; } else /* "after", omap[i] = amap[imap[i]] */ { olength = 1 << in_hdr.cmaplen; olbits = in_hdr.cmaplen; } /* Get convenient access to the input map */ imap = allocmap( in_hdr.ncmap, 1 << in_hdr.cmaplen, in_hdr.cmap ); /* Allocate an output map */ omap = allocmap( ochan, olength, NULL ); /* And do the application */ if ( apply == 1 ) applymap( imap, in_hdr.ncmap, 1 << in_hdr.cmaplen, 16, amap, nchan, length, bits, omap ); else applymap( amap, nchan, length, bits, imap, in_hdr.ncmap, 1 << in_hdr.cmaplen, 16, omap ); } else { /* "Copy" the applied map, and left justify it */ omap = allocmap( nchan, length, NULL ); bcopy( amap[0], omap[0], nchan * length * sizeof(rle_map) ); olength = length; olbits = lbits; ochan = nchan; shiftmap( omap, ochan, olength, bits ); } /* Now, open the output */ out_hdr = in_hdr; /* start by copying input parameters */ out_hdr.ncmap = ochan; out_hdr.cmaplen = olbits; out_hdr.cmap = omap[0]; if ( rle_cnt == 0 ) outfile = rle_open_f(cmd_name( argv ), outputfname, "w"); out_hdr.rle_file = outfile; rle_addhist( argv, &in_hdr, &out_hdr ); rle_put_setup( &out_hdr ); /* Copy the rest of the input to the output */ if ( rle_err != RLE_EMPTY ) rle_cp( &in_hdr, &out_hdr ); /* Free temp storage. */ free( omap[0] ); free( omap ); if ( apply ) { free( imap ); } if ( rle_err == RLE_EMPTY ) { rle_err = RLE_SUCCESS; break; } } /* Check for an error. EOF or EMPTY is ok if at least one image * has been read. Otherwise, print an error message. */ if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) ) rle_get_error( rle_err, cmd_name( argv ), inputfname ); exit( 0 ); } /***************************************************************** * TAG( allocmap ) * * Allocate a color map of a given size. * Inputs: * nchan: Number of channels in the map. * length: Length of each channel of the map. * cmap: If non-null, the storage to be used. * Outputs: * Returns a pointer to an array[nchan] of pointers to * array[length] of rle_map. The rle_map array can also * be addressed contiguously as return[0][chan*length+i]. * Assumptions: * If cmap is supplied, it is an array of nchan*length rle_maps. * Algorithm: * [None] */ rle_map ** allocmap( nchan, length, cmap ) int nchan; int length; rle_map * cmap; { rle_map ** map; register int i; map = (rle_map **)malloc( nchan * sizeof( rle_map * ) ); if ( cmap == NULL ) map[0] = (rle_map *)malloc( nchan * length * sizeof( rle_map ) ); else map[0] = cmap; for ( i = 1; i < nchan; i++ ) map[i] = &map[i-1][length]; return map; } /***************************************************************** * TAG( shiftmap ) * * Shift the entries in the color map to left justify them. * Inputs: * map: The color map. * nchan: Number of color channels in the map. * length: Number of entries in each channel. * bits: Number of bits in each entry. * Outputs: * map: Left justified map (modified in place). * Assumptions: * map[0] points to a contiguous array of nchan*length rle_maps * (as set up by allocmap). * Algorithm: * [None] */ void shiftmap( map, nchan, length, bits ) rle_map **map; int nchan, length, bits; { register rle_map * e; register int i; bits = 16 - bits; if ( bits == 0 ) return; /* no work! */ for ( i = nchan * length, e = map[0]; i > 0; i--, e++ ) *e <<= bits; } /***************************************************************** * TAG( applymap ) * * Compose two maps: map[submap]. * Inputs: * map: Map being "applied". * nchan: Number of channels in map. * length: Length of each channel in map. * bits: Number of bits used in each entry of map. * submap: Map used as subscript. * subchan: Number of channels in submap. * sublen: Length of submap. * subbits: Number of bits used in each entry of submap. * Outputs: * omap: Result map. * Omap has max(nchan,subchan) channels, and * sublen entries. * Assumptions: * Yeah. * Algorithm: * Basically, assign omap[c][i] = map[c][submap[c][i]]. If map has * only one channel, get omap[c][i] = map[0][submap[c][i]], and if * submap has only one channel, get omap[c][i] = map[c][submap[0][i]]. * Extra complications include shifting submap by the right number of * bits so that it will index the full range of map, and left-justifying * the output map. */ void applymap( map, nchan, length, bits, submap, subchan, sublen, subbits, omap ) int nchan, length, bits, subchan, sublen, subbits; rle_map **submap; rle_map **map; rle_map **omap; { register rle_map * s; /* pointer into submap */ register rle_map * o; /* pointer into omap */ rle_map ** mp, ** sp, ** op; /* pointer to channel of maps */ register int subshift; int c, i, ochan = ((nchan > subchan) ? nchan : subchan); /* Figure out how much to shift subscript */ if ( (1 << subbits) > length ) /* too many bits in subscript */ for ( subshift = 0; (1 << (subbits + subshift)) > length; subshift-- ) ; else /* not enough bits */ for ( subshift = 0; (1 << (subbits + subshift)) < length; subshift++ ) ; #ifdef NO_NEGATIVE_SHIFT if ( subshift >= 0 ) #endif for ( c = ochan, mp = map, sp = submap, op = omap; c > 0; c--, op++, (nchan > 1 ? mp++ : 0), (subchan > 1 ? sp++ : 0) ) for ( i = sublen, s = *sp, o = *op; i > 0; i--, s++, o++ ) *o = (*mp)[(*s) << subshift]; #ifdef NO_NEGATIVE_SHIFT else { subshift = -subshift; for ( c = ochan, mp = map, sp = submap, op = omap; c > 0; c--, op++, (nchan > 1 ? mp++ : 0), (subchan > 1 ? sp++ : 0) ) for ( i = sublen, s = *sp, o = *op; i > 0; i--, s++, o++ ) *o = (*mp)[(*s) >> subshift]; } #endif shiftmap( omap, ochan, sublen, bits ); } /***************************************************************** * TAG( linmap ) * * Build a linear map. * Inputs: * factor: Linear factor to multiply map entries by. * nchan: Number of color channels. * length: Length of each channel. * range: Range of elements of the map. * Outputs: * amap: Result map. * Assumptions: * [None] * Algorithm: * [None] */ void linmap( factor, nchan, length, range, amap ) double factor; int nchan, length, range; rle_map **amap; { register int i; double l = length - 1, m; for ( i = 0; i < length; i++ ) { m = range * ((double)i / l) * factor; if ( factor < 0 ) { m = range + m; if ( m < 0 ) m = 0; } else if ( m > range ) m = range; amap[0][i] = (rle_map)(0.5 + m); } for ( i = 1; i < nchan; i++ ) bcopy( (char *)amap[0], (char *)amap[i], length * sizeof(rle_map) ); } /***************************************************************** * TAG( gammap ) * * Build a gamma compensation map. * Inputs: * gamma: Gamma exponent. * nchan: Number of color channels. * length: Length of each channel. * range: Range of elements of the map. * Outputs: * amap: Result map. * Assumptions: * [None] * Algorithm: * [None] */ void gammap( gamma, nchan, length, range, amap ) double gamma; int nchan, length, range; rle_map **amap; { register int i; double l = length - 1; gamma = 1.0 / gamma; for ( i = 0; i < length; i++ ) amap[0][i] = (rle_map)(0.5 + range * pow( (double)i / l, gamma )); for ( i = 1; i < nchan; i++ ) bcopy( (char *)amap[0], (char *)amap[i], length * sizeof(rle_map) ); } /***************************************************************** * TAG( filemap ) * * Read a color map from a file * Inputs: * tflag: Flag for type of file: 1 means all entries for a * channel are together (-f), 2 means all entries for * a given index are together (-t). * mapfname: Name of file to read map from. * nchan: Number of color channels. * length: Length of each channel. * Outputs: * amap: Result map. * Assumptions: * [None] * Algorithm: * [None] */ void filemap( tflag, mapfname, nchan, length, amap ) int tflag, nchan, length; char *mapfname; rle_map **amap; { FILE * mapfile; register int c, i; int ent; mapfile = rle_open_f( "rleldmap", mapfname, "r" ); if ( tflag == 1 ) /* channel-major order */ for ( c = 0; c < nchan; c++ ) for ( i = 0; i < length; i++ ) switch ( fscanf( mapfile, "%d", &ent ) ) { case EOF: /* EOF */ fprintf( stderr, "rleldmap: Premature end of file reading map %s at channel %d, entry %d\n", mapfname, c, i ); exit(-1); /* NOTREACHED */ case 1: /* Got it */ amap[c][i] = ent; break; case 0: /* no conversion? */ fprintf( stderr, "rleldmap: Bad data in map %s at channel %d, entry %d\n", mapfname, c, i ); exit(-1); /* NOTREACHED */ default: /* error */ fprintf( stderr, "rleldmap: Error reading map %s at channel %d, entry %d\n", mapfname, c, i ); exit(-1); /* NOTREACHED */ } else /* Entry-major order */ for ( i = 0; i < length; i++ ) for ( c = 0; c < nchan; c++ ) switch ( fscanf( mapfile, "%d", &ent ) ) { case EOF: /* EOF */ fprintf( stderr, "rleldmap: Premature end of file reading map %s at entry %d, channel %d\n", mapfname, i, c ); exit(-1); /* NOTREACHED */ case 1: /* Got it */ amap[c][i] = ent; break; case 0: /* no conversion? */ fprintf( stderr, "rleldmap: Bad data in map %s at entry %d, channel %d\n", mapfname, i, c ); exit(-1); /* NOTREACHED */ default: /* error */ fprintf( stderr, "rleldmap: Error reading map %s at entry %d, channel %d: ", mapfname, i, c ); perror(""); exit(-1); /* NOTREACHED */ } if ( mapfile != stdin ) fclose( mapfile ); } /***************************************************************** * TAG( mfilemap ) * * Read a color map from a multiple files * Inputs: * mfnames: Name of files to read map from. Each file contains * the entries for a single channel of the map. * nchan: Number of color channels (thus number of files). * length: Length of each channel. * Outputs: * amap: Result map. * Assumptions: * [None] * Algorithm: * [None] */ void mfilemap( mfnames, nchan, length, amap ) char **mfnames; int nchan, length; rle_map **amap; { FILE * mapfile; register int c, i; int ent; for ( c = 0; c < nchan; c++, mfnames++ ) { mapfile = rle_open_f( "rleldmap", *mfnames, "r" ); for ( i = 0; i < length; i++ ) switch ( fscanf( mapfile, "%d", &ent ) ) { case EOF: /* EOF */ fprintf( stderr, "rleldmap: Premature end of file reading map %s at channel %d, entry %d\n", *mfnames, c, i ); exit(-1); /* NOTREACHED */ case 1: /* Got it */ amap[c][i] = ent; break; case 0: /* no conversion? */ fprintf( stderr, "rleldmap: Bad data in map %s at channel %d, entry %d\n", *mfnames, c, i ); exit(-1); /* NOTREACHED */ default: /* error */ fprintf( stderr, "rleldmap: Error reading map %s at channel %d, entry %d: ", *mfnames, c, i ); perror(""); exit(-1); /* NOTREACHED */ } if ( mapfile != stdin ) fclose( mapfile ); } } /***************************************************************** * TAG( get_rle_map ) * * Read the map from an RLE file. * Inputs: * fname: Name of file to read map from. * Outputs: * the_hdr: RLE header struct to fill in. * Assumptions: * [None] * Algorithm: * [None] */ void get_rle_map( the_hdr, fname ) rle_hdr *the_hdr; char *fname; { FILE * infile; infile = rle_open_f( "rleldmap", fname, "r" ); the_hdr->rle_file = infile; if ( rle_get_setup( the_hdr ) < 0 ) { fprintf( stderr, "rleldmap: Can't read setup information from %s\n", fname ); exit(-1); } if ( the_hdr->ncmap == 0 ) { fprintf( stderr, "rleldmap: No color map in %s\n", fname ); exit(-1); } if ( infile != stdin ) fclose( infile ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.