Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rlespiff.c
Go to the documentation of this file.
1 /*
2  * rlespiff.c - Spiff up an image by stretching the contrast.
3  *
4  * Author: Spencer W. Thomas
5  * EECS Dept.
6  * University of Michigan
7  * Date: Thu Feb 15 1990
8  * Copyright (c) 1990, University of Michigan
9  *
10  * Cast threshold as a double to prevent overflow error in calculating thresh
11  * Cliff Hathaway, University of Arizona Computer Science Dept. 082790
12  */
13 
14 #include <stdio.h>
15 #include "rle.h"
16 #include "rle_raw.h"
17 
18 void copy_raw();
19 
20 #define CLAMP(x) ((x)<0 ? 0 : ((x)>255 ? 255 : (x)))
21 
22 /*****************************************************************
23  * TAG( main )
24  *
25  * Spiffs up an image by stretching the contrast range so that the
26  * darkest pixel maps to black and the lightest to white. For color
27  * images, the determination is done on the min and max of the RGB
28  * values.
29  *
30  * Usage:
31  * rlespiff [-t threshold] [-b blacklevel] [-w whitelevel] [-s] [-v]
32  * [-o outfile] [infile]
33  * Inputs:
34  * threshold: The number of samples of a pixel value that
35  * should be considered insignificant. Specified
36  * in pixels/million. A threshold of 4 applied
37  * to a 512x512 image would mean that any value
38  * that existed at only one pixel would be
39  * ignored. Default is 10.
40  * blacklevel: The value of "black". Default is 0. The
41  * minimum value input pixel will map to this
42  * value on output.
43  * whitelevel: The value of "white". Default is 255. The
44  * maximum value input pixel will map to this
45  * value on output.
46  * -s: Treat each color channel separately.
47  * -v: Be verbose.
48  * infile: The input file. If not specified, file is
49  * read from standard input.
50  * Outputs:
51  * outfile: The spiffed up file is written here.
52  * Assumptions:
53  * The color map is ignored.
54  * Algorithm:
55  * Read the file and find the minimum and maximum pixel values.
56  * Then "rerun" the input, mapping the pixel values and writing
57  * them to the output file.
58  */
59 void
61 int argc;
62 char **argv;
63 {
64  int rle_cnt = 0;
65  int tflag = 0,
66  threshold = 10;
67  int bflag = 0,
68  blacklevel = 0;
69  int wflag = 0,
70  whitelevel = 255;
71  int sflag = 0;
72  int nhist;
73  int verbose = 0;
74  int oflag = 0;
75  char *outfname = NULL,
76  *infname = NULL;
77  FILE *outfile = stdout;
78  int rle_err;
79  rle_hdr in_hdr,
80  out_hdr;
81  rle_op **scan, ***save_scan;
82  register rle_op *scanp;
83  int *nraw, **save_nraw;
84  int y, ynext;
85  int c, hc, i, x;
86  register int t; /* Temp value. */
87  long int (*histo)[256];
88  int thresh; /* Mapped threshold. */
89  int maxval, minval;
90  int *slide;
91  float *stretch;
92 
93  in_hdr = *rle_hdr_init( NULL );
94  out_hdr = *rle_hdr_init( NULL );
95 
96  if ( scanargs( argc, argv,
97  "% t%-threshold!d b%-blacklevel!d w%-whitelevel!d s%- v%- \
98 \to%-outfile!s infile%s",
99  &tflag, &threshold, &bflag, &blacklevel,
100  &wflag, &whitelevel,
101  &sflag, &verbose, &oflag, &outfname, &infname ) == 0 )
102  exit( 1 );
103 
104  /* Open the files */
105  in_hdr.rle_file = rle_open_f( cmd_name( argv ), infname, "r" );
106  rle_names( &in_hdr, cmd_name( argv ), infname, 0 );
107  rle_names( &out_hdr, in_hdr.cmd, outfname, 0 );
108 
109  /* Loop over all images in input file */
110  for ( rle_cnt = 0;
111  (rle_err = rle_get_setup( &in_hdr )) == RLE_SUCCESS;
112  rle_cnt++ )
113  {
114  if ( rle_cnt == 0 )
115  outfile = rle_open_f( cmd_name( argv ), outfname, "w" );
116 
117  if ( rle_raw_alloc( &in_hdr, &scan, &nraw ) < 0 )
118  RLE_CHECK_ALLOC( in_hdr.cmd, 0, "image data" );
119 
120  save_scan = (rle_op ***)calloc( in_hdr.ymax + 1,
121  sizeof( rle_op ** ) );
122  save_nraw = (int **)calloc( in_hdr.ymax + 1,
123  sizeof( int * ) );
124  RLE_CHECK_ALLOC( in_hdr.cmd, save_scan && save_nraw, "image data" );
125 
126  nhist = sflag ? in_hdr.ncolors : 1;
127  histo = (long int (*)[256]) calloc( 256 * nhist, sizeof(long int) );
128  stretch = (float *)calloc( nhist, sizeof(float) );
129  slide = (int *)calloc( nhist, sizeof(int) );
130  RLE_CHECK_ALLOC( in_hdr.cmd, histo && stretch && slide, 0 );
131 
132  /* Read the input and find min & max */
133  while ( (y = rle_getraw( &in_hdr, scan, nraw )) != 32768 )
134  {
135  /* Histogram values. */
136  for ( c = 0; c < in_hdr.ncolors; c++ )
137  {
138  if ( sflag )
139  hc = c;
140  else
141  hc = 0;
142 
143  for ( i = 0, scanp = scan[c]; i < nraw[c]; i++, scanp++ )
144  switch ( scanp->opcode )
145  {
146  case RByteDataOp:
147  for ( x = 0; x < scanp->length; x++ )
148  histo[hc][scanp->u.pixels[x]]++;
149  break;
150  case RRunDataOp:
151  histo[hc][scanp->u.run_val] += scanp->length;
152  break;
153  }
154  }
155 
156  /* Save scanline data for second pass. */
157  copy_raw( &in_hdr, y, scan, nraw, save_scan, save_nraw );
158  }
159 
160 
161  /* Determine min & max */
162  thresh = (((double)threshold * (in_hdr.xmax - in_hdr.xmin + 1) *
163  (in_hdr.ymax - in_hdr.ymin + 1) +
164  500000)) / 1000000;
165 
166  if ( !sflag )
167  thresh *= in_hdr.ncolors;
168 
169  for ( hc = 0; hc < nhist; hc++ )
170  {
171  for ( i = 0; i < 256 && histo[hc][i] <= thresh; i++ )
172  ;
173  minval = i;
174  for ( i = 255; i >= 0 && histo[hc][i] <= thresh; i-- )
175  ;
176  maxval = i;
177 
178  /* Mapping parameters */
179  if ( maxval > minval )
180  stretch[hc] = (float)(whitelevel - blacklevel) /
181  (maxval - minval);
182  else
183  stretch[hc] = 1.0;
184  slide[hc] = blacklevel - stretch[hc] * minval;
185 
186  if ( verbose )
187  {
188  fprintf( stderr, "%s image %d",
189  in_hdr.rle_file == stdin ? "Standard input" : infname,
190  rle_cnt );
191  if ( sflag )
192  fprintf( stderr, ", channel %d", hc );
193  fprintf( stderr, " min = %d, max = %d\n", minval, maxval );
194  }
195  }
196 
197  /* Pass 2 -- map pixels and write output file */
198  (void)rle_hdr_cp( &in_hdr, &out_hdr );
199  out_hdr.rle_file = outfile;
200  rle_addhist( argv, &in_hdr, &out_hdr );
201  rle_put_setup( &out_hdr );
202  for ( y = in_hdr.ymin, ynext = -1;
203  y <= in_hdr.ymax;
204  y++ )
205  {
206  if ( save_scan[y] )
207  {
208  /* Map pixel values */
209  for ( c = 0; c < in_hdr.ncolors; c++ )
210  {
211  float h_stretch;
212  int h_slide;
213 
214  if ( sflag )
215  {
216  h_stretch = stretch[c];
217  h_slide = slide[c];
218  }
219  else
220  {
221  h_stretch = stretch[0];
222  h_slide = slide[0];
223  }
224 
225  for ( i = 0, scanp = save_scan[y][c];
226  i < save_nraw[y][c];
227  i++, scanp++ )
228  switch ( scanp->opcode )
229  {
230  case RByteDataOp:
231  for ( x = 0; x < scanp->length; x++ )
232  {
233  t = scanp->u.pixels[x] * h_stretch + h_slide;
234  scanp->u.pixels[x] = CLAMP( t );
235  }
236  break;
237  case RRunDataOp:
238  t = scanp->u.run_val * h_stretch + h_slide;
239  scanp->u.run_val = CLAMP( t );
240  break;
241  }
242  }
243 
244  if ( ynext == -1 )
245  {
246  ynext = in_hdr.ymin;
247  if ( y - ynext > 0 )
248  rle_skiprow( &out_hdr, y - ynext );
249  }
250  else
251  if ( y - ynext > 1 )
252  rle_skiprow( &out_hdr, y - ynext );
253  rle_putraw( save_scan[y], save_nraw[y], &out_hdr );
254  rle_freeraw( &in_hdr, save_scan[y], save_nraw[y] );
255  rle_raw_free( &in_hdr, save_scan[y], save_nraw[y] );
256  ynext = y; /* Most recent "real" scanline. */
257  }
258  }
259  rle_puteof( &out_hdr );
260  rle_raw_free( &in_hdr, scan, nraw );
261  free( stretch );
262  free( slide );
263  free( histo );
264  }
265 
266  if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) )
267  rle_get_error( rle_err, argv[0], infname );
268 
269  exit( 0 );
270 }
271 
272 
273 /*****************************************************************
274  * TAG( copy_raw )
275  *
276  * Copy the raw scan data into a save area.
277  * Inputs:
278  * the_hdr: Header describing input file.
279  * y: Number of this scanline.
280  * scan: Raw data for this scanline.
281  * nraw: Lengths of raw data for this scanline.
282  * Outputs:
283  * save_scan: Array of pointers to saved raw data.
284  * save_nraw: Array of pointers to saved counts.
285  * Assumptions:
286  * The arrays save_scan and save_nraw have at least
287  * y + 1 - the_hdr->ymin elements.
288  * Copies allocation algorithm from rle_raw_alloc to the extent
289  * that rle_raw_free can free the saved raw data and counts.
290  * Algorithm:
291  * Allocate memory, copy data. Copies pointers to saved pixel
292  * data, so caller need not call rle_freeraw.
293  */
294 void
296 rle_hdr *the_hdr;
297 int y;
298 rle_op **scan;
299 int *nraw;
300 rle_op ***save_scan;
301 int **save_nraw;
302 {
303  int totlen = 0;
304  register int c;
305 
306  /* Allocate space to save counts */
307  save_nraw[y] = (int *)malloc( (the_hdr->ncolors + the_hdr->alpha) *
308  sizeof(int) );
309  if ( save_nraw[y] == NULL )
310  goto malloc_err;
311  if ( the_hdr->alpha )
312  save_nraw[y]++;
313  /* Count total number of raw data to save, and save counts. */
314  for ( c = -the_hdr->alpha; c < the_hdr->ncolors; c++ )
315  totlen += save_nraw[y][c] = nraw[c];
316 
317  /* Allocate space to save raw data */
318  save_scan[y] = (rle_op **)malloc( (the_hdr->ncolors + the_hdr->alpha) *
319  sizeof(rle_op *) );
320  if ( save_scan[y] == NULL )
321  goto malloc_err;
322 /* BUG fixed by Michel GAUDET
323  * In case of totlen = 0 (happens if all runs in a given line)
324  * the return value of malloc is NULL
325  * and it is not an error of malloc
326  * Correction : add one unit to the size
327  */
328  save_scan[y][0] = (rle_op *)malloc( 1 + totlen * sizeof(rle_op) );
329  if ( save_scan[y][0] == NULL )
330  goto malloc_err;
331  if ( the_hdr->alpha )
332  save_scan[y]++;
333 
334  /* Save raw data */
335  for ( c = -the_hdr->alpha; c < the_hdr->ncolors; c++ )
336  {
337  if ( c > -the_hdr->alpha )
338  save_scan[y][c] = save_scan[y][c-1] + nraw[c-1];
339  bcopy( scan[c], save_scan[y][c], nraw[c] * sizeof(rle_op) );
340  }
341  return;
342 
343 malloc_err:
344  RLE_CHECK_ALLOC( the_hdr->cmd, 0, 0 );
345 }
FILE * rle_open_f(char *prog_name, char *file_name, char *mode)
Definition: rle_open_f.c:216
#define RRunDataOp
Definition: rle_code.h:41
int xmin
Definition: rle.h:100
rle_hdr * rle_hdr_cp(rle_hdr *from_hdr, rle_hdr *to_hdr)
Definition: rle_hdr.c:119
void rle_freeraw(rle_hdr *the_hdr, scanraw, nraw)
Definition: rle_getraw.c:268
int length
Definition: rle_raw.h:51
void rle_names(rle_hdr *the_hdr, const char *pgmname, const char *fname, int img_num)
Definition: rle_hdr.c:48
int rle_raw_alloc(rle_hdr *the_hdr, rle_op ***scanp, int **nrawp)
Definition: rle_raw_alc.c:60
int opcode
Definition: rle_raw.h:49
#define RLE_EMPTY
Definition: rle.h:73
char * cmd_name(char **argv)
Definition: cmd_name.c:31
void main(int argc, char **argv)
Definition: aliastorle.c:121
int rle_get_setup(rle_hdr *the_hdr)
Definition: rle_getrow.c:74
void rle_putraw(rle_op **scanraw, int *nraw, rle_hdr *the_hdr)
Definition: rle_putraw.c:60
#define RLE_SUCCESS
Definition: rle.h:70
void copy_raw(rle_hdr *the_hdr, int y, rle_op **scan, int *nraw, rle_op ***save_scan, int **save_nraw)
Definition: rlespiff.c:295
int ymin
Definition: rle.h:100
int rle_get_error(int code, const char *pgmname, const char *fname)
Definition: rle_error.c:76
int scanargs(int argc, char **argv, const char *format,...)
Definition: scanargs.c:94
const char * cmd
Definition: rle.h:133
void rle_puteof(rle_hdr *the_hdr)
Definition: rle_putrow.c:474
int xmax
Definition: rle.h:100
#define CLAMP(x)
Definition: rlespiff.c:20
#define RLE_EOF
Definition: rle.h:74
void rle_addhist(argv, rle_hdr *in_hdr, rle_hdr *out_hdr)
Definition: rle_addhist.c:54
void rle_skiprow(rle_hdr *the_hdr, int nrow)
Definition: rle_putrow.c:393
int ymax
Definition: rle.h:100
void rle_put_setup(rle_hdr *the_hdr)
Definition: rle_putrow.c:453
int alpha
Definition: rle.h:100
void rle_raw_free(rle_hdr *the_hdr, rle_op **scanp, nrawp)
Definition: rle_raw_alc.c:131
rle_hdr * rle_hdr_init(rle_hdr *the_hdr)
Definition: rle_hdr.c:267
FILE * rle_file
Definition: rle.h:114
unsigned int rle_getraw(rle_hdr *the_hdr, scanraw, nraw)
Definition: rle_getraw.c:78
int ncolors
Definition: rle.h:100
#define RByteDataOp
Definition: rle_code.h:40
#define RLE_CHECK_ALLOC(pgm, ptr, name)
Definition: rle.h:86