This is rlespiff.c in view mode; [Download] [Up]
/* * rlespiff.c - Spiff up an image by stretching the contrast. * * Author: Spencer W. Thomas * EECS Dept. * University of Michigan * Date: Thu Feb 15 1990 * Copyright (c) 1990, University of Michigan * * Cast threshold as a double to prevent overflow error in calculating thresh * Cliff Hathaway, University of Arizona Computer Science Dept. 082790 */ #include <stdio.h> #include <rle.h> #include <rle_raw.h> #ifdef USE_STDLIB_H #include <stdlib.h> #else #ifdef VOID_STAR extern void *malloc(), *calloc(); #else extern char *malloc(), *calloc(); #endif extern void free(), cfree(); #endif /* USE_STDLIB_H */ void copy_raw(); #define CLAMP(x) ((x)<0 ? 0 : ((x)>255 ? 255 : (x))) /***************************************************************** * TAG( main ) * * Spiffs up an image by stretching the contrast range so that the * darkest pixel maps to black and the lightest to white. For color * images, the determination is done on the min and max of the RGB * values. * * Usage: * rlespiff [-t threshold] [-b blacklevel] [-w whitelevel] [-s] [-v] * [-o outfile] [infile] * Inputs: * threshold: The number of samples of a pixel value that * should be considered insignificant. Specified * in pixels/million. A threshold of 4 applied * to a 512x512 image would mean that any value * that existed at only one pixel would be * ignored. Default is 10. * blacklevel: The value of "black". Default is 0. The * minimum value input pixel will map to this * value on output. * whitelevel: The value of "white". Default is 255. The * maximum value input pixel will map to this * value on output. * -s: Treat each color channel separately. * -v: Be verbose. * infile: The input file. If not specified, file is * read from standard input. * Outputs: * outfile: The spiffed up file is written here. * Assumptions: * The color map is ignored. * Algorithm: * Read the file and find the minimum and maximum pixel values. * Then "rerun" the input, mapping the pixel values and writing * them to the output file. */ void main( argc, argv ) int argc; char **argv; { int rle_cnt = 0; int tflag = 0, threshold = 10; int bflag = 0, blacklevel = 0; int wflag = 0, whitelevel = 255; int sflag = 0; int nhist; int verbose = 0; int oflag = 0; char *outfname = NULL, *infname = NULL; FILE *outfile = stdout; int rle_err; rle_hdr in_hdr, out_hdr; rle_op **scan, ***save_scan; register rle_op *scanp; int *nraw, **save_nraw; int y, ynext; int c, hc, i, x; register int t; /* Temp value. */ long int (*histo)[256]; int thresh; /* Mapped threshold. */ int maxval, minval; int *slide; float *stretch; if ( scanargs( argc, argv, "% t%-threshold!d b%-blacklevel!d w%-whitelevel!d s%- v%- \ \to%-outfile!s infile%s", &tflag, &threshold, &bflag, &blacklevel, &wflag, &whitelevel, &sflag, &verbose, &oflag, &outfname, &infname ) == 0 ) exit( 1 ); /* Open the files */ in_hdr.rle_file = rle_open_f( cmd_name( argv ), infname, "r" ); /* Loop over all images in input file */ while ( (rle_err = rle_get_setup( &in_hdr )) == RLE_SUCCESS ) { if ( rle_cnt == 0 ) outfile = rle_open_f( cmd_name( argv ), outfname, "w" ); rle_cnt++; /* Count images in this file. */ rle_raw_alloc( &in_hdr, &scan, &nraw ); save_scan = (rle_op ***)calloc( in_hdr.ymax + 1, sizeof( rle_op ** ) ); save_nraw = (int **)calloc( in_hdr.ymax + 1, sizeof( int * ) ); nhist = sflag ? in_hdr.ncolors : 1; histo = (long int (*)[256]) calloc( 256 * nhist, sizeof(long int) ); stretch = (float *)calloc( nhist, sizeof(float) ); slide = (int *)calloc( nhist, sizeof(int) ); /* Read the input and find min & max */ while ( (y = rle_getraw( &in_hdr, scan, nraw )) != 32768 ) { /* Histogram values. */ for ( c = 0; c < in_hdr.ncolors; c++ ) { if ( sflag ) hc = c; else hc = 0; for ( i = 0, scanp = scan[c]; i < nraw[c]; i++, scanp++ ) switch ( scanp->opcode ) { case RByteDataOp: for ( x = 0; x < scanp->length; x++ ) histo[hc][scanp->u.pixels[x]]++; break; case RRunDataOp: histo[hc][scanp->u.run_val] += scanp->length; break; } } /* Save scanline data for second pass. */ copy_raw( &in_hdr, y, scan, nraw, save_scan, save_nraw ); } /* Determine min & max */ thresh = (((double)threshold * (in_hdr.xmax - in_hdr.xmin + 1) * (in_hdr.ymax - in_hdr.ymin + 1) + 500000)) / 1000000; if ( !sflag ) thresh *= in_hdr.ncolors; for ( hc = 0; hc < nhist; hc++ ) { for ( i = 0; i < 256 && histo[hc][i] <= thresh; i++ ) ; minval = i; for ( i = 255; i >= 0 && histo[hc][i] <= thresh; i-- ) ; maxval = i; /* Mapping parameters */ if ( maxval > minval ) stretch[hc] = (float)(whitelevel - blacklevel) / (maxval - minval); else stretch[hc] = 1.0; slide[hc] = blacklevel - stretch[hc] * minval; if ( verbose ) { fprintf( stderr, "%s image %d", in_hdr.rle_file == stdin ? "Standard input" : infname, rle_cnt ); if ( sflag ) fprintf( stderr, ", channel %d", hc ); fprintf( stderr, " min = %d, max = %d\n", minval, maxval ); } } /* Pass 2 -- map pixels and write output file */ out_hdr = in_hdr; out_hdr.rle_file = outfile; rle_addhist( argv, &in_hdr, &out_hdr ); rle_put_setup( &out_hdr ); for ( y = in_hdr.ymin, ynext = -1; y <= in_hdr.ymax; y++ ) { if ( save_scan[y] ) { /* Map pixel values */ for ( c = 0; c < in_hdr.ncolors; c++ ) { float h_stretch; int h_slide; if ( sflag ) { h_stretch = stretch[c]; h_slide = slide[c]; } else { h_stretch = stretch[0]; h_slide = slide[0]; } for ( i = 0, scanp = save_scan[y][c]; i < save_nraw[y][c]; i++, scanp++ ) switch ( scanp->opcode ) { case RByteDataOp: for ( x = 0; x < scanp->length; x++ ) { t = scanp->u.pixels[x] * h_stretch + h_slide; scanp->u.pixels[x] = CLAMP( t ); } break; case RRunDataOp: t = scanp->u.run_val * h_stretch + h_slide; scanp->u.run_val = CLAMP( t ); break; } } if ( ynext == -1 ) { ynext = in_hdr.ymin; if ( y - ynext > 0 ) rle_skiprow( &out_hdr, y - ynext ); } else if ( y - ynext > 1 ) rle_skiprow( &out_hdr, y - ynext ); rle_putraw( save_scan[y], save_nraw[y], &out_hdr ); rle_freeraw( &in_hdr, save_scan[y], save_nraw[y] ); rle_raw_free( &in_hdr, save_scan[y], save_nraw[y] ); ynext = y; /* Most recent "real" scanline. */ } } rle_puteof( &out_hdr ); rle_raw_free( &in_hdr, scan, nraw ); cfree( stretch ); cfree( slide ); cfree( histo ); } if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) ) rle_get_error( rle_err, argv[0], infname ); exit( 0 ); } /***************************************************************** * TAG( copy_raw ) * * Copy the raw scan data into a save area. * Inputs: * the_hdr: Header describing input file. * y: Number of this scanline. * scan: Raw data for this scanline. * nraw: Lengths of raw data for this scanline. * Outputs: * save_scan: Array of pointers to saved raw data. * save_nraw: Array of pointers to saved counts. * Assumptions: * The arrays save_scan and save_nraw have at least * y + 1 - the_hdr->ymin elements. * Copies allocation algorithm from rle_raw_alloc to the extent * that rle_raw_free can free the saved raw data and counts. * Algorithm: * Allocate memory, copy data. Copies pointers to saved pixel * data, so caller need not call rle_freeraw. */ void copy_raw( the_hdr, y, scan, nraw, save_scan, save_nraw ) rle_hdr *the_hdr; int y; rle_op **scan; int *nraw; rle_op ***save_scan; int **save_nraw; { int totlen = 0; register int c; /* Allocate space to save counts */ save_nraw[y] = (int *)malloc( (the_hdr->ncolors + the_hdr->alpha) * sizeof(int) ); if ( save_nraw[y] == NULL ) goto malloc_err; if ( the_hdr->alpha ) save_nraw[y]++; /* Count total number of raw data to save, and save counts. */ for ( c = -the_hdr->alpha; c < the_hdr->ncolors; c++ ) totlen += save_nraw[y][c] = nraw[c]; /* Allocate space to save raw data */ save_scan[y] = (rle_op **)malloc( (the_hdr->ncolors + the_hdr->alpha) * sizeof(rle_op *) ); if ( save_scan[y] == NULL ) goto malloc_err; save_scan[y][0] = (rle_op *)malloc( totlen * sizeof(rle_op) ); if ( save_scan[y][0] == NULL ) goto malloc_err; if ( the_hdr->alpha ) save_scan[y]++; /* Save raw data */ for ( c = -the_hdr->alpha; c < the_hdr->ncolors; c++ ) { if ( c > -the_hdr->alpha ) save_scan[y][c] = save_scan[y][c-1] + nraw[c-1]; bcopy( scan[c], save_scan[y][c], nraw[c] * sizeof(rle_op) ); } return; malloc_err: fprintf( stderr, "rlespiff (copy_raw): Malloc failed, quitting: " ); perror( "" ); exit( 1 ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.