diff options
author | Henry Stiles <henry.stiles@artifex.com> | 1998-08-08 06:11:33 +0000 |
---|---|---|
committer | Henry Stiles <henry.stiles@artifex.com> | 1998-08-08 06:11:33 +0000 |
commit | 3305477b99710b8ce6223a0bdd5014ced4de6997 (patch) | |
tree | 2cd123878deab83af88cbfcbff04624712c5b46c /gs/src/gxshade.c | |
parent | b8cb922d73b866149ca3da2288f1edcf959c45c9 (diff) | |
download | ghostpdl-3305477b99710b8ce6223a0bdd5014ced4de6997.tar.gz |
Initial revision
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@277 06663e23-700e-0410-b217-a244a6096597
Diffstat (limited to 'gs/src/gxshade.c')
-rw-r--r-- | gs/src/gxshade.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/gs/src/gxshade.c b/gs/src/gxshade.c new file mode 100644 index 000000000..3d763062c --- /dev/null +++ b/gs/src/gxshade.c @@ -0,0 +1,363 @@ +/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved. + + This file is part of Aladdin Ghostscript. + + Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author + or distributor accepts any responsibility for the consequences of using it, + or for whether it serves any particular purpose or works at all, unless he + or she says so in writing. Refer to the Aladdin Ghostscript Free Public + License (the "License") for full details. + + Every copy of Aladdin Ghostscript must include a copy of the License, + normally in a plain ASCII text file named PUBLIC. The License grants you + the right to copy, modify and redistribute Aladdin Ghostscript, but only + under certain conditions described in the License. Among other things, the + License requires that the copyright notice and this notice be preserved on + all copies. + */ + +/*Id: gxshade.c */ +/* Shading rendering support */ +#include "math_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsrect.h" +#include "gxcspace.h" +#include "gscie.h" /* requires gscspace.h */ +#include "gxdevcli.h" +#include "gxistate.h" +#include "gxdht.h" /* for computing # of different colors */ +#include "gxpaint.h" +#include "gxshade.h" + +/* ================ Packed coordinate streams ================ */ + +/* Forward references */ +private int cs_next_packed_value(P3(shade_coord_stream_t *, int, uint *)); +private int cs_next_array_value(P3(shade_coord_stream_t *, int, uint *)); +private int cs_next_packed_decoded(P4(shade_coord_stream_t *, int, + const float[2], float *)); +private int cs_next_array_decoded(P4(shade_coord_stream_t *, int, + const float[2], float *)); + +/* Initialize a packed value stream. */ +void +shade_next_init(shade_coord_stream_t * cs, + const gs_shading_mesh_params_t * params, const gs_imager_state * pis) +{ + cs->params = params; + cs->pctm = &pis->ctm; + if (data_source_is_stream(params->DataSource)) { + cs->s = params->DataSource.data.strm; + } else { + sread_string(&cs->ds, params->DataSource.data.str.data, + params->DataSource.data.str.size); + cs->s = &cs->ds; + } + if (data_source_is_array(params->DataSource)) + cs->get_value = cs_next_array_value, + cs->get_decoded = cs_next_array_decoded; + else + cs->get_value = cs_next_packed_value, + cs->get_decoded = cs_next_packed_decoded; + cs->left = 0; +} + +/* Get the next (integer) value from a packed value stream. */ +/* 1 <= num_bits <= sizeof(uint) * 8. */ +private int +cs_next_packed_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue) +{ + uint bits = cs->bits; + int left = cs->left; + + if (left >= num_bits) { + /* We can satisfy this request with the current buffered bits. */ + cs->left = left -= num_bits; + *pvalue = (bits >> left) & ((1 << num_bits) - 1); + return 0; + } + /* We need more bits. */ + { + int needed = num_bits - left; + uint value = bits & ((1 << left) - 1); /* all the remaining bits */ + + for (; needed >= 8; needed -= 8) { + int b = sgetc(cs->s); + + if (b < 0) + return_error(gs_error_rangecheck); + value = (value << 8) + b; + } + if (needed == 0) { + cs->left = 0; + *pvalue = value; + return 0; + } { + int b = sgetc(cs->s); + + if (b < 0) + return_error(gs_error_rangecheck); + cs->bits = b; + cs->left = left = 8 - needed; + *pvalue = (value << needed) + (b >> left); + return 0; + } + } +} + +/* Get the next (integer) value from an unpacked array. */ +private int +cs_next_array_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue) +{ + float value; + uint read; + + if (sgets(cs->s, (byte *) & value, sizeof(float), &read) < 0 || + read != sizeof(float) || value < 0 || value >= (1 << num_bits) || + value != (int)value + ) + return_error(gs_error_rangecheck); + + *pvalue = (uint) value; + return 0; +} + +/* Get the next decoded floating point value. */ +private int +cs_next_packed_decoded(shade_coord_stream_t * cs, int num_bits, + const float decode[2], float *pvalue) +{ + uint value; + int code = next_value(cs, num_bits, &value); + double max_value = (double)(uint) ((1 << num_bits) - 1); + + if (code < 0) + return code; + *pvalue = + (decode == 0 ? value / max_value : + decode[0] + value * (decode[1] - decode[0]) / max_value); + return 0; +} + +/* Get the next floating point value from an array, without decoding. */ +private int +cs_next_array_decoded(shade_coord_stream_t * cs, int num_bits, + const float decode[2], float *pvalue) +{ + float value; + uint read; + + if (sgets(cs->s, (byte *) & value, sizeof(float), &read) < 0 || + read != sizeof(float) + ) + return_error(gs_error_rangecheck); + + *pvalue = value; + return 0; +} + +/* Get the next flag value. */ +/* Note that this always starts a new data byte. */ +int +shade_next_flag(shade_coord_stream_t * cs, int BitsPerFlag) +{ + uint flag; + int code; + + cs->left = 0; /* start a new byte if packed */ + code = next_value(cs, BitsPerFlag, &flag); + return (code < 0 ? code : flag); +} + +/* Get one or more coordinate pairs. */ +int +shade_next_coords(shade_coord_stream_t * cs, gs_fixed_point * ppt, + int num_points) +{ + int num_bits = cs->params->BitsPerCoordinate; + const float *decode = cs->params->Decode; + int code = 0; + int i; + + for (i = 0; i < num_points; ++i) { + float x, y; + + if ((code = next_decoded(cs, num_bits, decode, &x)) < 0 || + (code = next_decoded(cs, num_bits, decode, &y)) < 0 || + (code = gs_point_transform2fixed(cs->pctm, x, y, &ppt[i])) < 0 + ) + break; + } + return code; +} + +/* Get a color. Currently all this does is look up Indexed colors. */ +int +shade_next_color(shade_coord_stream_t * cs, float *pc) +{ + const float *decode = cs->params->Decode + 4; /* skip coord decode */ + const gs_color_space *pcs = cs->params->ColorSpace; + gs_color_space_index index = gs_color_space_get_index(pcs); + int num_bits = cs->params->BitsPerComponent; + + if (index == gs_color_space_index_Indexed) { + uint i; + int code = next_value(cs, num_bits, &i); + + if (code < 0) + return code; +/****** DO INDEXED LOOKUP TO pc[] ******/ + } else { + int i, code; + int ncomp = gs_color_space_num_components(pcs); + + for (i = 0; i < ncomp; ++i) + if ((code = next_decoded(cs, num_bits, decode + i * 2, &pc[i])) < 0) + return code; + } + return 0; +} + +/* Get the next vertex for a mesh element. */ +int +shade_next_vertex(shade_coord_stream_t * cs, mesh_vertex_t * vertex) +{ + int code = shade_next_coords(cs, &vertex->p, 1); + + if (code >= 0) + code = shade_next_color(cs, vertex->cc); + return code; +} + +/* ================ Shading rendering ================ */ + +/* Fill a (user space) rectangle with a shading. */ +int +gs_shading_fill_rectangle(const gs_shading_t * psh, const gs_rect * rect, + gx_device * dev, gs_imager_state * pis) +{ + gs_rect box; + const gs_rect *prect; + + if (psh->params.have_BBox) { + box = *rect; + rect_intersect(box, psh->params.BBox); + prect = &box; + } else { + prect = rect; + } + return (*psh->head.fill_rectangle) (psh, rect, dev, pis); +} + +/* Initialize the common parts of the recursion state. */ +void +shade_init_fill_state(shading_fill_state_t * pfs, const gs_shading_t * psh, + gx_device * dev, gs_imager_state * pis) +{ + const gs_color_space *pcs = psh->params.ColorSpace; + float max_error = pis->smoothness; + /* + * There's no point in trying to achieve smoothness beyond what + * the device can implement, i.e., the number of representable + * colors times the size of the halftone cell. + */ + long num_colors = + max(dev->color_info.max_gray, dev->color_info.max_color) + 1; + const gs_range *ranges = 0; + int ci; + + pfs->dev = dev; + pfs->pis = pis; + pfs->num_components = gs_color_space_num_components(pcs); +top: + switch ( gs_color_space_get_index(pcs) ) + { + case gs_color_space_index_Indexed: + pcs = gs_cspace_base_space(pcs); + goto top; + case gs_color_space_index_CIEDEFG: + ranges = pcs->params.defg->RangeDEFG.ranges; + break; + case gs_color_space_index_CIEDEF: + ranges = pcs->params.def->RangeDEF.ranges; + break; + case gs_color_space_index_CIEABC: + ranges = pcs->params.abc->RangeABC.ranges; + break; + case gs_color_space_index_CIEA: + ranges = &pcs->params.a->RangeA; + break; + default: + break; + } + if (num_colors <= 32) { + /****** WRONG FOR MULTI-PLANE HALFTONES ******/ + num_colors *= pis->dev_ht->order.num_levels; + } + if (max_error < 1.0 / num_colors) + max_error = 1.0 / num_colors; + for (ci = 0; ci < pfs->num_components; ++ci) + pfs->cc_max_error[ci] = + (ranges == 0 ? max_error : + max_error * (ranges[ci].rmax - ranges[ci].rmin)); +} + +/* Transform a bounding box into device space. */ +int +shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis, + gs_fixed_rect * rfixed) +{ + gs_rect dev_rect; + int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect); + + if (code >= 0) { + rfixed->p.x = float2fixed(dev_rect.p.x); + rfixed->p.y = float2fixed(dev_rect.p.y); + rfixed->q.x = float2fixed(dev_rect.q.x); + rfixed->q.y = float2fixed(dev_rect.q.y); + } + return code; +} + +/* Check whether 4 colors fall within the smoothness criterion. */ +bool +shade_colors4_converge(const gs_client_color cc[4], + const shading_fill_state_t * pfs) +{ + int ci; + + for (ci = 0; ci < pfs->num_components; ++ci) { + float + c0 = cc[0].paint.values[ci], c1 = cc[1].paint.values[ci], + c2 = cc[2].paint.values[ci], c3 = cc[3].paint.values[ci]; + float min01, max01, min23, max23; + + if (c0 < c1) + min01 = c0, max01 = c1; + else + min01 = c1, max01 = c0; + if (c2 < c3) + min23 = c2, max23 = c3; + else + min23 = c3, max23 = c2; + if (max(max01, max23) - min(min01, min23) > pfs->cc_max_error[ci]) + return false; + } + return true; +} + +/* Fill one piece of a shading. */ +int +shade_fill_path(const shading_fill_state_t * pfs, gx_path * ppath, + gx_device_color * pdevc) +{ + gx_fill_params params; + + params.rule = -1; /* irrelevant */ + params.adjust = pfs->pis->fill_adjust; + params.flatness = 0; /* irrelevant */ + params.fill_zero_width = false; + return (*dev_proc(pfs->dev, fill_path)) (pfs->dev, pfs->pis, ppath, + ¶ms, pdevc, NULL); +} |