#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	dispdfse.c (Display Error Diffusion)
 * Purpose:	Map 16 bit data to a single plane bitmap using error diffusion
 * Subroutine:	diffuse_sample()		returns: void
 * Subroutine:	diffuse_replicate()		returns: void
 * Xlib calls:	none
 * Copyright:	1989 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * History:	Algorithm from Bill Wyatt's linodots & John Tonry's halftone
 * Modified:	{0} Michael VanHilst	initial version	         7 July 1987
 *		{1} MVH fixed zoom rep code			21 June 1991
 *		{n} <who> -- <does what> -- <when>
 */

/*
 * Subroutine:	diffuse_sample
 * Purpose:	Perform subsampling and error diffusion to produce a bitmap
 *		image from 16 bit signed data through a scaling lookup table.
 *		Used when bitmap is same size or smaller than data image.
 * Method:	Sample every zoom'th data element in each direction
 */
void diffuse_sample ( short_data, data_width, zoom, bitmap, bytes_per_line,
		      x, y, width, height, lookup, errbuf, inverse )
     short *short_data;
     int data_width;
     int zoom;
     char *bitmap;
     int bytes_per_line;
     int x, y, width, height;
     register unsigned char *lookup;
     short *errbuf;
     int inverse;
{
  register int val;
  register short *error;
  register short *data;
  register char *bitmap_byte;
  register int maxval;
  char *bitmap_row;
  short *data_row;
  short *data_row_end;
  short error0;
  short bitmap_bit;
  short bitmap_first_bit;
  short x_step, y_step;
  short i;

  data_row = short_data;
  bitmap_row = bitmap + (y * bytes_per_line) + (x / 8);
  bitmap_first_bit = x & 7;	/* same as %8 */
  /* halftone standard of 256 levels */
  maxval = 256;
  error0 = 0;
  /* subsample line skipping */
  x_step = zoom;
  y_step = data_width * zoom;
  if( inverse ) {
    /* go through each row of the bitmap */
    for( i = 0; i < height; i++ ) {
      error = errbuf;
      data = data_row;
      data_row_end = data + width;
      bitmap_byte = bitmap_row;
      bitmap_bit = bitmap_first_bit;
      while( data < data_row_end ) {
	/* val is data value plus average of error remnants */
	val = lookup[*data] + ((*error + error0 + error[1] + error[2]) >> 2);
	/* save earlier error */
	error0 = *(++error);
	/* replace old error with this error */
	if( val < maxval ) {
	  *bitmap_byte |= 1 << bitmap_bit;
	  *error = val;
	} else
	  *error = val - maxval;
	data += x_step;
	/* update word and bit pointers */
	if( ++bitmap_bit > 7 ) {
	  bitmap_byte++;
	  bitmap_bit = 0;
	}
      }
      data_row += y_step;
      /* advance to next line in bitmap_byte */
      bitmap_row += bytes_per_line;
    }
  } else {
    /* go through each row of the bitmap */
    for( i = 0; i < height; i++ ) {
      error = errbuf;
      data = data_row;
      data_row_end = data + width;
      bitmap_byte = bitmap_row;
      bitmap_bit = bitmap_first_bit;
      while( data < data_row_end ) {
	/* val is data value plus average of error remnants */
	val = lookup[*data] + ((*error + error0 + error[1] + error[2]) >> 2);
	/* save earlier error */
	error0 = *(++error);
	/* replace old error with this error */
	if( val >= maxval ) {
	  *bitmap_byte |= 1 << bitmap_bit;
	  *error = val - maxval;
	} else
	  *error = val;
	data += x_step;
	/* update word and bit pointers */
	if( ++bitmap_bit > 7 ) {
	  bitmap_byte++;
	  bitmap_bit = 0;
	}
      }
      data_row += y_step;
      /* advance to next line in bitmap_byte */
      bitmap_row += bytes_per_line;
    }
  }
}

/*
 * Subroutine:	diffuse_replicate
 * Purpose:	Perform replication and error diffusion to produce a bitmap
 *		image from 16 bit signed data through a scaling lookup table.
 *		Used when bitmap is larger than data image.
 * Method:	Repeat data element zoom times in each direction
 */
void diffuse_replicate ( short_data, data_width, zoom, bitmap, bytes_per_line,
			 first_x_rep, first_y_rep, x, y, width, height,
			 lookup, errbuf, inverse )
     short *short_data;
     int data_width;
     int zoom;
     char *bitmap;
     int bytes_per_line;
     int first_x_rep;
     int first_y_rep;
     int x, y, width, height;
     register unsigned char *lookup;
     short *errbuf;
     int inverse;
{
  register int val;
  register short *error;
  register short *data;
  register char *bitmap_byte;
  register int maxval;
  short *data_row;
  char *bitmap_row;
  char *bitmap_row_end;
  int error0;
  int bitmap_bit;
  int bitmap_first_bit;
  int bitmap_last_bit;
  int bitmap_bytes_per_row;
  int x_step, y_step;
  int i;

  data_row = short_data;
  bitmap_row = bitmap + (y * bytes_per_line) + (x / 8);
  bitmap_first_bit = x & 7;	/* same as %8 */
  bitmap_last_bit = (width + bitmap_first_bit - 1) & 7;
  bitmap_bytes_per_row = (x + width + 7) / 8;
  if( bitmap_bytes_per_row >= bytes_per_line )
    bitmap_bytes_per_row = bytes_per_line - ((x / 8) + 1);
  else
    bitmap_bytes_per_row -= ((x / 8) + 1);
  /* halftone standard of 256 levels */
  maxval = 256;
  error0 = 0;
  /* convert first rep to first step toward zoom reps */
  y_step = 1 + zoom - first_y_rep;
  first_x_rep = 1 + zoom - first_x_rep;
  if( inverse ) {
    /* go through each row of the bitmap */
    for( i = 0; i < height; i++ ) {
      error = errbuf;
      x_step = first_x_rep;
      data = data_row;
      bitmap_byte = bitmap_row;
      bitmap_row_end = bitmap_byte + bitmap_bytes_per_row;
      bitmap_bit = bitmap_first_bit;
      while( (bitmap_byte < bitmap_row_end) ||
	     ((bitmap_byte == bitmap_row_end) &&
	      (bitmap_bit <= bitmap_last_bit)) ) {
	/* val is data value plus average of error remnants */
	val = lookup[*data] + ((*error + error0 + error[1] + error[2]) >> 2);
	/* save earlier error */
	error0 = *(++error);
	/* replace old error with this error */
	if( val < maxval ) {
	  *bitmap_byte |= 1 << bitmap_bit;
	  *error = val;
	} else
	  *error = val - maxval;
	if( ++bitmap_bit > 7 ) {
	  bitmap_byte++;
	  bitmap_bit = 0;
	}
	/* step forward after replication */
	if( ++x_step > zoom ) {
	  data++;
	  x_step = 1;
	}
      }
      /* advance one line after replication, else repeat this line */
      if( ++y_step > zoom ) {
	data_row += data_width;
	y_step = 1;
      }
      bitmap_row += bytes_per_line;
    }
  } else {
    /* go through each row of the bitmap */
    for( i = 0; i < height; i++ ) {
      error = errbuf;
      x_step = first_x_rep;
      data = data_row;
      bitmap_byte = bitmap_row;
      bitmap_row_end = bitmap_byte + bitmap_bytes_per_row;
      bitmap_bit = bitmap_first_bit;
      while( (bitmap_byte < bitmap_row_end) ||
	     ((bitmap_byte == bitmap_row_end) &&
	      (bitmap_bit <= bitmap_last_bit)) ) {
	/* val is data value plus average of error remnants */
	val = lookup[*data] + ((*error + error0 + error[1] + error[2]) >> 2);
	/* save earlier error */
	error0 = *(++error);
	/* replace old error with this error */
	if( val >= maxval ) {
	  *bitmap_byte |= 1 << bitmap_bit;
	  *error = val - maxval;
	} else
	  *error = val;
	if( ++bitmap_bit > 7 ) {
	  bitmap_byte++;
	  bitmap_bit = 0;
	}
	/* step forward after replication */
	if( ++x_step > zoom ) {
	  data++;
	  x_step = 1;
	}
      }
      /* advance one line after replication, else repeat this line */
      if( ++y_step > zoom ) {
	data_row += data_width;
	y_step = 1;
      }
      bitmap_row += bytes_per_line;
    }
  }
}


syntax highlighted by Code2HTML, v. 0.9.1