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.