Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rlequant.c
Go to the documentation of this file.
1 /*
2  * This software is copyrighted as noted below. It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is". Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  */
18 /*
19  * rlequant.c - Quantize an image to a given number of colors.
20  *
21  * Author: Spencer W. Thomas
22  * EECS Dept.
23  * University of Michigan
24  * Date: Tue Jun 12 1990
25  * Copyright (c) 1990, University of Michigan
26  * History:
27  * 13 September 1990: Clark: Fix problem with cropped images.
28  */
29 #ifndef lint
30 char rcsid[] = "$Header: /tmp_mnt/n/itn/hendrix/u/spencer/RCS/rlequant.c,v 3.0.1.8 1992/04/30 14:13:13 spencer Exp spencer $";
31 #endif
32 /*
33 rlequant() Tag the file.
34 */
35 
36 #include <stdio.h>
37 #include "rle.h"
38 #include "colorquant.h"
39 
40 #define Quantize(x) (x >> shift)
41 
42 /* Handle malloc errors. */
43 #define CHECK_MALLOC(type, ptr, size, desc)
44  if ( ((ptr) = (type *)malloc( size )) == NULL )
45  {
46  fprintf( stderr, "%s: Can't allocate memory for %s.\n",
47  MY_NAME, desc );
48  exit( RLE_NO_SPACE );
49  }
50 
51 /* An enumerated type for the state machine.
52  * If in NORMAL state, stays in normal state for all images.
53  * To do -m, start in INIT_HIST for first image, move to USE_HIST for
54  * subsequent images (only compute histogram at this point). Switch
55  * to PROCESS_HIST after finishing with input images. Then rewind
56  * file and output images.
57  *
58  * Note that INIT_HIST, USE_HIST, and PROCESS_HIST are defined in
59  * colorquant.h.
60  */
61 #define NORMAL 0
62 #ifndef INIT_HIST
63 #define INIT_HIST 1
64 #define USE_HIST 2
65 #define PROCESS_HIST 3
66 #endif
67 #define OUTPUT 4
68 typedef int state_t;
69 
70 static void mem_alloc(), read_input(), copy_hdr();
71 static void setup_output(), write_output(), free_mem(), add_cube();
72 
73 static CONST_DECL char *MY_NAME = "rlequant";
74 
75 /*****************************************************************
76  * TAG( main )
77  *
78  * Using Craig Kolb's colorquant code, quantize an RLE image to a
79  * specified number of colors.
80  * Usage:
81  * rlequant [-b bits] [-d] [-f] [-i cubeside] [-n colors]
82  * [-r mapfile] [-o outfile] [infile]
83  * Inputs:
84  * -b bits: The number of bits to which the image will be
85  * "prequantized". The default is 5. Normally
86  * this is fine, but some images have a very
87  * limited number of colors. The program will
88  * require more memory if a larger value is
89  * given: an array of size 2^(3*bits) is
90  * allocated. Must be <= 8.
91  * -c: Just generate a color map. The output file will
92  * be a 0x0 image with a color map. The
93  * rledither program can be used to quantize any
94  * input image to this color map.
95  * -d: Floyd Steinberg Dither the output.
96  * -f: "Fast" mode. The quantization accuracy will
97  * be a little worse, but it is usually acceptable.
98  * -i cubeside: Add a "color cube" to the output colormap.
99  * The cube will have cubeside elements on a
100  * side, and will thus take up cubeside^3
101  * colormap entries. The cube will be used for
102  * output quantization, but will not affect the
103  * choice of colors otherwise. (-i for "initialize").
104  * -m: Multiple image mode: create a color map that
105  * is "optimal" for the concatenation of all the
106  * input images. This is useful for creating
107  * quantized "movies" for 8-bit displays. If the
108  * input comes from a pipe, the -c flag must be
109  * specified.
110  * -n colors: The number of colors to quantize the image to.
111  * The output image will contain no more than
112  * this number of colors. Must be <= 256.
113  * -r mapfile: Read the color map from the RLE file 'mapfile'
114  * and add it to the output color map. If the
115  * input file has a color_map_length comment, its
116  * value is used as the size of the input map;
117  * otherwise, the full input map (usually 256
118  * entries) will be used.
119  * infile: The input RLE file. Default stdin.
120  * "-" means stdin.
121  * Outputs:
122  * -o outfile: The output RLE file. Default stdout.
123  * "-" means stdout. The output image will be a
124  * single channel image with a color map.
125  * Constraints:
126  * cubeside^3 + colors + size of mapfile color map <= 256.
127  * Assumptions:
128  * [None]
129  * Algorithm:
130  * Read image, call colorquant, write image with new colormap.
131  * If -m is specified, the processing is done in two passes. The
132  * first pass reads all the images and accumulates "Histogram"
133  * information in colorquant. At the end of the first pass, the
134  * set of representative colors is computed. The second pass (if
135  * -c is not specified) re-reads the input and quantizes the
136  * images. Because of this, the input cannot be coming from a
137  * pipe.
138  */
139 void
141 int argc;
142 char **argv;
143 {
144  char *infname = NULL,
145  *outfname = NULL,
146  *mapfname = NULL;
147  int oflag = 0;
148  int bflag = 0,
149  bits = 5;
150  int cflag = 0,
151  iflag = 0,
152  mflag = 0,
153  nflag = 0,
154  rflag = 0,
155  colors_in = 256;
156  int fflag = 0;
157  int dflag = 0;
158  int mapsize = 0; /* Size of input color map. */
159  int cubeside = 0,
160  cubesize;
161  int rle_cnt, rle_err, width, height, shift;
162  int colors = 0;
163  long entries;
164  FILE *outfile = stdout;
165  /* Headers for input and output files. */
166  rle_hdr in_hdr, out_hdr;
167  /* Header for RLE colormap file. */
168  rle_hdr map_hdr;
169  rle_pixel **rows; /* Will be used for scanline storage. */
170  rle_pixel *outrows[2]; /* For the output scanlines. */
171  rle_pixel *alpha = NULL, *red, *green, *blue; /* Image storage. */
172  rle_pixel *img_red, *img_green, *img_blue; /* Image storage. */
173  rle_pixel *colormap[3]; /* The quantized colormap. */
174  rle_pixel **inputmap = NULL; /* A given set of colors (see mapsize). */
175  rle_pixel *rgbmap; /* Used for quantization. */
176  state_t state;
177 
178  MY_NAME = cmd_name( argv );
179  in_hdr = *rle_hdr_init( NULL );
180  out_hdr = *rle_hdr_init( NULL );
181  map_hdr = *rle_hdr_init( NULL );
182 
183  if ( scanargs( argc, argv,
184  "% b%-bits!d c%- d%- f%- i%-cubeside!d m%- n%-colors!d r%-rlemap!s o%-outfile!s infile%s",
185  &bflag, &bits, &cflag, &dflag, &fflag,
186  &iflag, &cubeside,
187  &mflag, &nflag, &colors_in,
188  &rflag, &mapfname,
189  &oflag, &outfname, &infname ) == 0 )
190  exit( 1 );
191 
192  if ( iflag )
193  if ( cubeside <= 1 || cubeside > 6 )
194  {
195  fprintf( stderr,
196  "%s: Cubeside (%d given) must be be >= 2 and <= 6.\n",
197  MY_NAME, cubeside );
198  fprintf( stderr, "%s: Cubeside set to 0.", MY_NAME );
199  cubeside = 0;
200  }
201 
202  cubesize = cubeside * cubeside * cubeside;
203 
204  /* If an input map is specified, get it now. */
205  if ( rflag )
206  {
207  char *map_comment;
208 
209  map_hdr.rle_file = rle_open_f( MY_NAME, mapfname, "r" );
210  rle_names( &map_hdr, MY_NAME, mapfname, 0 );
211  rle_get_setup_ok( &map_hdr, MY_NAME, mapfname );
212  /* Check for a length comment. */
213  if ( (map_comment = rle_getcom( "color_map_length", &map_hdr )) )
214  mapsize = atoi( map_comment );
215  /* Otherwise, use the map length in the header. */
216  if ( mapsize == 0 )
217  mapsize = 1 << map_hdr.cmaplen;
218 
219  /* Build a color map. */
220  inputmap = buildmap( &map_hdr, 3, 1.0, 1.0 );
221  fclose( map_hdr.rle_file );
222  }
223 
224  if ( bits <= 0 || bits > 8 )
225  {
226  fprintf( stderr, "%s: The bits argument must be >0 and <= 8.\n",
227  MY_NAME );
228  exit( 1 );
229  }
230 
231  /* If number of colors not given, compute default. */
232  if ( !nflag )
233  {
234  colors_in = 256 - mapsize - cubesize;
235  if ( colors_in < 0 )
236  colors_in = 0;
237  }
238 
239  /* Sanity check. */
240  if ( colors_in + mapsize + cubesize <= 0 ||
241  colors_in + mapsize + cubesize > 256 )
242  {
243  fprintf( stderr,
244  "%s: colors + cubeside^3 + rlemap size (%d + %d + %d = %d ) \n\
245 \tmust be >0 and <= 256.\n",
246  MY_NAME, colors_in, cubesize, mapsize,
247  colors_in + cubesize + mapsize );
248  exit( 1 );
249  }
250 
251  /* If input color map or color cube, don't compute rgbmap twice. */
252  if ( mapsize > 0 || cubesize > 0 )
253  fflag |= CQ_NO_RGBMAP;
254 
255  /* Open the input file.
256  * The output file won't be opened until the first image header
257  * has been read. This avoids unnecessarily wiping out a
258  * pre-existing file if the input is garbage.
259  */
260  in_hdr.rle_file = rle_open_f( MY_NAME, infname, "r" );
261  rle_names( &in_hdr, MY_NAME, infname, 0 );
262  rle_names( &out_hdr, MY_NAME, outfname, 0 );
263 
264  /* Check for seekability in multiple image mode. */
265  if ( mflag && (!cflag) && ftell( in_hdr.rle_file ) < 0 )
266  {
267  fprintf( stderr,
268  "%s: Piped input with -m, colors will be chosen from first image only.\n",
269  MY_NAME );
270  mflag = -1;
271  }
272 
273  /* Allocate the new colormap. */
274  CHECK_MALLOC( rle_pixel, colormap[0], colors_in + cubesize + mapsize,
275  "colormap" );
276  CHECK_MALLOC( rle_pixel, colormap[1], colors_in + cubesize + mapsize,
277  "colormap" );
278  CHECK_MALLOC( rle_pixel, colormap[2], colors_in + cubesize + mapsize,
279  "colormap" );
280 
281  /* Allocate memory for the rgbmap. */
282  CHECK_MALLOC( rle_pixel, rgbmap, 1L << (3*bits), "RGB map" );
283 
284  /* Amount to shift incoming pixels by for prequantization. */
285  shift = 8 - bits;
286 
287  /* Repeat loop for -m flag.
288  * Exits when state == NORMAL or state == OUTPUT.
289  * When colors == 0, just do OUTPUT phase.
290  */
291  if ( colors_in == 0 )
292  state = OUTPUT;
293  else if ( mflag > 0 )
294  state = INIT_HIST;
295  else
296  state = NORMAL;
297 
298  do
299  {
300  /* Advance state machine.
301  * Rewind input if necessary.
302  */
303  if ( state == USE_HIST )
304  {
305  state = OUTPUT;
306  rewind( in_hdr.rle_file );
307  }
308 
309  /* Read images from the input file until the end of file is
310  * encountered or an error occurs.
311  */
312  rle_cnt = 0;
313  while ( (rle_err = rle_get_setup( &in_hdr )) == RLE_SUCCESS )
314  {
315  /* Open output file when the first header is successfully read. */
316  if ( rle_cnt == 0 )
317  outfile = rle_open_f( MY_NAME, outfname, "w" );
318 
319  /* Count the input images. */
320  rle_cnt++;
321 
322  /* Verify that the input image has at least 3 color channels. */
323  if ( in_hdr.ncolors < 3 )
324  fprintf( stderr,
325  "%s: Input image %d has only %d color%s, faking the other %d.\n",
326  MY_NAME, rle_cnt, in_hdr.ncolors,
327  in_hdr.ncolors == 1 ? "" : "s",
328  3 - in_hdr.ncolors );
329 
330  /* Copy input header to output.
331  * Only do it if it will be used:
332  * state == NORMAL or state == OUTPUT
333  * An image will be output normally.
334  * state == INIT_HIST && cflag In multiple
335  * image/color-map-only mode, we will copy the
336  * comments from the first image header.
337  */
338  if ( state == NORMAL || state == OUTPUT ||
339  (cflag && state == INIT_HIST) )
340  copy_hdr( argv, &in_hdr, &out_hdr, outfile, cflag );
341 
342  width = in_hdr.xmax + 1; /* Width of a scanline. */
343  height = in_hdr.ymax - in_hdr.ymin + 1; /* Height of image. */
344 
345  /* Total number of pixels in image. */
346  entries = width * height;
347 
348  /* Allocate memory for the imput image. */
349  mem_alloc( &in_hdr, entries, dflag, &rows,
350  &red, &green, &blue, &alpha,
351  &img_red, &img_green, &img_blue );
352 
353  /* Read and quantize the input image. */
354  if ( !(cflag && state == OUTPUT) )
355  read_input( &in_hdr, width, shift, dflag,
356  red, green, blue, alpha,
357  img_red, img_green, img_blue, rows );
358 
359  /* Compute the color quantization map. */
360  if ( state != OUTPUT )
361  colors = colorquant( red, green, blue, entries,
362  colormap, colors_in, bits,
363  rgbmap, fflag, state );
364 
365  /* Advance state machine. */
366  if ( state == INIT_HIST )
367  state = USE_HIST;
368 
369  if ( state == NORMAL || state == OUTPUT )
370  {
371  int i;
372 
373  /* Put in specified colormap now, if requested. */
374  for ( i = 0; i < mapsize; i++, colors++ )
375  {
376  colormap[0][colors] = inputmap[0][i];
377  colormap[1][colors] = inputmap[1][i];
378  colormap[2][colors] = inputmap[2][i];
379  }
380 
381  /* Put color cube in now, if requested. */
382  add_cube( colormap, colors, cubeside );
383  colors += cubesize;
384 
385  /* Recompute inverse colormap if necessary. */
386  if ( mapsize + cubesize > 0 )
387  {
388  unsigned long *dist_buf;
389 
390  /* Recompute rgbmap. */
391  CHECK_MALLOC( unsigned long, dist_buf,
392  (1L << (3*bits)) * sizeof(long),
393  "Distance buffer" );
394  inv_cmap( colors, colormap, bits, dist_buf, rgbmap );
395  free( dist_buf );
396 
397  /* If OUTPUT mode, don't want to do it again. */
398  if ( state == OUTPUT )
399  {
400  cubesize = 0;
401  mapsize = 0;
402  }
403  }
404 
405  /* Compute and write setup information to the output file. */
406  setup_output( &out_hdr, colors, colormap );
407 
408  /* Quantize (and maybe dither) the input image and write the
409  * output image.
410  */
411  write_output( &out_hdr, width, height, bits, dflag,
412  red, green, blue, alpha,
413  img_red, img_green, img_blue, rgbmap, colormap,
414  outrows );
415  /* mflag < 0 means compute map from first image, just
416  * apply it to the rest.
417  */
418  if (mflag < 0 && state == NORMAL)
419  state = OUTPUT;
420  }
421 
422  /* Free all the memory we allocated. */
423  free_mem( &in_hdr, dflag, red, green, blue, alpha,
424  img_red, img_green, img_blue, rows, outrows );
425  }
426 
427  /* Check for an error. EOF or EMPTY is ok if at least one image
428  * has been read. Otherwise, print an error message.
429  */
430  if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) )
431  {
432  rle_get_error( rle_err, MY_NAME, infname );
433  break;
434  }
435 
436  /* In multiple image mode, finish quantization processing. */
437  if ( state == USE_HIST )
438  {
439  colors = colorquant( NULL, NULL, NULL, 0,
440  colormap, colors_in, bits,
441  rgbmap, fflag, PROCESS_HIST );
442 
443  /* If multiple images and only outputting color map, do it now. */
444  if ( cflag )
445  {
446  int i;
447 
448  /* Put in specified colormap now, if requested. */
449  for ( i = 0; i < mapsize; i++, colors++ )
450  {
451  colormap[colors][0] = inputmap[i][0];
452  colormap[colors][1] = inputmap[i][1];
453  colormap[colors][2] = inputmap[i][2];
454  }
455  mapsize = 0;
456 
457  /* Add the extra colors to colormap. */
458  add_cube( colormap, colors, cubeside );
459  colors += cubesize;
460  cubesize = 0;
461 
462  /* Write the setup information, only. */
463  setup_output( &out_hdr, colors, colormap );
464  rle_puteof( &out_hdr );
465  /* Done. */
466  state = OUTPUT;
467  }
468  }
469  } while ( state != OUTPUT && state != NORMAL );
470 
471  exit( 0 );
472 }
473 
474 
475 /*
476  * copy_hdr -- copy information from the input header to the output.
477  *
478  * Inputs:
479  * argv: Command line, used to update history comment.
480  * in_hdr: Input image header.
481  * outfile: The output file pointer.
482  * cflag: If non-zero, output image will be 0x0.
483  * Outputs:
484  * out_hdr: Updated from in_hdr.
485  */
486 static void
488 char **argv;
489 FILE *outfile;
490 rle_hdr *in_hdr, *out_hdr;
491 int cflag;
492 {
493  static int zero = 0;
494 
495  /* The output header starts out as a copy of the input header.
496  * The FILE pointer is different, of course.
497  * Also, this output image will have only one channel.
498  */
499  rle_hdr_cp( in_hdr, out_hdr );
500  out_hdr->rle_file = outfile;
501  out_hdr->ncolors = 1;
502  out_hdr->bg_color = &zero;
503  out_hdr->background = 2;
504 
505  if ( cflag )
506  out_hdr->xmin = out_hdr->xmax = out_hdr->ymin = out_hdr->ymax = 0;
507 
508  rle_addhist( argv, in_hdr, out_hdr );
509 
510  /* Since rle_getrow and rle_putrow use different array origins,
511  * we will compensate by adjusting the xmin and xmax values in
512  * the input header. [rle_getrow assumes that the scanline
513  * array starts at pixel 0, while rle_putrow assumes that the
514  * scanline array starts at pixel xmin. This is a botch, but
515  * it's too late to change it now.]
516  */
517  in_hdr->xmax -= in_hdr->xmin;
518  in_hdr->xmin = 0;
519 
520 }
521 
522 static void
525 rle_hdr *hdr;
526 unsigned long entries;
527 int dflag;
528 rle_pixel ***rows;
529 rle_pixel **red, **green, **blue, **alpha;
530 rle_pixel **img_red, **img_green, **img_blue;
531 {
532  /* Allocate memory into which the image scanlines can be read.
533  * This should happen after the above adjustment, to minimize
534  * the amount of memory allocated.
535  */
536  if ( rle_row_alloc( hdr, rows ) < 0 )
537  {
538  fprintf( stderr, "%s: Unable to allocate scanline memory.\n",
539  MY_NAME );
540  exit( RLE_NO_SPACE );
541  }
542 
543  /* Allocate image memory for prequantized image. */
544  CHECK_MALLOC( rle_pixel, *red, entries, "input image" );
545  if ( hdr->ncolors > 1 )
546  {
547  CHECK_MALLOC( rle_pixel, *green, entries, "input image" );
548  }
549  else
550  *green = *red;
551  if ( hdr->ncolors > 2 )
552  {
553  CHECK_MALLOC( rle_pixel, *blue, entries, "input image" );
554  }
555  else
556  *blue = *green;
557 
558  if ( hdr->alpha )
559  CHECK_MALLOC( rle_pixel, *alpha, entries, "input image" );
560 
561  if (dflag) {
562  /* Allocate image memory for original image to dither on. */
563  CHECK_MALLOC( rle_pixel, *img_red, entries, "dithered image" );
564  if ( hdr->ncolors > 1 )
565  {
566  CHECK_MALLOC( rle_pixel, *img_green, entries, "dithered image" );
567  }
568  else
569  *img_green = *img_red;
570  if ( hdr->ncolors > 2 )
571  {
572  CHECK_MALLOC( rle_pixel, *img_blue, entries, "dithered image" );
573  }
574  else
575  *img_blue = *img_green;
576  }
577 }
578 
579 static void
582 rle_hdr *hdr;
583 int width, shift, dflag;
584 rle_pixel *red, *green, *blue, *alpha;
585 rle_pixel *img_red, *img_green, *img_blue;
586 rle_pixel **rows;
587 {
588  register rle_pixel *rp, *gp, *bp, *ap;
589  register rle_pixel *irp = NULL, *igp = NULL, *ibp = NULL;
590  int x, y;
591 
592  /* Set traversal pointers. */
593  rp = red;
594  gp = green;
595  bp = blue;
596  ap = alpha;
597  if (dflag) {
598  irp = img_red;
599  igp = img_green;
600  ibp = img_blue;
601  }
602 
603  /* Read the input image and copy it to the output file. */
604  for ( y = hdr->ymin; y <= hdr->ymax; y++ )
605  {
606  /* Read a scanline. */
607  rle_getrow( hdr, rows );
608 
609  /* Prequantize the pixels. */
610  for ( x = 0; x < width; x++ )
611  {
612  *rp++ = Quantize( rows[0][x] );
613  if ( hdr->ncolors > 1 )
614  {
615  *gp++ = Quantize( rows[1][x] );
616  if ( hdr->ncolors > 2 )
617  *bp++ = Quantize( rows[2][x] );
618  }
619  if ( hdr->alpha )
620  *ap++ = rows[-1][x];
621  if (dflag) {
622  *irp++ = rows[0][x];
623  if ( hdr->ncolors > 1 )
624  {
625  *igp++ = rows[1][x];
626  if ( hdr->ncolors > 2 )
627  *ibp++ = rows[2][x];
628  }
629  }
630  }
631  }
632 }
633 
634 /* add_cube -- Add a "cube" of colors to the output colormap. */
635 static void
637 rle_pixel *colormap[3];
638 int colors, cubeside;
639 {
640  register int r, g, b, i;
641 
642  /* Fill in the rest of the colormap with a color cube, as requested. */
643  if ( cubeside > 1 )
644  for ( r = 0; r < cubeside; r++ )
645  for ( g = 0; g < cubeside; g++ )
646  for ( b = 0; b < cubeside; b++ )
647  {
648  i = colors + (r * cubeside + g) * cubeside + b;
649  colormap[0][i] = (r * 255) / (cubeside - 1);
650  colormap[1][i] = (g * 255) / (cubeside - 1);
651  colormap[2][i] = (b * 255) / (cubeside - 1);
652  }
653 }
654 
655 static void
657 rle_hdr *hdr;
658 int colors;
659 rle_pixel *colormap[3];
660 {
661  char *buf;
662  int x, y;
663 
664  CHECK_MALLOC( char, buf, 80, "comment buffer" );
665 
666  /* Give the output image a colormap. */
667  CHECK_MALLOC( rle_map, hdr->cmap, 3 * 256 * sizeof( rle_map ),
668  "output colormap" );
669  hdr->ncmap = 3;
670  hdr->cmaplen = 8;
671  for ( y = 0; y < 3; y++ )
672  {
673  for ( x = 0; x < colors; x++ )
674  hdr->cmap[y * 256 + x] = colormap[y][x] << 8;
675  for ( ; x < 256; x++ )
676  hdr->cmap[y * 256 + x] = 0;
677  }
678 
679  /* Add a comment to the output image with the true colormap length. */
680  sprintf( buf, "color_map_length=%d", colors );
681  rle_putcom( buf, hdr );
682 
683  /* Write the output image header. */
684  rle_put_setup( hdr );
685 
686 }
687 
688 static void
691 rle_hdr *hdr;
692 int width, height, bits, dflag;
693 rle_pixel *red, *green, *blue, *alpha;
694 rle_pixel *img_red, *img_green, *img_blue;
695 rle_pixel *rgbmap;
696 rle_pixel *colormap[3];
697 rle_pixel *outrows[2];
698 {
699  int shift = 8 - bits;
700  register rle_pixel *rp, *gp, *bp, *ap;
701  register rle_pixel *irp, *igp, *ibp;
702  int x, y;
703 
704  /* Allocate memory for the output scanline. */
705  CHECK_MALLOC( rle_pixel, outrows[1], width, "output scanline" );
706 
707  ap = alpha;
708  if (!dflag) {
709  /* Set traversal pointers. */
710  rp = red;
711  gp = green;
712  bp = blue;
713 
714  /* Write the output image. */
715  for ( y = 0; y < height; y++ )
716  {
717  /* Point to the correct data. */
718  if ( hdr->alpha )
719  {
720  outrows[0] = ap;
721  ap += width;
722  }
723  for ( x = 0; x < width; x++, rp++, gp++, bp++ )
724  outrows[1][x] = rgbmap[(((*rp<<bits)|*gp)<<bits)|*bp];
725 
726  rle_putrow( &outrows[1], width, hdr );
727  }
728  }
729  else {
730  register short *thisptr, *nextptr ;
731  int lastline, lastpixel ;
732  short *thisline, *nextline, *tmpptr;
733 
734  /* Set traversal pointers. */
735  irp = img_red;
736  igp = img_green;
737  ibp = img_blue;
738 
739  CHECK_MALLOC( short, thisline, width * 3 * sizeof(short),
740  "dither scanline" );
741  CHECK_MALLOC( short, nextline, width * 3 * sizeof(short),
742  "dither scanline" );
743  nextptr = nextline;
744  for (x=0; x < width; x++)
745  {
746  *nextptr++ = *irp++ ;
747  *nextptr++ = *igp++ ;
748  *nextptr++ = *ibp++ ;
749  }
750  for (y=0; y < height; y++)
751  {
752  /* swap nextline into thisline and copy new nextline */
753  tmpptr = thisline ;
754  thisline = nextline ;
755  nextline = tmpptr ;
756  lastline = (y == height - 1) ;
757  if (!lastline)
758  {
759  nextptr = nextline;
760  for (x=0; x < width; x++)
761  {
762  *nextptr++ = *irp++ ;
763  *nextptr++ = *igp++ ;
764  *nextptr++ = *ibp++ ;
765  }
766  }
767 
768  thisptr = thisline ;
769  nextptr = nextline ;
770 
771  for(x=0; x < width ; x++)
772  {
773  int rval, gval, bval, color ;
774  rle_pixel r2,g2,b2 ;
775 
776  lastpixel = (x == width - 1) ;
777 
778  rval = *thisptr++ ;
779  gval = *thisptr++ ;
780  bval = *thisptr++ ;
781 
782  /* Current pixel has been accumulating error, it could be
783  * out of range.
784  */
785  if( rval < 0 ) rval = 0 ;
786  else if( rval > 255 ) rval = 255 ;
787  if( gval < 0 ) gval = 0 ;
788  else if( gval > 255 ) gval = 255 ;
789  if( bval < 0 ) bval = 0 ;
790  else if( bval > 255 ) bval = 255 ;
791 
792  r2 = Quantize(rval);
793  g2 = Quantize(gval);
794  b2 = Quantize(bval);
795 
796  color = rgbmap[(((r2<<bits)|g2)<<bits)|b2];
797  outrows[1][x] = color;
798 
799  rval -= colormap[0][color];
800  gval -= colormap[1][color];
801  bval -= colormap[2][color];
802 
803  if( !lastpixel )
804  {
805  thisptr[0] += rval * 7 / 16 ;
806  thisptr[1] += gval * 7 / 16 ;
807  thisptr[2] += bval * 7 / 16 ;
808  }
809  if( !lastline )
810  {
811  if( x != 0 )
812  {
813  nextptr[-3] += rval * 3 / 16 ;
814  nextptr[-2] += gval * 3 / 16 ;
815  nextptr[-1] += bval * 3 / 16 ;
816  }
817  nextptr[0] += rval * 5 / 16 ;
818  nextptr[1] += gval * 5 / 16 ;
819  nextptr[2] += bval * 5 / 16 ;
820  if( !lastpixel )
821  {
822  nextptr[3] += rval / 16 ;
823  nextptr[4] += gval / 16 ;
824  nextptr[5] += bval / 16 ;
825  }
826  nextptr += 3 ;
827  }
828  }
829 
830  if ( hdr->alpha )
831  {
832  outrows[0] = ap;
833  ap += width;
834  }
835  rle_putrow( &outrows[1], width, hdr );
836  }
837  }
838 
839  /* Write an end-of-image code. */
840  rle_puteof( hdr );
841 }
842 
843 
844 static void
847 rle_hdr *hdr;
848 int dflag;
849 rle_pixel *red, *green, *blue, *alpha;
850 rle_pixel *img_red, *img_green, *img_blue;
851 rle_pixel **rows;
852 rle_pixel *outrows[2];
853 {
854  /* Free image store. */
855  free( red );
856  if ( hdr->ncolors > 1 )
857  {
858  free( green );
859  if ( hdr->ncolors > 2 )
860  free( blue );
861  }
862  if ( hdr->alpha )
863  free( alpha );
864  if (dflag) {
865  /* Free image store. */
866  free( img_red );
867  if ( hdr->ncolors > 1 )
868  {
869  free( img_green );
870  if ( hdr->ncolors > 2 )
871  free( img_blue );
872  }
873  }
874  /* Free the scanline memory. */
875  rle_row_free( hdr, rows );
876  free( outrows[1] );
877 }
FILE * rle_open_f(char *prog_name, char *file_name, char *mode)
Definition: rle_open_f.c:216
static void add_cube(colormap, int colors, int cubeside)
Definition: rlequant.c:636
char rcsid[]
Definition: rleswap.c:28
int xmin
Definition: rle.h:100
rle_hdr * rle_hdr_cp(rle_hdr *from_hdr, rle_hdr *to_hdr)
Definition: rle_hdr.c:119
#define NORMAL
Definition: rlequant.c:61
static void write_output(rle_hdr *hdr, int width, int height, int bits, int dflag, rle_pixel *red, rle_pixel *green, rle_pixel *blue, rle_pixel *alpha, rle_pixel *img_red, rle_pixel *img_green, rle_pixel *img_blue, rle_pixel *rgbmap, colormap, outrows)
Definition: rlequant.c:689
void rle_names(rle_hdr *the_hdr, const char *pgmname, const char *fname, int img_num)
Definition: rle_hdr.c:48
void rle_row_free(rle_hdr *the_hdr, rle_pixel **scanp)
Definition: rle_row_alc.c:114
#define RLE_EMPTY
Definition: rle.h:73
char * cmd_name(char **argv)
Definition: cmd_name.c:31
static const char * MY_NAME
Definition: rlequant.c:73
#define PROCESS_HIST
Definition: colorquant.c:240
void main(int argc, char **argv)
Definition: aliastorle.c:121
static void setup_output(rle_hdr *hdr, int colors, colormap)
Definition: rlequant.c:656
int rle_get_setup(rle_hdr *the_hdr)
Definition: rle_getrow.c:74
rle_map * cmap
Definition: rle.h:112
int rle_row_alloc(rle_hdr *the_hdr, rle_pixel ***scanp)
Definition: rle_row_alc.c:56
int rle_getrow(rle_hdr *the_hdr, scanline)
Definition: rle_getrow.c:333
int * bg_color
Definition: rle.h:100
#define RLE_SUCCESS
Definition: rle.h:70
#define Quantize(x)
Definition: rlequant.c:40
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
rle_pixel ** buildmap(rle_hdr *the_hdr, int minmap, double orig_gamma, double new_gamma)
Definition: buildmap.c:56
void rle_puteof(rle_hdr *the_hdr)
Definition: rle_putrow.c:474
void rle_putrow(rows, int rowlen, rle_hdr *the_hdr)
Definition: rle_putrow.c:96
int xmax
Definition: rle.h:100
int colorquant(unsigned char *red, unsigned char *green, unsigned char *blue, unsigned long pixels, colormap, int colors, int bits, unsigned char *rgbmap, int flags, int accum_hist)
Definition: colorquant.c:242
#define INIT_HIST
Definition: colorquant.c:238
static void copy_hdr(char **argv, rle_hdr *in_hdr, rle_hdr *out_hdr, FILE *outfile, int cflag)
Definition: rlequant.c:487
int state_t
Definition: rlequant.c:68
#define RLE_NO_SPACE
Definition: rle.h:72
#define RLE_EOF
Definition: rle.h:74
#define CONST_DECL
Definition: rle_config.h:42
void rle_addhist(argv, rle_hdr *in_hdr, rle_hdr *out_hdr)
Definition: rle_addhist.c:54
#define CHECK_MALLOC(type, ptr, size, desc)
Definition: rlequant.c:43
void inv_cmap(int colors, colormap, int bits, unsigned long *dist_buf,*rgbmap)
Definition: inv_cmap.c:214
#define OUTPUT
Definition: rlequant.c:67
void rle_get_setup_ok(rle_hdr *the_hdr, const char *prog_name, const char *file_name)
Definition: rle_getrow.c:254
char * rle_getcom(char *name, rle_hdr *the_hdr) const
Definition: rle_getcom.c:81
static void read_input(rle_hdr *hdr, int width, int shift, int dflag, rle_pixel *red, rle_pixel *green, rle_pixel *blue, rle_pixel *alpha, rle_pixel *img_red, rle_pixel *img_green, rle_pixel *img_blue, rle_pixel **rows)
Definition: rlequant.c:580
int background
Definition: rle.h:100
int ncmap
Definition: rle.h:100
int ymax
Definition: rle.h:100
#define CQ_NO_RGBMAP
Definition: colorquant.h:59
unsigned char rle_pixel
Definition: rle.h:56
void rle_put_setup(rle_hdr *the_hdr)
Definition: rle_putrow.c:453
const char * rle_putcom(char *value, rle_hdr *the_hdr) const
Definition: rle_putcom.c:82
int cmaplen
Definition: rle.h:100
int alpha
Definition: rle.h:100
static void mem_alloc(rle_hdr *hdr, unsigned long entries, int dflag, rle_pixel ***rows, rle_pixel **red, rle_pixel **green, rle_pixel **blue, rle_pixel **alpha, rle_pixel **img_red, rle_pixel **img_green, rle_pixel **img_blue)
Definition: rlequant.c:523
unsigned short rle_map
Definition: rle.h:57
static void free_mem(rle_hdr *hdr, int dflag, rle_pixel *red, rle_pixel *green, rle_pixel *blue, rle_pixel *alpha, rle_pixel *img_red, rle_pixel *img_green, rle_pixel *img_blue, rle_pixel **rows, outrows)
Definition: rlequant.c:845
rle_hdr * rle_hdr_init(rle_hdr *the_hdr)
Definition: rle_hdr.c:267
#define USE_HIST
Definition: colorquant.c:239
FILE * rle_file
Definition: rle.h:114
int ncolors
Definition: rle.h:100