diff options
author | Ray Johnston <ray.johnston@artifex.com> | 2016-09-07 10:37:27 -0700 |
---|---|---|
committer | Michael Vrhel <michael.vrhel@artifex.com> | 2016-09-07 15:49:35 -0700 |
commit | c835d00d51a70d410e0092f9442d30bcf38e95f1 (patch) | |
tree | fc5158626c323b5a8b1208ee7549895a7ea0d42c | |
parent | 4b101952d81a5899972f81f7b18ef3becd5bd45e (diff) | |
download | ghostpdl-c835d00d51a70d410e0092f9442d30bcf38e95f1.tar.gz |
Soft Mask Matte Entry Bug 697097
Included getting the Matte color entries to the
transparency compositor action (Thanks to Ray)
and undoing the preblend with the Matte bias.
-rw-r--r-- | Resource/Init/pdf_draw.ps | 59 | ||||
-rw-r--r-- | base/gdevp14.c | 43 | ||||
-rw-r--r-- | base/gdevp14.h | 2 | ||||
-rw-r--r-- | base/gstparam.h | 7 | ||||
-rw-r--r-- | base/gstrans.c | 18 | ||||
-rw-r--r-- | base/gstrans.h | 4 | ||||
-rw-r--r-- | base/gxblend1.c | 60 | ||||
-rw-r--r-- | psi/ztrans.c | 17 |
8 files changed, 131 insertions, 79 deletions
diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps index 88c99acf4..fb2e564d8 100644 --- a/Resource/Init/pdf_draw.ps +++ b/Resource/Init/pdf_draw.ps @@ -2110,24 +2110,6 @@ currentdict /last-ditch-bpc-csp undef } bdef } if -/is_big_mask { % - is_big_mask <bool> - 1 0 dtransform dup mul exch dup mul add sqrt - 0 1 dtransform dup mul exch dup mul add sqrt mul - currentdevice getdeviceprops .dicttomark /BufferSpace .knownget not { - 4000000 % hack: Can't get the real default value from C source. - } if - 2 % arbitrary - div gt -} bind def - -% For development needs we define a special option for running with a new handler -% for images with a soft mask. -//systemdict /NEW_IMAGE3X .knownget not { //false } if { - /is_big_mask { % - is_big_mask <bool> - //false - } bdef -} if - /doimage { % <imagemask> doimage - % imagedict is currentdict, gets popped from dstack //null checkOPtrans { @@ -2149,38 +2131,19 @@ currentdict /last-ditch-bpc-csp undef } if DataSource exch - PDFusingtransparency - /PreserveSMask /GetDeviceParam .special_op { - exch pop not - }{ - //true - }ifelse - { - % This is a temporary workaround for the bug 689080, - % which is done under a rush of 8.63 release. - % The purpose is to disable a conversion of an image with soft mask - % into a Type 103 image, which currently allocates a full mask buffer - % before writing clist. - % With this workaround the Matte color is not working (ignored). - is_big_mask not - } { - //true % pdfwrite doesn't need the workaround explained above, - % and cannot work with it. - } ifelse - and { - currentdict /SMask knownoget - } { - //false - } ifelse { - makesoftmaskimage - } { - currentdict /Mask knownoget { - makemaskimage + currentdict /SMask known PDFusingtransparency and { + /PreserveSMask /GetDeviceParam .special_op { + pop pop + currentdict /SMask oget + makesoftmaskimage } if - } ifelse + } if + currentdict /Mask knownoget { + makemaskimage + } if % Stack: datasource imagemask - { currentdict end setfillstate { imagemask } } - { ColorSpace setgcolorspace currentdict end setfillblend { image } } + { currentdict end setfillstate { imagemask } } + { ColorSpace setgcolorspace currentdict end setfillblend { image } } ifelse PDFSTOPONERROR { exec //false } { stopped } ifelse { dup type /dicttype eq { pop } if % Sometimes image fails to restore the stack diff --git a/base/gdevp14.c b/base/gdevp14.c index e5e781dd2..8c077cef1 100644 --- a/base/gdevp14.c +++ b/base/gdevp14.c @@ -130,10 +130,10 @@ static void pdf14_debug_mask_stack_state(pdf14_ctx *ctx); #endif /* Buffer stack data structure */ -gs_private_st_ptrs6(st_pdf14_buf, pdf14_buf, "pdf14_buf", +gs_private_st_ptrs7(st_pdf14_buf, pdf14_buf, "pdf14_buf", pdf14_buf_enum_ptrs, pdf14_buf_reloc_ptrs, saved, data, backdrop, transfer_fn, mask_stack, - parent_color_info_procs); + matte, parent_color_info_procs); gs_private_st_ptrs2(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx", pdf14_ctx_enum_ptrs, pdf14_ctx_reloc_ptrs, @@ -624,6 +624,8 @@ pdf14_buf_new(gs_int_rect *rect, bool has_tags, bool has_alpha_g, result->n_planes = n_planes; result->rowstride = rowstride; result->transfer_fn = NULL; + result->matte_num_comps = 0; + result->matte = NULL; result->mask_stack = NULL; result->idle = idle; result->mask_id = 0; @@ -685,6 +687,7 @@ pdf14_buf_free(pdf14_buf *buf, gs_memory_t *memory) gs_free_object(memory, buf->mask_stack, "pdf14_buf_free"); gs_free_object(memory, buf->transfer_fn, "pdf14_buf_free"); + gs_free_object(memory, buf->matte, "pdf14_buf_free"); gs_free_object(memory, buf->data, "pdf14_buf_free"); while (old_parent_color_info) { @@ -1200,8 +1203,9 @@ static int pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, byte bg_alpha, byte *transfer_fn, bool idle, bool replacing, uint mask_id, gs_transparency_mask_subtype_t subtype, - int numcomps, int Background_components, - const float Background[], + int numcomps, + int Background_components, const float Background[], + int Matte_components, const float Matte[], const float GrayBackground) { pdf14_buf *buf; @@ -1230,6 +1234,14 @@ pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, byte bg_alpha, buf->shape = 0xff; buf->blend_mode = BLEND_MODE_Normal; buf->transfer_fn = transfer_fn; + buf->matte_num_comps = Matte_components; + if (Matte_components) { + buf->matte = (byte *)gs_alloc_bytes(ctx->memory, sizeof(float)*Matte_components, + "pdf14_push_transparency_mask"); + if (buf->matte == NULL) + return_error(gs_error_VMerror); + memcpy(buf->matte, Matte, size_of(float)*Matte_components); + } buf->mask_id = mask_id; /* If replacing=false, we start the mask for an image with SMask. In this case the image's SMask temporary replaces the @@ -2083,6 +2095,7 @@ pdf14_discard_trans_layer(gx_device *dev, gs_gstate * pgs) next = buf->saved; gs_free_object(ctx->memory, buf->transfer_fn, "pdf14_discard_trans_layer"); + gs_free_object(ctx->memory, buf->matte, "pdf14_discard_trans_layer"); gs_free_object(ctx->memory, buf->data, "pdf14_discard_trans_layer"); gs_free_object(ctx->memory, buf->backdrop, "pdf14_discard_trans_layer"); /* During the soft mask push, the mask_stack was copied (not moved) from @@ -4598,6 +4611,8 @@ pdf14_begin_transparency_mask(gx_device *dev, group_color_numcomps, ptmp->Background_components, ptmp->Background, + ptmp->Matte_components, + ptmp->Matte, ptmp->GrayBackground); } @@ -5850,6 +5865,7 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize, *pbuf++ = pparams->replacing; *pbuf++ = pparams->function_is_identity; *pbuf++ = pparams->Background_components; + *pbuf++ = pparams->Matte_components; put_value(pbuf, pparams->bbox); mask_id = pparams->mask_id; put_value(pbuf, mask_id); @@ -5861,6 +5877,12 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize, memcpy(pbuf, &pparams->GrayBackground, sizeof(pparams->GrayBackground)); pbuf += sizeof(pparams->GrayBackground); } + if (pparams->Matte_components) { + const int m = sizeof(pparams->Matte[0]) * pparams->Matte_components; + + memcpy(pbuf, pparams->Matte, m); + pbuf += m; + } if (!pparams->function_is_identity) mask_size = sizeof(pparams->transfer_fn); /* Color space information may be ICC based @@ -6024,9 +6046,9 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, break; case PDF14_BEGIN_TRANS_MASK: /* This is the largest transparency parameter at this time (potentially - * 1275 bytes in size if Background_components = - * GS_CLIENT_COLOR_MAX_COMPONENTS and we have a transfer function - * as well). + * 1531 bytes in size if Background_components = + * GS_CLIENT_COLOR_MAX_COMPONENTS and Matte_components = + * GS_CLIENT_COLOR_MAX_COMPONENTS and we have a transfer function as well). * * NOTE: * The clist reader must be able to handle this sized device. @@ -6042,6 +6064,7 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, params.replacing = *data++; params.function_is_identity = *data++; params.Background_components = *data++; + params.Matte_components = *data++; read_value(data, params.bbox); read_value(data, params.mask_id); if (params.Background_components) { @@ -6052,6 +6075,12 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, memcpy(¶ms.GrayBackground, data, sizeof(params.GrayBackground)); data += sizeof(params.GrayBackground); } + if (params.Matte_components) { + const int m = sizeof(params.Matte[0]) * params.Matte_components; + + memcpy(params.Matte, data, m); + data += m; + } read_value(data, params.icc_hash); if (params.function_is_identity) { int i; diff --git a/base/gdevp14.h b/base/gdevp14.h index 65247a63c..0c9b0bb0c 100644 --- a/base/gdevp14.h +++ b/base/gdevp14.h @@ -150,6 +150,8 @@ struct pdf14_buf_s { int n_planes; /* total number of planes including alpha, shape, alpha_g */ byte *data; byte *transfer_fn; + int matte_num_comps; + byte *matte; /* actually floats */ gs_int_rect dirty; pdf14_mask_t *mask_stack; bool idle; diff --git a/base/gstparam.h b/base/gstparam.h index 2141a456b..9b2cea70b 100644 --- a/base/gstparam.h +++ b/base/gstparam.h @@ -94,7 +94,9 @@ typedef struct gs_transparency_mask_params_s { const gs_color_space *ColorSpace; gs_transparency_mask_subtype_t subtype; int Background_components; + int Matte_components; float Background[GS_CLIENT_COLOR_MAX_COMPONENTS]; + float Matte[GS_CLIENT_COLOR_MAX_COMPONENTS]; float GrayBackground; int (*TransferFunction)(double in, float *out, void *proc_data); gs_function_t *TransferFunction_data; @@ -111,7 +113,9 @@ typedef struct gx_transparency_mask_params_s { int group_color_numcomps; gs_transparency_color_t group_color; int Background_components; + int Matte_components; float Background[GS_CLIENT_COLOR_MAX_COMPONENTS]; + float Matte[GS_CLIENT_COLOR_MAX_COMPONENTS]; float GrayBackground; bool function_is_identity; bool idle; @@ -132,10 +136,11 @@ typedef struct gx_transparency_mask_params_s { 1 + sizeof(float) * 6 /* See sput_matrix. */ + \ sizeof(((gs_pdf14trans_params_t *)0)->subtype) + \ sizeof(((gs_pdf14trans_params_t *)0)->group_color_numcomps) + \ - 4 /* group color, replacing, function_is_identity, Background_components */ + \ + 5 /* group color, replacing, function_is_identity, Background_components, Matte_components */ + \ sizeof(((gs_pdf14trans_params_t *)0)->bbox) + \ sizeof(((gs_pdf14trans_params_t *)0)->mask_id) + \ sizeof(((gs_pdf14trans_params_t *)0)->Background) + \ + sizeof(((gs_pdf14trans_params_t *)0)->Matte) + \ sizeof(float)*4 + /* If cmyk background */ \ sizeof(((gs_pdf14trans_params_t *)0)->GrayBackground) + \ sizeof(int64_t)) /* ICC band information */ diff --git a/base/gstrans.c b/base/gstrans.c index 9b00b93d6..91d2aba8b 100644 --- a/base/gstrans.c +++ b/base/gstrans.c @@ -507,6 +507,7 @@ gs_trans_mask_params_init(gs_transparency_mask_params_t *ptmp, ptmp->ColorSpace = 0; ptmp->subtype = subtype; ptmp->Background_components = 0; + ptmp->Matte_components = 0; ptmp->GrayBackground = 0.0; ptmp->TransferFunction = mask_transfer_identity; ptmp->TransferFunction_data = 0; @@ -522,6 +523,7 @@ gs_begin_transparency_mask(gs_gstate * pgs, gs_pdf14trans_params_t params = { 0 }; gs_pdf14trans_params_t params_color = { 0 }; const int l = sizeof(params.Background[0]) * ptmp->Background_components; + const int m = sizeof(params.Matte[0]) * ptmp->Matte_components; int i, code; gs_color_space *blend_color_space; gsicc_manager_t *icc_manager = pgs->icc_manager; @@ -535,6 +537,8 @@ gs_begin_transparency_mask(gs_gstate * pgs, params.subtype = ptmp->subtype; params.Background_components = ptmp->Background_components; memcpy(params.Background, ptmp->Background, l); + params.Matte_components = ptmp->Matte_components; + memcpy(params.Matte, ptmp->Matte, m); params.GrayBackground = ptmp->GrayBackground; params.transfer_function = ptmp->TransferFunction_data; params.function_is_identity = @@ -566,10 +570,11 @@ gs_begin_transparency_mask(gs_gstate * pgs, blend_color_space = gs_cspace_new_DeviceGray(pgs->memory); blend_color_space->cmm_icc_profile_data = pgs->icc_manager->default_gray; rc_increment(blend_color_space->cmm_icc_profile_data); - if_debug8m('v', pgs->memory, "[v](0x%lx)gs_begin_transparency_mask [%g %g %g %g]\n\ - subtype = %d Background_components = %d %s\n", + if_debug9m('v', pgs->memory, "[v](0x%lx)gs_begin_transparency_mask [%g %g %g %g]\n\ + subtype = %d Background_components = %d, Matte_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->Matte_components, (ptmp->TransferFunction == mask_transfer_identity ? "no TR" : "has TR")); /* Sample the transfer function */ @@ -614,12 +619,15 @@ gx_begin_transparency_mask(gs_gstate * pgs, gx_device * pdev, { gx_transparency_mask_params_t tmp; const int l = sizeof(pparams->Background[0]) * pparams->Background_components; + const int m = sizeof(pparams->Matte[0]) * pparams->Matte_components; tmp.group_color = pparams->group_color; tmp.subtype = pparams->subtype; tmp.group_color_numcomps = pparams->group_color_numcomps; tmp.Background_components = pparams->Background_components; memcpy(tmp.Background, pparams->Background, l); + tmp.Matte_components = pparams->Matte_components; + memcpy(tmp.Matte, pparams->Matte, m); tmp.GrayBackground = pparams->GrayBackground; tmp.function_is_identity = pparams->function_is_identity; tmp.idle = pparams->idle; @@ -635,12 +643,12 @@ gx_begin_transparency_mask(gs_gstate * pgs, gx_device * pdev, tmp.icc_hashcode = 0; } memcpy(tmp.transfer_fn, pparams->transfer_fn, size_of(tmp.transfer_fn)); - if_debug9m('v', pgs->memory, + if_debug10m('v', pgs->memory, "[v](0x%lx)gx_begin_transparency_mask [%g %g %g %g]\n" - " subtype = %d Background_components = %d Num_grp_clr_comp = %d %s\n", + " subtype = %d Background_components = %d Matte_components = %d Num_grp_clr_comp = %d %s\n", (ulong)pgs, pparams->bbox.p.x, pparams->bbox.p.y, pparams->bbox.q.x, pparams->bbox.q.y, - (int)tmp.subtype, tmp.Background_components, + (int)tmp.subtype, tmp.Background_components, tmp.Matte_components, tmp.group_color_numcomps, (tmp.function_is_identity ? "no TR" : "has TR")); diff --git a/base/gstrans.h b/base/gstrans.h index 23fc14de5..d06cc5234 100644 --- a/base/gstrans.h +++ b/base/gstrans.h @@ -91,9 +91,11 @@ struct gs_pdf14trans_params_s { gs_transparency_channel_selector_t csel; /* Parameters from the gx_transparency_mask_params_t structure */ gs_transparency_mask_subtype_t subtype; - int Background_components; bool function_is_identity; + int Background_components; float Background[GS_CLIENT_COLOR_MAX_COMPONENTS]; + int Matte_components; + float Matte[GS_CLIENT_COLOR_MAX_COMPONENTS]; float GrayBackground; /* This is used to determine if the softmask's bbox needs to be adjusted to the parent groups bbox. Since diff --git a/base/gxblend1.c b/base/gxblend1.c index 484cc643f..4a0a04fa9 100644 --- a/base/gxblend1.c +++ b/base/gxblend1.c @@ -311,6 +311,8 @@ pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf, byte pix_alpha; byte *backdrop_ptr = NULL; pdf14_device *pdev = (pdf14_device *)dev; + bool has_matte = false; + byte matte_alpha = 0xff; #if RAW_DUMP byte *composed_ptr = NULL; #endif @@ -354,6 +356,8 @@ pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf, mask_bg_alpha = mask_tr_fn[mask_bg_alpha]; tmp = alpha * mask_bg_alpha + 0x80; mask_bg_alpha = (tmp + (tmp >> 8)) >> 8; + if (maskbuf->matte != NULL) + has_matte = true; } n_chan--; #if RAW_DUMP @@ -388,30 +392,58 @@ pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf, group alpha value */ if (maskbuf != NULL) { if (!in_mask_rect) { - /* Special case where we have a soft mask but are outside the - range of the soft mask and must use the background alpha value */ + /* Special case where we have a soft mask but are outside + the range of the soft mask and must use the background + alpha value */ pix_alpha = mask_bg_alpha; + matte_alpha = 0xff; } else { /* If we are isolated, do not double apply the alpha */ - if (tos_isolated) { + if (tos_isolated) pix_alpha = 0xff; - } + /* If we have a matte entry (pre-multiplied) then get + the mask alpha so we can undo for proper blending */ + if (has_matte) + matte_alpha = mask_tr_fn[*mask_curr_ptr]; } } - /* Complement the components for subtractive color spaces */ - if (additive) { - for (i = 0; i <= n_chan; ++i) { - tos_pixel[i] = tos_ptr[i * tos_planestride]; - nos_pixel[i] = nos_ptr[i * nos_planestride]; - } - } else { - for (i = 0; i < n_chan; ++i) { - tos_pixel[i] = 255 - tos_ptr[i * tos_planestride]; - nos_pixel[i] = 255 - nos_ptr[i * nos_planestride]; + + if (has_matte && matte_alpha != 0 && matte_alpha < 0xff) { + for (i = 0; i < n_chan; i++) { + int val = (tos_ptr[i * tos_planestride] - maskbuf->matte[i] < 0 ? + 0 : tos_ptr[i * tos_planestride] - maskbuf->matte[i]); + int temp = ((((val * 0xff) << 8) / matte_alpha) >> 8) + maskbuf->matte[i]; + + if (temp > 0xff) + tos_pixel[i] = 0xff; + else + tos_pixel[i] = temp; + + if (!additive) { + tos_pixel[i] = 255 - tos_pixel[i]; + nos_pixel[i] = 255 - nos_ptr[i * nos_planestride]; + } else + nos_pixel[i] = nos_ptr[i * nos_planestride]; } + /* alpha */ tos_pixel[n_chan] = tos_ptr[n_chan * tos_planestride]; nos_pixel[n_chan] = nos_ptr[n_chan * nos_planestride]; + } else { + if (additive) { + for (i = 0; i <= n_chan; ++i) { + tos_pixel[i] = tos_ptr[i * tos_planestride]; + nos_pixel[i] = nos_ptr[i * nos_planestride]; + } + } else { + for (i = 0; i < n_chan; ++i) { + tos_pixel[i] = 255 - tos_ptr[i * tos_planestride]; + nos_pixel[i] = 255 - nos_ptr[i * nos_planestride]; + } + tos_pixel[n_chan] = tos_ptr[n_chan * tos_planestride]; + nos_pixel[n_chan] = nos_ptr[n_chan * nos_planestride]; + } } + if (mask_curr_ptr != NULL) { if (in_mask_rect) { byte mask = mask_tr_fn[*mask_curr_ptr++]; diff --git a/psi/ztrans.c b/psi/ztrans.c index d38d1c37b..3874dd451 100644 --- a/psi/ztrans.c +++ b/psi/ztrans.c @@ -231,7 +231,7 @@ zbegintransparencygroup(i_ctx_t *i_ctx_p) } else { /* the PDF interpreter sets the colorspace, so use it */ params.ColorSpace = gs_currentcolorspace(igs); - /* Lets make sure that it is not an ICC color space that came from + /* Lets make sure that it is not an ICC color space that came from a PS CIE color space or a PS color space. These are 1-way color spaces and cannot be used for group color spaces */ if (gs_color_space_is_PSCIE(params.ColorSpace)) @@ -287,6 +287,7 @@ zbegintransparencymaskgroup(i_ctx_t *i_ctx_p) return code; else if (code > 0) params.Background_components = code; + if ((code = dict_floats_param(imemory, dop, "GrayBackground", 1, ¶ms.GrayBackground, NULL)) < 0) return code; @@ -325,18 +326,28 @@ zbegintransparencymaskgroup(i_ctx_t *i_ctx_p) return code; } -/* - .begintransparencymaskimage - */ +/* <paramdict> .begintransparencymaskimage <paramdict> */ static int zbegintransparencymaskimage(i_ctx_t *i_ctx_p) { + os_ptr dop = osp; gs_transparency_mask_params_t params; gs_rect bbox = { { 0, 0} , { 1, 1} }; int code; gs_color_space *gray_cs = gs_cspace_new_DeviceGray(imemory); + check_type(*dop, t_dictionary); + check_dict_read(*dop); if (!gray_cs) return_error(gs_error_VMerror); gs_trans_mask_params_init(¶ms, TRANSPARENCY_MASK_Luminosity); + if ((code = dict_float_array_check_param(imemory, dop, "Matte", + GS_CLIENT_COLOR_MAX_COMPONENTS, + params.Matte, NULL, 0, + gs_error_rangecheck)) < 0) + return code; + else if (code > 0) + params.Matte_components = code; code = gs_begin_transparency_mask(igs, ¶ms, &bbox, true); if (code < 0) return code; @@ -527,7 +538,7 @@ const op_def ztrans2_op_defs[] = { {"5.begintransparencygroup", zbegintransparencygroup}, {"0.endtransparencygroup", zendtransparencygroup}, {"5.begintransparencymaskgroup", zbegintransparencymaskgroup}, - {"5.begintransparencymaskimage", zbegintransparencymaskimage}, + {"1.begintransparencymaskimage", zbegintransparencymaskimage}, {"1.endtransparencymask", zendtransparencymask}, {"1.image3x", zimage3x}, {"1.pushpdf14devicefilter", zpushpdf14devicefilter}, |