123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
-
- This software is provided AS-IS with no warranty, either express or
- implied.
-
- This software is distributed under license and may not be copied,
- modified or distributed except as expressly authorized under the terms
- of the license contained in the file LICENSE in this distribution.
-
- For more information about licensing, please refer to
- http://www.ghostscript.com/licensing/. For information on
- commercial licensing, go to http://www.artifex.com/licensing/ or
- contact Artifex Software, Inc., 101 Lucas Valley Road #110,
- San Rafael, CA 94903, U.S.A., +1(415)492-9861.
- */
- /* $Id: gxipixel.c,v 1.12 2005/07/21 19:32:06 alexcher Exp $ */
- /* Common code for ImageType 1 and 4 initialization */
- #include "gx.h"
- #include "math_.h"
- #include "memory_.h"
- #include "gpcheck.h"
- #include "gscdefs.h" /* for image class table */
- #include "gserrors.h"
- #include "gsstruct.h"
- #include "gsutil.h"
- #include "gxfixed.h"
- #include "gxfrac.h"
- #include "gxarith.h"
- #include "gxmatrix.h"
- #include "gsccolor.h"
- #include "gspaint.h"
- #include "gzstate.h"
- #include "gxdevice.h"
- #include "gzpath.h"
- #include "gzcpath.h"
- #include "gxdevmem.h"
- #include "gximage.h"
- #include "gxiparam.h"
- #include "gdevmrop.h"
- /* Structure descriptors */
- private_st_gx_image_enum();
- /* Image class procedures */
- extern_gx_image_class_table();
- /* Enumerator procedures */
- private const gx_image_enum_procs_t image1_enum_procs = {
- gx_image1_plane_data, gx_image1_end_image, gx_image1_flush
- };
- /* GC procedures */
- private
- ENUM_PTRS_WITH(image_enum_enum_ptrs, gx_image_enum *eptr)
- {
- int bps;
- gs_ptr_type_t ret;
- /* Enumerate the used members of clues.dev_color. */
- index -= gx_image_enum_num_ptrs;
- bps = eptr->unpack_bps;
- if (eptr->spp != 1)
- bps = 8;
- else if (bps > 8 || eptr->unpack == sample_unpack_copy)
- bps = 1;
- if (index >= (1 << bps) * st_device_color_max_ptrs) /* done */
- return 0;
- ret = ENUM_USING(st_device_color,
- &eptr->clues[(index / st_device_color_max_ptrs) *
- (255 / ((1 << bps) - 1))].dev_color,
- sizeof(eptr->clues[0].dev_color),
- index % st_device_color_max_ptrs);
- if (ret == 0) /* don't stop early */
- ENUM_RETURN(0);
- return ret;
- }
- #define e1(i,elt) ENUM_PTR(i,gx_image_enum,elt);
- gx_image_enum_do_ptrs(e1)
- #undef e1
- ENUM_PTRS_END
- private RELOC_PTRS_WITH(image_enum_reloc_ptrs, gx_image_enum *eptr)
- {
- int i;
- #define r1(i,elt) RELOC_PTR(gx_image_enum,elt);
- gx_image_enum_do_ptrs(r1)
- #undef r1
- {
- int bps = eptr->unpack_bps;
- if (eptr->spp != 1)
- bps = 8;
- else if (bps > 8 || eptr->unpack == sample_unpack_copy)
- bps = 1;
- for (i = 0; i <= 255; i += 255 / ((1 << bps) - 1))
- RELOC_USING(st_device_color,
- &eptr->clues[i].dev_color, sizeof(gx_device_color));
- }
- }
- RELOC_PTRS_END
- /* Forward declarations */
- private int color_draws_b_w(gx_device * dev,
- const gx_drawing_color * pdcolor);
- private void image_init_map(byte * map, int map_size, const float *decode);
- private void image_init_colors(gx_image_enum * penum, int bps, int spp,
- gs_image_format_t format,
- const float *decode,
- const gs_imager_state * pis, gx_device * dev,
- const gs_color_space * pcs, bool * pdcb);
- /* Procedures for unpacking the input data into bytes or fracs. */
- /*extern SAMPLE_UNPACK_PROC(sample_unpack_copy); *//* declared above */
- /*
- * Do common initialization for processing an ImageType 1 or 4 image.
- * Allocate the enumerator and fill in the following members:
- * rect
- */
- int
- gx_image_enum_alloc(const gs_image_common_t * pic,
- const gs_int_rect * prect, gs_memory_t * mem,
- gx_image_enum **ppenum)
- {
- const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic;
- int width = pim->Width, height = pim->Height;
- int bpc = pim->BitsPerComponent;
- gx_image_enum *penum;
- if (width < 0 || height < 0)
- return_error(gs_error_rangecheck);
- switch (pim->format) {
- case gs_image_format_chunky:
- case gs_image_format_component_planar:
- switch (bpc) {
- case 1: case 2: case 4: case 8: case 12: case 16: break;
- default: return_error(gs_error_rangecheck);
- }
- break;
- case gs_image_format_bit_planar:
- if (bpc < 1 || bpc > 8)
- return_error(gs_error_rangecheck);
- }
- if (prect) {
- if (prect->p.x < 0 || prect->p.y < 0 ||
- prect->q.x < prect->p.x || prect->q.y < prect->p.y ||
- prect->q.x > width || prect->q.y > height
- )
- return_error(gs_error_rangecheck);
- }
- penum = gs_alloc_struct(mem, gx_image_enum, &st_gx_image_enum,
- "gx_default_begin_image");
- if (penum == 0)
- return_error(gs_error_VMerror);
- if (prect) {
- penum->rect.x = prect->p.x;
- penum->rect.y = prect->p.y;
- penum->rect.w = prect->q.x - prect->p.x;
- penum->rect.h = prect->q.y - prect->p.y;
- } else {
- penum->rect.x = 0, penum->rect.y = 0;
- penum->rect.w = width, penum->rect.h = height;
- }
- #ifdef DEBUG
- if (gs_debug_c('b')) {
- dlprintf2("[b]Image: w=%d h=%d", width, height);
- if (prect)
- dprintf4(" ((%d,%d),(%d,%d))",
- prect->p.x, prect->p.y, prect->q.x, prect->q.y);
- }
- #endif
- *ppenum = penum;
- return 0;
- }
- /*
- * Finish initialization for processing an ImageType 1 or 4 image.
- * Assumes the following members of *penum are set in addition to those
- * set by gx_image_enum_alloc:
- * alpha, use_mask_color, mask_color (if use_mask_color is true),
- * masked, adjust
- */
- int
- gx_image_enum_begin(gx_device * dev, const gs_imager_state * pis,
- const gs_matrix *pmat, const gs_image_common_t * pic,
- const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
- gs_memory_t * mem, gx_image_enum *penum)
- {
- const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic;
- gs_image_format_t format = pim->format;
- const int width = pim->Width;
- const int height = pim->Height;
- const int bps = pim->BitsPerComponent;
- bool masked = penum->masked;
- const float *decode = pim->Decode;
- gs_matrix mat;
- int index_bps;
- const gs_color_space *pcs = pim->ColorSpace;
- gs_logical_operation_t lop = (pis ? pis->log_op : lop_default);
- int code;
- int log2_xbytes = (bps <= 8 ? 0 : arch_log2_sizeof_frac);
- int spp, nplanes, spread;
- uint bsize;
- byte *buffer;
- fixed mtx, mty;
- gs_fixed_point row_extent, col_extent, x_extent, y_extent;
- bool device_color;
- gs_fixed_rect obox, cbox;
- if (pmat == 0)
- pmat = &ctm_only(pis);
- if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
- (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0
- ) {
- gs_free_object(mem, penum, "gx_default_begin_image");
- return code;
- }
- penum->matrix = mat;
- if_debug6('b', " [%g %g %g %g %g %g]\n",
- mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
- /* following works for 1, 2, 4, 8, 12, 16 */
- index_bps = (bps < 8 ? bps >> 1 : (bps >> 2) + 1);
- mtx = float2fixed(mat.tx);
- mty = float2fixed(mat.ty);
- row_extent.x = float2fixed(width * mat.xx + mat.tx) - mtx;
- row_extent.y =
- (is_fzero(mat.xy) ? fixed_0 :
- float2fixed(width * mat.xy + mat.ty) - mty);
- col_extent.x =
- (is_fzero(mat.yx) ? fixed_0 :
- float2fixed(height * mat.yx + mat.tx) - mtx);
- col_extent.y = float2fixed(height * mat.yy + mat.ty) - mty;
- gx_image_enum_common_init((gx_image_enum_common_t *)penum,
- (const gs_data_image_t *)pim,
- &image1_enum_procs, dev,
- (masked ? 1 : cs_num_components(pcs)),
- format);
- if (penum->rect.w == width && penum->rect.h == height) {
- x_extent = row_extent;
- y_extent = col_extent;
- } else {
- int rw = penum->rect.w, rh = penum->rect.h;
- x_extent.x = float2fixed(rw * mat.xx + mat.tx) - mtx;
- x_extent.y =
- (is_fzero(mat.xy) ? fixed_0 :
- float2fixed(rw * mat.xy + mat.ty) - mty);
- y_extent.x =
- (is_fzero(mat.yx) ? fixed_0 :
- float2fixed(rh * mat.yx + mat.tx) - mtx);
- y_extent.y = float2fixed(rh * mat.yy + mat.ty) - mty;
- }
- if (masked) { /* This is imagemask. */
- if (bps != 1 || pcs != NULL || penum->alpha || decode[0] == decode[1]) {
- gs_free_object(mem, penum, "gx_default_begin_image");
- return_error(gs_error_rangecheck);
- }
- /* Initialize color entries 0 and 255. */
- set_nonclient_dev_color(&penum->icolor0, gx_no_color_index);
- penum->icolor1 = *pdcolor;
- memcpy(&penum->map[0].table.lookup4x1to32[0],
- (decode[0] < decode[1] ? lookup4x1to32_inverted :
- lookup4x1to32_identity),
- 16 * 4);
- penum->map[0].decoding = sd_none;
- spp = 1;
- lop = rop3_know_S_0(lop);
- } else { /* This is image, not imagemask. */
- const gs_color_space_type *pcst = pcs->type;
- int b_w_color;
- spp = cs_num_components(pcs);
- if (spp < 0) { /* Pattern not allowed */
- gs_free_object(mem, penum, "gx_default_begin_image");
- return_error(gs_error_rangecheck);
- }
- if (penum->alpha)
- ++spp;
- /* Use a less expensive format if possible. */
- switch (format) {
- case gs_image_format_bit_planar:
- if (bps > 1)
- break;
- format = gs_image_format_component_planar;
- case gs_image_format_component_planar:
- if (spp == 1)
- format = gs_image_format_chunky;
- default: /* chunky */
- break;
- }
- device_color = (*pcst->concrete_space) (pcs, pis) == pcs;
- image_init_colors(penum, bps, spp, format, decode, pis, dev,
- pcs, &device_color);
- /* Try to transform non-default RasterOps to something */
- /* that we implement less expensively. */
- if (!pim->CombineWithColor)
- lop = rop3_know_T_0(lop) & ~lop_T_transparent;
- else {
- if (rop3_uses_T(lop))
- switch (color_draws_b_w(dev, pdcolor)) {
- case 0:
- lop = rop3_know_T_0(lop);
- break;
- case 1:
- lop = rop3_know_T_1(lop);
- break;
- default:
- ;
- }
- }
- if (lop != rop3_S && /* if best case, no more work needed */
- !rop3_uses_T(lop) && bps == 1 && spp == 1 &&
- (b_w_color =
- color_draws_b_w(dev, &penum->icolor0)) >= 0 &&
- color_draws_b_w(dev, &penum->icolor1) == (b_w_color ^ 1)
- ) {
- if (b_w_color) { /* Swap the colors and invert the RasterOp source. */
- gx_device_color dcolor;
- dcolor = penum->icolor0;
- penum->icolor0 = penum->icolor1;
- penum->icolor1 = dcolor;
- lop = rop3_invert_S(lop);
- }
- /*
- * At this point, we know that the source pixels
- * correspond directly to the S input for the raster op,
- * i.e., icolor0 is black and icolor1 is white.
- */
- switch (lop) {
- case rop3_D & rop3_S:
- /* Implement this as an inverted mask writing 0s. */
- penum->icolor1 = penum->icolor0;
- /* (falls through) */
- case rop3_D | rop3_not(rop3_S):
- /* Implement this as an inverted mask writing 1s. */
- memcpy(&penum->map[0].table.lookup4x1to32[0],
- lookup4x1to32_inverted, 16 * 4);
- rmask: /* Fill in the remaining parameters for a mask. */
- penum->masked = masked = true;
- set_nonclient_dev_color(&penum->icolor0, gx_no_color_index);
- penum->map[0].decoding = sd_none;
- lop = rop3_T;
- break;
- case rop3_D & rop3_not(rop3_S):
- /* Implement this as a mask writing 0s. */
- penum->icolor1 = penum->icolor0;
- /* (falls through) */
- case rop3_D | rop3_S:
- /* Implement this as a mask writing 1s. */
- memcpy(&penum->map[0].table.lookup4x1to32[0],
- lookup4x1to32_identity, 16 * 4);
- goto rmask;
- default:
- ;
- }
- }
- }
- penum->device_color = device_color;
- /*
- * Adjust width upward for unpacking up to 7 trailing bits in
- * the row, plus 1 byte for end-of-run, plus up to 7 leading
- * bits for data_x offset within a packed byte.
- */
- bsize = ((bps > 8 ? width * 2 : width) + 15) * spp;
- buffer = gs_alloc_bytes(mem, bsize, "image buffer");
- if (buffer == 0) {
- gs_free_object(mem, penum, "gx_default_begin_image");
- return_error(gs_error_VMerror);
- }
- penum->bps = bps;
- penum->unpack_bps = bps;
- penum->log2_xbytes = log2_xbytes;
- penum->spp = spp;
- switch (format) {
- case gs_image_format_chunky:
- nplanes = 1;
- spread = 1 << log2_xbytes;
- break;
- case gs_image_format_component_planar:
- nplanes = spp;
- spread = spp << log2_xbytes;
- break;
- case gs_image_format_bit_planar:
- nplanes = spp * bps;
- spread = spp << log2_xbytes;
- break;
- default:
- /* No other cases are possible (checked by gx_image_enum_alloc). */
- return_error(gs_error_Fatal);
- }
- penum->num_planes = nplanes;
- penum->spread = spread;
- /*
- * If we're asked to interpolate in a partial image, we have to
- * assume that the client either really only is interested in
- * the given sub-image, or else is constructing output out of
- * overlapping pieces.
- */
- penum->interpolate = pim->Interpolate;
- penum->x_extent = x_extent;
- penum->y_extent = y_extent;
- penum->posture =
- ((x_extent.y | y_extent.x) == 0 ? image_portrait :
- (x_extent.x | y_extent.y) == 0 ? image_landscape :
- image_skewed);
- penum->pis = pis;
- penum->pcs = pcs;
- penum->memory = mem;
- penum->buffer = buffer;
- penum->buffer_size = bsize;
- penum->line = 0;
- penum->line_size = 0;
- penum->use_rop = lop != (masked ? rop3_T : rop3_S);
- #ifdef DEBUG
- if (gs_debug_c('*')) {
- if (penum->use_rop)
- dprintf1("[%03x]", lop);
- dprintf5("%c%d%c%dx%d ",
- (masked ? (color_is_pure(pdcolor) ? 'm' : 'h') : 'i'),
- bps,
- (penum->posture == image_portrait ? ' ' :
- penum->posture == image_landscape ? 'L' : 'T'),
- width, height);
- }
- #endif
- penum->slow_loop = 0;
- if (pcpath == 0) {
- (*dev_proc(dev, get_clipping_box)) (dev, &obox);
- cbox = obox;
- penum->clip_image = 0;
- } else
- penum->clip_image =
- (gx_cpath_outer_box(pcpath, &obox) | /* not || */
- gx_cpath_inner_box(pcpath, &cbox) ?
- 0 : image_clip_region);
- penum->clip_outer = obox;
- penum->clip_inner = cbox;
- penum->log_op = rop3_T; /* rop device takes care of this */
- penum->clip_dev = 0; /* in case we bail out */
- penum->rop_dev = 0; /* ditto */
- penum->scaler = 0; /* ditto */
- /*
- * If all four extrema of the image fall within the clipping
- * rectangle, clipping is never required. When making this check,
- * we must carefully take into account the fact that we only care
- * about pixel centers.
- */
- {
- fixed
- epx = min(row_extent.x, 0) + min(col_extent.x, 0),
- eqx = max(row_extent.x, 0) + max(col_extent.x, 0),
- epy = min(row_extent.y, 0) + min(col_extent.y, 0),
- eqy = max(row_extent.y, 0) + max(col_extent.y, 0);
- {
- int hwx, hwy;
- switch (penum->posture) {
- case image_portrait:
- hwx = width, hwy = height;
- break;
- case image_landscape:
- hwx = height, hwy = width;
- break;
- default:
- hwx = hwy = 0;
- }
- /*
- * If the image is only 1 sample wide or high,
- * and is less than 1 device pixel wide or high,
- * move it slightly so that it covers pixel centers.
- * This is a hack to work around a bug in some old
- * versions of TeX/dvips, which use 1-bit-high images
- * to draw horizontal and vertical lines without
- * positioning them properly.
- */
- if (hwx == 1 && eqx - epx < fixed_1) {
- fixed diff =
- arith_rshift_1(row_extent.x + col_extent.x);
- mtx = (((mtx + diff) | fixed_half) & -fixed_half) - diff;
- }
- if (hwy == 1 && eqy - epy < fixed_1) {
- fixed diff =
- arith_rshift_1(row_extent.y + col_extent.y);
- mty = (((mty + diff) | fixed_half) & -fixed_half) - diff;
- }
- }
- if_debug5('b', "[b]Image: %sspp=%d, bps=%d, mt=(%g,%g)\n",
- (masked? "masked, " : ""), spp, bps,
- fixed2float(mtx), fixed2float(mty));
- if_debug9('b',
- "[b] cbox=(%g,%g),(%g,%g), obox=(%g,%g),(%g,%g), clip_image=0x%x\n",
- fixed2float(cbox.p.x), fixed2float(cbox.p.y),
- fixed2float(cbox.q.x), fixed2float(cbox.q.y),
- fixed2float(obox.p.x), fixed2float(obox.p.y),
- fixed2float(obox.q.x), fixed2float(obox.q.y),
- penum->clip_image);
- dda_init(penum->dda.row.x, mtx, col_extent.x, height);
- dda_init(penum->dda.row.y, mty, col_extent.y, height);
- if (penum->rect.y) {
- dda_advance(penum->dda.row.x, penum->rect.y);
- dda_advance(penum->dda.row.y, penum->rect.y);
- }
- penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x);
- penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y);
- dda_init(penum->dda.strip.x, penum->cur.x, row_extent.x, width);
- dda_init(penum->dda.strip.y, penum->cur.y, row_extent.y, width);
- if (penum->rect.x) {
- dda_advance(penum->dda.strip.x, penum->rect.x);
- dda_advance(penum->dda.strip.y, penum->rect.x);
- } {
- fixed ox = dda_current(penum->dda.strip.x);
- fixed oy = dda_current(penum->dda.strip.y);
- if (!penum->clip_image) /* i.e., not clip region */
- penum->clip_image =
- (fixed_pixround(ox + epx) < fixed_pixround(cbox.p.x) ?
- image_clip_xmin : 0) +
- (fixed_pixround(ox + eqx) >= fixed_pixround(cbox.q.x) ?
- image_clip_xmax : 0) +
- (fixed_pixround(oy + epy) < fixed_pixround(cbox.p.y) ?
- image_clip_ymin : 0) +
- (fixed_pixround(oy + eqy) >= fixed_pixround(cbox.q.y) ?
- image_clip_ymax : 0);
- }
- }
- penum->y = 0;
- penum->used.x = 0;
- penum->used.y = 0;
- {
- static sample_unpack_proc_t procs[2][6] = {
- { sample_unpack_1, sample_unpack_2,
- sample_unpack_4, sample_unpack_8,
- 0, 0
- },
- { sample_unpack_1_interleaved, sample_unpack_2_interleaved,
- sample_unpack_4_interleaved, sample_unpack_8_interleaved,
- 0, 0
- }};
- int num_planes = penum->num_planes;
- bool interleaved = (num_planes == 1 && penum->plane_depths[0] != penum->bps);
- int i;
- procs[0][4] = procs[1][4] = sample_unpack_12_proc;
- procs[0][5] = procs[1][5] = sample_unpack_16_proc;
- if (interleaved) {
- int num_components = penum->plane_depths[0] / penum->bps;
- for (i = 1; i < num_components; i++) {
- if (decode[0] != decode[i * 2 + 0] ||
- decode[1] != decode[i * 2 + 1])
- break;
- }
- if (i == num_components)
- interleaved = false; /* Use single table. */
- }
- if (index_bps >= 4) {
- if ((penum->unpack = procs[interleaved][index_bps]) == 0) { /* bps case not supported. */
- gx_default_end_image(dev,
- (gx_image_enum_common_t *) penum,
- false);
- return_error(gs_error_rangecheck);
- }
- } else {
- penum->unpack = procs[interleaved][index_bps];
- }
- if_debug1('b', "[b]unpack=%d\n", bps);
- /* Set up pixel0 for image class procedures. */
- penum->dda.pixel0 = penum->dda.strip;
- for (i = 0; i < gx_image_class_table_count; ++i)
- if ((penum->render = gx_image_class_table[i](penum)) != 0)
- break;
- if (i == gx_image_class_table_count) {
- /* No available class can handle this image. */
- gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
- false);
- return_error(gs_error_rangecheck);
- }
- }
- if (penum->clip_image && pcpath) { /* Set up the clipping device. */
- gx_device_clip *cdev =
- gs_alloc_struct(mem, gx_device_clip,
- &st_device_clip, "image clipper");
- if (cdev == 0) {
- gx_default_end_image(dev,
- (gx_image_enum_common_t *) penum,
- false);
- return_error(gs_error_VMerror);
- }
- gx_make_clip_translate_device(cdev, gx_cpath_list(pcpath), 0, 0, mem);
- gx_device_retain((gx_device *)cdev, true); /* will free explicitly */
- gx_device_set_target((gx_device_forward *)cdev, dev);
- (*dev_proc(cdev, open_device)) ((gx_device *) cdev);
- penum->clip_dev = cdev;
- }
- if (penum->use_rop) { /* Set up the RasterOp source device. */
- gx_device_rop_texture *rtdev;
- code = gx_alloc_rop_texture_device(&rtdev, mem,
- "image RasterOp");
- if (code < 0) {
- gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
- false);
- return code;
- }
- gx_make_rop_texture_device(rtdev,
- (penum->clip_dev != 0 ?
- (gx_device *) penum->clip_dev :
- dev), lop, pdcolor);
- penum->rop_dev = rtdev;
- }
- return 0;
- }
- /* If a drawing color is black or white, return 0 or 1 respectively, */
- /* otherwise return -1. */
- private int
- color_draws_b_w(gx_device * dev, const gx_drawing_color * pdcolor)
- {
- if (color_is_pure(pdcolor)) {
- gx_color_value rgb[3];
- (*dev_proc(dev, map_color_rgb)) (dev, gx_dc_pure_color(pdcolor),
- rgb);
- if (!(rgb[0] | rgb[1] | rgb[2]))
- return 0;
- if ((rgb[0] & rgb[1] & rgb[2]) == gx_max_color_value)
- return 1;
- }
- return -1;
- }
- /* Export this for use by image_render_ functions */
- void
- image_init_clues(gx_image_enum * penum, int bps, int spp)
- {
- /* Initialize the color table */
- #define ictype(i)\
- penum->clues[i].dev_color.type
- switch ((spp == 1 ? bps : 8)) {
- case 8: /* includes all color images */
- {
- register gx_image_clue *pcht = &penum->clues[0];
- register int n = 64; /* 8 bits means 256 clues, do */
- /* 4 at a time for efficiency */
- do {
- pcht[0].dev_color.type =
- pcht[1].dev_color.type =
- pcht[2].dev_color.type =
- pcht[3].dev_color.type =
- gx_dc_type_none;
- pcht[0].key = pcht[1].key =
- pcht[2].key = pcht[3].key = 0;
- pcht += 4;
- }
- while (--n > 0);
- penum->clues[0].key = 1; /* guarantee no hit */
- break;
- }
- case 4:
- ictype(17) = ictype(2 * 17) = ictype(3 * 17) =
- ictype(4 * 17) = ictype(6 * 17) = ictype(7 * 17) =
- ictype(8 * 17) = ictype(9 * 17) = ictype(11 * 17) =
- ictype(12 * 17) = ictype(13 * 17) = ictype(14 * 17) =
- gx_dc_type_none;
- /* falls through */
- case 2:
- ictype(5 * 17) = ictype(10 * 17) = gx_dc_type_none;
- #undef ictype
- }
- }
- /* Initialize the color mapping tables for a non-mask image. */
- private void
- image_init_colors(gx_image_enum * penum, int bps, int spp,
- gs_image_format_t format, const float *decode /*[spp*2] */ ,
- const gs_imager_state * pis, gx_device * dev,
- const gs_color_space * pcs, bool * pdcb)
- {
- int ci;
- static const float default_decode[] = {
- 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0
- };
- image_init_clues(penum, bps, spp);
- /* Initialize the maps from samples to intensities. */
- for (ci = 0; ci < spp; ci++) {
- sample_map *pmap = &penum->map[ci];
- /* If the decoding is [0 1] or [1 0], we can fold it */
- /* into the expansion of the sample values; */
- /* otherwise, we have to use the floating point method. */
- const float *this_decode = &decode[ci * 2];
- const float *map_decode; /* decoding used to */
- /* construct the expansion map */
- const float *real_decode; /* decoding for expanded samples */
- bool no_decode;
- map_decode = real_decode = this_decode;
- if (map_decode[0] == 0.0 && map_decode[1] == 1.0)
- no_decode = true;
- else if (map_decode[0] == 1.0 && map_decode[1] == 0.0 && bps <= 8) {
- no_decode = true;
- real_decode = default_decode;
- } else {
- no_decode = false;
- *pdcb = false;
- map_decode = default_decode;
- }
- if (bps > 2 || format != gs_image_format_chunky) {
- if (bps <= 8)
- image_init_map(&pmap->table.lookup8[0], 1 << bps,
- map_decode);
- } else { /* The map index encompasses more than one pixel. */
- byte map[4];
- register int i;
- image_init_map(&map[0], 1 << bps, map_decode);
- switch (bps) {
- case 1:
- {
- register bits32 *p = &pmap->table.lookup4x1to32[0];
- if (map[0] == 0 && map[1] == 0xff)
- memcpy((byte *) p, lookup4x1to32_identity, 16 * 4);
- else if (map[0] == 0xff && map[1] == 0)
- memcpy((byte *) p, lookup4x1to32_inverted, 16 * 4);
- else
- for (i = 0; i < 16; i++, p++)
- ((byte *) p)[0] = map[i >> 3],
- ((byte *) p)[1] = map[(i >> 2) & 1],
- ((byte *) p)[2] = map[(i >> 1) & 1],
- ((byte *) p)[3] = map[i & 1];
- }
- break;
- case 2:
- {
- register bits16 *p = &pmap->table.lookup2x2to16[0];
- for (i = 0; i < 16; i++, p++)
- ((byte *) p)[0] = map[i >> 2],
- ((byte *) p)[1] = map[i & 3];
- }
- break;
- }
- }
- pmap->decode_base /* = decode_lookup[0] */ = real_decode[0];
- pmap->decode_factor =
- (real_decode[1] - real_decode[0]) /
- (bps <= 8 ? 255.0 : (float)frac_1);
- pmap->decode_max /* = decode_lookup[15] */ = real_decode[1];
- if (no_decode) {
- pmap->decoding = sd_none;
- pmap->inverted = map_decode[0] != 0;
- } else if (bps <= 4) {
- int step = 15 / ((1 << bps) - 1);
- int i;
- pmap->decoding = sd_lookup;
- for (i = 15 - step; i > 0; i -= step)
- pmap->decode_lookup[i] = pmap->decode_base +
- i * (255.0 / 15) * pmap->decode_factor;
- } else
- pmap->decoding = sd_compute;
- if (spp == 1) { /* and ci == 0 *//* Pre-map entries 0 and 255. */
- gs_client_color cc;
- cc.paint.values[0] = real_decode[0];
- (*pcs->type->remap_color) (&cc, pcs, &penum->icolor0,
- pis, dev, gs_color_select_source);
- cc.paint.values[0] = real_decode[1];
- (*pcs->type->remap_color) (&cc, pcs, &penum->icolor1,
- pis, dev, gs_color_select_source);
- }
- }
- }
- /* Construct a mapping table for sample values. */
- /* map_size is 2, 4, 16, or 256. Note that 255 % (map_size - 1) == 0, */
- /* so the division 0xffffL / (map_size - 1) is always exact. */
- private void
- image_init_map(byte * map, int map_size, const float *decode)
- {
- float min_v = decode[0];
- float diff_v = decode[1] - min_v;
- if (diff_v == 1 || diff_v == -1) { /* We can do the stepping with integers, without overflow. */
- byte *limit = map + map_size;
- uint value = (uint)(min_v * 0xffffL);
- int diff = (int)(diff_v * (0xffffL / (map_size - 1)));
- for (; map != limit; map++, value += diff)
- *map = value >> 8;
- } else { /* Step in floating point, with clamping. */
- int i;
- for (i = 0; i < map_size; ++i) {
- int value = (int)((min_v + diff_v * i / (map_size - 1)) * 255);
- map[i] = (value < 0 ? 0 : value > 255 ? 255 : value);
- }
- }
- }
- /*
- * Scale a pair of mask_color values to match the scaling of each sample to
- * a full byte, and complement and swap them if the map incorporates
- * a Decode = [1 0] inversion.
- */
- void
- gx_image_scale_mask_colors(gx_image_enum *penum, int component_index)
- {
- uint scale = 255 / ((1 << penum->bps) - 1);
- uint *values = &penum->mask_color.values[component_index * 2];
- uint v0 = values[0] *= scale;
- uint v1 = values[1] *= scale;
- if (penum->map[component_index].decoding == sd_none &&
- penum->map[component_index].inverted
- ) {
- values[0] = 255 - v1;
- values[1] = 255 - v0;
- }
- }
|