/* Copyright (C) 1993, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gxcht.c,v 1.3.2.1.2.1 2003/01/17 00:49:03 giles Exp $ */ /* Color halftone rendering for Ghostscript imaging library */ #include "memory_.h" #include "gx.h" #include "gserrors.h" #include "gsutil.h" /* for id generation */ #include "gxarith.h" #include "gxfixed.h" #include "gxmatrix.h" #include "gxdevice.h" #include "gxcmap.h" #include "gxdcolor.h" #include "gxistate.h" #include "gzht.h" /* Define whether to force use of the slow code, for testing. */ #define USE_SLOW_CODE 0 /* Define the size of the tile buffer allocated on the stack. */ #define tile_longs_LARGE 256 #define tile_longs_SMALL 64 #if arch_small_memory # define tile_longs_allocated tile_longs_SMALL # define tile_longs tile_longs_SMALL #else # define tile_longs_allocated tile_longs_LARGE # ifdef DEBUG # define tile_longs\ (gs_debug_c('.') ? tile_longs_SMALL : tile_longs_LARGE) # else # define tile_longs tile_longs_LARGE # endif #endif /* Define the colored halftone device color type. */ gs_private_st_ptrs1(st_dc_ht_colored, gx_device_color, "dc_ht_colored", dc_ht_colored_enum_ptrs, dc_ht_colored_reloc_ptrs, colors.colored.c_ht); private dev_color_proc_load(gx_dc_ht_colored_load); private dev_color_proc_fill_rectangle(gx_dc_ht_colored_fill_rectangle); private dev_color_proc_equal(gx_dc_ht_colored_equal); const gx_device_color_type_t gx_dc_type_data_ht_colored = { &st_dc_ht_colored, gx_dc_ht_colored_load, gx_dc_ht_colored_fill_rectangle, gx_dc_default_fill_masked, gx_dc_ht_colored_equal }; #undef gx_dc_type_ht_colored const gx_device_color_type_t *const gx_dc_type_ht_colored = &gx_dc_type_data_ht_colored; #define gx_dc_type_ht_colored (&gx_dc_type_data_ht_colored) /* Compare two colored halftones for equality. */ private bool gx_dc_ht_colored_equal(const gx_device_color * pdevc1, const gx_device_color * pdevc2) { uint num_comp, m, i; if (pdevc2->type != pdevc1->type || pdevc1->colors.colored.c_ht != pdevc2->colors.colored.c_ht || pdevc1->colors.colored.alpha != pdevc2->colors.colored.alpha || pdevc1->colors.colored.plane_mask != pdevc2->colors.colored.plane_mask || pdevc1->phase.x != pdevc2->phase.x || pdevc1->phase.y != pdevc2->phase.y ) return false; for (m = pdevc1->colors.colored.plane_mask, i = 0; m != 0; m >>=1, i++) if(m & 1) if (pdevc1->colors.colored.c_base[i] != pdevc2->colors.colored.c_base[i] || pdevc1->colors.colored.c_level[i] != pdevc2->colors.colored.c_level[i]) return false; } /* Define an abbreviation for a heavily used value. */ #define MAX_DCC GX_DEVICE_COLOR_MAX_COMPONENTS /* Forward references. */ /* Use a typedef to attempt to work around overly picky compilers. */ typedef gx_color_value gx_color_value_array[MAX_DCC]; typedef struct color_values_pair_s { gx_color_value_array values[2]; } color_values_pair_t; #define SET_HT_COLORS_PROC(proc)\ int proc(P7(\ color_values_pair_t *pvp,\ gx_color_index colors[1 << MAX_DCC],\ const gx_const_strip_bitmap *sbits[MAX_DCC],\ const gx_device_color *pdevc,\ gx_device *dev,\ gx_ht_cache *caches[MAX_DCC],\ int nplanes\ )) private SET_HT_COLORS_PROC(set_ht_colors_le_4); private SET_HT_COLORS_PROC(set_cmyk_1bit_colors); private SET_HT_COLORS_PROC(set_ht_colors_gt_4); #define SET_COLOR_HT_PROC(proc)\ void proc(P14(\ byte *dest_data, /* the output tile */\ uint dest_raster, /* ibid. */\ int px, /* the initial phase of the output tile */\ int py,\ int w, /* how much of the tile to set */\ int h,\ int depth, /* depth of tile (4, 8, 16, 24, 32) */\ int special, /* >0 means special 1-bit CMYK */\ int nplanes,\ gx_color_index plane_mask, /* which planes are halftoned */\ gx_device *dev, /* in case we are mapping lazily */\ const color_values_pair_t *pvp, /* color values ditto */\ gx_color_index colors[1 << MAX_DCC], /* the actual colors for the tile, */\ /* actually [1 << nplanes] */\ const gx_const_strip_bitmap * sbits[MAX_DCC] /* the bitmaps for the planes, */\ /* actually [nplanes] */\ )) private SET_COLOR_HT_PROC(set_color_ht_le_4); private SET_COLOR_HT_PROC(set_color_ht_gt_4); /* Prepare to use a colored halftone, by loading the default cache. */ private int gx_dc_ht_colored_load(gx_device_color * pdevc, const gs_imager_state * pis, gx_device * ignore_dev, gs_color_select_t select) { gx_device_halftone *pdht = pdevc->colors.colored.c_ht; gx_ht_cache *pcache = pis->ht_cache; gx_ht_order *porder = (pdht->components ? &pdht->components[0].corder : &pdht->order); if (pcache->order.bit_data != porder->bit_data) gx_ht_init_cache(pcache, porder); /* Set the cache pointers in the default order. */ pdht->order.cache = porder->cache = pcache; return 0; } /* Fill a rectangle with a colored halftone. */ /* Note that we treat this as "texture" for RasterOp. */ private int gx_dc_ht_colored_fill_rectangle(const gx_device_color * pdevc, int x, int y, int w, int h, gx_device * dev, gs_logical_operation_t lop, const gx_rop_source_t * source) { ulong tbits[tile_longs_allocated]; const uint tile_bytes = tile_longs * size_of(long); gx_strip_bitmap tiles; gx_rop_source_t no_source; const gx_device_halftone *pdht = pdevc->colors.colored.c_ht; int depth = dev->color_info.depth; int nplanes = dev->color_info.num_components; SET_HT_COLORS_PROC((*set_ht_colors)) = ( #if USE_SLOW_CODE set_ht_colors_gt_4 #else dev_proc(dev, map_cmyk_color) == cmyk_1bit_map_cmyk_color ? set_cmyk_1bit_colors : nplanes < 4 ? set_ht_colors_le_4 : set_ht_colors_gt_4 #endif ); SET_COLOR_HT_PROC((*set_color_ht)) = ( #if !USE_SLOW_CODE !(pdevc->colors.colored.plane_mask & ~(gx_color_index)15) && set_ht_colors != set_ht_colors_gt_4 ? set_color_ht_le_4 : #endif set_color_ht_gt_4); color_values_pair_t vp; gx_color_index colors[1 << MAX_DCC]; const gx_const_strip_bitmap *sbits[MAX_DCC]; gx_ht_cache *caches[MAX_DCC]; int special; int code = 0; int raster; uint size_x; int dw, dh; int lw = pdht->lcm_width, lh = pdht->lcm_height; bool no_rop; int i; if (w <= 0 || h <= 0) return 0; if ((w | h) >= 16) { /* It's worth taking the trouble to check the clipping box. */ gs_fixed_rect cbox; int t; dev_proc(dev, get_clipping_box)(dev, &cbox); if ((t = fixed2int(cbox.p.x)) > x) { if ((w += x - t) <= 0) return 0; x = t; } if ((t = fixed2int(cbox.p.y)) > y) { if ((h += y - t) <= 0) return 0; y = t; } if ((t = fixed2int(cbox.q.x)) < x + w) if ((w = t - x) <= 0) return 0; if ((t = fixed2int(cbox.q.y)) < y + h) if ((h = t - y) <= 0) return 0; } /* Colored halftone patterns are unconditionally opaque. */ lop &= ~lop_T_transparent; if (pdht->components == 0) { caches[0] = caches[1] = caches[2] = caches[3] = pdht->order.cache; for (i = 4; i < nplanes; ++i) caches[i] = pdht->order.cache; } else { gx_ht_order_component *pocs = pdht->components; caches[0] = pocs[pdht->color_indices[0]].corder.cache; caches[1] = pocs[pdht->color_indices[1]].corder.cache; caches[2] = pocs[pdht->color_indices[2]].corder.cache; caches[3] = pocs[pdht->color_indices[3]].corder.cache; for (i = 4; i < nplanes; ++i) caches[i] = pocs[pdht->color_indices[i]].corder.cache; } special = set_ht_colors(&vp, colors, sbits, pdevc, dev, caches, nplanes); no_rop = source == NULL && lop_no_S_is_T(lop); /* * If the LCM of the plane cell sizes is smaller than the rectangle * being filled, compute a single tile and let tile_rectangle do the * replication. */ if ((w > lw || h > lh) && (raster = bitmap_raster(lw * depth)) <= tile_bytes / lh ) { /* * The only reason we need to do fit_fill here is that if the * device is a clipper, the caller might be counting on it to do * all necessary clipping. Actually, we should clip against the * device's clipping box, not the default.... */ fit_fill(dev, x, y, w, h); /* Check to make sure we still have a big rectangle. */ if (w > lw || h > lh) { tiles.data = (byte *)tbits; tiles.raster = raster; tiles.rep_width = tiles.size.x = lw; tiles.rep_height = tiles.size.y = lh; tiles.id = gs_next_ids(1); tiles.rep_shift = tiles.shift = 0; set_color_ht((byte *)tbits, raster, 0, 0, lw, lh, depth, special, nplanes, pdevc->colors.colored.plane_mask, dev, &vp, colors, sbits); if (no_rop) return (*dev_proc(dev, strip_tile_rectangle)) (dev, &tiles, x, y, w, h, gx_no_color_index, gx_no_color_index, pdevc->phase.x, pdevc->phase.y); if (source == NULL) set_rop_no_source(source, no_source, dev); return (*dev_proc(dev, strip_copy_rop)) (dev, source->sdata, source->sourcex, source->sraster, source->id, (source->use_scolors ? source->scolors : NULL), &tiles, NULL, x, y, w, h, pdevc->phase.x, pdevc->phase.y, lop); } } size_x = w * depth; raster = bitmap_raster(size_x); if (raster > tile_bytes) { /* * We can't even do an entire line at once. See above for * why we do the X equivalent of fit_fill here. */ if (x < 0) w += x, x = 0; if (x > dev->width - w) w = dev->width - x; if (w <= 0) return 0; size_x = w * depth; raster = bitmap_raster(size_x); if (raster > tile_bytes) { /* We'll have to do a partial line. */ dw = tile_bytes * 8 / depth; size_x = dw * depth; raster = bitmap_raster(size_x); dh = 1; goto fit; } } /* Do as many lines as will fit. */ dw = w; dh = tile_bytes / raster; if (dh > h) dh = h; fit: /* Now the tile will definitely fit. */ if (!no_rop) { tiles.data = (byte *)tbits; tiles.id = gx_no_bitmap_id; tiles.raster = raster; tiles.rep_width = tiles.size.x = size_x / depth; tiles.rep_shift = tiles.shift = 0; } while (w) { int cy = y, ch = dh, left = h; for (;;) { set_color_ht((byte *)tbits, raster, x + pdevc->phase.x, cy + pdevc->phase.y, dw, ch, depth, special, nplanes, pdevc->colors.colored.plane_mask, dev, &vp, colors, sbits); if (no_rop) { code = (*dev_proc(dev, copy_color)) (dev, (byte *)tbits, 0, raster, gx_no_bitmap_id, x, cy, dw, ch); } else { tiles.rep_height = tiles.size.y = ch; if (source == NULL) set_rop_no_source(source, no_source, dev); /****** WRONG - MUST ADJUST source VALUES ******/ code = (*dev_proc(dev, strip_copy_rop)) (dev, source->sdata, source->sourcex, source->sraster, source->id, (source->use_scolors ? source->scolors : NULL), &tiles, NULL, x, cy, dw, ch, 0, 0, lop); } if (code < 0) return code; if (!(left -= ch)) break; cy += ch; if (ch > left) ch = left; } if (!(w -= dw)) break; x += dw; if (dw > w) dw = w; } return code; } /* ---------------- Color table setup ---------------- */ /* * We could cache this if we had a place to store it. Even a 1-element * cache would help performance substantially. * Key: device + c_base/c_level of device color * Value: colors table */ /* * We construct color halftone tiles out of multiple "planes". * Each plane specifies halftoning for one component (R/G/B, C/M/Y/K, * or DeviceN components). */ private const struct { ulong pad; /* to get bytes aligned properly */ byte bytes[sizeof(ulong) * 8]; /* 8 is arbitrary */ } ht_no_bitmap_data = { 0 }; private const gx_const_strip_bitmap ht_no_bitmap = { &ht_no_bitmap_data.bytes[0], sizeof(ulong), {sizeof(ulong) * 8, sizeof(ht_no_bitmap_data.bytes) / sizeof(ulong)}, gx_no_bitmap_id, 1, 1, 0, 0 }; /* Set the color value(s) and halftone mask for one plane. */ /* Free variables: pvp, pdc, sbits */ #define SET_PLANE_COLOR_CONSTANT(i)\ BEGIN\ pvp->values[1][i] = pvp->values[0][i] = pdc->colors.colored.c_base[i];\ sbits[i] = &ht_no_bitmap;\ END /* Free variables: pvp, pdc, sbits, caches, invert, max_color */ #define SET_PLANE_COLOR(i)\ BEGIN\ uint q = pdc->colors.colored.c_base[i];\ uint r = pdc->colors.colored.c_level[i];\ \ pvp->values[0][i] = fractional_color(q, max_color);\ if (r == 0)\ pvp->values[1][i] = pvp->values[0][i], sbits[i] = &ht_no_bitmap;\ else if (!invert) {\ pvp->values[1][i] = fractional_color(q + 1, max_color);\ sbits[i] = (const gx_const_strip_bitmap *)\ &gx_render_ht(caches[i], r)->tiles;\ } else { \ const gx_device_halftone *pdht = pdc->colors.colored.c_ht; \ int nlevels =\ (pdht->components ?\ pdht->components[pdht->color_indices[i]].corder.num_levels :\ pdht->order.num_levels);\ \ pvp->values[1][i] = pvp->values[0][i]; \ pvp->values[0][i] = fractional_color(q + 1, max_color); \ sbits[i] = (const gx_const_strip_bitmap *)\ &gx_render_ht(caches[i], nlevels - r)->tiles; \ }\ END /* Set up the colors and the individual plane halftone bitmaps. */ private int set_ht_colors_le_4(color_values_pair_t *pvp /* only used internally */, gx_color_index colors[1 << MAX_DCC], const gx_const_strip_bitmap * sbits[MAX_DCC], const gx_device_color * pdc, gx_device * dev, gx_ht_cache * caches[MAX_DCC], int nplanes) { gx_color_value max_color = dev->color_info.dither_colors - 1; /* * NB: the halftone orders are all set up for an additive color space. * To make these work with a subtractive device space such as CMYK, * it is necessary to invert both the color level and the color * pair. Note that if the original color was provided an additive * space, this will reverse (in an approximate sense) the color * conversion performed to express the color in the device space. */ bool invert = dev->color_info.num_components >= 4; /****** HACK ******/ SET_PLANE_COLOR(0); SET_PLANE_COLOR(1); SET_PLANE_COLOR(2); if (nplanes == 3) { gx_color_value alpha = pdc->colors.colored.alpha; if (alpha == gx_max_color_value) { #ifndef DEBUG # undef gx_map_rgb_color dev_proc_map_rgb_color((*gx_map_rgb_color)) = dev_proc(dev, map_rgb_color); #endif #define M(i)\ colors[i] = gx_map_rgb_color(dev, pvp->values[(i) & 1][0],\ pvp->values[((i) & 2) >> 1][1],\ pvp->values[(i) >> 2][2]) M(0); M(1); M(2); M(3); M(4); M(5); M(6); M(7); #undef M } else { #ifndef DEBUG # undef gx_map_rgb_alpha_color dev_proc_map_rgb_alpha_color((*gx_map_rgb_alpha_color)) = dev_proc(dev, map_rgb_alpha_color); #endif #define M(i)\ colors[i] = gx_map_rgb_alpha_color(dev, pvp->values[(i) & 1][0],\ pvp->values[((i) & 2) >> 1][1],\ pvp->values[(i) >> 2][2], alpha) M(0); M(1); M(2); M(3); M(4); M(5); M(6); M(7); #undef M } } else { #ifdef DEBUG # define do_map_cmyk_color(dev, c, m, y, k) gx_map_cmyk_color(dev, c, m, y, k) #else dev_proc_map_cmyk_color((*do_map_cmyk_color)) = dev_proc(dev, map_cmyk_color); #endif SET_PLANE_COLOR(3); if (nplanes > 4) { /* * Set colors for any planes beyond the 4th. Since this code * only handles the case of at most 4 active planes, we know * that any further planes are constant. */ /****** DOESN'T MAP COLORS RIGHT, DOESN'T HANDLE ALPHA ******/ int pi; for (pi = 4; pi < nplanes; ++pi) SET_PLANE_COLOR_CONSTANT(pi); } /* * For CMYK output, especially if the input was RGB, it's * common for one or more of the components to be zero. * Each zero component can cut the cost of color mapping in * half, so it's worth doing a little checking here. */ #define M(i)\ colors[i] = do_map_cmyk_color(dev, pvp->values[(i) & 1][0],\ pvp->values[((i) & 2) >> 1][1],\ pvp->values[((i) & 4) >> 2][2],\ pvp->values[(i) >> 3][3]) /* We know that plane_mask <= 15. */ switch ((int)pdc->colors.colored.plane_mask) { case 15: M(15); M(14); M(13); M(12); M(11); M(10); M(9); M(8); case 7: M(7); M(6); M(5); M(4); c3: case 3: M(3); M(2); c1: case 1: M(1); break; case 14: M(14); M(12); M(10); M(8); case 6: M(6); M(4); c2: case 2: M(2); break; case 13: M(13); M(12); M(9); M(8); case 5: M(5); M(4); goto c1; case 12: M(12); M(8); case 4: M(4); break; case 11: M(11); M(10); M(9); M(8); goto c3; case 10: M(10); M(8); goto c2; case 9: M(9); M(8); goto c1; case 8: M(8); break; case 0:; } M(0); #undef M } return 0; } /* Set up colors using the standard 1-bit CMYK mapping. */ private int set_cmyk_1bit_colors(color_values_pair_t *ignore_pvp, gx_color_index colors[1 << MAX_DCC /*16 used*/], const gx_const_strip_bitmap * sbits[MAX_DCC /*4 used*/], const gx_device_color * pdc, gx_device * dev, gx_ht_cache * caches[MAX_DCC /*4 used*/], int nplanes /*4*/) { const gx_device_halftone *pdht = pdc->colors.colored.c_ht; /* * By reversing the order of the planes, we make the pixel values * line up with the color indices. Then instead of a lookup, we * can compute the pixels directly using a Boolean function. * * We compute each output bit * out[i] = (in[i] & mask1) | (~in[i] & mask0) * We store the two masks in colors[0] and colors[1], since the * colors array is otherwise unused in this case. We duplicate * the values in all the nibbles so we can do several pixels at a time. */ bits32 mask0 = 0, mask1 = 0; #define SET_PLANE_COLOR_CMYK(i, mask)\ BEGIN\ uint r = pdc->colors.colored.c_level[i];\ \ if (r == 0) {\ if (pdc->colors.colored.c_base[i])\ mask0 |= mask, mask1 |= mask;\ sbits[3 - i] = &ht_no_bitmap;\ } else {\ int nlevels =\ (pdht->components ?\ pdht->components[pdht->color_indices[i]].corder.num_levels :\ pdht->order.num_levels);\ \ mask0 |= mask;\ sbits[3 - i] = (const gx_const_strip_bitmap *)\ &gx_render_ht(caches[i], nlevels - r)->tiles;\ }\ END /* Suppress a compiler warning about signed/unsigned constants. */ SET_PLANE_COLOR_CMYK(0, /*0x88888888*/ (bits32)~0x77777777); SET_PLANE_COLOR_CMYK(1, 0x44444444); SET_PLANE_COLOR_CMYK(2, 0x22222222); SET_PLANE_COLOR_CMYK(3, 0x11111111); #undef SET_PLANE_COLOR_CMYK { gx_ht_cache *ctemp; ctemp = caches[0], caches[0] = caches[3], caches[3] = ctemp; ctemp = caches[1], caches[1] = caches[2], caches[2] = ctemp; } colors[0] = mask0; colors[1] = mask1; return 1; } /* * Set up colors for >4 planes. In this case, we compute the colors * themselves lazily. */ private int set_ht_colors_gt_4(color_values_pair_t *pvp, gx_color_index colors[1 << MAX_DCC], const gx_const_strip_bitmap * sbits[MAX_DCC], const gx_device_color * pdc, gx_device * dev, gx_ht_cache * caches[MAX_DCC], int nplanes) { gx_color_value max_color = dev->color_info.dither_colors - 1; /* See set_ht_color_le_4 for invert. */ bool invert = true; /****** HACK ******/ gx_color_index plane_mask = pdc->colors.colored.plane_mask; int i; gx_color_index ci; /* Set the color values and halftone caches. */ for (i = 0; i < nplanes; ++i) if ((plane_mask >> i) & 1) SET_PLANE_COLOR(i); else SET_PLANE_COLOR_CONSTANT(i); /* * Clear the color table entries that will actually be used, namely, * those whose indices are either 0 or 1 in bits selected by plane_mask * and 0 in all other bits. */ ci = 0; do { colors[ci] = gx_no_color_index; } while ((ci = ((ci | ~plane_mask) + 1) & plane_mask) != 0); return 0; } /* ---------------- Color rendering ---------------- */ /* Define the bookkeeping structure for each plane of halftone rendering. */ typedef struct tile_cursor_s { int tile_shift; /* X shift per copy of tile */ int xoffset; int xshift; uint xbytes; int xbits; const byte *row; const byte *tdata; uint raster; const byte *data; int bit_shift; } tile_cursor_t; /* * Initialize one plane cursor, including setting up for the first row * (data and bit_shift). */ private void init_tile_cursor(int i, tile_cursor_t *ptc, const gx_const_strip_bitmap *btile, int endx, int lasty) { int tw = btile->size.x; int bx = ((ptc->tile_shift = btile->shift) == 0 ? endx : endx + lasty / btile->size.y * ptc->tile_shift) % tw; int by = lasty % btile->size.y; ptc->xoffset = bx >> 3; ptc->xshift = 8 - (bx & 7); ptc->xbytes = (tw - 1) >> 3; ptc->xbits = ((tw - 1) & 7) + 1; ptc->tdata = btile->data; ptc->raster = btile->raster; ptc->row = ptc->tdata + by * ptc->raster; ptc->data = ptc->row + ptc->xoffset; ptc->bit_shift = ptc->xshift; if_debug6('h', "[h]plane %d: size=%d,%d shift=%d bx=%d by=%dn", i, tw, btile->size.y, btile->shift, bx, by); } /* Step a cursor to the next row. */ private void wrap_shifted_cursor(tile_cursor_t *ptc, const gx_const_strip_bitmap *psbit) { ptc->row += ptc->raster * (psbit->size.y - 1); if (ptc->tile_shift) { if ((ptc->xshift += ptc->tile_shift) >= 8) { if ((ptc->xoffset -= ptc->xshift >> 3) < 0) { /* wrap around in X */ int bx = (ptc->xoffset << 3) + 8 - (ptc->xshift & 7) + psbit->size.x; ptc->xoffset = bx >> 3; ptc->xshift = 8 - (bx & 7); } else ptc->xshift &= 7; } } } #define STEP_ROW(c, i)\ BEGIN\ if (c.row > c.tdata)\ c.row -= c.raster;\ else { /* wrap around to end of tile */\ wrap_shifted_cursor(&c, sbits[i]);\ }\ c.data = c.row + c.xoffset;\ c.bit_shift = c.xshift;\ END /* Define a table for expanding 8x1 bits to 8x4. */ private const bits32 expand_8x1_to_8x4[256] = { #define X16(c)\ c+0, c+1, c+0x10, c+0x11, c+0x100, c+0x101, c+0x110, c+0x111,\ c+0x1000, c+0x1001, c+0x1010, c+0x1011, c+0x1100, c+0x1101, c+0x1110, c+0x1111 X16(0x00000000), X16(0x00010000), X16(0x00100000), X16(0x00110000), X16(0x01000000), X16(0x01010000), X16(0x01100000), X16(0x01110000), X16(0x10000000), X16(0x10010000), X16(0x10100000), X16(0x10110000), X16(0x11000000), X16(0x11010000), X16(0x11100000), X16(0x11110000) #undef X16 }; /* * Render the combined halftone for nplanes <= 4. */ private void set_color_ht_le_4(byte *dest_data, uint dest_raster, int px, int py, int w, int h, int depth, int special, int nplanes, gx_color_index plane_mask, gx_device *ignore_dev, const color_values_pair_t *ignore_pvp, gx_color_index colors[1 << MAX_DCC], const gx_const_strip_bitmap * sbits[MAX_DCC]) { /* * Note that the planes are specified in the order RGB or CMYK, but * the indices used for the internal colors array are BGR or KYMC, * except for the special 1-bit CMYK case. */ int x, y; tile_cursor_t cursor[MAX_DCC]; int dbytes = depth >> 3; byte *dest_row = dest_data + dest_raster * (h - 1) + (w * depth) / 8; if (special > 0) { /* Planes are in reverse order. */ plane_mask = "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017"[plane_mask]; } if_debug6('h', "[h]color_ht: x=%d y=%d w=%d h=%d plane_mask=0x%lu depth=%d\n", px, py, w, h, (ulong)plane_mask, depth); /* Do one-time cursor initialization. */ { int endx = w + px; int lasty = h - 1 + py; if (plane_mask & 1) init_tile_cursor(0, &cursor[0], sbits[0], endx, lasty); if (plane_mask & 2) init_tile_cursor(1, &cursor[1], sbits[1], endx, lasty); if (plane_mask & 4) init_tile_cursor(2, &cursor[2], sbits[2], endx, lasty); if (plane_mask & 8) init_tile_cursor(3, &cursor[3], sbits[3], endx, lasty); } /* Now compute the actual tile. */ for (y = h; ; dest_row -= dest_raster) { byte *dest = dest_row; --y; for (x = w; x > 0;) { bits32 indices; int nx, i; register uint bits; /* Get the next byte's worth of bits. Note that there may be */ /* excess bits set beyond the 8th. */ #define NEXT_BITS(c)\ BEGIN\ if (c.data > c.row) {\ bits = ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\ c.data--;\ } else {\ bits = *c.data >> c.bit_shift;\ c.data += c.xbytes;\ if ((c.bit_shift -= c.xbits) < 0) {\ bits |= *c.data << -c.bit_shift;\ c.bit_shift += 8;\ } else {\ bits |= ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\ c.data--;\ }\ }\ END if (plane_mask & 1) { NEXT_BITS(cursor[0]); indices = expand_8x1_to_8x4[bits & 0xff]; } else indices = 0; if (plane_mask & 2) { NEXT_BITS(cursor[1]); indices |= expand_8x1_to_8x4[bits & 0xff] << 1; } if (plane_mask & 4) { NEXT_BITS(cursor[2]); indices |= expand_8x1_to_8x4[bits & 0xff] << 2; } if (plane_mask & 8) { NEXT_BITS(cursor[3]); indices |= expand_8x1_to_8x4[bits & 0xff] << 3; } #undef NEXT_BITS nx = min(x, 8); /* 1 <= nx <= 8 */ x -= nx; switch (dbytes) { case 0: /* 4 */ if (special > 0) { /* Special 1-bit CMYK. */ /* Compute all the pixels at once! */ indices = (indices & colors[1]) | (~indices & colors[0]); i = nx; if ((x + nx) & 1) { /* First pixel is even nibble. */ *dest = (*dest & 0xf) + ((indices & 0xf) << 4); indices >>= 4; --i; } /* Now 0 <= i <= 8. */ for (; (i -= 2) >= 0; indices >>= 8) *--dest = (byte)indices; /* Check for final odd nibble. */ if (i & 1) *--dest = indices & 0xf; } else { /* Other 4-bit pixel */ i = nx; if ((x + nx) & 1) { /* First pixel is even nibble. */ *dest = (*dest & 0xf) + ((byte)colors[indices & 0xf] << 4); indices >>= 4; --i; } /* Now 0 <= i <= 8. */ for (; (i -= 2) >= 0; indices >>= 8) *--dest = (byte)colors[indices & 0xf] + ((byte)colors[(indices >> 4) & 0xf] << 4); /* Check for final odd nibble. */ if (i & 1) *--dest = (byte)colors[indices & 0xf]; } break; case 4: /* 32 */ for (i = nx; --i >= 0; indices >>= 4) { bits32 tcolor = (bits32)colors[indices & 0xf]; dest -= 4; dest[3] = (byte)tcolor; dest[2] = (byte)(tcolor >> 8); tcolor >>= 16; dest[1] = (byte)tcolor; dest[0] = (byte)(tcolor >> 8); } break; case 3: /* 24 */ for (i = nx; --i >= 0; indices >>= 4) { bits32 tcolor = (bits32)colors[indices & 0xf]; dest -= 3; dest[2] = (byte) tcolor; dest[1] = (byte)(tcolor >> 8); dest[0] = (byte)(tcolor >> 16); } break; case 2: /* 16 */ for (i = nx; --i >= 0; indices >>= 4) { uint tcolor = (uint)colors[indices & 0xf]; dest -= 2; dest[1] = (byte)tcolor; dest[0] = (byte)(tcolor >> 8); } break; case 1: /* 8 */ for (i = nx; --i >= 0; indices >>= 4) *--dest = (byte)colors[indices & 0xf]; break; } } if (y == 0) break; if (plane_mask & 1) STEP_ROW(cursor[0], 0); if (plane_mask & 2) STEP_ROW(cursor[1], 1); if (plane_mask & 4) STEP_ROW(cursor[2], 2); if (plane_mask & 8) STEP_ROW(cursor[3], 3); } } /* * Render the combined halftone for nplanes > 4. We haven't made any * attempt to optimize this code. */ private void set_color_ht_gt_4(byte *dest_data, uint dest_raster, int px, int py, int w, int h, int depth, int special, int num_planes, gx_color_index plane_mask, gx_device *dev, const color_values_pair_t *pvp, gx_color_index colors[1 << MAX_DCC], const gx_const_strip_bitmap * sbits[MAX_DCC]) { int x, y; tile_cursor_t cursor[MAX_DCC]; int dbytes = depth >> 3; byte *dest_row = dest_data + dest_raster * (h - 1) + (w * depth) / 8; int pmin, pmax; gx_color_value cv[MAX_DCC]; /* Compute the range of active planes. */ if (plane_mask == 0) pmin = 0, pmax = -1; else { for (pmin = 0; !((plane_mask >> pmin) & 1); ) ++pmin; for (pmax = 0; (plane_mask >> pmax) > 1; ) ++pmax; } /* Do one-time cursor initialization. */ { int endx = w + px; int lasty = h - 1 + py; int i; for (i = pmin; i <= pmax; ++i) if ((plane_mask >> i) & 1) init_tile_cursor(i, &cursor[i], sbits[i], endx, lasty); } /* Pre-load the color value for the unchanging planes. */ { int i; for (i = 0; i < pmin; ++i) cv[i] = pvp->values[0][i]; for (i = pmax + 1; i < num_planes; ++i) cv[i] = pvp->values[0][i]; } /* Now compute the actual tile. */ for (y = h; ; dest_row -= dest_raster) { byte *dest = dest_row; int i; --y; for (x = w; x > 0;) { gx_color_index index = 0; gx_color_index tcolor; for (i = pmin; i <= pmax; ++i) if ((plane_mask >> i) & 1) { /* Get the next bit from an individual mask. */ tile_cursor_t *ptc = &cursor[i]; byte tile_bit; b: if (ptc->bit_shift < 8) tile_bit = *ptc->data >> ptc->bit_shift++; else if (ptc->data > ptc->row) { tile_bit = *--(ptc->data); ptc->bit_shift = 1; } else { /* Wrap around. */ ptc->data += ptc->xbytes; ptc->bit_shift = 8 - ptc->xbits; goto b; } index |= (gx_color_index)(tile_bit & 1) << i; } tcolor = colors[index]; if (tcolor == gx_no_color_index) { /* Map the color value now. */ int i; for (i = pmin; i <= pmax; ++i) cv[i] = pvp->values[(index >> i) & 1][i]; /****** HACK -- NO WAY TO MAP GENERAL COLORS ******/ tcolor = colors[index] = gx_map_cmyk_color(dev, cv[0], cv[1], cv[2], cv[3]); } --x; switch (dbytes) { case 0: /* 4 -- might be 2, but we don't support this */ if (x & 1) { /* odd nibble */ *--dest = (byte)tcolor; } else { /* even nibble */ *dest = (*dest & 0xf) + ((byte)tcolor << 4); } break; case 4: /* 32 */ dest[-4] = (byte)(tcolor >> 24); case 3: /* 24 */ dest[-3] = (byte)(tcolor >> 16); case 2: /* 16 */ dest[-2] = (byte)(tcolor >> 8); case 1: /* 8 */ dest[-1] = (byte)tcolor; dest -= dbytes; break; } } if (y == 0) break; for (i = pmin; i <= pmax; ++i) if ((plane_mask >> i) & 1) STEP_ROW(cursor[i], i); } }