DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦1a79f68e3⟧ TextFile

    Length: 10877 (0x2a7d)
    Types: TextFile
    Names: »gxht.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »gxht.c« 

TextFile

/* Copyright (C) 1989 Aladdin Enterprises.  All rights reserved.
   Distributed by Free Software Foundation, Inc.

This file is part of Ghostscript.

Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing.  Refer
to the Ghostscript General Public License for full details.

Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License.  A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities.  It should be in a file named COPYING.  Among other
things, the copyright notice and this notice must be preserved on all
copies.  */

/* gxht.c */
/* Halftone rendering routines for GhostScript imaging library */
#include "gx.h"
#include "gserrors.h"
#include "gxfixed.h"			/* ditto */
#include "gxmatrix.h"			/* for gxdevice.h */
#include "gxbitmap.h"
#include "gzstate.h"
#include "gzdevice.h"
#include "gzcolor.h"			/* requires gxdevice.h */
#include "gzhalfto.h"

/* We cache the rendering of one gray level for one screen. */
/* The screen is identified by its whitening order vector. */
typedef struct gx_ht_cache_s ht_cache;
struct gx_ht_cache_s {
	int level;			/* the cached gray level, i.e. */
					/* the number of spots whitened, */
					/* or -1 if the cache is empty */
	ht_bit *order;			/* the cached order vector */
	int max_height;			/* the maximum height */
	gx_bitmap tile;		/* the currently rendered tile */
};
private ht_cache cache;
#define max_ht_cache 200
private byte cache_bits[max_ht_cache];
/* Bit masks for whitening vector.  We have to initialize these */
/* indirectly, because they are different for big- and little-endian */
/* machines. */
typedef unsigned short bit16;
private byte single_bits8[16*2] =
   {	0x80,0, 0x40,0, 0x20,0, 0x10,0, 8,0, 4,0, 2,0, 1,0,
	0,0x80, 0,0x40, 0,0x20, 0,0x10, 0,8, 0,4, 0,2, 0,1
   };
private bit16 *single_bits = (bit16 *)single_bits8;
private byte mb1[2] =
   {	0xff,0xff };
private byte mb2[4] =
   {	0xaa,0xaa, 0x55,0x55 };
private byte mb3[6] =
   {	0x92,0x49, 0x49,0x24, 0x24,0x92 };
private byte mb4[8] =
   {	0x88,0x88, 0x44,0x44, 0x22,0x22, 0x11,0x11 };
private byte mb5[10] =
   {	0x84,0x21, 0x42,0x10, 0x21,0x08, 0x10,0x84, 0x08,0x42 };
private byte mb6[12] =
   {	0x82,0x08, 0x41,0x04, 0x20,0x82, 0x10,0x41, 0x08,0x20, 0x04,0x10 };
private byte mb7[14] =
   {	0x81,0x02, 0x40,0x81, 0x20,0x40, 0x10,0x20, 0x08,0x10, 0x04,0x08,
		0x02,0x04
   };
private byte mb8[16] =
   {	0x80,0x80, 0x40,0x40, 0x20,0x20, 0x10,0x10, 0x08,0x08, 0x04,0x04,
		0x02,0x02, 0x01,0x01
   };
private bit16 *multi_bits[9] =
   {	0, (bit16 *)mb1, (bit16 *)mb2, (bit16 *)mb3, (bit16 *)mb4,
	(bit16 *)mb5, (bit16 *)mb6, (bit16 *)mb7, (bit16 *)mb8
   };

/* Construct the order vector.  order is an array of ht_bits: */
/* order[i].offset contains the index of the bit position */
/* that is i'th in the whitening order. */
int
gx_ht_construct_order(ht_bit *order, int width, int height)
{	uint i;
	uint size = (uint)(width * height);
	int padding = (-width) & 15;
	if ( (width + padding) / 8 * height > max_ht_cache )
		return_error(gs_error_limitcheck);	/* can't cache the rendering */
	/* Initialize the halftone machinery. */
	/* We should really only do this once, at startup, */
	/* but it does no harm to do it now, and it's easier */
	/* than requiring a separate call. */
	cache.level = -1;
	cache.tile.data = cache_bits;
	/* Convert sequential indices to */
	/* byte indices and mask values. */
	for ( i = 0; i < size; i++ )
	   {	int pix = order[i].offset;
		pix += pix / width * padding;
		order[i].offset = (pix >> 4) << 1;
		order[i].mask =
			(width <= 8 ?
			 multi_bits[width][pix & 15] :
			 single_bits[pix & 15]);
	   }
#ifdef DEBUG
if ( gs_debug['h'] )
	   {	printf("[h]Halftone order %lx:\n", (ulong)order);
		for ( i = 0; i < size; i++ )
			printf("%4d: %u:%x\n", i, order[i].offset,
				order[i].mask);
	   }
#endif
	return 0;
}

/* Compute the device color for drawing */
void
gx_color_render(gs_color *pcolor, gs_state *pgs)
{	device *pdev = pgs->device;
	gx_device *dev = pdev->info;
	if ( !pcolor->saturation )	/* monochrome */
	  switch ( pcolor->brightness )
	    {
	    case 0:
	      pcolor->dev_color.color2 = pcolor->dev_color.color1 = pdev->black;
	      pcolor->dev_color.halftone_level = 0;	/* pure color */
	      return;
	    case max_color_param:
	      pcolor->dev_color.color2 = pcolor->dev_color.color1 = pdev->white;
	      pcolor->dev_color.halftone_level = 0;	/* pure color */
	      return;
	    }
	{ unsigned long max_value = dev->max_rgb_value;
	  unsigned short dev_rgb[3];
	  /* We divide each color axis into K*N+1 buckets, */
	  /* where K is the number of distinguishable device colors */
	  /* and N is the number of pixels in the halftone screen. */
	  int hsize = pgs->halftone->order_size;
	  unsigned long modulus = hsize * max_value;
	  unsigned long want_r, want_g, want_b;
	  unsigned short r, g, b;
	  unsigned short rem_r, rem_g, rem_b;
	  want_r = (pcolor->red * modulus + max_color_param / 2) / max_color_param;
	  r = want_r / hsize;
	  rem_r = want_r % hsize;
	  if ( pcolor->saturation )
	    { want_g = (pcolor->green * modulus + max_color_param / 2) / max_color_param;
	      g = want_g / hsize;
	      rem_g = want_g % hsize;
	      want_b = (pcolor->blue * modulus + max_color_param / 2) / max_color_param;
	      b = want_b / hsize;
	      rem_b = want_b % hsize;
	    }
	  else
	    want_g = want_b = want_r,
	    g = b = r,
	    rem_g = rem_g = rem_r;
	  /* Get the device's approximation to the right color. */
	  pcolor->dev_color.color1 = (*dev->procs->map_rgb_color)(dev, r, g, b);
	  /* Compare the actual values against the desired ones. */
	  /* If they are the same to within the modulus, */
	  /* we can't do better using a halftone. */
	  (*dev->procs->map_color_rgb)(dev, pcolor->dev_color.color1, dev_rgb);
#ifdef DEBUG
if ( gs_debug['c'] )
	   {	printf("[c]%u,%u,%u ->(dev) %u,%u,%u -> %ld ->\n",
			pcolor->red, pcolor->green, pcolor->blue,
			r, g, b, (long)pcolor->dev_color.color1);
		printf("    (dev) %u,%u,%u; want %ld,%ld,%ld\n",
			dev_rgb[0], dev_rgb[1], dev_rgb[2],
			want_r, want_g, want_b);
	   }
		
#endif
	  if ( r == dev_rgb[0] && rem_r == 0 &&
	      (!pcolor->saturation ||
		g == dev_rgb[1] && rem_g == 0 &&
		b == dev_rgb[2] && rem_b == 0) )
	    { /* No halftone needed, thank goodness. */
	      pcolor->dev_color.color2 = pcolor->dev_color.color1;
	      pcolor->dev_color.halftone_level = 0;	/* pure color */
	      return;
	    }
	  /* Must use halftone.  The following is a pretty feeble */
	  /* attempt at color halftoning.  It only works for */
	  /* monochrome and gray level, with a device that always */
	  /* returns a color that exactly matches the request. */
	  { int level = rem_r;
	    int other_r, other_g, other_b;
#define compute_other(other_c, c, index)\
    other_c = 2 * c + 1 - dev_rgb[index];\
    if ( other_c < 0 ) other_c = 0;\
    else if ( other_c > max_value ) other_c = max_value
	    compute_other(other_r, r, 0);
	    if ( pcolor->saturation )
	      { compute_other(other_g, g, 1);
		compute_other(other_b, b, 2);
		if ( level == 0 ) level = rem_g;
		if ( level == 0 ) level = rem_b;
	      }
	    else
	      other_g = other_b = other_r;
	    pcolor->dev_color.color2 = (*dev->procs->map_rgb_color)(dev, other_r, other_g, other_b);	/* the lighter color */
	    pcolor->dev_color.halftone_level = level;
	    /* Load the rendering cache if needed */
	     { void gx_color_load(P2(gx_device_color *, gs_state *));
	       gx_color_load(&pcolor->dev_color, pgs);
	     }
	  }
	}
}

/* Load the device color into the halftone cache if needed. */
private void render_ht(P3(ht_cache *, int, halftone *));
void
gx_color_load(register gx_device_color *pdevc, gs_state *pgs)
{	int level = pdevc->halftone_level;
	halftone *pht;
	if ( level == 0 ) return;	/* no halftone */
	pht = pgs->halftone;
	if ( cache.level != level || cache.order != pht->order )
	 { ht_bit *order = pht->order;
	   if ( order != cache.order ) cache.level = -1;	/* discard old bits */
	   render_ht(&cache, level, pht);
	 }
	pdevc->tile = &cache.tile;
}

/* Compute and save the rendering of a given gray level */
/* with the current halftone.  We do this for the entire cell, */
/* on the grounds that if we are filling areas much smaller */
/* than one cell, the cell size is probably set wrong. */
/* If the cache is already loaded, we adjust it incrementally: */
/* this saves a lot of time for the average image, where */
/* gray levels don't change abruptly. */
/* Note that we will never be asked to cache levels 0 or order_size, */
/* which correspond to black or white respectively. */
private void
render_ht(ht_cache *pcache, int level /* [1..order_size-1] */, halftone *pht)
{	ht_bit *order = pcache->order;
	register ht_bit *oldp;
	register ht_bit *newp;
	register byte *bits = pcache->tile.data;
	pcache->tile.height = pht->height;	/* in case it was expanded */
	if ( pcache->level < 0 )
	   {	/* The cache is empty.  Preload it with */
		/* whichever of all-0s and all-1s will be faster. */
		uint bits_size;
		static int up_to_16[] =
			/* up_to_16[i] = 16 / i * i */
			{ 0, 16, 16, 15, 16, 15, 12, 14, 16 };
		int width_unit = (pht->width <= 8 ? up_to_16[pht->width] : pht->width);
		pcache->tile.width = width_unit;
		pcache->tile.raster = ((pcache->tile.width + 15) >> 4) << 1;
		pcache->max_height = max_ht_cache / pcache->tile.raster;
		bits_size = pcache->tile.raster * pcache->tile.height;
		order = pht->order;
		pcache->order = order;
		if ( level >= pht->order_size >> 1 )
		   {	pcache->level = pht->order_size;
			memset(bits, 0xff, bits_size);
		   }
		else
		   {	pcache->level = 0;
			memset(bits, 0, bits_size);
		   }
	   }
	newp = &order[level];
	oldp = &order[pcache->level];
	if ( level > pcache->level )
	   {	/* New level is lighter, turn on bits. */
		do
		   {	*(bit16 *)&bits[oldp->offset] += oldp->mask;
		   }
		while ( ++oldp != newp );
	   }
	else
	   {	/* New level is darker, turn off bits. */
		do
		   {	*(bit16 *)&bits[newp->offset] -= newp->mask;
		   }
		while ( oldp != ++newp );
	   }
#ifdef DEBUG
if ( gs_debug['h'] )
	   {	byte *p = bits;
		int wb = pcache->tile.raster;
		byte *ptr = bits + wb * pcache->tile.height;
		printf("[h]Halftone cache %lx: old=%d, new=%d, w=%d(%d), h=%d(%d):\n",
			(ulong)bits, pcache->level, level, pcache->tile.width,
		        pht->width, pcache->tile.height, pht->height);
		while ( p < ptr )
		   {	printf(" %02x", *p++);
			if ( (p - bits) % wb == 0 ) printf("\n");
		   }
	   }
#endif
	pcache->level = level;
	pcache->order = order;
}