blob: e2e14d06369f524233ca073cd9b81ed21d1334d2 [file] [log] [blame]
/* Copyright (C) 1989, 1990 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 "memory_.h"
#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 "gzht.h"
/*
* We don't want to remember all the values of the halftone screen,
* because they would take up space proportional to P^3, where P is
* the number of pixels in a cell. Instead, we pick some number N of
* patterns to cache. Each cache slot covers a range of (P+1)/N
* different gray levels: we "slide" the contents of the slot back and
* forth within this range by incrementally adding and dropping 1-bits.
* N>=0 (obviously); N<=P+1 (likewise); also, so that we can simplify things
* by preallocating the bookkeeping information for the cache, we define
* a constant max_cached_tiles which is an a priori maximum value for N.
*
* Note that the raster for each tile must be a multiple of 32 bits,
* to satisfy the copy_mono device routine, even though a multiple of
* 16 bits would otherwise be sufficient.
*/
#define max_cached_tiles 25
typedef struct bit_tile_s {
int level; /* the cached gray level, i.e. */
/* the number of spots whitened, */
/* or -1 if the cache is empty */
gx_bitmap tile; /* the currently rendered tile */
} bit_tile;
typedef struct gx_ht_cache_s {
/* The following are set when the cache is created. */
byte *bits; /* the base of the bits */
uint bits_size; /* the space available for bits */
/* The following are reset each time the cache is initialized */
/* for a new screen. */
ht_bit *order; /* the cached order vector */
int num_cached; /* actual # of cached tiles */
int levels_per_tile; /* # of levels per cached tile */
bit_tile tiles[max_cached_tiles]; /* the cached tiles */
} ht_cache;
private ht_cache cache;
#define max_ht_bits 1000 /* arbitrary, maybe too small */
private byte cache_bits[max_ht_bits];
/* 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
};
#define 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) & 31;
if ( (width + padding) / 8 * height > max_ht_bits )
return_error(gs_error_limitcheck); /* can't cache the rendering */
/* Clear the cache, to avoid confusion in case */
/* the address of a new order vector matches that of a */
/* (deallocated) old one. */
cache.order = NULL;
cache.bits = cache_bits;
cache.bits_size = max_ht_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;
}
/* Load the device color into the halftone cache if needed. */
private void render_ht(P3(bit_tile *, int, halftone *));
private void init_ht(P2(ht_cache *, halftone *));
void
gx_color_load(register gx_device_color *pdevc, gs_state *pgs)
{ int level = pdevc->halftone_level;
halftone *pht;
bit_tile *bt;
if ( level == 0 ) return; /* no halftone */
pht = pgs->halftone;
if ( cache.order != pht->order )
init_ht(&cache, pht);
bt = &cache.tiles[level / cache.levels_per_tile];
if ( bt->level != level )
render_ht(bt, level, pht);
pdevc->tile = &bt->tile;
}
/* Initialize the tile cache for a given screen. */
/* Cache as many different levels as will fit. */
private void
init_ht(ht_cache *pcache, halftone *pht)
{ int width = pht->width;
int height = pht->height;
int size = width * height;
static int up_to_16[] =
/* up_to_16[i] = 16 / i * i */
{ 0, 16, 16, 15, 16, 15, 12, 14, 16 };
int width_unit = (width <= 8 ? up_to_16[width] : width);
uint raster = ((width + 31) >> 5) << 2;
uint tile_bytes = raster * height;
int num_cached;
int i;
byte *tbits = pcache->bits;
/* Make sure num_cached is within bounds */
num_cached = max_ht_bits / tile_bytes;
if ( num_cached > size ) num_cached = size;
if ( num_cached > max_cached_tiles ) num_cached = max_cached_tiles;
for ( i = 0; i < num_cached; i++ )
{ register bit_tile *bt = &pcache->tiles[i];
bt->level = -1;
bt->tile.data = tbits;
bt->tile.raster = raster;
bt->tile.width = width_unit;
bt->tile.height = height;
tbits += tile_bytes;
}
pcache->order = pht->order;
pcache->num_cached = num_cached;
pcache->levels_per_tile = (size + num_cached - 1) / num_cached;
}
/*
* Compute and save the rendering of a given gray level
* with the current halftone. The cache holds multiple tiles,
* where each tile covers a range of possible levels.
* If the tile whose range includes the desired level 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(bit_tile *pbt, int level /* [1..order_size-1] */, halftone *pht)
{ ht_bit *order = pht->order;
register ht_bit *p;
register ht_bit *endp;
register byte *bits = pbt->tile.data;
int old_level = pbt->level;
if ( old_level < 0 )
{ /* The cache is empty. Preload it with */
/* whichever of all-0s and all-1s will be faster. */
uint tile_bytes = pbt->tile.raster * pbt->tile.height;
if ( level >= pht->order_size >> 1 )
{ old_level = pht->order_size;
memset(bits, 0xff, tile_bytes);
}
else
{ old_level = 0;
memset(bits, 0, tile_bytes);
}
}
#ifdef DEBUG
if ( level < 0 || level > pht->order_size || level == old_level )
{ dprintf3("Error in render_ht: level=%d, old_level=%d, order_size=%d=n", level, old_level, pht->order_size);
exit(1);
}
#endif
/* Note that we can use the same loop to turn bits either */
/* on or off, using xor. We use < to compare pointers, */
/* rather than ==, because Turbo C only compares the */
/* low 16 bits for < and > but compares all 32 bits for ==. */
if ( level > old_level )
p = &order[old_level], endp = &order[level];
else
p = &order[level], endp = &order[old_level];
/* Invert bits between the two pointers */
do
{ *(bit16 *)&bits[p->offset] ^= p->mask;
}
while ( ++p < endp );
#ifdef DEBUG
if ( gs_debug['h'] )
{ byte *p = bits;
int wb = pbt->tile.raster;
byte *ptr = bits + wb * pbt->tile.height;
printf("[h]Halftone cache %lx: old=%d, new=%d, w=%d(%d), h=%d(%d):\n",
(ulong)bits, old_level, level, pbt->tile.width,
pht->width, pbt->tile.height, pht->height);
while ( p < ptr )
{ printf(" %02x", *p++);
if ( (p - bits) % wb == 0 ) printf("\n");
}
}
#endif
pbt->level = level;
}