diff options
Diffstat (limited to 'gs/base/gstrans.c')
-rw-r--r-- | gs/base/gstrans.c | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/gs/base/gstrans.c b/gs/base/gstrans.c new file mode 100644 index 000000000..35ea7e40d --- /dev/null +++ b/gs/base/gstrans.c @@ -0,0 +1,463 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + 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 that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* Implementation of transparency, other than rendering */ +#include "math_.h" +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gstrans.h" +#include "gsutil.h" +#include "gzstate.h" +#include "gxdevcli.h" +#include "gdevdevn.h" +#include "gxblend.h" +#include "gdevp14.h" + +#define PUSH_TS 0 + +/* ------ Transparency-related graphics state elements ------ */ + +int +gs_setblendmode(gs_state *pgs, gs_blend_mode_t mode) +{ +#ifdef DEBUG + if (gs_debug_c('v')) { + static const char *const bm_names[] = { GS_BLEND_MODE_NAMES }; + + dlprintf1("[v](0x%lx)blend_mode = ", (ulong)pgs); + if (mode >= 0 && mode < countof(bm_names)) + dprintf1("%s\n", bm_names[mode]); + else + dprintf1("%d??\n", (int)mode); + } +#endif + if (mode < 0 || mode > MAX_BLEND_MODE) + return_error(gs_error_rangecheck); + pgs->blend_mode = mode; + return 0; +} + +gs_blend_mode_t +gs_currentblendmode(const gs_state *pgs) +{ + return pgs->blend_mode; +} + +int +gs_setopacityalpha(gs_state *pgs, floatp alpha) +{ + if_debug2('v', "[v](0x%lx)opacity.alpha = %g\n", (ulong)pgs, alpha); + pgs->opacity.alpha = (alpha < 0.0 ? 0.0 : alpha > 1.0 ? 1.0 : alpha); + return 0; +} + +float +gs_currentopacityalpha(const gs_state *pgs) +{ + return pgs->opacity.alpha; +} + +int +gs_setshapealpha(gs_state *pgs, floatp alpha) +{ + if_debug2('v', "[v](0x%lx)shape.alpha = %g\n", (ulong)pgs, alpha); + pgs->shape.alpha = (alpha < 0.0 ? 0.0 : alpha > 1.0 ? 1.0 : alpha); + return 0; +} + +float +gs_currentshapealpha(const gs_state *pgs) +{ + return pgs->shape.alpha; +} + +int +gs_settextknockout(gs_state *pgs, bool knockout) +{ + if_debug2('v', "[v](0x%lx)text_knockout = %s\n", (ulong)pgs, + (knockout ? "true" : "false")); + pgs->text_knockout = knockout; + return 0; +} + +bool +gs_currenttextknockout(const gs_state *pgs) +{ + return pgs->text_knockout; +} + +/* ------ Transparency rendering stack ------ */ + +gs_transparency_state_type_t +gs_current_transparency_type(const gs_state *pgs) +{ + return (pgs->transparency_stack == 0 ? 0 : + pgs->transparency_stack->type); +} + +/* Support for dummy implementation */ +gs_private_st_ptrs1(st_transparency_state, gs_transparency_state_t, + "gs_transparency_state_t", transparency_state_enum_ptrs, + transparency_state_reloc_ptrs, saved); +#if PUSH_TS +static int +push_transparency_stack(gs_state *pgs, gs_transparency_state_type_t type, + client_name_t cname) +{ + gs_transparency_state_t *pts = + gs_alloc_struct(pgs->memory, gs_transparency_state_t, + &st_transparency_state, cname); + + if (pts == 0) + return_error(gs_error_VMerror); + pts->saved = pgs->transparency_stack; + pts->type = type; + pgs->transparency_stack = pts; + return 0; +} +#endif +static void +pop_transparency_stack(gs_state *pgs, client_name_t cname) +{ + gs_transparency_state_t *pts = pgs->transparency_stack; /* known non-0 */ + gs_transparency_state_t *saved = pts->saved; + + gs_free_object(pgs->memory, pts, cname); + pgs->transparency_stack = saved; + +} + +/* + * Push a PDF 1.4 transparency compositor onto the current device. Note that + * if the current device already is a PDF 1.4 transparency compositor, the + * create_compositor will update its parameters but not create a new + * compositor device. + */ +static int +gs_state_update_pdf14trans(gs_state * pgs, gs_pdf14trans_params_t * pparams) +{ + gs_imager_state * pis = (gs_imager_state *)pgs; + gx_device * dev = pgs->device; + gx_device *pdf14dev = NULL; + int code; + + /* + * Send the PDF 1.4 create compositor action specified by the parameters. + */ + code = send_pdf14trans(pis, dev, &pdf14dev, pparams, pgs->memory); + /* + * If we created a new PDF 1.4 compositor device then we need to install it + * into the graphics state. + */ + if (code >= 0 && pdf14dev != dev) + gx_set_device_only(pgs, pdf14dev); + + return code; +} + +void +gs_trans_group_params_init(gs_transparency_group_params_t *ptgp) +{ + ptgp->ColorSpace = 0; /* bogus, but can't do better */ + ptgp->Isolated = false; + ptgp->Knockout = false; + ptgp->image_with_SMask = false; + ptgp->mask_id = 0; +} + +int +gs_begin_transparency_group(gs_state *pgs, + const gs_transparency_group_params_t *ptgp, + const gs_rect *pbbox) +{ + gs_pdf14trans_params_t params = { 0 }; + +#ifdef DEBUG + if (gs_debug_c('v')) { + static const char *const cs_names[] = { + GS_COLOR_SPACE_TYPE_NAMES + }; + + dlprintf5("[v](0x%lx)begin_transparency_group [%g %g %g %g]\n", + (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y); + if (ptgp->ColorSpace) + dprintf1(" CS = %s", + cs_names[(int)gs_color_space_get_index(ptgp->ColorSpace)]); + else + dputs(" (no CS)"); + dprintf2(" Isolated = %d Knockout = %d\n", + ptgp->Isolated, ptgp->Knockout); + } +#endif + /* + * Put parameters into a compositor parameter and then call the + * create_compositor. This will pass the data to the PDF 1.4 + * transparency device. + */ + params.pdf14_op = PDF14_BEGIN_TRANS_GROUP; + params.Isolated = ptgp->Isolated; + params.Knockout = ptgp->Knockout; + params.image_with_SMask = ptgp->image_with_SMask; + params.opacity = pgs->opacity; + params.shape = pgs->shape; + params.blend_mode = pgs->blend_mode; + /* + * We are currently doing nothing with the colorspace. Currently + * the blending colorspace is based upon the processs color model + * of the output device. + */ + params.bbox = *pbbox; + return gs_state_update_pdf14trans(pgs, ¶ms); +} + +int +gx_begin_transparency_group(gs_imager_state * pis, gx_device * pdev, + const gs_pdf14trans_params_t * pparams) +{ + gs_transparency_group_params_t tgp = {0}; + gs_rect bbox; + + if (pparams->Background_components != 0 && + pparams->Background_components != pdev->color_info.num_components) + return_error(gs_error_rangecheck); + tgp.Isolated = pparams->Isolated; + tgp.Knockout = pparams->Knockout; + tgp.idle = pparams->idle; + tgp.mask_id = pparams->mask_id; + pis->opacity.alpha = pparams->opacity.alpha; + pis->shape.alpha = pparams->shape.alpha; + pis->blend_mode = pparams->blend_mode; + bbox = pparams->bbox; +#ifdef DEBUG + if (gs_debug_c('v')) { + static const char *const cs_names[] = { + GS_COLOR_SPACE_TYPE_NAMES + }; + + dlprintf5("[v](0x%lx)gx_begin_transparency_group [%g %g %g %g]\n", + (ulong)pis, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y); + if (tgp.ColorSpace) + dprintf1(" CS = %s", + cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]); + else + dputs(" (no CS)"); + dprintf2(" Isolated = %d Knockout = %d\n", + tgp.Isolated, tgp.Knockout); + } +#endif + if (dev_proc(pdev, begin_transparency_group) != 0) + return (*dev_proc(pdev, begin_transparency_group)) (pdev, &tgp, + &bbox, pis, NULL, NULL); + else + return 0; +} + +int +gs_end_transparency_group(gs_state *pgs) +{ + gs_pdf14trans_params_t params = { 0 }; + + if_debug0('v', "[v]gs_end_transparency_group\n"); + params.pdf14_op = PDF14_END_TRANS_GROUP; /* Other parameters not used */ + return gs_state_update_pdf14trans(pgs, ¶ms); +} + +int +gx_end_transparency_group(gs_imager_state * pis, gx_device * pdev) +{ + if_debug0('v', "[v]gx_end_transparency_group\n"); + if (dev_proc(pdev, end_transparency_group) != 0) + return (*dev_proc(pdev, end_transparency_group)) (pdev, pis, NULL); + else + return 0; +} + +/* + * Handler for identity mask transfer functions. + */ +static int +mask_transfer_identity(floatp in, float *out, void *proc_data) +{ + *out = (float) in; + return 0; +} + +void +gs_trans_mask_params_init(gs_transparency_mask_params_t *ptmp, + gs_transparency_mask_subtype_t subtype) +{ + ptmp->subtype = subtype; + ptmp->Background_components = 0; + ptmp->TransferFunction = mask_transfer_identity; + ptmp->TransferFunction_data = 0; + ptmp->replacing = false; +} + +int +gs_begin_transparency_mask(gs_state * pgs, + const gs_transparency_mask_params_t * ptmp, + const gs_rect * pbbox, bool mask_is_image) +{ + gs_pdf14trans_params_t params = { 0 }; + const int l = sizeof(params.Background[0]) * ptmp->Background_components; + int i; + + if_debug8('v', "[v](0x%lx)gs_begin_transparency_mask [%g %g %g %g]\n\ + subtype = %d Background_components = %d %s\n", + (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y, + (int)ptmp->subtype, ptmp->Background_components, + (ptmp->TransferFunction == mask_transfer_identity ? "no TR" : + "has TR")); + params.pdf14_op = PDF14_BEGIN_TRANS_MASK; + params.bbox = *pbbox; + params.subtype = ptmp->subtype; + params.Background_components = ptmp->Background_components; + memcpy(params.Background, ptmp->Background, l); + params.GrayBackground = ptmp->GrayBackground; + params.transfer_function = ptmp->TransferFunction_data; + params.function_is_identity = + (ptmp->TransferFunction == mask_transfer_identity); + params.mask_is_image = mask_is_image; + params.replacing = ptmp->replacing; + /* Sample the transfer function */ + for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) { + float in = (float)(i * (1.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1))); + float out; + + ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data); + params.transfer_fn[i] = (byte)floor((double)(out * 255 + 0.5)); + } + return gs_state_update_pdf14trans(pgs, ¶ms); +} + +int +gx_begin_transparency_mask(gs_imager_state * pis, gx_device * pdev, + const gs_pdf14trans_params_t * pparams) +{ + gx_transparency_mask_params_t tmp; + const int l = sizeof(pparams->Background[0]) * pparams->Background_components; + + tmp.subtype = pparams->subtype; + tmp.Background_components = pparams->Background_components; + memcpy(tmp.Background, pparams->Background, l); + tmp.GrayBackground = pparams->GrayBackground; + tmp.function_is_identity = pparams->function_is_identity; + tmp.idle = pparams->idle; + tmp.replacing = pparams->replacing; + tmp.mask_id = pparams->mask_id; + memcpy(tmp.transfer_fn, pparams->transfer_fn, size_of(tmp.transfer_fn)); + if_debug8('v', "[v](0x%lx)gx_begin_transparency_mask [%g %g %g %g]\n\ + subtype = %d Background_components = %d %s\n", + (ulong)pis, pparams->bbox.p.x, pparams->bbox.p.y, + pparams->bbox.q.x, pparams->bbox.q.y, + (int)tmp.subtype, tmp.Background_components, + (tmp.function_is_identity ? "no TR" : + "has TR")); + if (dev_proc(pdev, begin_transparency_mask) != 0) + return (*dev_proc(pdev, begin_transparency_mask)) + (pdev, &tmp, &(pparams->bbox), pis, NULL, NULL); + else + return 0; +} + +int +gs_end_transparency_mask(gs_state *pgs, + gs_transparency_channel_selector_t csel) +{ + gs_pdf14trans_params_t params = { 0 }; + + if_debug2('v', "[v](0x%lx)gs_end_transparency_mask(%d)\n", (ulong)pgs, + (int)csel); + + params.pdf14_op = PDF14_END_TRANS_MASK; /* Other parameters not used */ + params.csel = csel; + return gs_state_update_pdf14trans(pgs, ¶ms); +} + +int +gx_end_transparency_mask(gs_imager_state * pis, gx_device * pdev, + const gs_pdf14trans_params_t * pparams) +{ + if_debug2('v', "[v](0x%lx)gx_end_transparency_mask(%d)\n", (ulong)pis, + (int)pparams->csel); + if (dev_proc(pdev, end_transparency_mask) != 0) + return (*dev_proc(pdev, end_transparency_mask)) (pdev, NULL); + else + return 0; +} + +int +gs_discard_transparency_layer(gs_state *pgs) +{ + /****** NYI, DUMMY ******/ + gs_transparency_state_t *pts = pgs->transparency_stack; + + if_debug1('v', "[v](0x%lx)gs_discard_transparency_layer\n", (ulong)pgs); + if (!pts) + return_error(gs_error_rangecheck); + pop_transparency_stack(pgs, "gs_discard_transparency_layer"); + return 0; +} + +/* + * We really only care about the number of spot colors when we have + * a device which supports spot colors. With the other devices we use + * the tint transform function for DeviceN and Separation color spaces + * and convert spot colors into process colors. + */ +static int +get_num_pdf14_spot_colors(gs_state * pgs) +{ + gx_device * dev = pgs->device; + gs_devn_params * pclist_devn_params = dev_proc(dev, ret_devn_params)(dev); + + /* + * Devices which support spot colors store the PageSpotColors device + * parameter inside their devn_params structure. (This is done by the + * devn_put_params routine.) The PageSpotColors device parameter is + * set by pdf_main whenever a PDF page is being processed. See + * countspotcolors in lib/pdf_main.ps. + */ + if (pclist_devn_params != NULL) { + return pclist_devn_params->page_spot_colors; + } + return 0; +} + +int +gs_push_pdf14trans_device(gs_state * pgs) +{ + gs_pdf14trans_params_t params = { 0 }; + + params.pdf14_op = PDF14_PUSH_DEVICE; + /* + * We really only care about the number of spot colors when we have + * a device which supports spot colors. With the other devices we use + * the tint transform function for DeviceN and Separation color spaces + * and convert spot colors into process colors. + */ + params.num_spot_colors = get_num_pdf14_spot_colors(pgs); + /* Note: Other parameters not used */ + return gs_state_update_pdf14trans(pgs, ¶ms); +} + +int +gs_pop_pdf14trans_device(gs_state * pgs) +{ + gs_pdf14trans_params_t params = { 0 }; + + params.pdf14_op = PDF14_POP_DEVICE; /* Other parameters not used */ + return gs_state_update_pdf14trans(pgs, ¶ms); +} |