diff options
author | Timothy Osborn <timothy.osborn@artifex.com> | 2007-03-23 13:56:11 +0000 |
---|---|---|
committer | Timothy Osborn <timothy.osborn@artifex.com> | 2007-03-23 13:56:11 +0000 |
commit | a735c9f699f7c1121276a2c8761a06d3770928ce (patch) | |
tree | 5e3cc3167c9bde6d313ff857cf2c5cf0e0ae8e88 | |
parent | bbf19d56ef91433e6997998101eed6e584afb354 (diff) |
Custom color hooks code merge
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@7795 a1074d23-0009-0410-80fe-cf8c14f379e6
56 files changed, 4052 insertions, 1060 deletions
diff --git a/gs/lib/pdf_main.ps b/gs/lib/pdf_main.ps index 09eefdf3c..007f65892 100644 --- a/gs/lib/pdf_main.ps +++ b/gs/lib/pdf_main.ps @@ -461,6 +461,7 @@ pdfdict begin if pdfopenfile begin pdfopencache + writeoutputintents .writepdfmarks { % Copy bookmarks (outline) to the output. Trailer /Root oget /Outlines knownoget { @@ -1147,6 +1148,10 @@ end readonly def } ifelse % Don't change the page size if we are going to fit the PDF to the page systemdict /PDFFitPage known { currentdict /PageSize undef } if + % Determine the number of spot colors used on the page. Note: This searches + % the pages resources. It may be high if a spot color is in a resource but + % is not actually used on the page. + << /PageSpotColors 3 index countspotcolors >> setpagedevice % Let the device know if we will be using PDF 1.4 transparency. % The clist logic may need to adjust the size of bands. 1 index pageusestransparency /PageUsesTransparency exch def @@ -1274,6 +1279,9 @@ end readonly def % problems, for example with the pnga device. endpage end % scratch dict + % Indicate that the number of spot colors is unknown in case the next page + % imaged is a PS file. + << /PageSpotColors -1 >> setpagedevice % Some PDF files don't have matching q/Q (gsave/grestore) so we need % to clean up any left over dicts from the dictstack countdictstack PDFdictstackcount sub dup 0 ne { @@ -1409,6 +1417,119 @@ end readonly def } if } bind def +% Add a color name to our spot color list. Ignore /All and /None +/putspotcolor { % <name> <spotcolordict> putspotcolor - + % The 'name' could be a string. If so then convert to a name. + exch dup type /stringtype eq { cvn } if + dup dup /None eq exch /All eq or { pop pop } { 0 put } ifelse +} bind def + +% Determine which spot colors are used within a color space Note: This +% dict will include all colors used in Separation or DeviceN color spaces. +% Thus it may include Cyan, Magenta, Yellow, and Black. +% <colorspace> <spotcolordict> colorspacespotcolors - +/colorspacespotcolors { + exch dup type /arraytype eq { + % If we have an Indexed color space then get the base space. + dup 0 oget dup /Indexed eq { + pop 1 oget 2 copy colorspacespotcolors + } { + % Stack: <spotcolordict> <colorspace> <colorspacetype> + dup /Separation eq exch /DeviceN eq or { + dup 1 oget dup type /arraytype eq { + { oforce 2 index putspotcolor } forall + } { + 2 index putspotcolor + } ifelse + } if + } ifelse + } if + pop pop +} bind def + +% Check the Resources of a page, form, or annotation. Determine which spot +% colors are used within the resource Note: The spot color dict will include +% all colors used in Separation or DeviceN color spaces. Thus it may include +% Cyan, Magenta, Yellow, and Black. We also pass a dict that is used to check +% for loops in the resource list. +% <spotcolordict> <loopdict> <page/form/annot dict> +% resourcespotcolors <spotcolordict> <loopdict> +/resourcespotcolors { + { % Use loop to provide an exitable context. + % Exit if no Resources entry + /Resources knownoget not { exit } if + % Exit if we have already seen this dict + 2 copy known { pop exit } if + + % Save the Resources dict into our loop checking dict. + 2 copy 0 put + + % Scan resources that might contain a color space. + dup /ColorSpace knownoget { + { exch pop oforce 3 index colorspacespotcolors } forall + } if + dup /Pattern knownoget { + { exch pop oforce 4 copy exch pop resourcespotcolors pop pop pop } forall + } if + dup /Shading knownoget { + { exch pop oforce /ColorSpace oget 3 index colorspacespotcolors } forall + } if + /XObject knownoget { + { exch pop oforce dup + /Subtype get /Form eq { resourcespotcolors } { pop } ifelse + } forall + } if + exit + } loop +} bind def + +% Determine which spot colors are used within the annotations. Note: This +% dict will include all colors used in Separation or DeviceN color spaces. +% Thus it may include Cyan, Magenta, Yellow, and Black. +% <spotcolordict> <loopdict> <annotsarray> +% annotsspotcolors <spotcolordict> <loopdict> +/annotsspotcolors { + { oforce /AP knownoget { % Get appearance dict for the annoation + /N knownoget { % Get the /N (i.e. normal) appearance stream + resourcespotcolors + } if % If normal appearance streamknown + } if % If AP dict known + } forall +} bind def + +% Determine spot colors are used within a page. We are creating a dict to +% hold the spot color names as keys. Using a dict avoids having to worry +% about duplicate entries. The keys in the dict contain the spot color +% names. However the values have no meaning. Note: This dict will include +% all colors used in Separation or DeviceN color spaces specified in the +% page's resources. Thus it may include Cyan, Magenta, Yellow, and Black. +% There is no attempt to verify that these color spaces are actually used +% within the object streams for the page. +/pagespotcolors { % <pagedict> pagespotcolors <spotcolordict> + dup + % Create a dict to hold spot color names. + 0 dict exch + % Create a dict to be used to check for reference loops. + 4 dict exch + % Check for color spaces in the Resources + resourcespotcolors + % Also check for color spaces in the annotations. + 3 -1 roll + /Annots knownoget { annotsspotcolors } if + pop % Discard reference loop dict +} bind def + +% Determine how many (if any) spot colors are used by a page. +% Note: This count does not include Cyan, Magenta, Yellow, or Black +/countspotcolors { % <pagedict> countspotcolors <count> + pagespotcolors % Get dict with all spot colors + dup length % spot color dict length + % Remove CMYK from the spot color count. + [ /Cyan /Magenta /Yellow /Black ] + { 2 index exch known { 1 sub } if } forall + exch pop % Remove spot color dict +} bind def + % ------ ColorSpace substitution support ------ % % @@ -1458,7 +1579,47 @@ end readonly def } bind def - +% Write OutputIntents to device if the device handles it +/writeoutputintents { + currentdevice 1 dict dup /OutputIntent null put readonly + .getdeviceparams + mark ne { pop pop + % device supports OutputIntent parameter + Trailer /Root oget /OutputIntents knownoget { + { % process all output profiles present + dup length dict .copydict + dup /DestOutputProfile knownoget { + PDFfile fileposition exch + mark exch { oforce } forall .dicttomark + true resolvestream + [ { counttomark 1 add index + 64000 string readstring + not { exit} if + } loop + ] exch closefile + 0 1 index { length add } forall .bytestring + 0 3 2 roll { + 3 copy putinterval + length add + } forall pop + exch PDFfile exch setfileposition + 1 index /DestOutputProfile 3 2 roll put + } if + % Convert to string array because it's easier for the device + [ 1 index /OutputCondition knownoget not { () } if + 2 index /OutputConditionIdentifier knownoget not { () } if + 3 index /RegistryName knownoget not { () } if + 4 index /Info knownoget not { () } if + 5 index /DestOutputProfile knownoget not { () } if + ] + [ /OutputIntent 3 2 roll .pdfputparams pop pop + pop % done with this OutputIntent dictionary + } forall + } if % OutputIntents known + % tell device there are no more OutputIntents + [ /OutputIntent [ ] .pdfputparams pop pop + } if +} bind def end % pdfdict .setglobal diff --git a/gs/lib/pdf_ops.ps b/gs/lib/pdf_ops.ps index 25ad66881..3af5db732 100644 --- a/gs/lib/pdf_ops.ps +++ b/gs/lib/pdf_ops.ps @@ -25,6 +25,13 @@ systemdict /pdfmark known not { userdict /pdfmark { cleartomark } bind put } if +/renderingintentdict mark + /Absolute 0 + /RelativeColorimetric 1 + /Saturation 2 + /Perceptual 3 +.dicttomark readonly def + userdict /GS_PDF_ProcSet 127 dict dup begin % ---------------- Abbreviations ---------------- % @@ -194,7 +201,7 @@ nodict readonly pop /K { 4 array astore cvx //csdevcmyk scput } bdef /cs { csset fcput } bdef /CS { csset scput } bdef -/ri { pop } bdef +/ri { //renderingintentdict exch .knownget { .setrenderingintent } if } bdef % We have to break up sc according to the number of operands. /sc1 { /FillColor gput } bdef /SC1 { /StrokeColor gput } bdef diff --git a/gs/src/gdevbbox.c b/gs/src/gdevbbox.c index 536d6d806..e23eeac3e 100644 --- a/gs/src/gdevbbox.c +++ b/gs/src/gdevbbox.c @@ -272,6 +272,7 @@ gx_device_bbox_init(gx_device_bbox * dev, gx_device * target, gs_memory_t *mem) set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); set_dev_proc(dev, get_page_device, gx_forward_get_page_device); + set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); gx_device_set_target((gx_device_forward *)dev, target); } else { gx_device_fill_in_procs((gx_device *)dev); diff --git a/gs/src/gdevdevn.c b/gs/src/gdevdevn.c index 7889ca2bd..58ac0dbe7 100644 --- a/gs/src/gdevdevn.c +++ b/gs/src/gdevdevn.c @@ -25,6 +25,8 @@ #include "gxdcconv.h" #include "gdevdevn.h" #include "gsequivc.h" +#include "gxblend.h" +#include "gdevp14.h" /* * Utility routines for common DeviceN related parameters: @@ -349,6 +351,7 @@ devn_put_params(gx_device * pdev, gs_param_list * plist, bool num_spot_changed = false; int num_order = pdevn_params->num_separation_order_names; int max_sep = pdevn_params->max_separations; + int page_spot_colors = pdevn_params->page_spot_colors; gs_param_string_array scna; /* SeparationColorNames array */ gs_param_string_array sona; /* SeparationOrder names array */ @@ -415,7 +418,8 @@ devn_put_params(gx_device * pdev, gs_param_list * plist, num_order = sona.size; for (i = 0; i < num_spot + npcmcolors; i++) - pdevn_params->separation_order_map[i] = GX_DEVICE_COLOR_MAX_COMPONENTS; + pdevn_params->separation_order_map[i] = + GX_DEVICE_COLOR_MAX_COMPONENTS; for (i = 0; i < num_order; i++) { /* * Check if names match either the process color model or @@ -445,25 +449,29 @@ devn_put_params(gx_device * pdev, gs_param_list * plist, case 0: if (max_sep < 1 || max_sep > GX_DEVICE_COLOR_MAX_COMPONENTS) return_error(gs_error_rangecheck); -#if !USE_COMPRESSED_ENCODING - /* - * If we are not using a compressed pixel encoding, then the - * device depth (pixel size) varies with the number of - * separations. The depth is constant with the compressed - * encoding scheme. - */ - { - int depth = - bpc_to_depth(max_sep, pdevn_params->bitspercomponent); - - if (depth > 8 * size_of(gx_color_index)) - return_error(gs_error_rangecheck); - pdev->color_info.depth = depth; - } -#endif - pdevn_params->max_separations = - pdev->color_info.max_components = - pdev->color_info.num_components = max_sep; + } + /* + * The PDF interpreter scans the resources for pages to try to + * determine the number of spot colors. (Unfortuneately there is + * no way to determine the number of spot colors for a PS page + * except to interpret the entire page.) The spot color count for + * a PDF page may be high since there may be spot colors in a PDF + * page's resources that are not used. However this does give us + * an upper limit on the number of spot colors. A value of -1 + * indicates that the number of spot colors in unknown (a PS file). + */ + code = param_read_int(plist, param_name = "PageSpotColors", + &page_spot_colors); + switch (code) { + default: + param_signal_error(plist, param_name, code); + case 1: + break; + case 0: + if (page_spot_colors < -1) + return_error(gs_error_rangecheck); + if (page_spot_colors > GX_DEVICE_COLOR_MAX_COMPONENTS) + page_spot_colors = GX_DEVICE_COLOR_MAX_COMPONENTS; } /* * The DeviceN device can have zero components if nothing has been @@ -477,10 +485,14 @@ devn_put_params(gx_device * pdev, gs_param_list * plist, * SeparationColorNames, SeparationOrder, or MaxSeparations. */ if (num_spot_changed || pdevn_params->max_separations != max_sep || - pdevn_params->num_separation_order_names != num_order) { + pdevn_params->num_separation_order_names != num_order || + pdevn_params->page_spot_colors != page_spot_colors) { pdevn_params->separations.num_separations = num_spot; pdevn_params->num_separation_order_names = num_order; pdevn_params->max_separations = max_sep; + pdevn_params->page_spot_colors = page_spot_colors; + if (max_sep != 0) + pdev->color_info.max_components = max_sep; /* * If we have SeparationOrder specified then the number of * components is given by the number of names in the list. @@ -489,10 +501,17 @@ devn_put_params(gx_device * pdev, gs_param_list * plist, * of ProcessColorModel components plus the number of * SeparationColorNames is used. */ - pdev->color_info.num_components = (num_order) ? num_order + pdev->color_info.num_components = (num_order) + ? num_order : (pdevn_params->max_separations) - ? pdevn_params->max_separations - : npcmcolors + num_spot; + ? pdevn_params->max_separations + : (page_spot_colors >= 0) + ? npcmcolors + num_spot + page_spot_colors + : pdev->color_info.max_components; + if (pdev->color_info.num_components > + pdev->color_info.max_components) + pdev->color_info.num_components = + pdev->color_info.max_components; #if !USE_COMPRESSED_ENCODING /* * See earlier comment about the depth and non compressed @@ -550,7 +569,15 @@ devn_printer_put_params(gx_device * pdev, gs_param_list * plist, /* Reset the sparable and linear shift, masks, bits. */ set_linear_color_bits_mask_shift(pdev); } - + /* + * Also check for parameters which are being passed from the PDF 1.4 + * compositior clist write device. This device needs to pass info + * to the PDF 1.4 compositor clist reader device. However this device + * is not crated until the clist is being read. Thus we have to buffer + * this info in the output device. (This is only needed for devices + * which support spot colors.) + */ + code = pdf14_put_devn_params(pdev, pdevn_params, plist); return code; } @@ -643,7 +670,7 @@ print_compressed_color_list(compressed_color_list_t * pcomp_list, int num_comp) /* * Allocate an list level element for our encode color list. */ -private compressed_color_list_t * +compressed_color_list_t * alloc_compressed_color_list_elem(gs_memory_t * mem, int num_comps) { compressed_color_list_t * plist = @@ -659,6 +686,43 @@ alloc_compressed_color_list_elem(gs_memory_t * mem, int num_comps) } /* + * Free the elements of a compressed color list. + */ +void +free_compressed_color_list(gs_memory_t * mem, + compressed_color_list_t * pcomp_list) +{ + int i; + + if (pcomp_list == NULL) + return; + + /* Discard the sub levels. */ + for (i = 0; i < pcomp_list->num_sub_level_ptrs; i++) + free_compressed_color_list(mem, pcomp_list->u.sub_level_ptrs[i]); + + gs_free_object(mem, pcomp_list, "free_compressed_color_list"); + return; +} + +/* + * Free a set of separation names + */ +void +free_separation_names(gs_memory_t * mem, + gs_separations * pseparation) +{ + int i; + + /* Discard the sub levels. */ + for (i = 0; i < pseparation->num_separations; i++) + gs_free_object(mem, pseparation->names[i].data, + "free_separation_names"); + pseparation->num_separations = 0; + return; +} + +/* * Add a new set of bit mapped colorant lists to our list of encoded color * colorants. */ @@ -840,7 +904,7 @@ init_compressed_color_list(gs_memory_t *mem) * the number of colorants being used times size of the colorant value saved * must fit into a gx_color_index value. */ -static int num_comp_bits[MAX_ENCODED_COMPONENTS + 1] = { +int num_comp_bits[MAX_ENCODED_COMPONENTS + 1] = { 8, /* 0 colorants - not used */ 8, /* 1 colorants */ 8, /* 2 colorants */ @@ -868,7 +932,7 @@ static int num_comp_bits[MAX_ENCODED_COMPONENTS + 1] = { #define gx_color_value_factor(num_bits) \ ((gx_max_color_value << 8) + 0xff) / ((1 << num_bits) - 1) -static int comp_bit_factor[MAX_ENCODED_COMPONENTS + 1] = { +int comp_bit_factor[MAX_ENCODED_COMPONENTS + 1] = { gx_color_value_factor(8), /* 0 colorants (8 bits) */ gx_color_value_factor(8), /* 1 colorants (8 bits) */ gx_color_value_factor(8), /* 2 colorants (8 bits) */ @@ -1193,7 +1257,7 @@ devn_encode_compressed_color(gx_device *pdev, const gx_color_value colors[], /* * Find the bit map for given bit map index. */ -private comp_bit_map_list_t * +comp_bit_map_list_t * find_bit_map(gx_color_index index, compressed_color_list_t * pcomp_list) { int loc = (int)(index >> (NUM_GX_COLOR_INDEX_BITS - 8)); @@ -1336,8 +1400,6 @@ devn_unpack_row(gx_device * dev, int num_comp, gs_devn_params * pdevn_params, *out++ = solid_color >> 8; else { *out++ = (factor * ((int)color & bit_mask)) >> 16; - if (comp_num == 3 && out[-1] != 0) - comp_num = comp_num; color >>= bit_count; } } @@ -1521,6 +1583,7 @@ const spotcmyk_device gs_spotcmyk_device = DeviceCMYKComponents, /* Names of color model colorants */ 4, /* Number colorants for CMYK */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ 0, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ @@ -1540,6 +1603,7 @@ const spotcmyk_device gs_devicen_device = NULL, /* No names for standard DeviceN color model */ 0, /* No standard colorants for DeviceN */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ 0, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ diff --git a/gs/src/gdevdevn.h b/gs/src/gdevdevn.h index d2c2cdcc7..2c3eff0ea 100644 --- a/gs/src/gdevdevn.h +++ b/gs/src/gdevdevn.h @@ -90,6 +90,15 @@ typedef struct gs_devn_params_s { fixed_colorant_names_list std_colorant_names; int num_std_colorant_names; /* Number of names in list */ int max_separations; /* From MaxSeparation parameter */ + /* + * This value comes from scanning color space resources in PDF files. + * Thus this value is only valid for PDF files. The value may also + * be high if there are color space resources that are defined for + * a page but which are not actually used. This value does give us + * a maximum value for the number of spot colors. + * From the PageSpotColors parameter. + */ + int page_spot_colors; /* * Separation info (if any). @@ -109,9 +118,23 @@ typedef struct gs_devn_params_s { * Pointer to our list of which colorant combinations are being used. */ struct compressed_color_list_s * compressed_color_list; + /* + * If the file is using PDF 1.4 transparency compositing and we are using + * the clist then we need to pass the compressed color list from the PDF + * 1.4 clist writer device to the PDF 1.4 reader device. However that + * device is not created until the clist is read and being processed. + * We need to temporary hold that data in the output device until after + * clist reader PDF 1.4 compositing device is created. The PDF 1.4 + * compositor may also have a different list of separations. + */ + struct compressed_color_list_s * pdf14_compressed_color_list; + gs_separations pdf14_separations; } gs_devn_params_t; -typedef gs_devn_params_t gs_devn_params; +#ifndef gs_devn_params_DEFINED +# define gs_devn_params_DEFINED +typedef struct gs_devn_params_s gs_devn_params; +#endif extern fixed_colorant_name DeviceCMYKComponents[]; @@ -465,9 +488,53 @@ int devn_unpack_row(gx_device * dev, int num_comp, gs_devn_params * pdevn_params int width, byte * in, byte * out); /* + * Find the bit map for given bit map index. + */ +comp_bit_map_list_t * find_bit_map(gx_color_index index, + compressed_color_list_t * pcomp_list); + +/* + * Allocate an list level element for our encode color list. + */ +compressed_color_list_t * alloc_compressed_color_list_elem(gs_memory_t * mem, + int num_comps); + +/* + * The elements of this array contain the number of bits used to encode a color + * value in a 'compressed' gx_color_index value. The index into the array is + * the number of compressed components. + */ +extern int num_comp_bits[]; + +/* + * Values used to decompressed the colorants in our encoded values back into + * a gx_color value. The color value will be (comp_bits * entry) >> 8 + * The number of bits in comp_bits are defined in the num_comp_bits table. + * These values are chosen to expand these bit combinations back to 16 bit values + * (after shifting right 8 bits). + */ +/* + * The elements of this array contain factors used to convert compressed color + * values to gx_color_values. The index into the array is the number of + * compressed components. + */ +extern int comp_bit_factor[]; + +/* * A routine for debugging the encoded color colorant list. This routine * dumps the contents of the list. */ void print_compressed_color_list(compressed_color_list_t * pcomp_list, int num_comp); +/* + * Free the elements of a compressed color list. + */ +void free_compressed_color_list(gs_memory_t * mem, + compressed_color_list_t * pcomp_list); + +/* + * Free a set of separation names + */ +void free_separation_names(gs_memory_t * mem, gs_separations * pseparation); + #endif /* ifndef gdevdevn_INCLUDED */ diff --git a/gs/src/gdevdflt.c b/gs/src/gdevdflt.c index d43389da4..25a93f41c 100644 --- a/gs/src/gdevdflt.c +++ b/gs/src/gdevdflt.c @@ -665,6 +665,7 @@ gx_device_fill_in_procs(register gx_device * dev) fill_dev_proc(dev, fill_linear_color_trapezoid, gx_default_fill_linear_color_trapezoid); fill_dev_proc(dev, fill_linear_color_triangle, gx_default_fill_linear_color_triangle); fill_dev_proc(dev, update_spot_equivalent_colors, gx_default_update_spot_equivalent_colors); + fill_dev_proc(dev, ret_devn_params, gx_default_ret_devn_params); } int @@ -889,7 +890,7 @@ gx_default_include_color_space(gx_device *pdev, gs_color_space *cspace, } /* - * If a device want to determine an equivalent color for its spot colors then + * If a device wants to determine an equivalent color for its spot colors then * it needs to implement this method. See comments at the start of * src/gsequivc.c. */ @@ -899,6 +900,16 @@ gx_default_update_spot_equivalent_colors(gx_device *pdev, const gs_state * pgs) return 0; } +/* + * If a device wants to determine implement support for spot colors then + * it needs to implement this method. + */ +gs_devn_params * +gx_default_ret_devn_params(gx_device *pdev) +{ + return NULL; +} + /* ---------------- Default per-instance procedures ---------------- */ int diff --git a/gs/src/gdevdsp.c b/gs/src/gdevdsp.c index 776f295fb..b36a83bcc 100644 --- a/gs/src/gdevdsp.c +++ b/gs/src/gdevdsp.c @@ -89,6 +89,7 @@ private dev_proc_get_color_comp_index(display_separation_get_color_comp_index); private dev_proc_encode_color(display_separation_encode_color); private dev_proc_decode_color(display_separation_decode_color); private dev_proc_update_spot_equivalent_colors(display_update_spot_equivalent_colors); +private dev_proc_ret_devn_params(display_ret_devn_params); private const gx_device_procs display_procs = @@ -153,7 +154,8 @@ private const gx_device_procs display_procs = NULL, /* fill_linear_color_scanline */\ NULL, /* fill_linear_color_trapezoid */\ NULL, /* fill_linear_color_triangle */\ - display_update_spot_equivalent_colors /* update_spot_equivalent_colors */ + display_update_spot_equivalent_colors, /* update_spot_equivalent_colors */ + display_ret_devn_params /* ret_devn_params */\ }; /* GC descriptor */ @@ -207,6 +209,7 @@ const gx_device_display gs_display_device = DeviceCMYKComponents, /* Names of color model colorants */ 4, /* Number of colorants for CMYK */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ {0}, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ @@ -1166,6 +1169,17 @@ display_update_spot_equivalent_colors(gx_device * dev, const gs_state * pgs) } /* + * Device proc for returning a pointer to DeviceN parameter structure + */ +private gs_devn_params * +display_ret_devn_params(gx_device * dev) +{ + gx_device_display * pdev = (gx_device_display *)dev; + + return &pdev->devn_params; +} + +/* * This routine will check to see if the color component name match those * that are available amoung the current device's color components. * diff --git a/gs/src/gdevnfwd.c b/gs/src/gdevnfwd.c index 1abc6afa1..0fea55b1b 100644 --- a/gs/src/gdevnfwd.c +++ b/gs/src/gdevnfwd.c @@ -104,6 +104,7 @@ gx_device_forward_fill_in_procs(register gx_device_forward * dev) fill_dev_proc(dev, fill_linear_color_trapezoid, gx_forward_fill_linear_color_trapezoid); fill_dev_proc(dev, fill_linear_color_triangle, gx_forward_fill_linear_color_triangle); fill_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); + fill_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); gx_device_fill_in_procs((gx_device *) dev); } @@ -843,6 +844,17 @@ gx_forward_update_spot_equivalent_colors(gx_device *dev, const gs_state * pgs) return code; } +gs_devn_params * +gx_forward_ret_devn_params(gx_device *dev) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + if (tdev != NULL) + return dev_proc(tdev, ret_devn_params)(tdev); + return NULL; +} + /* ---------------- The null device(s) ---------------- */ diff --git a/gs/src/gdevp14.c b/gs/src/gdevp14.c index 22593a62d..911b76363 100644 --- a/gs/src/gdevp14.c +++ b/gs/src/gdevp14.c @@ -31,6 +31,7 @@ #include "gsimage.h" #include "gsrect.h" #include "gzstate.h" +#include "gdevdevn.h" #include "gdevp14.h" #include "gsovrc.h" #include "gxcmap.h" @@ -38,6 +39,19 @@ #include "gstrans.h" #include "gsutil.h" #include "gxcldev.h" +#include "gxdcconv.h" + +/* + * We chose the blending color space based upon the process color model of the + * output device. For gray, RGB, CMYK, or CMYK+spot devices, the choice is + * usually simple. For other devices or if the user is doing custom color + * processing then the user may want to control this choice. + */ +#define AUTO_CUSTOM_BLENDING 0 +#define ALWAYS_USE_CUSTOM_BLENDING 1 +#define DO_NOT_USE_CUSTOM_BLENDING 2 + +#define CUSTOM_BLENDING_MODE AUTO_CUSTOM_BLENDING /* #define DUMP_TO_PNG */ @@ -49,7 +63,7 @@ /* Buffer stack data structure */ -#define PDF14_MAX_PLANES 16 +#define PDF14_MAX_PLANES GX_DEVICE_COLOR_MAX_COMPONENTS /* GC procedures for buffer stack */ @@ -77,6 +91,115 @@ gs_private_st_ptrs2(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx", pdf14_ctx_enum_ptrs, pdf14_ctx_reloc_ptrs, stack, maskbuf); +/* + * Unpack a device color. This routine is similar to the device's + * decode_color procedure except for two things. The procedure produces 1 + * byte values instead of gx_color_values (2 bytes) and the output values + * are inverted for subtractive color spaces (like CMYK). A separate + * procedure is used instead of the decode_color to minimize execution time. + */ +private void +pdf14_unpack_additive(int num_comp, gx_color_index color, + pdf14_device * p14dev, byte * out) +{ + int i; + + for (i = num_comp - 1; i >= 0; i--) { + out[i] = (byte)(color & 0xff); + color >>= 8; + } +} + +/* + * Unpack a device color. This routine is similar to the device's + * decode_color procedure except for two things. The procedure produces 1 + * byte values instead of gx_color_values (2 bytes) and the output values + * are inverted for subtractive color spaces (like CMYK). A separate + * procedure is used instead of the decode_color to minimize execution time. + */ +private void +pdf14_unpack_subtractive(int num_comp, gx_color_index color, + pdf14_device * p14dev, byte * out) +{ + int i; + + for (i = num_comp - 1; i >= 0; i--) { + out[i] = 0xff - (byte)(color & 0xff); + color >>= 8; + } +} + +/* + * Unpack a 'compressed' CMYK color index. The color index value is unpacked + * into a set of 8 bit values. For more information about 'compressed' color + * index values see the comments before the devn_encode_compressed_color routine. + * + * Note: For simplicity of coding the calling routines, this routine will also + * handle 'uncompressed' color index values. + */ +private void +pdf14_unpack_compressed(int num_comp, gx_color_index color, + pdf14_device * p14dev, byte * out) +{ + int comp_num; + + if (p14dev->devn_params.compressed_color_list == NULL) { + /* + * For 'uncompressed' data we simply have to unpack the gx_color_index + * value directly. + */ + for (comp_num = num_comp - 1; comp_num >= 0; comp_num--) { + out[comp_num] = 0xff - (byte)(color & 0xff); + color >>= 8; + } + } + else { + int factor, bit_count, bit_mask; + comp_bit_map_list_t * pbitmap; + gx_color_value solid_color = 0xff; + + pbitmap = find_bit_map(color, + p14dev->devn_params.compressed_color_list); + bit_count = num_comp_bits[pbitmap->num_non_solid_comp]; + bit_mask = (1 << bit_count) - 1; + factor = comp_bit_factor[pbitmap->num_non_solid_comp]; + if (pbitmap->solid_not_100) { + solid_color = 0xff - ((factor * ((int)color & bit_mask)) >> 16); + color >>= bit_count; + } + for (comp_num = 0; comp_num < num_comp; comp_num++) { + if (colorant_present(pbitmap, colorants, comp_num)) { + if (colorant_present(pbitmap, solid_colorants, comp_num)) + *out++ = (byte)solid_color; + else { + *out++ = 0xff - ((factor * ((int)color & bit_mask)) >> 16); + color >>= bit_count; + } + } + else + *out++ = 0xff; + } + } +} + +/* + * Unpack a device color. This routine is used for devices in which we do + * not know the details of the process color model. In this case we use + * the device's decode_color procedure. + */ +private void +pdf14_unpack_custom(int num_comp, gx_color_index color, + pdf14_device * p14dev, byte * out) +{ + int i; + gx_device * tdev = p14dev->target; + gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS]; + + dev_proc(tdev, decode_color)(tdev, color, cm_values); + for (i = 0; i < num_comp; i++) + out[i] = 0xff - gx_color_value_to_byte(cm_values[i]); +} + /* ------ The device descriptors ------ */ /* @@ -89,8 +212,12 @@ private int pdf14_open(gx_device * pdev); private dev_proc_close_device(pdf14_close); private int pdf14_output_page(gx_device * pdev, int num_copies, int flush); private dev_proc_put_params(pdf14_put_params); +private dev_proc_get_color_comp_index(pdf14_cmykspot_get_color_comp_index); +private dev_proc_get_color_mapping_procs(pdf14_cmykspot_get_color_mapping_procs); private dev_proc_encode_color(pdf14_encode_color); +private dev_proc_encode_color(pdf14_compressed_encode_color); private dev_proc_decode_color(pdf14_decode_color); +private dev_proc_decode_color(pdf14_compressed_decode_color); private dev_proc_fill_rectangle(pdf14_fill_rectangle); private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle); private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle_ko_simple); @@ -105,6 +232,7 @@ private dev_proc_begin_transparency_group(pdf14_begin_transparency_group); private dev_proc_end_transparency_group(pdf14_end_transparency_group); private dev_proc_begin_transparency_mask(pdf14_begin_transparency_mask); private dev_proc_end_transparency_mask(pdf14_end_transparency_mask); +private int pdf14_clist_get_param_compressed_color_list(pdf14_device * p14dev); private const gx_color_map_procs * pdf14_get_cmap_procs(const gs_imager_state *, const gx_device *); @@ -114,15 +242,15 @@ private const gx_color_map_procs * /* 24-bit color. */ -#define pdf14_procs(get_color_mapping_procs, get_color_comp_index) \ +#define pdf14_dev_procs(get_color_mapping_procs, get_color_comp_index, encode_color, decode_color) \ {\ pdf14_open, /* open */\ NULL, /* get_initial_matrix */\ NULL, /* sync_output */\ pdf14_output_page, /* output_page */\ pdf14_close, /* close */\ - pdf14_encode_color, /* rgb_map_rgb_color */\ - pdf14_decode_color, /* gx_default_rgb_map_color_rgb */\ + encode_color, /* rgb_map_rgb_color */\ + decode_color, /* gx_default_rgb_map_color_rgb */\ pdf14_fill_rectangle, /* fill_rectangle */\ NULL, /* tile_rectangle */\ pdf14_copy_mono, /* copy_mono */\ @@ -167,55 +295,215 @@ private const gx_color_map_procs * NULL, /* discard_transparency_layer */\ get_color_mapping_procs, /* get_color_mapping_procs */\ get_color_comp_index, /* get_color_comp_index */\ - pdf14_encode_color, /* encode_color */\ - pdf14_decode_color /* decode_color */\ + encode_color, /* encode_color */\ + decode_color, /* decode_color */\ + NULL, /* pattern_manage */\ + NULL, /* fill_rectangle_hl_color */\ + NULL, /* include_color_space */\ + NULL, /* fill_linear_color_scanline */\ + NULL, /* fill_linear_color_trapezoid */\ + NULL, /* fill_linear_color_triangle */\ + gx_forward_update_spot_equivalent_colors /* update spot */\ } private const gx_device_procs pdf14_Gray_procs = - pdf14_procs(gx_default_DevGray_get_color_mapping_procs, - gx_default_DevGray_get_color_comp_index); + pdf14_dev_procs(gx_default_DevGray_get_color_mapping_procs, + gx_default_DevGray_get_color_comp_index, + pdf14_encode_color, pdf14_decode_color); private const gx_device_procs pdf14_RGB_procs = - pdf14_procs(gx_default_DevRGB_get_color_mapping_procs, - gx_default_DevRGB_get_color_comp_index); + pdf14_dev_procs(gx_default_DevRGB_get_color_mapping_procs, + gx_default_DevRGB_get_color_comp_index, + pdf14_encode_color, pdf14_decode_color); private const gx_device_procs pdf14_CMYK_procs = - pdf14_procs(gx_default_DevCMYK_get_color_mapping_procs, - gx_default_DevCMYK_get_color_comp_index); + pdf14_dev_procs(gx_default_DevCMYK_get_color_mapping_procs, + gx_default_DevCMYK_get_color_comp_index, + pdf14_encode_color, pdf14_decode_color); + +private const gx_device_procs pdf14_CMYKspot_procs = + pdf14_dev_procs(pdf14_cmykspot_get_color_mapping_procs, + pdf14_cmykspot_get_color_comp_index, + pdf14_compressed_encode_color, + pdf14_compressed_decode_color); + +private const gx_device_procs pdf14_custom_procs = + pdf14_dev_procs(gx_forward_get_color_mapping_procs, + gx_forward_get_color_comp_index, + gx_forward_encode_color, + gx_forward_decode_color); gs_private_st_composite_use_final(st_pdf14_device, pdf14_device, "pdf14_device", pdf14_device_enum_ptrs, pdf14_device_reloc_ptrs, gx_device_finalize); +private int pdf14_put_image(gx_device * dev, gs_imager_state * pis, + gx_device * target); +private int pdf14_cmykspot_put_image(gx_device * dev, gs_imager_state * pis, + gx_device * target); +private int pdf14_custom_put_image(gx_device * dev, gs_imager_state * pis, + gx_device * target); + +private const pdf14_procs_t gray_pdf14_procs = { + pdf14_unpack_additive, + pdf14_put_image +}; + +private const pdf14_procs_t rgb_pdf14_procs = { + pdf14_unpack_additive, + pdf14_put_image +}; + +private const pdf14_procs_t cmyk_pdf14_procs = { + pdf14_unpack_subtractive, + pdf14_put_image +}; + +private const pdf14_procs_t cmykspot_pdf14_procs = { + pdf14_unpack_compressed, + pdf14_cmykspot_put_image +}; + +private const pdf14_procs_t custom_pdf14_procs = { + pdf14_unpack_custom, + pdf14_custom_put_image +}; + +private const pdf14_nonseparable_blending_procs_t gray_blending_procs = { + art_blend_luminosity_rgb_8, + art_blend_saturation_rgb_8 +}; + +private const pdf14_nonseparable_blending_procs_t rgb_blending_procs = { + art_blend_luminosity_rgb_8, + art_blend_saturation_rgb_8 +}; + +private const pdf14_nonseparable_blending_procs_t cmyk_blending_procs = { + art_blend_luminosity_cmyk_8, + art_blend_saturation_cmyk_8 +}; + +private const pdf14_nonseparable_blending_procs_t custom_blending_procs = { + art_blend_luminosity_custom_8, + art_blend_saturation_custom_8 +}; + const pdf14_device gs_pdf14_Gray_device = { std_device_color_stype_body(pdf14_device, &pdf14_Gray_procs, "pdf14gray", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256), - { 0 } + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &gray_pdf14_procs, + &gray_blending_procs }; const pdf14_device gs_pdf14_RGB_device = { std_device_color_stype_body(pdf14_device, &pdf14_RGB_procs, "pdf14RGB", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256), - { 0 } + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &rgb_pdf14_procs, + &rgb_blending_procs }; const pdf14_device gs_pdf14_CMYK_device = { std_device_std_color_full_body_type(pdf14_device, &pdf14_CMYK_procs, - "PDF14cmyk", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32, - 0, 0, 0, 0, 0, 0), - { 0 } + "PDF14cmyk", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32, + 0, 0, 0, 0, 0, 0), + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &cmyk_pdf14_procs, + &cmyk_blending_procs +}; + +const pdf14_device gs_pdf14_CMYKspot_device = { + std_device_part1_(pdf14_device, &pdf14_CMYKspot_procs, "PDF14cmykspot", &st_pdf14_device, open_init_closed), + dci_values(GX_DEVICE_COLOR_MAX_COMPONENTS,64,255,255,256,256), + std_device_part2_(XSIZE, YSIZE, X_DPI, Y_DPI), + offset_margin_values(0, 0, 0, 0, 0, 0), + std_device_part3_(), + { 0 }, /* Procs */ + NULL, /* target */ + /* DeviceN parameters */ + { 8, /* Not used - Bits per color */ + DeviceCMYKComponents, /* Names of color model colorants */ + 4, /* Number colorants for CMYK */ + 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ + {0}, /* SeparationNames */ + 0, /* SeparationOrder names */ + {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ + }, + &cmykspot_pdf14_procs, + &cmyk_blending_procs +}; + +/* + * The 'custom' PDF 1.4 compositor device is for working with those devices + * which support spot colors but do not have a CMYK process color model. + * + * This causes some problems with the Hue, Saturation, Color, and Luminosity + * blending modes. These blending modes are 'non separable' and depend upon + * knowing the details of the blending color space. However we use the + * process color model of the output device for our blending color space. + * With an unknown process color model, we have to fall back to some 'guesses' + * about how to treat these blending modes. + */ +const pdf14_device gs_pdf14_custom_device = { + std_device_part1_(pdf14_device, &pdf14_custom_procs, "PDF14custom", &st_pdf14_device, open_init_closed), + dci_values(GX_DEVICE_COLOR_MAX_COMPONENTS,64,255,255,256,256), + std_device_part2_(XSIZE, YSIZE, X_DPI, Y_DPI), + offset_margin_values(0, 0, 0, 0, 0, 0), + std_device_part3_(), + { 0 }, /* Procs */ + NULL, /* target */ + /* DeviceN parameters */ + { 8, /* Not used - Bits per color */ + DeviceCMYKComponents, /* Names of color model colorants */ + 4, /* Number colorants for CMYK */ + 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ + {0}, /* SeparationNames */ + 0, /* SeparationOrder names */ + {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ + }, + &custom_pdf14_procs, + &custom_blending_procs }; /* GC procedures */ private -ENUM_PTRS_WITH(pdf14_device_enum_ptrs, pdf14_device *pdev) return 0; +ENUM_PTRS_WITH(pdf14_device_enum_ptrs, pdf14_device *pdev) +{ + index -= 3; + if (index < pdev->devn_params.separations.num_separations) + ENUM_RETURN(pdev->devn_params.separations.names[index].data); + index -= pdev->devn_params.separations.num_separations; + if (index < pdev->devn_params.pdf14_separations.num_separations) + ENUM_RETURN(pdev->devn_params.pdf14_separations.names[index].data); + return 0; +} case 0: return ENUM_OBJ(pdev->ctx); case 1: ENUM_RETURN(gx_device_enum_ptr(pdev->target)); +case 2: ENUM_RETURN(pdev->devn_params.compressed_color_list); ENUM_PTRS_END + private RELOC_PTRS_WITH(pdf14_device_reloc_ptrs, pdf14_device *pdev) { + { + int i; + + for (i = 0; i < pdev->devn_params.separations.num_separations; ++i) { + RELOC_PTR(pdf14_device, devn_params.separations.names[i].data); + } + } + RELOC_PTR(pdf14_device, devn_params.compressed_color_list); RELOC_VAR(pdev->ctx); pdev->target = gx_device_reloc_ptr(pdev->target, gcst); } @@ -406,28 +694,29 @@ pdf14_push_transparency_group(pdf14_ctx *ctx, gs_int_rect *rect, int n_chan_copy = buf->n_chan + (tos->has_shape ? 1 : 0); for (i = 0; i < n_chan_copy; i++) { - byte *buf_ptr = buf_plane; - byte *tos_ptr = tos_plane; - int y; - - for (y = y0; y < y1; ++y) { - memcpy (buf_ptr, tos_ptr, width); - buf_ptr += buf->rowstride; - tos_ptr += tos->rowstride; + byte *buf_ptr = buf_plane; + byte *tos_ptr = tos_plane; + int y; + + for (y = y0; y < y1; ++y) { + memcpy (buf_ptr, tos_ptr, width); + buf_ptr += buf->rowstride; + tos_ptr += tos->rowstride; + } + buf_plane += buf->planestride; + tos_plane += tos->planestride; } - buf_plane += buf->planestride; - tos_plane += tos->planestride; - } if (has_shape && !tos->has_shape) - memset (buf_plane, 0, buf->planestride); + memset (buf_plane, 0, buf->planestride); + } } - } - return 0; + return 0; } private int -pdf14_pop_transparency_group(pdf14_ctx *ctx) +pdf14_pop_transparency_group(pdf14_ctx *ctx, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { pdf14_buf *tos = ctx->stack; pdf14_buf *nos = tos->saved; @@ -547,15 +836,13 @@ pdf14_pop_transparency_group(pdf14_ctx *ctx) pix_alpha, shape); } else if (tos_isolated) { art_pdf_composite_group_8(nos_pixel, nos_alpha_g_ptr, - tos_pixel, - n_chan - 1, - pix_alpha, blend_mode); + tos_pixel, n_chan - 1, + pix_alpha, blend_mode, pblend_procs); } else { byte tos_alpha_g = tos_ptr[x + tos_alpha_g_offset]; art_pdf_recomposite_group_8(nos_pixel, nos_alpha_g_ptr, - tos_pixel, tos_alpha_g, - n_chan - 1, - pix_alpha, blend_mode); + tos_pixel, tos_alpha_g, n_chan - 1, + pix_alpha, blend_mode, pblend_procs); } if (nos_has_shape) { nos_ptr[x + nos_shape_offset] = @@ -685,6 +972,100 @@ pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out) return 0; } +/* + * Encode a list of colorant values into a gx_color_index_value. For more + * information about 'compressed' color index values see the comments before + * the devn_encode_compressed_color routine. + */ +private gx_color_index +pdf14_compressed_encode_color(gx_device *dev, const gx_color_value colors[]) +{ + return devn_encode_compressed_color(dev, colors, + &(((pdf14_device *)dev)->devn_params)); +} + +/* + * Decode a gx_color_index value back to a list of colorant values. For more + * information about 'compressed' color index values see the comments before + * the devn_encode_compressed_color routine. + */ +private int +pdf14_compressed_decode_color(gx_device * dev, gx_color_index color, + gx_color_value * out) +{ + return devn_decode_compressed_color(dev, color, out, + &(((pdf14_device *)dev)->devn_params)); +} + +static void +pdf14_gray_cs_to_cmyk_cm(gx_device * dev, frac gray, frac out[]) +{ + int num_comp = dev->color_info.num_components; + + out[0] = out[1] = out[2] = frac_0; + out[3] = frac_1 - gray; + for (--num_comp; num_comp > 3; num_comp--) + out[num_comp] = 0; +} + +/* + * Default map from DeviceRGB color space to DeviceCMYK color + * model. Since this mapping is defined by the PostScript language + * it is unlikely that any device with a DeviceCMYK color model + * would define this mapping on its own. + * + * If the imager state is not available, map as though the black + * generation and undercolor removal functions are identity + * transformations. This mode is used primarily to support the + * raster operation (rop) feature of PCL, which requires that + * the raster operation be performed in an RGB color space. + * Note that default black generation and undercolor removal + * functions in PostScript need NOT be identity transformations: + * often they are { pop 0 }. + */ +static void +pdf14_rgb_cs_to_cmyk_cm(gx_device * dev, const gs_imager_state *pis, + frac r, frac g, frac b, frac out[]) +{ + int num_comp = dev->color_info.num_components; + + if (pis != 0) + color_rgb_to_cmyk(r, g, b, pis, out); + else { + frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b; + frac k = min(c, min(m, g)); + + out[0] = c - k; + out[1] = m - k; + out[2] = y - k; + out[3] = k; + } + for (--num_comp; num_comp > 3; num_comp--) + out[num_comp] = 0; +} + +void +pdf14_cmyk_cs_to_cmyk_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) +{ + int num_comp = dev->color_info.num_components; + + out[0] = c; + out[1] = m; + out[2] = y; + out[3] = k; + for (--num_comp; num_comp > 3; num_comp--) + out[num_comp] = 0; +} +static const gx_cm_color_map_procs pdf14_DeviceCMYKspot_procs = { + pdf14_gray_cs_to_cmyk_cm, pdf14_rgb_cs_to_cmyk_cm, pdf14_cmyk_cs_to_cmyk_cm +}; + +const gx_cm_color_map_procs * +pdf14_cmykspot_get_color_mapping_procs(const gx_device * dev) +{ + return &pdf14_DeviceCMYKspot_procs; +} + #ifdef DUMP_TO_PNG /* Dumps a planar RGBA image to a PNG file. */ private int @@ -799,8 +1180,9 @@ dump_planar_rgba(gs_memory_t *mem, const pdf14_buf *pbuf) * Return code: negative on error. **/ private int -pdf14_put_image(pdf14_device *pdev, gs_imager_state *pis, gx_device *target) +pdf14_put_image(gx_device * dev, gs_imager_state * pis, gx_device * target) { + const pdf14_device * pdev = (pdf14_device *)dev; int code; gs_image1_t image; gs_matrix pmat; @@ -931,6 +1313,180 @@ pdf14_put_image(pdf14_device *pdev, gs_imager_state *pis, gx_device *target) return code; } +/** + * pdf14_cmykspot_put_image: Put rendered image to target device. + * @pdev: The PDF 1.4 rendering device. + * @pis: State for image draw operation. + * @target: The target device. + * + * Puts the rendered image in @pdev's buffer to @target. This is called + * as part of the sequence of popping the PDF 1.4 device filter. + * + * Return code: negative on error. + **/ +private int +pdf14_cmykspot_put_image(gx_device * dev, gs_imager_state * pis, gx_device * target) +{ + pdf14_device * pdev = (pdf14_device *)dev; + int code = 0; + int width = pdev->width; + int height = pdev->height; + int x, y, tmp, comp_num, output_comp_num; + pdf14_buf *buf = pdev->ctx->stack; + int planestride = buf->planestride; + int num_comp = buf->n_chan - 1; + byte *buf_ptr = buf->data; + const byte bg = pdev->ctx->additive ? gx_max_color_value : 0; + gx_color_index color; + gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; + gx_color_value comp; + byte a; + int input_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; + int output_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; + int num_known_comp = 0; + int output_num_comp = target->color_info.num_components; + gs_devn_params * pdevn_params = &pdev->devn_params; + gs_separations * pseparations = &pdevn_params->separations; + int num_sep = pseparations->num_separations++; + + if_debug0('v', "[v]pdf14_cmykspot_put_image\n"); + /* + * The process color model for the PDF 1.4 compositor device is CMYK plus + * spot colors. The target device may have only some of these colorants due + * to the SeparationOrder device parameter. Thus we need to determine the + * mapping between the PDF 1.4 compositor and the target device. Note: + * There should not be a spot colorant in the PDF 1.4 device that is not + * present in the target device. + */ + /* Check if target processes CMYK colorants. */ + for (comp_num = 0; comp_num < 4; comp_num++) { + const char * pcomp_name = (const char *)DeviceCMYKComponents[comp_num]; + + output_comp_num = dev_proc(target, get_color_comp_index) + (target, pcomp_name, strlen(pcomp_name), NO_COMP_NAME_TYPE); + if (output_comp_num >=0 && + output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { + output_map[num_known_comp] = output_comp_num; + input_map[num_known_comp++] = comp_num; + } + } + /* Check if target processes our spot colorants. */ + for (comp_num = 0; comp_num < num_sep; comp_num++) { + output_comp_num = dev_proc(target, get_color_comp_index) + (target, (const char *)(pseparations->names[comp_num].data), + pseparations->names[comp_num].size, NO_COMP_NAME_TYPE); + if (output_comp_num >= 0 && + output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { + output_map[num_known_comp] = output_comp_num; + input_map[num_known_comp++] = comp_num + 4; + } + } + + /* Clear all output colorants first */ + for (comp_num = 0; comp_num < output_num_comp; comp_num++) + cv[comp_num] = 0; + + /* Send pixel data to the target device. */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + /* composite CMYKA, etc. pixel with over solid background */ + a = buf_ptr[x + planestride * num_comp]; + + if ((a + 1) & 0xfe) { + a ^= 0xff; + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = buf_ptr[x + planestride * input_map[comp_num]]; + tmp = ((bg - comp) * a) + 0x80; + comp += tmp + (tmp >> 8); + cv[output_map[comp_num]] = comp; + } + } else if (a == 0) { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + cv[output_map[comp_num]] = bg; + } + } else { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = buf_ptr[x + planestride * input_map[comp_num]]; + cv[output_map[comp_num]] = (comp << 8) + comp; + } + } + color = dev_proc(target, encode_color)(target, cv); + code = dev_proc(target, fill_rectangle)(target, x, y, 1, 1, color); + } + + buf_ptr += buf->rowstride; + } + + return code; +} + +/** + * pdf14_custom_put_image: Put rendered image to target device. + * @pdev: The PDF 1.4 rendering device. + * @pis: State for image draw operation. + * @target: The target device. + * + * Puts the rendered image in @pdev's buffer to @target. This is called + * as part of the sequence of popping the PDF 1.4 device filter. + * + * Return code: negative on error. + **/ +private int +pdf14_custom_put_image(gx_device * dev, gs_imager_state * pis, gx_device * target) +{ + pdf14_device * pdev = (pdf14_device *)dev; + int code = 0; + int width = pdev->width; + int height = pdev->height; + int x, y, tmp, comp_num; + pdf14_buf *buf = pdev->ctx->stack; + int planestride = buf->planestride; + int num_comp = buf->n_chan - 1; + byte *buf_ptr = buf->data; + const byte bg = pdev->ctx->additive ? gx_max_color_value : 0; + gx_color_index color; + gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; + gx_color_value comp; + byte a; + + if_debug0('v', "[v]pdf14_custom_put_image\n"); + + /* Send pixel data to the target device. */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + /* composite CMYKA, etc. pixel with over solid background */ + a = buf_ptr[x + planestride * num_comp]; + + if ((a + 1) & 0xfe) { + a ^= 0xff; + for (comp_num = 0; comp_num < num_comp; comp_num++) { + comp = buf_ptr[x + planestride * comp_num]; + tmp = ((bg - comp) * a) + 0x80; + comp += tmp + (tmp >> 8); + cv[comp_num] = comp; + } + } else if (a == 0) { + for (comp_num = 0; comp_num < num_comp; comp_num++) { + cv[comp_num] = bg; + } + } else { + for (comp_num = 0; comp_num < num_comp; comp_num++) { + comp = buf_ptr[x + planestride * comp_num]; + cv[comp_num] = (comp << 8) + comp; + } + } + color = dev_proc(target, encode_color)(target, cv); + code = dev_proc(target, fill_rectangle)(target, x, y, 1, 1, color); + } + + buf_ptr += buf->rowstride; + } + + return code; +} + private int pdf14_close(gx_device *dev) { @@ -1001,6 +1557,15 @@ pdf14_forward_put_params(gx_device * dev, gs_param_list * plist) return code; } +/* Function prototypes */ +int put_param_compressed_color_list_elem(gx_device * pdev, + gs_param_list * plist, compressed_color_list_t ** pret_comp_list, + char * keyname, int num_comps); +int put_param_pdf14_spot_names(gx_device * pdev, + gs_separations * pseparations, gs_param_list * plist); +#define PDF14CompressedColorListParamName "PDF14CompressedColorList" +#define PDF14NumSpotColorsParamName "PDF14NumSpotColors" + /* * The put_params method for the PDF 1.4 device will check if the * target device has closed and, if so, close itself. Note: This routine is @@ -1021,6 +1586,11 @@ pdf14_put_params(gx_device * dev, gs_param_list * plist) code = gs_closedevice(dev); gs_pdf14_device_copy_params(dev, tdev); } +#if 0 + put_param_compressed_color_list_elem(pdev, plist, &pret_comp_list, + PDF14CompressedColorListParamName, TOP_ENCODED_LEVEL); + put_param_pdf14_spot_names(dev, &pdev->devn_params, plist); +#endif return code; } @@ -1188,17 +1758,61 @@ pdf14_disable_device(gx_device * dev) private pdf14_default_colorspace_t pdf14_determine_default_blend_cs(gx_device * pdev) { - if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE) - /* Use DeviceCMYK for all subrtactive process color models. */ - return DeviceCMYK; - else { + if (pdev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) /* * Note: We do not allow the SeparationOrder device parameter for * additive devices. Thus we always have 1 colorant for DeviceGray * and 3 colorants for DeviceRGB. We do not currently support * blending in a DeviceGray color space. Thus we oniy use DeviceRGB. */ - return DeviceRGB; + return PDF14_DeviceRGB; + else { + /* + * Check if the device is CMYK only or CMYK plus spot colors. + */ + int i, output_comp_num, num_cmyk_used = 0, num_cmyk = 0; + +#if CUSTOM_BLENDING_MODE == ALWAYS_USE_CUSTOM_BLENDING + return PDF14_DeviceCustom; +#endif + /* + * Count the number of CMYK process components supported by the output + * device. + */ + for (i = 0; i < 4; i++) { + const char * pcomp_name = (const char *)DeviceCMYKComponents[i]; + + output_comp_num = dev_proc(pdev, get_color_comp_index) + (pdev, pcomp_name, strlen(pcomp_name), NO_COMP_NAME_TYPE); + + if (output_comp_num >= 0) { + num_cmyk++; + if (output_comp_num != GX_DEVICE_COLOR_MAX_COMPONENTS) + num_cmyk_used++; + } + } + /* + * Check if the device supports only CMYK. Otherewise we assume that + * the output device supports spot colors. Note: This algorithm can + * be fooled if the SeparationOrder device parameter is being used by + * the output device device to only select CMYK. + */ + if (num_cmyk_used == 4 && pdev->color_info.num_components == 4 + && pdev->color_info.max_components == 4) + return PDF14_DeviceCMYK; + /* + * Check if we should use the 'custom' PDF 1.4 compositor device. + * This device is only needed for those devices which do not support + * a basic CMYK process color model. + */ +#if CUSTOM_BLENDING_MODE == AUTO_USE_CUSTOM_BLENDING + if (num_cmyk != 4) + return PDF14_DeviceCustom; +#endif + /* + * Otherewise we use a CMYK plus spot colors for blending. + */ + return PDF14_DeviceCMYKspot; } } @@ -1209,21 +1823,53 @@ pdf14_determine_default_blend_cs(gx_device * pdev) * currently only using a color space based upon the device. */ private int -get_pdf14_device_proto(gx_device * dev, - const pdf14_device ** pdevproto) +get_pdf14_device_proto(gx_device * dev, pdf14_device ** pdevproto, + pdf14_device * ptempdevproto, gs_imager_state * pis, + const gs_pdf14trans_t * pdf14pct) { pdf14_default_colorspace_t dev_cs = pdf14_determine_default_blend_cs(dev); switch (dev_cs) { - case DeviceGray: - *pdevproto = &gs_pdf14_Gray_device; + case PDF14_DeviceGray: + *pdevproto = (pdf14_device *)&gs_pdf14_Gray_device; + break; + case PDF14_DeviceRGB: + *pdevproto = (pdf14_device *)&gs_pdf14_RGB_device; break; - case DeviceRGB: - *pdevproto = &gs_pdf14_RGB_device; + case PDF14_DeviceCMYK: + *pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device; break; - case DeviceCMYK: - *pdevproto = &gs_pdf14_CMYK_device; + case PDF14_DeviceCMYKspot: + *pdevproto = (pdf14_device *)&gs_pdf14_CMYKspot_device; + /* + * The number of components for the PDF14 device is the sum + * of the process components and the number of spot colors + * for the page. + */ + if (pdf14pct->params.num_spot_colors >= 0) { + *ptempdevproto = **pdevproto; + ptempdevproto->devn_params.page_spot_colors = + pdf14pct->params.num_spot_colors; + ptempdevproto->color_info.num_components = + ptempdevproto->devn_params.num_std_colorant_names + + pdf14pct->params.num_spot_colors; + if (ptempdevproto->color_info.num_components > + ptempdevproto->color_info.max_components) + ptempdevproto->color_info.num_components = + ptempdevproto->color_info.max_components; + *pdevproto = ptempdevproto; + } + break; + case PDF14_DeviceCustom: + /* + * We are using the output device's process color model. The + * color_info for the PDF 1.4 compositing device needs to match + * the output device. + */ + *ptempdevproto = gs_pdf14_custom_device; + ptempdevproto->color_info = dev->color_info; + *pdevproto = ptempdevproto; break; default: /* Should not occur */ return_error(gs_error_rangecheck); @@ -1240,11 +1886,12 @@ get_pdf14_device_proto(gx_device * dev, */ private int pdf14_recreate_device(gs_memory_t *mem, gs_imager_state * pis, - gx_device * dev) + gx_device * dev, const gs_pdf14trans_t * pdf14pct) { pdf14_device * pdev = (pdf14_device *)dev; gx_device * target = pdev->target; - const pdf14_device * dev_proto; + pdf14_device * dev_proto; + pdf14_device temp_dev_proto; int code; if_debug0('v', "[v]pdf14_recreate_device\n"); @@ -1253,10 +1900,11 @@ pdf14_recreate_device(gs_memory_t *mem, gs_imager_state * pis, * We will not use the entire prototype device but we will set the * color related info and the device procs to match the prototype. */ - code = get_pdf14_device_proto(target, &dev_proto); + code = get_pdf14_device_proto(target, &dev_proto, + &temp_dev_proto, pis, pdf14pct); if (code < 0) return code; - pdev->color_info = dev_proto->color_info; + pdev->color_info = temp_dev_proto.color_info; pdev->procs = dev_proto->procs; gx_device_fill_in_procs(dev); check_device_separable((gx_device *)pdev); @@ -1281,12 +1929,13 @@ gx_update_pdf14_compositor(gx_device * pdev, gs_imager_state * pis, case PDF14_PUSH_DEVICE: p14dev->blend_mode = 0; p14dev->opacity = p14dev->shape = 0.0; - pdf14_recreate_device(mem, pis, pdev); + pdf14_recreate_device(mem, pis, pdev, pdf14pct); break; case PDF14_POP_DEVICE: pis->get_cmap_procs = p14dev->save_get_cmap_procs; gx_set_cmap_procs(pis, p14dev->target); - code = pdf14_put_image(p14dev, pis, p14dev->target); + /* Send image out raster data to output device */ + p14dev->pdf14_procs->put_image(pdev, pis, p14dev->target); pdf14_disable_device(pdev); pdf14_close(pdev); break; @@ -1524,7 +2173,7 @@ pdf14_end_transparency_group(gx_device *dev, int code; if_debug0('v', "[v]end_transparency_group\n"); - code = pdf14_pop_transparency_group(pdev->ctx); + code = pdf14_pop_transparency_group(pdev->ctx, pdev->blend_procs); return code; } @@ -1582,6 +2231,7 @@ pdf14_mark_fill_rectangle(gx_device * dev, byte shape = 0; /* Quiet compiler. */ byte src_alpha; + /* NB: gx_color_index is 4 or 8 bytes */ if (sizeof(color) <= sizeof(ulong)) if_debug7('v', "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx bm %d, nc %d,\n", x, y, w, h, (ulong)color, blend_mode, num_chan); @@ -1590,21 +2240,13 @@ pdf14_mark_fill_rectangle(gx_device * dev, x, y, w, h, (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color, blend_mode, num_chan); - /* NB: gx_color_index is 4 or 8 bytes */ - /* Complement the components for subtractive color spaces */ - if (additive) { - for (i = num_comp - 1; i >= 0; i--) { - src[i] = (byte)(color & 0xff); - color >>= 8; - } - } - else { - for (i = num_comp - 1; i >= 0; i--) { - src[i] = (byte)(0xff - (color & 0xff)); - color >>= 8; - } - } + /* + * Unpack the gx_color_index values. Complement the components for subtractive + * color spaces. + */ + pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src); + src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5); if (has_shape) shape = (byte)floor (255 * pdev->shape + 0.5); @@ -1634,7 +2276,8 @@ pdf14_mark_fill_rectangle(gx_device * dev, dst[k] = 255 - dst_ptr[k * planestride]; dst[num_comp] = dst_ptr[num_comp * planestride]; } - art_pdf_composite_pixel_alpha_8(dst, src, num_comp, blend_mode); + art_pdf_composite_pixel_alpha_8(dst, src, num_comp, + blend_mode, pdev->blend_procs); /* Complement the results for subtractive color spaces */ if (additive) { for (k = 0; k < num_chan; ++k) @@ -1688,19 +2331,12 @@ pdf14_mark_fill_rectangle_ko_simple(gx_device * dev, (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color, num_chan); - /* Complement the components for subtractive color spaces */ - if (additive) { - for (i = num_comp - 1; i >= 0; i--) { - src[i] = (byte)(color & 0xff); - color >>= 8; - } - } - else { - for (i = num_comp - 1; i >= 0; i--) { - src[i] = (byte)(0xff - (color & 0xff)); - color >>= 8; - } - } + /* + * Unpack the gx_color_index values. Complement the components for subtractive + * color spaces. + */ + pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src); + src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5); opacity = (byte)floor (255 * pdev->opacity + 0.5); @@ -1997,15 +2633,16 @@ pdf14_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev) int gs_pdf14_device_push(gs_memory_t *mem, gs_imager_state * pis, - gx_device ** pdev, gx_device * target) + gx_device ** pdev, gx_device * target, const gs_pdf14trans_t * pdf14pct) { - const pdf14_device * dev_proto; - pdf14_device *p14dev; + pdf14_device * dev_proto; + pdf14_device * p14dev, temp_dev_proto; int code; if_debug0('v', "[v]gs_pdf14_device_push\n"); - code = get_pdf14_device_proto(target, &dev_proto); + code = get_pdf14_device_proto(target, &dev_proto, + &temp_dev_proto, pis, pdf14pct); if (code < 0) return code; code = gs_copydevice((gx_device **) &p14dev, @@ -2013,13 +2650,13 @@ gs_pdf14_device_push(gs_memory_t *mem, gs_imager_state * pis, if (code < 0) return code; - check_device_separable((gx_device *)p14dev); - gx_device_fill_in_procs((gx_device *)p14dev); - gs_pdf14_device_copy_params((gx_device *)p14dev, target); rc_assign(p14dev->target, target, "gs_pdf14_device_push"); + check_device_separable((gx_device *)p14dev); + gx_device_fill_in_procs((gx_device *)p14dev); + p14dev->save_get_cmap_procs = pis->get_cmap_procs; pis->get_cmap_procs = pdf14_get_cmap_procs; gx_set_cmap_procs(pis, (gx_device *)p14dev); @@ -2089,6 +2726,8 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize) default: /* Should not occur. */ break; case PDF14_PUSH_DEVICE: + put_value(pbuf, pparams->num_spot_colors); + break; case PDF14_POP_DEVICE: case PDF14_END_TRANS_GROUP: case PDF14_END_TRANS_MASK: @@ -2183,6 +2822,8 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, default: /* Should not occur. */ break; case PDF14_PUSH_DEVICE: + read_value(data, params.num_spot_colors); + break; case PDF14_POP_DEVICE: case PDF14_END_TRANS_GROUP: break; /* No data */ @@ -2263,10 +2904,12 @@ c_pdf14trans_create_default_compositor(const gs_composite_t * pct, /* * We only handle the push operation. All other operations are ignored. + * The other operations will be handled by the create_compositor routine + * for the PDF 1.4 compositing device. */ switch (pdf14pct->params.pdf14_op) { case PDF14_PUSH_DEVICE: - code = gs_pdf14_device_push(mem, pis, &p14dev, tdev); + code = gs_pdf14_device_push(mem, pis, &p14dev, tdev, pdf14pct); *pp14dev = p14dev; break; default: @@ -2380,22 +3023,12 @@ send_pdf14trans(gs_imager_state * pis, gx_device * dev, * This section provides support for this device. */ -/* Define the default alpha-compositing device. */ -typedef struct pdf14_clist_device_s { - gx_device_forward_common; - const gx_color_map_procs *(*save_get_cmap_procs)(const gs_imager_state *, - const gx_device *); - gx_device_color_info saved_target_color_info; - float opacity; - float shape; - gs_blend_mode_t blend_mode; - bool text_knockout; -} pdf14_clist_device; - -gs_private_st_suffix_add0_final(st_pdf14_clist_device, - pdf14_clist_device, "pdf14_clist_device", - device_c_pdf14_clist_enum_ptrs, device_c_pdf14_clist_reloc_ptrs, - gx_device_finalize, st_device_forward); +/* + * Define the default pre-clist (clist writer) PDF 1.4 compositing device. + * We actually use the same structure for both the clist writer and reader + * devices. However we use separate names to identify the routines for each + * device. + */ #define pdf14_clist_procs(get_color_mapping_procs, get_color_comp_index,\ encode_color, decode_color) \ @@ -2452,7 +3085,14 @@ gs_private_st_suffix_add0_final(st_pdf14_clist_device, get_color_mapping_procs, /* get_color_mapping_procs */\ get_color_comp_index, /* get_color_comp_index */\ encode_color, /* encode_color */\ - decode_color /* decode_color */\ + decode_color, /* decode_color */\ + NULL, /* pattern_manage */\ + NULL, /* fill_rectangle_hl_color */\ + NULL, /* include_color_space */\ + NULL, /* fill_linear_color_scanline */\ + NULL, /* fill_linear_color_trapezoid */\ + NULL, /* fill_linear_color_triangle */\ + gx_forward_update_spot_equivalent_colors /* update spot */\ } private dev_proc_create_compositor(pdf14_clist_create_compositor); @@ -2480,28 +3120,97 @@ private const gx_device_procs pdf14_clist_CMYK_procs = gx_default_DevCMYK_get_color_comp_index, cmyk_8bit_map_cmyk_color, cmyk_8bit_map_color_cmyk); +private const gx_device_procs pdf14_clist_CMYKspot_procs = + pdf14_clist_procs(pdf14_cmykspot_get_color_mapping_procs, + pdf14_cmykspot_get_color_comp_index, + pdf14_compressed_encode_color, + pdf14_compressed_decode_color); + +private const gx_device_procs pdf14_clist_custom_procs = + pdf14_clist_procs(gx_forward_get_color_mapping_procs, + gx_forward_get_color_comp_index, + gx_forward_encode_color, + gx_forward_decode_color); + const pdf14_clist_device pdf14_clist_Gray_device = { std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_Gray_procs, - "pdf14clistgray", &st_pdf14_clist_device, + "pdf14clistgray", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256), - { 0 } + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &gray_pdf14_procs, + &gray_blending_procs }; const pdf14_clist_device pdf14_clist_RGB_device = { std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_RGB_procs, - "pdf14clistRGB", &st_pdf14_clist_device, + "pdf14clistRGB", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256), - { 0 } + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &rgb_pdf14_procs, + &rgb_blending_procs }; const pdf14_clist_device pdf14_clist_CMYK_device = { std_device_std_color_full_body_type(pdf14_clist_device, &pdf14_clist_CMYK_procs, "PDF14clistcmyk", - &st_pdf14_clist_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32, + &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32, 0, 0, 0, 0, 0, 0), - { 0 } + { 0 }, /* Procs */ + NULL, /* target */ + { 0 }, /* devn_params - not used */ + &cmyk_pdf14_procs, + &cmyk_blending_procs +}; + +const pdf14_clist_device pdf14_clist_CMYKspot_device = { + std_device_part1_(pdf14_device, &pdf14_clist_CMYKspot_procs, "PDF14clistcmykspot", &st_pdf14_device, open_init_closed), + dci_values(GX_DEVICE_COLOR_MAX_COMPONENTS,64,255,255,256,256), + std_device_part2_(XSIZE, YSIZE, X_DPI, Y_DPI), + offset_margin_values(0, 0, 0, 0, 0, 0), + std_device_part3_(), + { 0 }, /* Procs */ + NULL, /* target */ + /* DeviceN parameters */ + { 8, /* Not used - Bits per color */ + DeviceCMYKComponents, /* Names of color model colorants */ + 4, /* Number colorants for CMYK */ + 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ + {0}, /* SeparationNames */ + 0, /* SeparationOrder names */ + {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ + }, + &cmykspot_pdf14_procs, + &cmyk_blending_procs }; +const pdf14_clist_device pdf14_clist_custom_device = { + std_device_part1_(pdf14_device, &pdf14_clist_CMYKspot_procs, "PDF14clistcustom", &st_pdf14_device, open_init_closed), + dci_values(GX_DEVICE_COLOR_MAX_COMPONENTS,64,255,255,256,256), + std_device_part2_(XSIZE, YSIZE, X_DPI, Y_DPI), + offset_margin_values(0, 0, 0, 0, 0, 0), + std_device_part3_(), + { 0 }, /* Procs */ + NULL, /* target */ + /* DeviceN parameters */ + { 8, /* Not used - Bits per color */ + DeviceCMYKComponents, /* Names of color model colorants */ + 4, /* Number colorants for CMYK */ + 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ + {0}, /* SeparationNames */ + 0, /* SeparationOrder names */ + {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ + }, + &custom_pdf14_procs, + &custom_blending_procs +}; + + /* * the PDF 1.4 transparency spec says that color space for blending * operations can be based upon either a color space specified in the @@ -2509,21 +3218,54 @@ const pdf14_clist_device pdf14_clist_CMYK_device = { * currently only using a color space based upon the device. */ private int -get_pdf14_clist_device_proto(gx_device * dev, - const pdf14_clist_device ** pdevproto) +get_pdf14_clist_device_proto(gx_device * dev, pdf14_clist_device ** pdevproto, + pdf14_clist_device * ptempdevproto, gs_imager_state * pis, + const gs_pdf14trans_t * pdf14pct) { pdf14_default_colorspace_t dev_cs = pdf14_determine_default_blend_cs(dev); switch (dev_cs) { - case DeviceGray: - *pdevproto = &pdf14_clist_Gray_device; + case PDF14_DeviceGray: + *pdevproto = (pdf14_clist_device *)&pdf14_clist_Gray_device; + break; + case PDF14_DeviceRGB: + *pdevproto = (pdf14_clist_device *)&pdf14_clist_RGB_device; break; - case DeviceRGB: - *pdevproto = &pdf14_clist_RGB_device; + case PDF14_DeviceCMYK: + *pdevproto = (pdf14_clist_device *)&pdf14_clist_CMYK_device; break; - case DeviceCMYK: - *pdevproto = &pdf14_clist_CMYK_device; + case PDF14_DeviceCMYKspot: + *pdevproto = (pdf14_clist_device *)&pdf14_clist_CMYKspot_device; + *pdevproto = (pdf14_clist_device *)&pdf14_clist_custom_device; + /* + * The number of components for the PDF14 device is the sum + * of the process components and the number of spot colors + * for the page. + */ + if (pdf14pct->params.num_spot_colors >= 0) { + *ptempdevproto = **pdevproto; + ptempdevproto->devn_params.page_spot_colors = + pdf14pct->params.num_spot_colors; + ptempdevproto->color_info.num_components = + ptempdevproto->devn_params.num_std_colorant_names + + pdf14pct->params.num_spot_colors; + if (ptempdevproto->color_info.num_components > + ptempdevproto->color_info.max_components) + ptempdevproto->color_info.num_components = + ptempdevproto->color_info.max_components; + *pdevproto = ptempdevproto; + } + break; + case PDF14_DeviceCustom: + /* + * We are using the output device's process color model. The + * color_info for the PDF 1.4 compositing device needs to match + * the output device. + */ + *ptempdevproto = pdf14_clist_custom_device; + ptempdevproto->color_info = dev->color_info; + *pdevproto = ptempdevproto; break; default: /* Should not occur */ return_error(gs_error_rangecheck); @@ -2533,18 +3275,19 @@ get_pdf14_clist_device_proto(gx_device * dev, private int pdf14_create_clist_device(gs_memory_t *mem, gs_imager_state * pis, - gx_device ** ppdev, gx_device * target) + gx_device ** ppdev, gx_device * target, + const gs_pdf14trans_t * pdf14pct) { - const pdf14_clist_device * dev_proto; - pdf14_clist_device *pdev; + pdf14_clist_device * dev_proto; + pdf14_clist_device * pdev, temp_dev_proto; int code; if_debug0('v', "[v]pdf14_create_clist_device\n"); - code = get_pdf14_clist_device_proto(target, &dev_proto); + code = get_pdf14_clist_device_proto(target, &dev_proto, + &temp_dev_proto, pis, pdf14pct); if (code < 0) return code; - code = gs_copydevice((gx_device **) &pdev, (const gx_device *) dev_proto, mem); if (code < 0) @@ -2558,6 +3301,7 @@ pdf14_create_clist_device(gs_memory_t *mem, gs_imager_state * pis, rc_assign(pdev->target, target, "pdf14_create_clist_device"); code = dev_proc((gx_device *) pdev, open_device) ((gx_device *) pdev); + pdev->pclist_device = target; *ppdev = (gx_device *) pdev; return code; } @@ -2597,11 +3341,12 @@ pdf14_disable_clist_device(gs_memory_t *mem, gs_imager_state * pis, */ private int pdf14_recreate_clist_device(gs_memory_t *mem, gs_imager_state * pis, - gx_device * dev) + gx_device * dev, const gs_pdf14trans_t * pdf14pct) { pdf14_clist_device * pdev = (pdf14_clist_device *)dev; gx_device * target = pdev->target; - const pdf14_clist_device * dev_proto; + pdf14_clist_device * dev_proto; + pdf14_clist_device temp_dev_proto; int code; if_debug0('v', "[v]pdf14_recreate_clist_device\n"); @@ -2610,7 +3355,8 @@ pdf14_recreate_clist_device(gs_memory_t *mem, gs_imager_state * pis, * We will not use the entire prototype device but we will set the * color related info to match the prototype. */ - code = get_pdf14_clist_device_proto(target, &dev_proto); + code = get_pdf14_clist_device_proto(target, &dev_proto, + &temp_dev_proto, pis, pdf14pct); if (code < 0) return code; pdev->color_info = dev_proto->color_info; @@ -2622,6 +3368,366 @@ pdf14_recreate_clist_device(gs_memory_t *mem, gs_imager_state * pis, } /* + * Key names are normally C const strings. However we need to create temp + * parameter key names. They only need to have a short life. We need to + * create a parameter list with the key names. Then we will put the parameters + * into the clist. That process will create a permanent copy of the key + * name. At that point we can release our temp key names. + */ +typedef struct keyname_link_list_s { + struct keyname_link_list_s * next; + char * key_name; + } keyname_link_list_t; + +/* + * The GC description for the keyname link list is being included for + * completeness. Since this structure is only temporary, this structure + * should never be exposed to the GC. + */ +gs_private_st_ptrs2(st_keyname_link_list, keyname_link_list_t, + "keyname_link_list", keyname_link_list_enum_ptrs, + keyname_link_list_reloc_ptrs, next, key_name); + +/* See comments before the definition of keyname_link_list_t */ +private int +free_temp_keyname_list(gs_memory_t * mem, keyname_link_list_t * plist) +{ + keyname_link_list_t * pthis_elem; + + while (plist != NULL) { + pthis_elem = plist; + plist = plist->next; + gs_free_object(mem, (byte *)pthis_elem, "free_temp_keyname_list"); + } + return 0; +} + +/* Put a data value into our 'string' */ +#define put_data(pdata, value, count)\ + for(j = 0; j < count; j++)\ + *pdata++ = (byte)((value) >> (j * 8)) + +/* + * Convert a compressed color list element into a set of device parameters. + * Note: This routine recursively calls itself. As a result it can create + * mulitple device parameters. The parameters are 'strings'. Actually the + * data is stored in the strings as binary data. + * + * See comments before the definition of keyname_link_list_t + */ +private int +get_param_compressed_color_list_elem(pdf14_clist_device * pdev, + gs_param_list * plist, compressed_color_list_t * pcomp_list, + char * keyname, keyname_link_list_t ** pkeyname_list) +{ + int max_list_elem_size = + 6 + NUM_ENCODE_LIST_ITEMS * sizeof(comp_bit_map_list_t); + int code, i, j; + byte * pdata; + gs_param_string str; + + if (pcomp_list == NULL) /* Exit if we don not have a list. */ + return 0; + + /* Allocate a string for temp data */ + pdata = gs_alloc_bytes(pdev->memory, max_list_elem_size, + "convert_compressed_color_list_elem"); + str.data = (const byte *)pdata; + str.persistent = false; + + put_data(pdata, pcomp_list->num_sub_level_ptrs, 2); + put_data(pdata, pcomp_list->first_bit_map, 2); + + /* . */ + for (i = pcomp_list->first_bit_map; i < NUM_ENCODE_LIST_ITEMS; i++) { + put_data(pdata, pcomp_list->u.comp_data[i].num_comp, 2); + put_data(pdata, pcomp_list->u.comp_data[i].num_non_solid_comp, 2); + put_data(pdata, pcomp_list->u.comp_data[i].solid_not_100, 1); + put_data(pdata, pcomp_list->u.comp_data[i].colorants, + sizeof(pcomp_list->u.comp_data[i].colorants)); + if (pcomp_list->u.comp_data[i].num_comp != + pcomp_list->u.comp_data[i].num_non_solid_comp) { + put_data(pdata, pcomp_list->u.comp_data[i].solid_colorants, + sizeof(pcomp_list->u.comp_data[i].solid_colorants)); + } + } + str.size = pdata - str.data; + code = param_write_string(plist, keyname, &str); + gs_free_object(pdev->memory, (byte *)str.data, + "convert_compressed_color_list_elem"); + + /* Convert the sub levels. */ + for (i = 0; i < pcomp_list->num_sub_level_ptrs; i++) { + /* + * We generate a keyname for the sub level elements based upon + * the keyname for the current level. See comments before the + * definition of keyname_link_list_t for comments about the lifetime + * of the keynames. + */ + /* Allocate a string for the keyname */ + char * keyname_buf = (char *)gs_alloc_bytes(pdev->memory, + strlen(keyname) + 10, "convert_compressed_color_list_elem"); + /* + * Allocate a link list element so we can keep track of the memory + * allocated to hold the keynames. + */ + keyname_link_list_t * pkeyname_list_elem = + gs_alloc_struct(pdev->memory, keyname_link_list_t, + &st_keyname_link_list, "convert_compressed_color_list_elem"); + pkeyname_list_elem->next = *pkeyname_list; + pkeyname_list_elem->key_name = keyname_buf; + *pkeyname_list = pkeyname_list_elem; + sprintf(keyname_buf, "%s_%d", keyname, i); + get_param_compressed_color_list_elem(pdev, plist, + pcomp_list->u.sub_level_ptrs[i], keyname_buf, + pkeyname_list); + } + + return 0;; +} +#undef put_data + +/* Get data value from our 'string' */ +#define get_data(pdata, value, count)\ + j = count - 1;\ + value = pdata[j--];\ + for(; j >= 0; j--)\ + value = (value <<= 8) | pdata[j];\ + pdata += count + +/* + * Retrieve a compressed color list from a set of device parameters. + * Note: This routine recursively calls itself. As a result it can process + * mulitple device parameters and create the entire compressed color list. + * The parameters are 'strings'. Actually the data is stored in the strings + * as binary data. + */ +int +put_param_compressed_color_list_elem(gx_device * pdev, + gs_param_list * plist, compressed_color_list_t ** pret_comp_list, + char * keyname, int num_comps) +{ + int code, i, j; + byte * pdata; + gs_param_string str; + compressed_color_list_t * pcomp_list; + + /* Check if the given keyname is present. */ + code = param_read_string(plist, keyname, &str); + switch (code) { + case 0: + break; /* We have the given keyname, continue. */ + default: + param_signal_error(plist, keyname, code); + case 1: + *pret_comp_list = NULL; + return 0; + } + /* Allocate a compressed color list element. */ + pdata = (byte *)str.data; + pcomp_list = alloc_compressed_color_list_elem(pdev->memory, num_comps); + get_data(pdata, pcomp_list->num_sub_level_ptrs, 2); + get_data(pdata, pcomp_list->first_bit_map, 2); + + /* Read the bit maps */ + for (i = pcomp_list->first_bit_map; i < NUM_ENCODE_LIST_ITEMS; i++) { + get_data(pdata, pcomp_list->u.comp_data[i].num_comp, 2); + get_data(pdata, pcomp_list->u.comp_data[i].num_non_solid_comp, 2); + get_data(pdata, pcomp_list->u.comp_data[i].solid_not_100, 1); + get_data(pdata, pcomp_list->u.comp_data[i].colorants, + sizeof(pcomp_list->u.comp_data[i].colorants)); + if (pcomp_list->u.comp_data[i].num_comp != + pcomp_list->u.comp_data[i].num_non_solid_comp) { + get_data(pdata, pcomp_list->u.comp_data[i].solid_colorants, + sizeof(pcomp_list->u.comp_data[i].solid_colorants)); + } + } + + /* Get the sub levels. */ + for (i = 0; i < pcomp_list->num_sub_level_ptrs; i++) { + char buff[50]; + compressed_color_list_t * sub_list_ptr; + + sprintf(buff, "%s_%d", keyname, i); + put_param_compressed_color_list_elem(pdev, plist, + &sub_list_ptr, buff, num_comps - 1); + pcomp_list->u.sub_level_ptrs[i] = sub_list_ptr; + } + + *pret_comp_list = pcomp_list; + return 0;; +} +#undef get_data + +/* + * Convert a list of spot color names into a set of device parameters. + * This is done to transfer information from the PDf14 clist writer + * compositing device to the PDF14 clist reader compositing device. + * + * See comments before the definition of keyname_link_list_t + */ +private int +get_param_spot_color_names(pdf14_clist_device * pdev, + gs_param_list * plist, keyname_link_list_t ** pkeyname_list) +{ + int code, i; + gs_param_string str; + gs_separations * separations = &pdev->devn_params.separations; + int num_spot_colors = separations->num_separations; + + if (num_spot_colors == 0) + return 0; + + code = param_write_int(plist, PDF14NumSpotColorsParamName, + &num_spot_colors); + for (i = 0; i < num_spot_colors; i++) { + /* + * We generate a keyname for the spot color based upon the + * spot color number. See comments before the definition of + * keyname_link_list_t for comments about the lifetime of the keynames. + */ + /* Allocate a string for the keyname */ + char * keyname_buf = (char *)gs_alloc_bytes(pdev->memory, + strlen("PDF14SpotName_") + 10, "get_param_spot_color_names"); + /* + * Allocate a link list element so we can keep track of the memory + * allocated to hold the keynames. + */ + keyname_link_list_t * pkeyname_list_elem = + gs_alloc_struct(pdev->memory, keyname_link_list_t, + &st_keyname_link_list, "get_param_spot_color_names"); + pkeyname_list_elem->next = *pkeyname_list; + pkeyname_list_elem->key_name = keyname_buf; + *pkeyname_list = pkeyname_list_elem; + sprintf(keyname_buf, "%PDF14SpotName_%d", i); + str.size = separations->names[i].size; + str.data = separations->names[i].data; + str.persistent = false; + code = param_write_string(plist, keyname_buf, &str); + } + return 0;; +} + +/* + * Retrieve a list of spot color names for the PDF14 device. + */ +int +put_param_pdf14_spot_names(gx_device * pdev, + gs_separations * pseparations, gs_param_list * plist) +{ + int code, num_spot_colors, i; + gs_param_string str; + + /* Check if the given keyname is present. */ + code = param_read_int(plist, PDF14NumSpotColorsParamName, + &num_spot_colors); + switch (code) { + default: + param_signal_error(plist, PDF14NumSpotColorsParamName, code); + break; + case 1: + return 0; + case 0: + if (num_spot_colors < 1 || + num_spot_colors > GX_DEVICE_COLOR_MAX_COMPONENTS) + return_error(gs_error_rangecheck); + for (i = 0; i < num_spot_colors; i++) { + char buff[20]; + byte * sep_name; + + sprintf(buff, "PDF14SpotName_%d", i); + code = param_read_string(plist, buff, &str); + switch (code) { + default: + param_signal_error(plist, buff, code); + break; + case 0: + sep_name = gs_alloc_bytes(pdev->memory, + str.size, "put_param_pdf14_spot_names"); + memcpy(sep_name, str.data, str.size); + pseparations->names[i].size = str.size; + pseparations->names[i].data = sep_name; + } + } + pseparations->num_separations = num_spot_colors; + break; + } + return 0;; +} + +private int +pdf14_clist_get_param_compressed_color_list(pdf14_device * p14dev) +{ + gx_device_clist_writer * cldev = (gx_device_clist_writer *)p14dev->pclist_device; + gs_c_param_list param_list; + keyname_link_list_t * pkeyname_list_head = NULL; + int code; + + /* + * If a put_params call fails, the device will be left in a closed + * state, but higher-level code won't notice this fact. We flag this by + * setting permanent_error, which prevents writing to the command list. + */ + + if (cldev->permanent_error) + return cldev->permanent_error; + gs_c_param_list_write(¶m_list, p14dev->memory); + code = get_param_compressed_color_list_elem(p14dev, + (gs_param_list *)¶m_list, + p14dev->devn_params.compressed_color_list, + PDF14CompressedColorListParamName, &pkeyname_list_head); + get_param_spot_color_names(p14dev, (gs_param_list *)¶m_list, + &pkeyname_list_head); + if (code >= 0) { + gx_device * tdev = p14dev->target; + + gs_c_param_list_read(¶m_list); + // put_param_compressed_color_list_elem(p14dev, + // (gs_param_list *)¶m_list, + // &pret_comp_list, "PDF14CompressedColorList", + // TOP_ENCODED_LEVEL); + // put_param_pdf14_spot_names(p14dev, (gs_param_list *)¶m_list); +#if 1 + code = dev_proc(tdev, put_params)(tdev, (gs_param_list *)¶m_list); +#else + /* + * This call will put the compressed color list info into the + * clist. However there are two problems. The info goes into + * the list at the end of the list. + */ + code = cmd_put_params(cldev, (gs_param_list *)¶m_list ); +#endif + } + gs_c_param_list_release(¶m_list); + free_temp_keyname_list(p14dev->memory, pkeyname_list_head); + + return code; +} + +/* + * This procedure will have information from the PDF 1.4 clist writing + * clist compositior device. This is information output the compressed + * color list info which is needed for the support of spot colors in + * PDF 1.4 compositing. This info needs to be passed to the PDF 1.4 + * clist reading compositor. However this device is not created until + * the clist is read. To get this info to that device, we have to + * temporarily store that info in the output device. This routine saves + * that info in the output device. + */ +int +pdf14_put_devn_params(gx_device * pdev, gs_devn_params * pdevn_params, + gs_param_list * plist) +{ + int code = put_param_compressed_color_list_elem(pdev, plist, + &pdevn_params->pdf14_compressed_color_list, + PDF14CompressedColorListParamName, TOP_ENCODED_LEVEL); + if (code >= 0) + code = put_param_pdf14_spot_names(pdev, + &pdevn_params->pdf14_separations, plist); + return code; +} + +/* * When we are banding, we have two PDF 1.4 compositor devices. One for * when we are creating the clist. The second is for imaging the data from * the clist. This routine is part of the clist writing PDF 1.4 device. @@ -2647,7 +3753,7 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, pdev->save_get_cmap_procs = pis->get_cmap_procs; pis->get_cmap_procs = pdf14_get_cmap_procs; gx_set_cmap_procs(pis, dev); - code = pdf14_recreate_clist_device(mem, pis, dev); + code = pdf14_recreate_clist_device(mem, pis, dev, pdf14pct); pdev->blend_mode = pdev->text_knockout = 0; pdev->opacity = pdev->shape = 0.0; if (code < 0) @@ -2667,6 +3773,12 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, return code; } case PDF14_POP_DEVICE: + /* + * For spot colors we use a 'compressed encoding' for + * gx_color_index values. Send the related data struct + * to the clist. + */ + pdf14_clist_get_param_compressed_color_list(pdev); /* Restore the color_info for the clist device */ pdev->target->color_info = pdev->saved_target_color_info; pis->get_cmap_procs = pdev->save_get_cmap_procs; @@ -2950,7 +4062,7 @@ c_pdf14trans_clist_write_update(const gs_composite_t * pcte, gx_device * dev, /* We only handle the push/pop operations */ switch (pdf14pct->params.pdf14_op) { case PDF14_PUSH_DEVICE: - code = pdf14_create_clist_device(mem, pis, pcdev, dev); + code = pdf14_create_clist_device(mem, pis, pcdev, dev, pdf14pct); /* * Set the color_info of the clist device to match the compositing * device. We will restore it when the compositor is popped. @@ -2996,6 +4108,7 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev, { pdf14_device * p14dev = (pdf14_device *)tdev; gs_pdf14trans_t * pdf14pct = (gs_pdf14trans_t *) pcte; + gs_devn_params * pclist_devn_params; /* * We only handle the push/pop operations. Save and restore the color_info @@ -3005,14 +4118,139 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev, */ switch (pdf14pct->params.pdf14_op) { case PDF14_PUSH_DEVICE: - p14dev->saved_clist_color_info = cdev->color_info; + p14dev->saved_target_color_info = cdev->color_info; cdev->color_info = p14dev->color_info; + /* + * If we are blending using spot colors (i.e. the output device + * supports spot colors) then we need to transfer compressed + * color info from the clist PDF 1.4 compositing reader device + * to the clist writer PDF 1.4 compositing device. + * This info was transfered from that device to the output + * device as a set of device parameters. However the clist + * reader PDF 1.4 compositing device did not exist when the + * device parameters were read from the clist. So that info + * was buffered into the output device. + */ + pclist_devn_params = dev_proc(cdev, ret_devn_params)(cdev); + if (pclist_devn_params != NULL) { + int num_comp = p14dev->color_info.num_components; + /* + * The number of components for the PDF14 device is the sum + * of the process components and the number of spot colors + * for the page. + */ + p14dev->devn_params.page_spot_colors = + pclist_devn_params->page_spot_colors; + p14dev->color_info.num_components = + p14dev->devn_params.num_std_colorant_names + + p14dev->devn_params.page_spot_colors; + /* Transfer the data for the compressed color encoding. */ + // free_compressed_color_list(p14dev->memory, + // p14dev->devn_params.compressed_color_list); + p14dev->devn_params.compressed_color_list = + pclist_devn_params->pdf14_compressed_color_list; + // free_separation_names(p14dev->memory, + // &p14dev->devn_params.separations); + p14dev->devn_params.separations = + pclist_devn_params->pdf14_separations; + if ( num_comp != p14dev->color_info.num_components) { + dev_proc(tdev, open_device) (tdev); + dev_proc(tdev, open_device) (tdev); + } + } break; case PDF14_POP_DEVICE: - cdev->color_info = p14dev->saved_clist_color_info; + cdev->color_info = p14dev->saved_target_color_info; break; default: break; /* do nothing for remaining ops */ } return 0; } + +/* + * This routine will check to see if the color component name matches those + * that are available amoung the current device's color components. If the + * color name is known to the output device then we add it to the list of + * colorants for the PDF 1.4 transparency compositor. + * + * Notes: There are currently three different versions of The PDF 1.4 + * transparency compositor device. The choice of which one is being used + * depends upon the process color model of the output device. This procedure + * is only used if the output (target) device uses a CMYK plus spot color + * process color model. + * + * Parameters: + * dev - pointer to device data structure. + * pname - pointer to name (zero termination not required) + * nlength - length of the name + * + * This routine returns a positive value (0 to n) which is the device colorant + * number if the name is found. It returns GX_DEVICE_COLOR_MAX_COMPONENTS if + * the colorant is not being used due to a SeparationOrder device parameter. + * It returns a negative value if not found. + */ +private int +pdf14_cmykspot_get_color_comp_index(gx_device * dev, const char * pname, + int name_size, int component_type) +{ + pdf14_device * pdev = (pdf14_device *) dev; + gx_device * tdev = pdev->target; + gs_devn_params * pdevn_params = &pdev->devn_params; + gs_separations * pseparations = &pdevn_params->separations; + int comp_index; + + /* + * If this is not a separation name then simply forward it to the target + * device. + */ + if (component_type == NO_COMP_NAME_TYPE) + return dev_proc(tdev, get_color_comp_index) + (tdev, pname, name_size, component_type); + /* + * Check if the component is in either the process color model list + * or in the SeparationNames list. + */ + comp_index = check_pcm_and_separation_names(dev, pdevn_params, + pname, name_size, component_type); + /* + * Return the colorant number if we know this name. + */ + if (comp_index >= 0) + return comp_index; + /* + * If we do not know this color, check if the output (target) device does. + */ + comp_index = dev_proc(tdev, get_color_comp_index) + (tdev, pname, name_size, component_type); + /* + * Ignore color if unknown to the output device or if color is not being + * imaged due to the SeparationOrder device parameter. + */ + if (comp_index < 0 || comp_index == GX_DEVICE_COLOR_MAX_COMPONENTS) + return comp_index; + + /* + * This is a new colorant. Add it to our list of colorants. + */ + if (pseparations->num_separations < GX_DEVICE_COLOR_MAX_COMPONENTS - 1) { + int sep_num = pseparations->num_separations++; + int color_component_number; + byte * sep_name; + + sep_name = gs_alloc_bytes(dev->memory, + name_size, "pdf14_cmykspot_get_color_comp_index"); + memcpy(sep_name, pname, name_size); + pseparations->names[sep_num].size = name_size; + pseparations->names[sep_num].data = sep_name; + color_component_number = sep_num + pdevn_params->num_std_colorant_names; + if (color_component_number >= dev->color_info.num_components) + color_component_number = GX_DEVICE_COLOR_MAX_COMPONENTS; + else + pdevn_params->separation_order_map[color_component_number] = + color_component_number; + return color_component_number; + } + + return GX_DEVICE_COLOR_MAX_COMPONENTS; +} diff --git a/gs/src/gdevp14.h b/gs/src/gdevp14.h index e5f1d1315..f8395a16a 100644 --- a/gs/src/gdevp14.h +++ b/gs/src/gdevp14.h @@ -17,9 +17,11 @@ # define gdevp14_INCLUDED typedef enum { - DeviceGray = 0, - DeviceRGB = 1, - DeviceCMYK = 2 + PDF14_DeviceGray = 0, + PDF14_DeviceRGB = 1, + PDF14_DeviceCMYK = 2, + PDF14_DeviceCMYKspot = 3, + PDF14_DeviceCustom = 4 } pdf14_default_colorspace_t; typedef struct pdf14_buf_s pdf14_buf; @@ -63,23 +65,103 @@ struct pdf14_ctx_s { int n_chan; }; +#ifndef gs_devn_params_DEFINED +# define gs_devn_params_DEFINED +typedef struct gs_devn_params_s gs_devn_params; +#endif + +#ifndef gs_imager_state_DEFINED +# define gs_imager_state_DEFINED +typedef struct gs_imager_state_s gs_imager_state; +#endif + +#ifndef gx_device_DEFINED +# define gx_device_DEFINED +typedef struct gx_device_s gx_device; +#endif + +#ifndef gs_pdf14trans_params_DEFINED +# define gs_pdf14trans_params_DEFINED +typedef struct gs_pdf14trans_params_s gs_pdf14trans_params_t; +#endif + +typedef struct pdf14_device_s pdf14_device; + +/* + * This structure contains procedures for processing routine which differ + * between the different blending color spaces. + */ +typedef struct { + /* + * Unpack a device color. This routine is similar to the device's + * decode_color procedure except for two things. The procedure produces + * 1 byte values instead of gx_color_values (2 bytes) and the output + * values are inverted for subtractive color spaces (like CMYK). + * A separate procedure is used instead of the decode_color to minimize + * execution time. + */ + void (* unpack_color)(int num_comp, gx_color_index color, + pdf14_device * p14dev, byte * out); + /* + * This procedure sends the final rasterized transparency data to the + * output device as an image. + */ + int (* put_image)(gx_device * dev, + gs_imager_state * pis, gx_device * target); +} pdf14_procs_s; + +typedef pdf14_procs_s pdf14_procs_t; + +/* + * Define the default post-clist (clist reader) PDF 1.4 compositing device. + * We actually use the same structure for both the clist writer and reader + * devices. However we use separate names to identify the routines for each + * device. + */ typedef struct pdf14_device_s { gx_device_forward_common; + gs_devn_params devn_params; /* Must follow gx_device_forward_common */ + const pdf14_procs_t * pdf14_procs; /* Must follow devn_params. */ + const pdf14_nonseparable_blending_procs_t * blend_procs; /* Must follow pdf14_procs */ pdf14_ctx *ctx; float opacity; float shape; float alpha; /* alpha = opacity * shape */ gs_blend_mode_t blend_mode; + bool text_knockout; + gx_device * pclist_device; const gx_color_map_procs *(*save_get_cmap_procs)(const gs_imager_state *, const gx_device *); - gx_device_color_info saved_clist_color_info; -} pdf14_device; - -int gs_pdf14_device_push(gs_memory_t *mem, gs_imager_state * pis, - gx_device * * pdev, gx_device * target); - + gx_device_color_info saved_target_color_info; +} pdf14_device_t; + +/* + * Define the default pre-clist (clist writer) PDF 1.4 compositing device. + * We actually use the same structure for both the clist writer and reader + * devices. However we use separate names to identify the routines for each + * device. + */ +typedef struct pdf14_device_s pdf14_clist_device; + +/* + * Send a PDF 1.4 transparency compositor action to the specified device. + */ int send_pdf14trans(gs_imager_state * pis, gx_device * dev, gx_device * * pcdev, gs_pdf14trans_params_t * pparams, gs_memory_t * mem); +/* + * This procedure will save information from the PDF 1.4 clist writing + * clist compositior device. This is information about the compressed + * color list info which is needed for the support of spot colors in + * PDF 1.4 compositing. This info needs to be passed to the PDF 1.4 + * clist reading compositor. However this device is not created until + * the clist is read. To get this info to that device, we have to + * temporarily store that info in the output device. This routine saves + * that info in the output device. + */ +int +pdf14_put_devn_params(gx_device * pdev, gs_devn_params * pdevn_params, + gs_param_list * plist); + #endif /* gdevp14_INCLUDED */ diff --git a/gs/src/gdevpbm.c b/gs/src/gdevpbm.c index ab714e7f3..72c6f0232 100644 --- a/gs/src/gdevpbm.c +++ b/gs/src/gdevpbm.c @@ -429,8 +429,12 @@ private int ppm_get_params(gx_device * pdev, gs_param_list * plist) { gx_device_pbm * const bdev = (gx_device_pbm *)pdev; + int code; - return gdev_prn_get_params_planar(pdev, plist, &bdev->UsePlanarBuffer); + code = gdev_prn_get_params_planar(pdev, plist, &bdev->UsePlanarBuffer); + if (code < 0) return code; + code = param_write_null(plist, "OutputIntent"); + return code; } private int @@ -443,8 +447,26 @@ ppm_put_params(gx_device * pdev, gs_param_list * plist) int ecode = 0; int code; long v; + gs_param_string_array intent; const char *vname; + if ((code = param_read_string_array(plist, "OutputIntent", &intent)) == 0) { + int i, j; + + dlprintf1("%d strings:\n", intent.size); + for (i = 0; i < intent.size; i++) { + const gs_param_string *s = &intent.data[i]; + dlprintf2(" %d: size %d:", i, s->size); + if (i < 4) { + for (j = 0; j < s->size; j++) + dlprintf1("%c", s->data[j]); + } else { + for (j = 0; j < 16; j++) + dlprintf1(" %02x", s->data[j]); + } + dlprintf("\n"); + } + } save_info = pdev->color_info; if ((code = param_read_long(plist, (vname = "GrayValues"), &v)) != 1 || (code = param_read_long(plist, (vname = "RedValues"), &v)) != 1 || diff --git a/gs/src/gdevpnga.c b/gs/src/gdevpnga.c index 158ab45f0..13ee23a9d 100644 --- a/gs/src/gdevpnga.c +++ b/gs/src/gdevpnga.c @@ -19,6 +19,7 @@ #include "gscdefs.h" #include "gsdevice.h" #include "gdevmem.h" +#include "gxcindex.h" #include "gxblend.h" #include "gxtext.h" diff --git a/gs/src/gdevprn.c b/gs/src/gdevprn.c index b0d7c551e..a097223ba 100644 --- a/gs/src/gdevprn.c +++ b/gs/src/gdevprn.c @@ -401,6 +401,7 @@ gdev_prn_allocate(gx_device *pdev, gdev_prn_space_params *new_space_params, COPY_PROC(stroke_path); COPY_PROC(fill_rectangle_hl_color); COPY_PROC(update_spot_equivalent_colors); + COPY_PROC(ret_devn_params); #undef COPY_PROC /* If using a command list, already opened the device. */ if (is_command_list) diff --git a/gs/src/gdevpsd.c b/gs/src/gdevpsd.c index 7dfe27b4a..6686abf95 100644 --- a/gs/src/gdevpsd.c +++ b/gs/src/gdevpsd.c @@ -244,6 +244,7 @@ const psd_device gs_psdrgb_device = DeviceRGBComponents, /* Names of color model colorants */ 3, /* Number colorants for RGB */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ 0, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ @@ -287,6 +288,7 @@ const psd_device gs_psdcmyk_device = DeviceCMYKComponents, /* Names of color model colorants */ 4, /* Number colorants for CMYK */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ 0, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ diff --git a/gs/src/gdevrops.c b/gs/src/gdevrops.c index e47f4c781..5eef5ba23 100644 --- a/gs/src/gdevrops.c +++ b/gs/src/gdevrops.c @@ -105,7 +105,8 @@ private const gx_device_rop_texture gs_rop_texture_device = { gx_forward_fill_linear_color_scanline, gx_forward_fill_linear_color_trapezoid, gx_forward_fill_linear_color_triangle, - gx_forward_update_spot_equivalent_colors + gx_forward_update_spot_equivalent_colors, + gx_forward_ret_devn_parms }, 0, /* target */ lop_default /* log_op */ diff --git a/gs/src/gdevtsep.c b/gs/src/gdevtsep.c index d8583f735..2fa9f63d1 100644 --- a/gs/src/gdevtsep.c +++ b/gs/src/gdevtsep.c @@ -238,6 +238,7 @@ private dev_proc_decode_color(tiffsep_decode_color); private dev_proc_encode_color(tiffsep_encode_compressed_color); private dev_proc_decode_color(tiffsep_decode_compressed_color); private dev_proc_update_spot_equivalent_colors(tiffsep_update_spot_equivalent_colors); +private dev_proc_ret_devn_params(tiffsep_ret_devn_params); /* @@ -362,7 +363,8 @@ gs_private_st_composite_final(st_tiffsep_device, tiffsep_device, NULL, /* fill_linear_color_scanline */\ NULL, /* fill_linear_color_trapezoid */\ NULL, /* fill_linear_color_triangle */\ - tiffsep_update_spot_equivalent_colors /* update_spot_equivalent_colors */\ + tiffsep_update_spot_equivalent_colors, /* update_spot_equivalent_colors */\ + tiffsep_ret_devn_params /* ret_devn_params */\ } #define tiffsep_device_body(procs, dname, ncomp, pol, depth, mg, mc, sl, cn)\ @@ -421,6 +423,7 @@ const tiffsep_device gs_tiffsep_device = DeviceCMYKComponents, /* Names of color model colorants */ 4, /* Number colorants for CMYK */ 0, /* MaxSeparations has not been specified */ + -1, /* PageSpotColors has not been specified */ {0}, /* SeparationNames */ 0, /* SeparationOrder names */ {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ @@ -555,6 +558,17 @@ tiffsep_update_spot_equivalent_colors(gx_device * dev, const gs_state * pgs) return 0; } +/* + * Device proc for returning a pointer to DeviceN parameter structure + */ +private gs_devn_params * +tiffsep_ret_devn_params(gx_device * dev) +{ + tiffsep_device * pdev = (tiffsep_device *)dev; + + return &pdev->devn_params; +} + /* Get parameters. We provide a default CRD. */ private int tiffsep_get_params(gx_device * pdev, gs_param_list * plist) diff --git a/gs/src/gscdevn.c b/gs/src/gscdevn.c index c2c857f84..26402a5d5 100644 --- a/gs/src/gscdevn.c +++ b/gs/src/gscdevn.c @@ -398,10 +398,12 @@ gx_remap_concrete_DeviceN(const frac * pconc, const gs_color_space * pcs, dprintf("gx_remap_concrete_DeviceN: color space id mismatch"); #endif -#if ENABLE_NAMED_COLOR_CALLBACK - if (pis->color_component_map.use_named_color_callback) { - return gx_remap_concrete_named_color_DeviceN(pconc, pcs, pdc, +#if ENABLE_CUSTOM_COLOR_CALLBACK + if (pis->custom_color_callback) { + int code = gx_remap_concrete_custom_color_DeviceN(pconc, pcs, pdc, pis, dev, select); + if (code >= 0) + return code; } #endif if (pis->color_component_map.use_alt_cspace) { @@ -502,16 +504,15 @@ private int gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs) { int code; -#if ENABLE_NAMED_COLOR_CALLBACK +#if ENABLE_CUSTOM_COLOR_CALLBACK /* - * Check if we want to use the callback color processing for this color space. + * Check if we want to use the callback color processing for this + * color space. */ - bool use_named_color_callback = - named_color_callback_install_DeviceN(pgs->color_space, pgs); + bool use_custom_color_callback = + custom_color_callback_install_DeviceN(pcs, pgs); - pgs->color_component_map.use_named_color_callback = - use_named_color_callback; - if (use_named_color_callback) { + if (use_custom_color_callback) { /* * We are using the callback instead of the alternate tint transform * for this color space. @@ -522,6 +523,7 @@ gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs) return 0; } #endif + code = check_DeviceN_component_names(pcs, pgs); if (code < 0) return code; diff --git a/gs/src/gscie.c b/gs/src/gscie.c index f3b2346c2..dc0bdd819 100644 --- a/gs/src/gscie.c +++ b/gs/src/gscie.c @@ -419,6 +419,22 @@ gx_install_CIEDEFG(const gs_color_space * pcs, gs_state * pgs) { gs_cie_defg *pcie = pcs->params.defg; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) { + if (pcb->client_procs->install_CIEBasedDEFG(pcb, pcs, pgs)) + /* Exit if the client will handle the colorspace completely */ + return 0; + } + } +#endif CIE_LOAD_CACHE_BODY(pcie->caches_defg.DecodeDEFG, pcie->RangeDEFG.ranges, &pcie->DecodeDEFG, DecodeDEFG_default, pcie, "DecodeDEFG"); @@ -430,6 +446,22 @@ gx_install_CIEDEF(const gs_color_space * pcs, gs_state * pgs) { gs_cie_def *pcie = pcs->params.def; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) { + if (pcb->client_procs->install_CIEBasedDEF(pcb, pcs, pgs)) + /* Exit if the client will handle the colorspace completely */ + return 0; + } + } +#endif CIE_LOAD_CACHE_BODY(pcie->caches_def.DecodeDEF, pcie->RangeDEF.ranges, &pcie->DecodeDEF, DecodeDEF_default, pcie, "DecodeDEF"); @@ -439,6 +471,22 @@ gx_install_CIEDEF(const gs_color_space * pcs, gs_state * pgs) int gx_install_CIEABC(const gs_color_space * pcs, gs_state * pgs) { +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) { + if (pcb->client_procs->install_CIEBasedABC(pcb, pcs, pgs)) + /* Exit if the client will handle the colorspace completely */ + return 0; + } + } +#endif return gx_install_cie_abc(pcs->params.abc, pgs); } @@ -449,6 +497,22 @@ gx_install_CIEA(const gs_color_space * pcs, gs_state * pgs) gs_sample_loop_params_t lp; int i; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) { + if (pcb->client_procs->install_CIEBasedA(pcb, pcs, pgs)) + /* Exit if the client will handle the colorspace completely */ + return 0; + } + } +#endif gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp, &pcie->RangeA, "DecodeA"); for (i = 0; i <= lp.N; ++i) { diff --git a/gs/src/gsciemap.c b/gs/src/gsciemap.c index 508c4035a..9ba82acae 100644 --- a/gs/src/gsciemap.c +++ b/gs/src/gsciemap.c @@ -202,6 +202,80 @@ gx_concretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs, } #undef SCALE_TO_RANGE +#if ENABLE_CUSTOM_COLOR_CALLBACK +/* + * This routine is only used if ENABLE_CUSTOM_COLOR_CALLBACK is true. + * Otherwise we use gx_default_remap_color directly for CIEBasedDEFG color + * spaces. + * + * Render a CIEBasedDEFG color. + */ +int +gx_remap_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + if (pcb->client_procs->remap_CIEBasedDEFG(pcb, pc, pcs, + pdc, pis, dev, select) == 0) + return 0; + } + /* Use default routine for non custom color processing. */ + return gx_default_remap_color(pc, pcs, pdc, pis, dev, select); +} + +/* + * This routine is only used if ENABLE_CUSTOM_COLOR_CALLBACK is true. + * Otherwise we use gx_default_remap_color directly for CIEBasedDEF color + * spaces. + * + * Render a CIEBasedDEF color. + */ +int +gx_remap_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + if (pcb->client_procs->remap_CIEBasedDEF(pcb, pc, pcs, + pdc, pis, dev, select) == 0) + return 0; + } + /* Use default routine for non custom color processing. */ + return gx_default_remap_color(pc, pcs, pdc, pis, dev, select); +} + +/* + * This routine is only used if ENABLE_CUSTOM_COLOR_CALLBACK is true. + * Otherwise we use gx_default_remap_color directly for CIEBasedA color + * spaces. + * + * Render a CIEBasedA color. + */ +int +gx_remap_CIEA(const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + if (pcb->client_procs->remap_CIEBasedA(pcb, pc, pcs, + pdc, pis, dev, select) == 0) + return 0; + } + /* Use default routine for non custom color processing. */ + return gx_default_remap_color(pc, pcs, pdc, pis, dev, select); +} +#endif + /* Render a CIEBasedABC color. */ /* We provide both remap and concretize, but only the former */ /* needs to be efficient. */ @@ -216,6 +290,19 @@ gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs, if_debug3('c', "[c]remap CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + if (pcb->client_procs->remap_CIEBasedABC(pcb, pc, pcs, + pdc, pis, dev, select) == 0) + return 0; + } + } +#endif + CIE_CHECK_RENDERING(pcs, conc, pis, goto map3); vec3.u = float2cie_cached(pc->paint.values[0]); vec3.v = float2cie_cached(pc->paint.values[1]); diff --git a/gs/src/gscolor2.c b/gs/src/gscolor2.c index 508c57921..238f45ba5 100644 --- a/gs/src/gscolor2.c +++ b/gs/src/gscolor2.c @@ -52,6 +52,8 @@ gs_setcolorspace(gs_state * pgs, gs_color_space * pcs) } if (code >= 0) { + pgs->color_space->pclient_color_space_data = + pcs->pclient_color_space_data; cs_full_init_color(pgs->ccolor, pcs); gx_unset_dev_color(pgs); } diff --git a/gs/src/gscscie.c b/gs/src/gscscie.c index 75073b44c..01de213fe 100644 --- a/gs/src/gscscie.c +++ b/gs/src/gscscie.c @@ -51,7 +51,12 @@ const gs_color_space_type gs_color_space_type_CIEDEFG = { gx_init_CIE, gx_restrict_CIEDEFG, gx_concrete_space_CIE, gx_concretize_CIEDEFG, NULL, - gx_default_remap_color, gx_install_CIE, +#if ENABLE_CUSTOM_COLOR_CALLBACK + gx_remap_CIEDEFG, +#else + gx_default_remap_color, +#endif + gx_install_CIE, gx_spot_colors_set_overprint, gx_final_CIEDEFG, gx_no_adjust_color_count, gx_serialize_CIEDEFG, @@ -70,7 +75,12 @@ const gs_color_space_type gs_color_space_type_CIEDEF = { gx_init_CIE, gx_restrict_CIEDEF, gx_concrete_space_CIE, gx_concretize_CIEDEF, NULL, - gx_default_remap_color, gx_install_CIE, +#if ENABLE_CUSTOM_COLOR_CALLBACK + gx_remap_CIEDEF, +#else + gx_default_remap_color, +#endif + gx_install_CIE, gx_spot_colors_set_overprint, gx_final_CIEDEF, gx_no_adjust_color_count, gx_serialize_CIEDEF, @@ -108,7 +118,12 @@ const gs_color_space_type gs_color_space_type_CIEA = { gx_init_CIE, gx_restrict_CIEA, gx_concrete_space_CIE, gx_concretize_CIEA, NULL, - gx_default_remap_color, gx_install_CIE, +#if ENABLE_CUSTOM_COLOR_CALLBACK + gx_remap_CIEA, +#else + gx_default_remap_color, +#endif + gx_install_CIE, gx_spot_colors_set_overprint, gx_final_CIEA, gx_no_adjust_color_count, gx_serialize_CIEA, diff --git a/gs/src/gscsepr.c b/gs/src/gscsepr.c index 5e25e0250..266bcece1 100644 --- a/gs/src/gscsepr.c +++ b/gs/src/gscsepr.c @@ -30,6 +30,7 @@ #include "gxdevcli.h" #include "gsovrc.h" #include "stream.h" +#include "gsnamecl.h" /* ---------------- Color space ---------------- */ @@ -105,17 +106,15 @@ private int gx_install_Separation(const gs_color_space * pcs, gs_state * pgs) { int code; -#if ENABLE_NAMED_COLOR_CALLBACK +#if ENABLE_CUSTOM_COLOR_CALLBACK /* - * Check if we want to use the named color callback color processing for + * Check if we want to use the custom color callback color processing for * this color space. */ - bool use_named_color_callback = - named_color_callback_install_Separation(pgs->color_space, pgs); + bool use_custom_color_callback = + custom_color_callback_install_Separation(pcs, pgs); - pgs->color_component_map.use_named_color_callback = - use_named_color_callback; - if (use_named_color_callback) { + if (use_custom_color_callback) { /* * We are using the callback instead of the alternate tint transform * for this color space. @@ -354,12 +353,15 @@ gx_remap_concrete_Separation(const frac * pconc, const gs_color_space * pcs, dprintf("gx_remap_concrete_Separation: color space id mismatch"); #endif -#if ENABLE_NAMED_COLOR_CALLBACK - if (pis->color_component_map.use_named_color_callback) { - return gx_remap_concrete_named_color_Separation(pconc, pcs, pdc, +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + int code = gx_remap_concrete_custom_color_Separation(pconc, pcs, pdc, pis, dev, select); + if (code >= 0) + return code; } #endif + if (pis->color_component_map.use_alt_cspace) { const gs_color_space *pacs = pcs->base_space; diff --git a/gs/src/gscspace.c b/gs/src/gscspace.c index 36a67d2e0..18858b5cd 100644 --- a/gs/src/gscspace.c +++ b/gs/src/gscspace.c @@ -29,6 +29,9 @@ #include "gzstate.h" #include "stream.h" +private cs_proc_install_cspace(gx_install_DeviceGray); +private cs_proc_install_cspace(gx_install_DeviceRGB); +private cs_proc_install_cspace(gx_install_DeviceCMYK); /* * Define the standard color space types. We include DeviceCMYK in the base * build because it's too awkward to omit it, but we don't provide any of @@ -41,7 +44,7 @@ private const gs_color_space_type gs_color_space_type_DeviceGray = { gx_init_paint_1, gx_restrict01_paint_1, gx_same_concrete_space, gx_concretize_DeviceGray, gx_remap_concrete_DGray, - gx_remap_DeviceGray, gx_no_install_cspace, + gx_remap_DeviceGray, gx_install_DeviceGray, gx_spot_colors_set_overprint, NULL, gx_no_adjust_color_count, gx_serialize_cspace_type, @@ -53,7 +56,7 @@ private const gs_color_space_type gs_color_space_type_DeviceRGB = { gx_init_paint_3, gx_restrict01_paint_3, gx_same_concrete_space, gx_concretize_DeviceRGB, gx_remap_concrete_DRGB, - gx_remap_DeviceRGB, gx_no_install_cspace, + gx_remap_DeviceRGB, gx_install_DeviceRGB, gx_spot_colors_set_overprint, NULL, gx_no_adjust_color_count, gx_serialize_cspace_type, @@ -68,7 +71,7 @@ private const gs_color_space_type gs_color_space_type_DeviceCMYK = { gx_init_paint_4, gx_restrict01_paint_4, gx_same_concrete_space, gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK, - gx_remap_DeviceCMYK, gx_no_install_cspace, + gx_remap_DeviceCMYK, gx_install_DeviceCMYK, gx_set_overprint_DeviceCMYK, NULL, gx_no_adjust_color_count, gx_serialize_cspace_type, @@ -90,6 +93,15 @@ gs_cspace_final(void *vptr) if (pcs->type->final) pcs->type->final(pcs); if_debug2('c', "[c]cspace final %08x %d\n", pcs, pcs->id); + +#if ENABLE_CUSTOM_COLOR_CALLBACK + + client_color_space_data_t *pclient_data = pcs->pclient_color_space_data; + if ( pclient_data ) + pclient_data->client_adjust_cspace_count( pcs, -1 ); + +#endif /*ENABLE_CUSTOM_COLOR_CALLBACK*/ + rc_decrement_only(pcs->base_space, "gs_cspace_final"); } @@ -106,9 +118,14 @@ gs_cspace_alloc_with_id(gs_memory_t *mem, ulong id, pcs->type = pcstype; pcs->id = id; pcs->base_space = NULL; + pcs->pclient_color_space_data = NULL; return pcs; } +private cs_proc_install_cspace(gx_install_DeviceGray); +private cs_proc_install_cspace(gx_install_DeviceRGB); +private cs_proc_install_cspace(gx_install_DeviceCMYK); + /* * Generic allocation function for colorspace implementations. Return * NULL on allocation failure. @@ -165,6 +182,24 @@ gs_color_space_restrict_color(gs_client_color *pcc, const gs_color_space *pcs) cs_restrict_color(pcc, pcs); } +/* Install a DeviceGray color space. */ +private int +gx_install_DeviceGray(const gs_color_space * pcs, gs_state * pgs) +{ +#if ENABLE_CUSTOM_COLOR_CALLBACK + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) + pcb->client_procs->install_DeviceGray(pcb, pcs, pgs); +#endif + return 0; +} + int gx_num_components_1(const gs_color_space * pcs) { @@ -199,6 +234,42 @@ gx_no_install_cspace(const gs_color_space * pcs, gs_state * pgs) { return 0; } + +/* Install a DeviceRGB color space. */ +private int +gx_install_DeviceRGB(const gs_color_space * pcs, gs_state * pgs) +{ +#if ENABLE_CUSTOM_COLOR_CALLBACK + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) + pcb->client_procs->install_DeviceRGB(pcb, pcs, pgs); +#endif + return 0; +} + +/* Install a DeviceCMYK color space. */ +private int +gx_install_DeviceCMYK(const gs_color_space * pcs, gs_state * pgs) +{ +#if ENABLE_CUSTOM_COLOR_CALLBACK + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) + pcb->client_procs->install_DeviceCMYK(pcb, pcs, pgs); +#endif + return 0; +} /* * Push an overprint compositor onto the current device indicating that, diff --git a/gs/src/gscspace.h b/gs/src/gscspace.h index c5516e5ee..7f6dd8c6f 100644 --- a/gs/src/gscspace.h +++ b/gs/src/gscspace.h @@ -19,7 +19,6 @@ #include "gsmemory.h" #include "gsiparam.h" -#include "gsnamecl.h" #include "gsrefct.h" /* @@ -188,9 +187,6 @@ typedef struct gs_separation_params_s { separation_type sep_type; bool use_alt_cspace; gs_callback_func_get_colorname_string *get_colorname_string; -#if ENABLE_NAMED_COLOR_CALLBACK - named_color_params_t named_color_params; -#endif } gs_separation_params; typedef struct gs_device_n_params_s { @@ -200,11 +196,11 @@ typedef struct gs_device_n_params_s { gs_device_n_attributes *colorants; bool use_alt_cspace; gs_callback_func_get_colorname_string *get_colorname_string; -#if ENABLE_NAMED_COLOR_CALLBACK - named_color_params_t named_color_params; -#endif } gs_device_n_params; +/* Define an abstract type for the client color space data */ +typedef struct client_color_space_data_s client_color_space_data_t; + /* * Non-direct paint space: Indexed space. * @@ -251,6 +247,7 @@ struct gs_color_space_s { rc_header rc; gs_id id; gs_color_space *base_space; + client_color_space_data_t *pclient_color_space_data; union { gs_device_pixel_params pixel; gs_cie_defg * defg; diff --git a/gs/src/gsdparam.c b/gs/src/gsdparam.c index 15ef65710..95590c0ff 100644 --- a/gs/src/gsdparam.c +++ b/gs/src/gsdparam.c @@ -117,12 +117,6 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist) /* Transmit the values. */ -#if ENABLE_NAMED_COLOR_CALLBACK - /* The named color callback pointer */ - code = named_color_callback_get_params(dev, plist); - if (code < 0) - return code; -#endif if ( /* Standard parameters */ @@ -481,12 +475,6 @@ e: param_signal_error(plist, param_name, ecode);\ }\ END -#if ENABLE_NAMED_COLOR_CALLBACK - /* The named_color callback pointer */ - code = named_color_callback_put_params(dev, plist); - if (code < 0) - ecode = code; -#endif /* * The actual value of LeadingEdge must be changed inside this routine, * so that we can detect that it has been changed. Thus, instead of a diff --git a/gs/src/gsdps1.c b/gs/src/gsdps1.c index 1355fb571..4fa539711 100644 --- a/gs/src/gsdps1.c +++ b/gs/src/gsdps1.c @@ -28,6 +28,7 @@ #include "gzpath.h" #include "gzcpath.h" #include "gzstate.h" +#include "gsutil.h" /* * Define how much rounding slop setbbox should leave, @@ -196,6 +197,9 @@ gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) dev_proc(pdev, fill_rectangle_hl_color)(pdev, &empty, pis, pdc, NULL) == 0); + /* Processing a fill object operation */ + gs_set_object_tag(pgs, GS_PATH_TAG); + gx_set_dev_color(pgs); if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && diff --git a/gs/src/gsicc.c b/gs/src/gsicc.c index c5eb8e623..9ceb2838b 100644 --- a/gs/src/gsicc.c +++ b/gs/src/gsicc.c @@ -115,6 +115,9 @@ private cs_proc_init_color(gx_init_CIEICC); private cs_proc_restrict_color(gx_restrict_CIEICC); private cs_proc_concrete_space(gx_concrete_space_CIEICC); private cs_proc_concretize_color(gx_concretize_CIEICC); +#if ENABLE_CUSTOM_COLOR_CALLBACK +private cs_proc_remap_color(gx_remap_ICCBased); +#endif private cs_proc_final(gx_final_CIEICC); private cs_proc_serialize(gx_serialize_CIEICC); @@ -129,7 +132,11 @@ private const gs_color_space_type gs_color_space_type_CIEICC = { gx_concrete_space_CIEICC, /* concrete_space */ gx_concretize_CIEICC, /* concreteize_color */ NULL, /* remap_concrete_color */ +#if ENABLE_CUSTOM_COLOR_CALLBACK + gx_remap_ICCBased, /* remap_color */ +#else gx_default_remap_color, /* remap_color */ +#endif gx_install_CIE, /* install_cpsace */ gx_spot_colors_set_overprint, /* set_overprint */ gx_final_CIEICC, /* final */ @@ -294,6 +301,32 @@ gx_concretize_CIEICC( return 0; } +#if ENABLE_CUSTOM_COLOR_CALLBACK +/* + * This routine is only used if ENABLE_CUSTOM_COLOR_CALLBACK is true. + * Otherwise we use gx_default_remap_color directly for CIEBasedDEFG color + * spaces. + * + * Render a CIEBasedDEFG color. + */ +int +gx_remap_ICCBased(const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + if (pcb->client_procs->remap_ICCBased(pcb, pc, pcs, + pdc, pis, dev, select) == 0) + return 0; + } + /* Use default routine for non custom color processing. */ + return gx_default_remap_color(pc, pcs, pdc, pis, dev, select); +} +#endif + /* * Finalize the contents of an ICC color space. Now that color space * objects have straightforward reference counting discipline, there's @@ -550,6 +583,22 @@ gx_install_CIEICC(const gs_color_space * pcs, gs_state * pgs) const gs_icc_params * picc_params = (const gs_icc_params *)&pcs->params.icc; gs_cie_icc * picc_info = picc_params->picc_info; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + /* + * Check if we want to use the callback color processing for this + * color space. + */ + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) pgs->custom_color_callback; + + if (pcb != NULL) { + if (pcb->client_procs->install_ICCBased(pcb, pcs, pgs)) + /* Exit if the client will handle the colorspace completely */ + return 0; + } + } +#endif /* update the stub information used by the joint caches */ gx_cie_load_common_cache(&picc_info->common, pgs); gx_cie_common_complete(&picc_info->common); diff --git a/gs/src/gsimage.c b/gs/src/gsimage.c index 62613a493..ceaa87b89 100644 --- a/gs/src/gsimage.c +++ b/gs/src/gsimage.c @@ -27,7 +27,7 @@ #include "gxpath.h" /* for gx_effective_clip_path */ #include "gximask.h" #include "gzstate.h" - +#include "gsutil.h" /* The main internal invariant for the gs_image machinery is @@ -196,6 +196,9 @@ gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs, if (code < 0) return code; + /* Processing an image object operation */ + gs_set_object_tag(pgs, GS_IMAGE_TAG); + if (uses_color) { gx_set_dev_color(pgs); code = gs_state_color_load(pgs); diff --git a/gs/src/gsnamecl.c b/gs/src/gsnamecl.c index 6abe7dde3..dc48df4ac 100644 --- a/gs/src/gsnamecl.c +++ b/gs/src/gsnamecl.c @@ -39,19 +39,19 @@ #include "gscspace.h"
#include "gxdevice.h"
#include "gzstate.h"
+#include "gsutil.h"
-#if ENABLE_NAMED_COLOR_CALLBACK /* Defined in src/gsnamecl.h */
-
+#if ENABLE_CUSTOM_COLOR_CALLBACK /* Defined in src/gsnamecl.h */
+
/*
* Check if we want to use the callback color processing logic for the given
* Separation color space.
*/
bool
-named_color_callback_install_Separation(gs_color_space * pcs, gs_state * pgs)
+custom_color_callback_install_Separation(gs_color_space * pcs, gs_state * pgs)
{
- gx_device * dev = pgs->device;
- client_named_color_params_t * pcb =
- (client_named_color_params_t *) dev->named_color_callback;
+ client_custom_color_params_t * pcb =
+ (client_custom_color_params_t *) pgs->custom_color_callback;
return (pcb == NULL) ? false
: pcb->client_procs->install_Separation(pcb, pcs, pgs);
@@ -62,30 +62,29 @@ named_color_callback_install_Separation(gs_color_space * pcs, gs_state * pgs) * DeviceN color space.
*/
bool
-named_color_callback_install_DeviceN(gs_color_space * pcs, gs_state * pgs)
+custom_color_callback_install_DeviceN(gs_color_space * pcs, gs_state * pgs)
{
- gx_device * dev = pgs->device;
- client_named_color_params_t * pcb =
- (client_named_color_params_t *) dev->named_color_callback;
-
+ client_custom_color_params_t * pcb =
+ (client_custom_color_params_t *) pgs->custom_color_callback;
+
return (pcb == NULL) ? false
- : pcb->client_procs->install_DeviceN(pcb, pcs, pgs);
-}
-
+ : pcb->client_procs->install_DeviceN(pcb, pcs, pgs);
+ }
+
/*
- * Convert a Separation color using the 'named color' callback into device color.
- */
+ * Convert a Separation color using the 'custom color' callback into
+ * device color.
+*/
int
-gx_remap_concrete_named_color_Separation(const frac * pconc,
- const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+gx_remap_concrete_custom_color_Separation(const frac * pconc,
+ const gs_color_space * pcs, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
{
- client_named_color_params_t * pcb =
- (client_named_color_params_t *) dev->named_color_callback;
-
- if (pcb == NULL) {
- dlprintf("ERROR: Named color callback is NULL\n");
- return_error(gs_error_rangecheck);
+ client_custom_color_params_t * pcb =
+ (client_custom_color_params_t *) pis->custom_color_callback;
+
+ if (pcb == NULL) {
+ return_error(gs_error_rangecheck);
}
else
return pcb->client_procs->remap_Separation(pcb, pconc,
@@ -93,119 +92,124 @@ gx_remap_concrete_named_color_Separation(const frac * pconc, }
/*
- * Convert a DeviceN color using the 'named color' callback into device color.
+ * Convert a DeviceN color using the 'custom color' callback into device
+ * color.
*/
int
-gx_remap_concrete_named_color_DeviceN(const frac * pconc,
+gx_remap_concrete_custom_color_DeviceN(const frac * pconc,
const gs_color_space * pcs, gx_device_color * pdc,
const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
{
- client_named_color_params_t * pcb =
- (client_named_color_params_t *) dev->named_color_callback;
-
- if (pcb == NULL) {
- dlprintf("ERROR: Named color callback is NULL\n");
- return_error(gs_error_rangecheck);
+ client_custom_color_params_t * pcb =
+ (client_custom_color_params_t *) pis->custom_color_callback;
+
+ if (pcb == NULL) {
+ return_error(gs_error_rangecheck);
}
else
- return pcb->client_procs->remap_DeviceN(pcb, pconc,
+ return pcb->client_procs->remap_DeviceN(pcb, pconc,
pcs, pdc, pis, dev, select);
}
/*
- * Get the 'Named color' client callback parameter block pointer. This value
+ * Get the 'custom color' client callback parameter block pointer. This value
* is passed as a string type device paramter. A string is being used since
* PostScript does not support pointers as a type. Note: An integer type
* is not being used since PS intergers are nominally 32 bits. Thus there
* would be a problem using integers to pass pointer values on 64 bit systems.
*/
int
-named_color_callback_get_params(gx_device * dev, gs_param_list * plist)
+custom_color_callback_get_params(gs_state * pgs, gs_param_list * plist)
{
/* Convert our pointer to a PostScript hex string */
char buf[64] = "16#";
int buf_pos = 3;
- gs_param_string named_color_param;
+ gs_param_string custom_color_param;
int idx;
int val;
size_t iptr;
-
+
idx = ((int)sizeof(size_t)) * 8 - 4;
- iptr = (size_t)(dev->named_color_callback);
+ iptr = (size_t)(pgs->custom_color_callback);
while (idx >= 0) {
val = (int)(iptr >> idx) & 0xf;
- if (val <= 9)
- buf[buf_pos++] = '0' + val;
+ if (val <= 9)
+ buf[buf_pos++] = '0' + val;
else
buf[buf_pos++] = 'a' - 10 + val;
idx -= 4;
}
- buf[buf_pos] = '\0';
-
- param_string_from_transient_string(named_color_param, buf);
+ param_string_from_transient_string(custom_color_param, buf);
- return param_write_string(plist, "NamedColorCallback", &named_color_param);
+ return param_write_string(plist, CustomColorCallbackParamName,
+ &custom_color_param);
}
/*
- * Put the 'Named color' client callback parameter block pointer. This value
+ * Put the 'custom color' client callback parameter block pointer. This value
* is passed as a string type device paramter. A string is being used since
* PostScript does not support pointers as a type. Note: An integer type
* is not being used since PS integers are nominally 32 bits. Thus there
* would be a problem using integers to pass pointer values on 64 bit systems.
*/
int
-named_color_callback_put_params(gx_device * dev, gs_param_list * plist)
+custom_color_callback_put_params(gs_state * pgs, gs_param_list * plist)
{
int code;
- size_t iptr = (size_t)(dev->named_color_callback);
+ size_t iptr = (size_t)(pgs->custom_color_callback);
gs_param_string dh = { 0 };
- switch (code = param_read_string(plist, "NamedColorCallback", &dh)) {
+ switch (code = param_read_string(plist, CustomColorCallbackParamName, &dh)) {
case 0:
- {
- /*
- * Convert from a string to a pointer.
- * It is assumed that size_t has the same size as a pointer.
- * Allow formats (1234), (10#1234) or (16#04d2).
- */
- int i;
- int base = 10;
- int val;
- code = 0;
- for (i = 0; i < dh.size; i++) {
- val = dh.data[i];
- if ((val >= '0') && (val <= '9'))
- val = val - '0';
- else if ((val >= 'A') && (val <= 'F'))
+ {
+ /*
+ * Convert from a string to a pointer.
+ * It is assumed that size_t has the same size as a pointer.
+ * Allow formats (1234), (10#1234) or (16#04d2).
+ */
+ uint i;
+ int base = 10;
+ int val;
+ code = 0;
+ for (i = 0; i < dh.size; i++) {
+ val = dh.data[i];
+ if ((val >= '0') && (val <= '9'))
+ val = val - '0';
+ else if ((val >= 'A') && (val <= 'F'))
val = val - 'A' + 10;
- else if ((val >= 'a') && (val <= 'f'))
+ else if ((val >= 'a') && (val <= 'f'))
val = val - 'a' + 10;
- else if (val == '#' && ((iptr == 10) || (iptr == 16))) {
+ else if (val == '#' && ((iptr == 10) || (iptr == 16))) {
base = (int) iptr;
iptr = 0;
continue;
- }
- else {
+ }
+ else {
code = gs_error_rangecheck;
break;
- }
- iptr = iptr * base + val;
- }
- }
- break;
+ }
+ iptr = iptr * base + val;
+ }
+ }
+ break;
default:
case 1:
dh.data = 0;
break;
}
if (code < 0) {
- param_signal_error(plist, "NamedColorCallback", code);
+ param_signal_error(plist, "CustomColorCallback", code);
+ }
+ else if (pgs->custom_color_callback != (void *)iptr) {
+ pgs->custom_color_callback = (void *)iptr;
+ /*
+ * Custom color processing can depend upon the type of object
+ * being imaged so we enable object type tagging.
+ */
+ gs_enable_object_tagging();
}
- else
- dev->named_color_callback = (void *)iptr;
return 0;
}
-#endif /* ENABLE_NAMED_COLOR_CALLBACK */
+#endif /* ENABLE_CUSTOM_COLOR_CALLBACK */
diff --git a/gs/src/gsnamecl.h b/gs/src/gsnamecl.h index b215bd5dc..783c7fd77 100644 --- a/gs/src/gsnamecl.h +++ b/gs/src/gsnamecl.h @@ -9,173 +9,299 @@ 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$ */
-/* Global definitions for the 'Named Color' callback handling. */
-
-#ifndef gsnamecl_INCLUDED
-# define gsnamecl_INCLUDED
-
-#include "gxfrac.h"
-#include "gsccolor.h"
-#include "gscsel.h"
-
-/*
- * Enable 'named color' callback color processing. Note: There is a sample
- * implementation in src/gsncdemo.c.
- */
-#define ENABLE_NAMED_COLOR_CALLBACK 0 /* 0 --> disabled, 1 --> enabled */
-
-/*
- * For comments upon the client API for working with the 'named color'
- * callback logic see the section labeled: "NAMED COLOR CALLBACK CLIENT
- * APPLICATION INTERFACE" below.
- */
-
-/*
- * Type for holding 'named color' callback related parameters
- */
-typedef struct named_color_params_s {
- /*
- * If true, then use the 'named color' callback color processing path
- * for determining colorants.
- */
- bool use_named_color_callback;
- /*
- * Storage for the 'named color' callback related parameters.
- * Note: This storage is actually for the client. This may be enough
- * for some clients. It is enough for our demo example. A more complete
- * implementation would probably include a client callback for for when
- * a color space is finished (i.e. the reference count is zero or it
- * is garbage collected).
- */
- int color_index[GS_CLIENT_COLOR_MAX_COMPONENTS];
-} named_color_params_t;
-
-#ifndef gs_color_space_DEFINED
-# define gs_color_space_DEFINED
-typedef struct gs_color_space_s gs_color_space;
-#endif
-
-#ifndef gx_device_color_DEFINED
-# define gx_device_color_DEFINED
-typedef struct gx_device_color_s gx_device_color;
-#endif
-
-#ifndef gs_state_DEFINED
-# define gs_state_DEFINED
-typedef struct gs_state_s gs_state;
-#endif
-
-#ifndef gs_imager_state_DEFINED
-# define gs_imager_state_DEFINED
-typedef struct gs_imager_state_s gs_imager_state;
-#endif
-
-#ifndef gx_device_DEFINED
-# define gx_device_DEFINED
-typedef struct gx_device_s gx_device;
-#endif
-
-/* Define an opaque type for parameter lists. */
-#ifndef gs_param_list_DEFINED
-# define gs_param_list_DEFINED
-typedef struct gs_param_list_s gs_param_list;
-#endif
-
-/*
- * Put the 'named color' client callback parameter block pointer. This value
- * is passed as a string type device paramter. A string is being used since
- * PostScript does not support pointers as a type. Note: An integer type
- * is not being used since PS intergers are nominally 32 bits. Thus there
- * would be a problem using integers to pass pointer values on 64 bit systems.
- */
-int named_color_put_params(gx_device * dev, gs_param_list * plist);
-
-/*
- * Get the 'named color' client callback parameter block pointer. This value
- * is passed as a string type device paramter. A string is being used since
- * PostScript does not support pointers as a type. Note: An integer type
- * is not being used since PS intergers are nominally 32 bits. Thus there
- * would be a problem using integers to pass pointer values on 64 bit systems.
- */
-int named_color_get_params(gx_device * dev, gs_param_list * plist);
-
-/*
- * Check if we want to use the 'named color' callback processing logic for the
- * given Separation color space.
- */
-bool named_color_install_Separation(gs_color_space * pcs, gs_state * pgs);
-
-/*
- * Check if we want to use the 'named color' callback processing logic for the
- * given DeviceN color space.
- */
-bool named_color_install_DeviceN(gs_color_space * pcs, gs_state * pgs);
-
-/*
- * Convert a Separation color into device colorants using the 'named color'
- * client callback.
- */
-int gx_remap_concrete_named_color_Separation(const frac * pconc,
- const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select);
-
-/*
- * Convert a DeviceN color into device colorants using the 'named color'
- * client callback.
- */
-int gx_remap_concrete_named_color_DeviceN(const frac * pconc,
- const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select);
-
-/* "CLIENT NAMED COLOR APPLICATION INTERFACE" */
-/*
- * In order to give some flexibility to the Ghostscript client API, we are
- * allowing the client to define a set of call back procedures for processing
- * color spaces with 'named colors', i.e. Separation and DeviceN.
- */
-/*
- * The 'named color' call back structure definitions. The call back structure
- * consists of a pointer to a list of client 'named color' color handling
- * procedures and a pointer to a client data structure.
- */
-typedef struct client_named_color_params_s {
- struct client_named_color_procs_s * client_procs; /* Client callback handlers */
- void * data; /* For client data */
-} client_named_color_params_t;
-
-/*
- * Define the client 'named color' callback procedures.
- */
-typedef struct client_named_color_procs_s {
- /*
- * Check if we want to use the callback color processing logic for the
- * given Separation color space.
- */
- bool (* install_Separation)(client_named_color_params_t * pparams,
- gs_color_space * pcs, gs_state * pgs);
- /*
- * Convert a Separation color into device color.
- */
- int (* remap_Separation)(client_named_color_params_t * pparams,
- const frac * pconc, const gs_color_space * pcs,
- gx_device_color * pdc, const gs_imager_state * pis,
- gx_device * dev, gs_color_select_t select);
- /*
- * Check if we want to use the callback color processing logic for the
- * given DeviceN color space.
- */
- bool (* install_DeviceN)(client_named_color_params_t * pparams,
- gs_color_space * pcs, gs_state * pgs);
- /*
- * Convert a DeviceN color into device color.
- */
- int (* remap_DeviceN)(client_named_color_params_t * pparams, const frac * pconc,
- const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select);
-
-} client_named_color_procs_t;
-
-#endif /* ifndef gsnamecl_INCLUDED */
+*/ +/* $Id$ */ +/* Global definitions for the 'Named Color' callback handling. */ + +#ifndef gsnamecl_INCLUDED +# define gsnamecl_INCLUDED + +#include "gxfrac.h" +#include "gsccolor.h" +#include "gscsel.h" +#include "gxcspace.h" + +/* + * Enable custom client callback color processing. Note: There is a sample + * implementation in src/gsncdemo.c. + */ +#define ENABLE_CUSTOM_COLOR_CALLBACK 1 /* 0 --> disabled, 1 --> enabled */ + + +#if ENABLE_CUSTOM_COLOR_CALLBACK +/* Ptr to custom color callback struct */ +#define CUSTOM_COLOR_PTR void * custom_color_callback; +#define INIT_CUSTOM_COLOR_PTR NULL, /* Initial value */ +#else +#define CUSTOM_COLOR_PTR +#define INIT_CUSTOM_COLOR_PTR +#endif + +#define CustomColorCallbackParamName "CustomColorCallback" + +/* + * For comments upon the client API for working with the custom client + * callback logic see the section labeled: "CLIENT COLOR CALLBACK + * APPLICATION INTERFACE" below. + * + * Also see the comments at the start of src/gsnamecl.c + */ + +#ifndef gs_color_space_DEFINED +# define gs_color_space_DEFINED +typedef struct gs_color_space_s gs_color_space; +#endif + +#ifndef gx_device_color_DEFINED +# define gx_device_color_DEFINED +typedef struct gx_device_color_s gx_device_color; +#endif + +#ifndef gs_state_DEFINED +# define gs_state_DEFINED +typedef struct gs_state_s gs_state; +#endif + +#ifndef gs_imager_state_DEFINED +# define gs_imager_state_DEFINED +typedef struct gs_imager_state_s gs_imager_state; +#endif + +#ifndef gx_device_DEFINED +# define gx_device_DEFINED +typedef struct gx_device_s gx_device; +#endif + +#ifndef i_ctx_t_DEFINED +#define i_ctx_t_DEFINED +typedef struct gs_context_state_s i_ctx_t; +#endif + +/* Define an opaque type for parameter lists. */ +#ifndef gs_param_list_DEFINED +# define gs_param_list_DEFINED +typedef struct gs_param_list_s gs_param_list; +#endif + +#define cs_proc_adjust_client_cspace_count(proc)\ + void proc(const gs_color_space *, int) + +/* + * Put the 'custom color' client callback parameter block pointer. This value + * is passed as a string type user paramter. A string is being used since + * PostScript does not support pointers as a type. Note: An integer type + * is not being used since PS integers are nominally 32 bits. Thus there + * would be a problem using integers to pass pointer values on 64 bit systems. + */ +int custom_color_callback_put_params(gs_state * pgs, gs_param_list * plist); + +/* + * Get the custom client client callback parameter block pointer. This value + * is passed as a string type user paramter. A string is being used since + * PostScript does not support pointers as a type. Note: An integer type + * is not being used since PS intergers are nominally 32 bits. Thus there + * would be a problem using integers to pass pointer values on 64 bit systems. + */ +int custom_color_callback_get_params(gs_state * pgs, gs_param_list * plist); + +/* + * Check if we want to use the callback color processing logic for the given + * Separation color space. + */ +bool custom_color_callback_install_Separation(gs_color_space * pcs, + gs_state * pgs); + +/* + * Check if we want to use the custom client callback processing logic for the + * given DeviceN color space. + */ +bool custom_color_callback_install_DeviceN(gs_color_space * pcs, gs_state * pgs); + +/* + * Convert a Separation color into device colorants using the custom client + * client callback. + */ +int gx_remap_concrete_custom_color_Separation(const frac * pconc, + const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select); + +/* + * Convert a DeviceN color into device colorants using the custom client + * client callback. + */ +int gx_remap_concrete_custom_color_DeviceN(const frac * pconc, + const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select); + +/* "CLIENT COLOR CALLBACK APPLICATION INTERFACE" */ +/* + * In order to give some flexibility to the Ghostscript client API, we are + * allowing the client to define a set of call back procedures for processing + * color spaces. + * + * See the comments at the start of src/gsnamecl.c + */ +/* + * The 'client color' call back structure definitions. The call back structure + * consists of a pointer to a list of client color space handling procedures + * and a pointer to a client data structure. + */ +typedef struct client_custom_color_params_s { + /* Client callback handlers */ + struct client_custom_color_procs_s * client_procs; + /* For global client data */ + void * data; +} client_custom_color_params_t; + + +/* + * Define a base type for client color space data. Most clients will + * overload this type with a structure of their own. That type must + * start with a pointer to a handler routine for the structure's + * reference count. + */ +typedef struct client_color_space_data_s { + cs_proc_adjust_client_cspace_count((*client_adjust_cspace_count)); +} client_color_space__data_t; + +/* + * Define the client custom client callback procedures. + */ +typedef struct client_custom_color_procs_s { + /* + * Install a DeviceGray color space. + */ + bool (* install_DeviceGray)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a DeviceGray color into device color. + */ + int (* remap_DeviceGray)(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Install a DeviceRGB color space. + */ + bool (* install_DeviceRGB)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a DeviceRGB color into device color. + */ + int (* remap_DeviceRGB)(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Install a DeviceCMYK color space. + */ + bool (* install_DeviceCMYK)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a DeviceGray color into device color. + */ + int (* remap_DeviceCMYK)(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given Separation color space. + */ + bool (* install_Separation)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a Separation color into device color. + */ + int (* remap_Separation)(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given DeviceN color space. + */ + bool (* install_DeviceN)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a DeviceN color into device color. + */ + int (* remap_DeviceN)(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given CIEBasedA color space. + */ + bool (* install_CIEBasedA)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Please note that the 'complex' color spaces (CIEBasedA, CIEBasedABC, + * CIEBasedDEF, CIEBasedDEFG, and ICCBased) have a different prototype, + * versus the simpler color spces, for the callback for converting a + * the color values. + */ + /* + * Convert a CIEBasedA color into device color. + */ + int (* remap_CIEBasedA)(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given CIEBasedABC color space. + */ + bool (* install_CIEBasedABC)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a CIEBasedABC color into device color. + */ + int (* remap_CIEBasedABC)(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given CIEBasedDEF color space. + */ + bool (* install_CIEBasedDEF)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a CIEBasedDEF color into device color. + */ + int (* remap_CIEBasedDEF)(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given CIEBasedDEFG color space. + */ + bool (* install_CIEBasedDEFG)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a CIEBasedDEFG color into device color. + */ + int (* remap_CIEBasedDEFG)(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + /* + * Check if we want to use the callback color processing logic for the + * given ICCBased color space. + */ + bool (* install_ICCBased)(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs); + /* + * Convert a ICCBased color into device color. + */ + int (* remap_ICCBased)(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, + gx_device * dev, gs_color_select_t select); + +} client_custom_color_procs_t; + +#endif /* ifndef gsnamecl_INCLUDED */ diff --git a/gs/src/gsncdemo.c b/gs/src/gsncdemo.c index ed2747005..e561a3707 100644 --- a/gs/src/gsncdemo.c +++ b/gs/src/gsncdemo.c @@ -9,428 +9,897 @@ 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$ */
-/* Sample implementation for handling PANTONE Colors */
-
-/*
- * PANTONE is a registered trademark and PANTONE colors are a
- * licensed product of Pantone Inc. See http://www.pantone.com
- * for more information.
- */
-
-/*
- * This module has been created to demonstrate how to support the use of
- * PANTONE colors to the Ghostscript graphics library. PANTONE colors
- * are specified in both PostScript and PDF files via the use of DeviceN
- * or Separation color spaces.
- *
- * This implementation consists of four routines. There are a pair of
- * routines for both Separation and DeviceN color spaces. Each pair consists
- * of a routine that is called when the color space is installed and a
- * second routine that is called to transform colors in that color space
- * into device colorant values. The routines client_pantone_install_Separation
- * and client_pantone_install_DeviceN are called when Separation or DeviceN
- * color space is installed. These routines determine if Pantone colors are
- * used inside the color space. These routines return true if colors in the
- * color space should be processed via the second pair of routines.
- * The routines client_pantone_remap_Separation and client_pantone_remap_DeviceN
- * are then called whenever a color is specified (and the 'install' routines
- * returned true). This second set of routines act as a replacement for the
- * alternate tine transform functions.
- *
- * To use this code:
- * 1. Set ENABLE_NAMED_COLOR_CALLBACK in gsnamecl.h to 1
- * 2. Provide your implementation of the Pantone callback routines. See
- * the client_pantone_install_Separation, client_pantone_remap_Separation,
- * client_pantone_install_DeviceN, and client_pantone_remap_DeviceN for
- * an example of these routines.
- * 3. Define a Pantone callback parameter structure (see the 'demo_procs'
- * example structure below) and pass it as a parameter to Ghostscript.
- * This can be done on the command line by use of -sPantoneCallBack=16#xxxx
- * where xxxx is the address of the call parameter structure specified as
- * a hex ascii string.
- *
- * Since this is only a 'demo' implementation, the example implementation does
- * not have some features which might be expected in a 'real' implementation.
- *
- * 1. The Pantone color data table does not have actual entries for all
- * of the different Pantone colors. This data is not included since
- * the values are dependent upon specific details of the output device,
- * inks, etc.
- * 2. Colors in PostScript and PDF are specified with by values between
- * 0 and 1. The output colorant values are scaled linearly.
- * 3. DeviceN color spaces can specify multiple colors. However this
- * implementation assumes that if a PANTONE color is specified in a
- * DeviceN color space, then only PANTONE colors or CMYK are present.
- * This was done to keep the code simple. If other colors are present,
- * then this implementation falls back to using the alternate color space
- * specified with the DeviceN color space. (This is the normal PS
- * and PDF operation.)
- */
-
-#include "stdpre.h"
-#include "math_.h"
-#include "memory_.h"
-#include "gx.h"
-#include "gserrors.h"
-#include "gscdefs.h"
-#include "gscspace.h"
-#include "gxdevice.h"
-#include "gzstate.h"
-
-#if ENABLE_NAMED_COLOR_CALLBACK /* Defined in src/gsnamecl.h */
-
-/*
- * This s a list of PANTONE color names and a set of equivalent CMYK values,
- */
-typedef struct pantone_list_s {
- const char *name; /* Name of the PANTONE color */
- double c, m, y, k; /* Equivalent CMYK values */
-} pantone_list_t;
-
-/*
- * Since this is only a 'demo' list, the list does have not entries for all
- * of the different PANTONE colors. Creation of a real list is left as an
- * exercise for the user.
- */
-private const pantone_list_t pantone_list[] = {
- { "PantoneCyan", 1, 0, 0, 0 },
- { "PantoneMagenta", 0, 1, 0, 0 },
- { "PantoneYellow", 0, 0, 1, 0 },
- { "PantoneBlack", 0, 0, 0, 1 },
-};
-
-/*
- * We will handle color spaces that include both PANTONE colors, CMYK, and
- * 'None'. 'None' is a special case in DeviceN color spaces. It has no
- * effects upon the output color but it can be present in DeviceN color
- * spaces in a PDF file. To simplify the code, we need pantone index values
- * for these five 'colors'.
- */
-#define PANTONE_NONE count_of(pantone_list)
-#define PANTONE_CYAN (PANTONE_NONE + 1)
-#define PANTONE_MAGENTA (PANTONE_NONE + 2)
-#define PANTONE_YELLOW (PANTONE_NONE + 3)
-#define PANTONE_BLACK (PANTONE_NONE + 4)
-
-/* Compare two names */
-#define compare_names(name1, name_size1, name2, name_size2) \
- (name_size1 == name_size2 && \
- (memcmp((const char *)name1, (const char *)name2, name_size1) == 0))
-
-/*
- * Check if we want to use the PANTONE color processing logic for the given
- * Separation color space.
- */
-private bool
-client_pantone_install_Separation(client_named_color_params_t * pparam,
- gs_color_space * pcs, gs_state * pgs)
-{
- const gs_separation_name name = pcs->params.separation.sep_name;
- int pan_index;
- byte * pname;
- uint name_size;
- gx_device * dev = pgs->device;
- int num_pantone_colors = count_of(pantone_list);
- bool use_named_color_callback = false;
-
- /*
- * Get the character string and length for the component name.
- */
- pcs->params.separation.get_colorname_string(dev->memory, name,
- &pname, &name_size);
- /*
- * Compare the colorant name to those in our PANTONE color list.
- */
- for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) {
- const char * pan_name = pantone_list[pan_index].name;
-
- if (compare_names(pname, name_size, pan_name, strlen(pan_name))) {
- pcs->params.separation.named_color_params.color_index[0] = pan_index;
- use_named_color_callback = true;
- break;
- }
- }
- pcs->params.device_n.named_color_params.use_named_color_callback =
- use_named_color_callback;
- return (use_named_color_callback);
-}
-
-/*
- * Check if we want to use the PANTONE color processing logic for the given
- * DeviceN color space.
- */
-private bool
-client_pantone_install_DeviceN(client_named_color_params_t * pparam,
- gs_color_space * pcs, gs_state * pgs)
-{
- const gs_separation_name *names = pcs->params.device_n.names;
- int num_comp = pcs->params.device_n.num_components;
- int i;
- int pan_index;
- byte * pname;
- uint name_size;
- gx_device * dev = pgs->device;
- int num_pantone_colors = count_of(pantone_list);
- bool pantone_found = false;
- bool other_separation_found = false;
- bool use_pantone;
- const char none_str[] = "None";
- const uint none_size = strlen(none_str);
- const char cyan_str[] = "Cyan";
- const uint cyan_size = strlen(cyan_str);
- const char magenta_str[] = "Magenta";
- const uint magenta_size = strlen(magenta_str);
- const char yellow_str[] = "Yellow";
- const uint yellow_size = strlen(yellow_str);
- const char black_str[] = "Black";
- const uint black_size = strlen(black_str);
-
- /*
- * Now check the names of the color components.
- */
- for(i = 0; i < num_comp; i++ ) {
- bool match = false;
-
- /*
- * Get the character string and length for the component name.
- */
- pcs->params.device_n.get_colorname_string(dev->memory, names[i],
- &pname, &name_size);
- /*
- * Postscript does not include /None as a color component but it is
- * allowed in PDF so we accept it. We simply skip components named
- * 'None'.
- */
- if (compare_names(none_str, none_size, pname, name_size)) {
- pcs->params.device_n.named_color_params.color_index[i] =
- PANTONE_NONE;
- continue;
- }
- /*
- * Check if our color space includes the CMYK process colors.
- */
- if (compare_names(cyan_str, cyan_size, pname, name_size)) {
- pcs->params.device_n.named_color_params.color_index[i] =
- PANTONE_CYAN;
- continue;
- }
- if (compare_names(magenta_str, magenta_size, pname, name_size)) {
- pcs->params.device_n.named_color_params.color_index[i] =
- PANTONE_MAGENTA;
- continue;
- }
- if (compare_names(yellow_str, yellow_size, pname, name_size)) {
- pcs->params.device_n.named_color_params.color_index[i] =
- PANTONE_YELLOW;
- continue;
- }
- if (compare_names(black_str, black_size, pname, name_size)) {
- pcs->params.device_n.named_color_params.color_index[i] =
- PANTONE_BLACK;
- continue;
- }
- /*
- * Compare the colorant name to those in our Pantone color list.
- */
- for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) {
- const char * pan_name = pantone_list[pan_index].name;
-
- if (compare_names(pname, name_size, pan_name, strlen(pan_name))) {
- pcs->params.device_n.named_color_params.color_index[i] =
- pan_index;
- match = pantone_found = true;
- break;
- }
- }
- if (!match) { /* Exit if we find a non Pantone color */
- other_separation_found = true;
- break;
- }
- }
- /*
- * Handle this color space as a 'pantone color space' if we have only
- * PANTONE colors and CMYK. Any other separations will force us to
- * use the alternate tint transform for the DeviceN color space.
- */
- use_pantone = pantone_found && !other_separation_found;
- pcs->params.device_n.named_color_params.use_named_color_callback =
- use_pantone;
- return (use_pantone);
-}
-
-
-/*
- * Convert a set of color values in a 'PANTONE color space' into a device
- * color values.
- *
- * This routine creates an equivalent CMYK color and then uses
- * gx_remap_concrete_cmyk to convert this into device colorants. Note: It
- * is possible to go directy to the output device colorants. However the
- * pantone_install_xxx routines should verify that the expected device
- * colorants match the actual device colorants. (For instance, Ghostscript
- * can install temporary compositing devices for functions like handling
- * PDF 1.4 transparency. The compositing devices may have a process color
- * models which differ from the final output device.)
- */
-private int
-client_pantone_remap_color(client_named_color_params_t * pparam,
- const frac * pconc, const named_color_params_t * pparams,
- gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
- gs_color_select_t select, int num_comp)
-{
- int i, pantone_index, cvalue;
- int cyan = 0;
- int magenta = 0;
- int yellow = 0;
- int black = 0;
- frac cc, cm, cy, ck;
- const pantone_list_t * plist;
-
- /*
- * Create a CMYK representation of the various colors in our color space.
- * Note: If we have multiple components, then we do a simple sum of the
- * CMYK equivalent for each color. If desired, a more complex handling is
- * left to the user.
- */
- for (i = 0; i < num_comp; i++) {
- cvalue = pconc[i];
- pantone_index = pparams->color_index[i];
- switch (pantone_index) {
- case PANTONE_NONE:
- break;
- case PANTONE_CYAN:
- cyan += cvalue;
- break;
- case PANTONE_MAGENTA:
- magenta += cvalue;
- break;
- case PANTONE_YELLOW:
- yellow += cvalue;
- break;
- case PANTONE_BLACK:
- black += cvalue;
- break;
- default:
- plist = &(pantone_list[pantone_index]);
- cyan += (int) floor(cvalue * plist->c);
- magenta += (int) floor(cvalue * plist->m);
- yellow += (int) floor(cvalue * plist->y);
- black += (int) floor(cvalue * plist->k);
- break;
- }
- }
- /* Clamp our color values */
- cc = (cyan > frac_1) ? frac_1 : (cyan < frac_0) ? frac_0 : cyan;
- cm = (magenta > frac_1) ? frac_1 : (magenta < frac_0) ? frac_0 : magenta;
- cy = (yellow > frac_1) ? frac_1 : (yellow < frac_0) ? frac_0 : yellow;
- ck = (black > frac_1) ? frac_1 : (black < frac_0) ? frac_0 : black;
- gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pis, dev, select);
- return 0;
-}
-
-/*
- * Convert a Separation color (with PANTONE colorants) into device color.
- */
-private int
-client_pantone_remap_Separation(client_named_color_params_t * pparam,
- const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
-{
- return client_pantone_remap_color(pparam, pconc,
- &(pcs->params.separation.named_color_params), pdc, pis, dev, select, 1);
-}
-
-/*
- * Convert a DeviceN color (with PANTONE colorants) into device color.
- */
-private int
-client_pantone_remap_DeviceN(client_named_color_params_t * pparam,
- const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc,
- const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
-{
- return client_pantone_remap_color(pparam, pconc,
- &(pcs->params.device_n.named_color_params), pdc, pis, dev, select,
- gs_color_space_num_components(pcs));
-}
-
-/*
- * Client call back procedures for our PANTONE demo.
- */
-client_named_color_procs_t demo_procs = {
- client_pantone_install_Separation,
- client_pantone_remap_Separation,
- client_pantone_install_DeviceN,
- client_pantone_remap_DeviceN,
-};
-
-/*
- * Demo version of the PANTONE call back parameter structure.
- */
-client_named_color_params_t demo_callback = {
- &demo_procs,
- /*
- * Use our 'list' of Pantone colors as an example data.
- */
- (void *)(&pantone_list)
-};
-#endif /* ENABLE_NAMED_COLOR_CALLBACK */
-
-/*
- * This procedure is here to simplify debugging. Normally one would expect the
- * PANTONE callback structure to be set up by a calling application. Since I
- * do not have a calling application, I need a simple way to setup the callback
- * parameter. The callback parameter is passed as a string value. This
- * routine puts the address of our demo callback structure into the provided
- * string.
- *
- * This routine allows the PANTONE logic to be enabled by adding the following
- * to the command line:
- * -c "<< /NamedColorCallBack 32 string .pantonecallback >> setpagedevice" -f
- */
-#include "memory_.h"
-#include "ghost.h"
-#include "oper.h"
-#include "iddict.h"
-#include "store.h"
-
-/* <string> .pantonecallback <string> */
-private int
-zpantonecallback(i_ctx_t *i_ctx_p)
-{
-#if ENABLE_NAMED_COLOR_CALLBACK
- os_ptr op = osp;
- int val, idx, buf_pos = 3;
- size_t iptr;
-#define PTR_STRING_SIZE (2 * size_of(void *) + 3)
-
- /* Verify that the string size is big enough for our output */
- check_type(*op, t_string);
- check_write(*op);
- if (r_size(op) < PTR_STRING_SIZE)
- return_error(e_rangecheck);
-
- /* Convert our call back parameter structure pointer into a string */
- op->value.bytes[0] = '1';
- op->value.bytes[1] = '6';
- op->value.bytes[2] = '#';
- iptr = (size_t)(&demo_callback);
- for (idx = ((int)size_of(size_t)) * 8 - 4; idx >= 0; idx -= 4) {
- val = (int)(iptr >> idx) & 0xf;
- op->value.bytes[buf_pos++] = (byte)((val <= 9) ? '0' + val
- : 'a' - 10 + val);
- }
- r_size(op) = PTR_STRING_SIZE;
-#endif /* ENABLE_NAMED_COLOR_CALLBACK */
- return 0;
-}
-
-/* ------ Initialization procedure ------ */
-
-const op_def pantone_op_defs[] =
-{
- {"1.pantonecallback", zpantonecallback},
- op_def_end(0)
-};
-
+*/ +/* $Id$ */ +/* Sample implementation for client custom processing of color spaces. */ + +/* + * If this flag is 1 then we also do custom processing for the DeviceGray, + * DeviceRGB, and DeviceCMYK color spaces. For these color spaces, we + * convert all text to shades of red, all images to shades of green and + * all lines and fills to shades of blue. if the flag is 0 then our example + * only handles PANTONE colors (see comment below). + */ +#define OBJECT_TYPE_EXAMPLE 1 /* 0 --> disabled, 1 --> enabled */ + +/* + * This module has been created to demonstrate how to support the use of + * PANTONE colors to the Ghostscript graphics library. PANTONE colors + * are specified in both PostScript and PDF files via the use of DeviceN + * or Separation color spaces. + * + * PANTONE is a registered trademark and PANTONE colors are a + * licensed product of Pantone Inc. See http://www.pantone.com + * for more information. + * + * See the comments at the start of src/gsnamecl.c for description of the + * client color processing routines. + * + * Since this is only a 'demo' implementation, the example implementation does + * not have some features which might be expected in a 'real' implementation. + * + * 1. The Pantone color data table does not have actual entries for all + * of the different Pantone colors. This data is not included since + * the values are dependent upon specific details of the output device, + * inks, etc. + * 2. Colors in PostScript and PDF are specified with by values between + * 0 and 1. The output colorant values are scaled linearly. + * 3. DeviceN color spaces can specify multiple colors. However this + * implementation assumes that if a PANTONE color is specified in a + * DeviceN color space, then only PANTONE colors or CMYK are present. + * This was done to keep the code simple. If other colors are present, + * then this implementation falls back to using the alternate color space + * specified with the DeviceN color space. (This is the normal PS + * and PDF operation.) + */ + +#include "stdpre.h" +#include "math_.h" +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gscdefs.h" +#include "gscspace.h" +#include "gscie.h" +#include "gsicc.h" +#include "gxdevice.h" +#include "gzstate.h" +#include "malloc_.h" +#include "memory_.h" +#include "ghost.h" +#include "oper.h" +#include "iddict.h" +#include "store.h" +#include "gsutil.h" + +#if ENABLE_CUSTOM_COLOR_CALLBACK /* Defined in src/gsnamecl.h */ + +/* + * This s a list of PANTONE color names and a set of equivalent CMYK values, + */ +typedef struct pantone_list_s { + const char *name; /* Name of the PANTONE color */ + double c, m, y, k; /* Equivalent CMYK values */ +} pantone_list_t; + +/* + * Since this is only a 'demo' list, the list does have not entries for all + * of the different PANTONE colors. Creation of a real list is left as an + * exercise for the user. + */ +private const pantone_list_t pantone_list[] = { + { "PantoneCyan", 1, 0, 0, 0 }, + { "PantoneMagenta", 0, 1, 0, 0 }, + { "PantoneYellow", 0, 0, 1, 0 }, + { "PantoneBlack", 0, 0, 0, 1 }, + { "Orange", 0, 1, .5, 0 } +}; + +/* + * We will handle color spaces that include both PANTONE colors, CMYK, and + * 'None'. 'None' is a special case in DeviceN color spaces. It has no + * effects upon the output color but it can be present in DeviceN color + * spaces in a PDF file. To simplify the code, we need pantone index values + * for these five 'colors'. + */ +#define PANTONE_NONE count_of(pantone_list) +#define PANTONE_CYAN (PANTONE_NONE + 1) +#define PANTONE_MAGENTA (PANTONE_NONE + 2) +#define PANTONE_YELLOW (PANTONE_NONE + 3) +#define PANTONE_BLACK (PANTONE_NONE + 4) + +/* Compare two names */ +#define compare_names(name1, name_size1, name2, name_size2) \ + (name_size1 == name_size2 && \ + (memcmp((const char *)name1, (const char *)name2, name_size1) == 0)) + +/* + * Define a structure for holding our client specific data. In our demo, + * we are only supporting Separation and DeviceN color spaces. To make + * life simpler, we are using the same data structure for both types + * of color spaces. + */ +typedef struct demo_color_space_data_s { + /* + * All client color space data blocks must begin with a routine for + * handling the reference counts for the data block. + */ + cs_proc_adjust_client_cspace_count((*client_adjust_cspace_count)); + + /* Use a reference count for knowing when to release the data block. */ + int ref_count; + + /* A flag which indicates the client wants to process the color space. */ + bool client_is_going_to_handle_color_space; + + /* + * We store an index into our Pantone color translation table for each + * colorant in the color space. + */ + int color_index[GS_CLIENT_COLOR_MAX_COMPONENTS]; +} demo_color_space_data_t; + +/* + * Dummy install routine for color spaces which are not handled by the client. + */ +private bool +client_install_no_op(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs) +{ + return false; /* Do nothing */ +} + +/* + * Dummy convert routine for simple color spaces (gray, RGB, CMYK, DeviceN, + * and Separation) which are not handled by the client. + */ +private int +client_remap_simple_no_op(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + /* + * Returning an error value will cause GS to use its normal processes + * for handling the color space. + */ + return_error(gs_error_rangecheck); +} + +/* + * Dummy convert routine for complex color spaces (CIEBasedA, CIEBasedABC, + * CIEBasedDEF, CIEBasedDEF, CIEBasedDEFG, ICCBased) which are not handled + * by the client. + */ +private int +client_remap_complex_no_op(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + /* + * Returning an error value will cause GS to use its normal processes + * for handling the color space. + */ + return_error(gs_error_rangecheck); +} + +/* + * Since this is an example for a client, we are using the system + * malloc and free routines instead of the normal GS memory management + * routines. + */ +private void +client_adjust_cspace_count(const gs_color_space * pcs, int delta) +{ + demo_color_space_data_t * pdata = + (demo_color_space_data_t *)(pcs->pclient_color_space_data); + + pdata->ref_count += delta; + if (pdata->ref_count <= 0) + free(pdata); +} + +/* + * Allocate a data block for holding our data for the client specific + * data for a color space. In our demo, we are only supporting the + * Separation and DeviceN color spaces. We use a single data structure + * to make the code simpler. + */ +private demo_color_space_data_t * +allocate_client_data_block(int initial_ref_count) +{ + /* + * Since this is an example for a client, we are using the system + * malloc routine instead of the GS memory management routines. + * As a result, the client is responsible for freeing the data + * block. For this purpose, we are using a simple reference count. + * See client_adjust_cspace_count. + */ + demo_color_space_data_t * pdata = + (demo_color_space_data_t *)malloc(size_of(demo_color_space_data_t)); + + if (pdata != NULL) { + pdata->ref_count = 1; + + /* + * All client color space data blocks must have a pointer to a + * reference count adjust routine as their first field. + */ + pdata->client_adjust_cspace_count = client_adjust_cspace_count; + + } + + return pdata; +} + +private bool +client_install_generic(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs) +{ + demo_color_space_data_t * pclient_data; + + /* Exit if we have already installed this color space. */ + if (pcs->pclient_color_space_data != NULL) + return true; + + pclient_data = allocate_client_data_block(1); + pcs->pclient_color_space_data = (client_color_space_data_t *) pclient_data; + if (pclient_data) + { + pclient_data->client_is_going_to_handle_color_space = 1; + return true; + } + return false; +} + +/* + * Check if we want to use the PANTONE color processing logic for the given + * Separation color space. + */ +private bool +client_pantone_install_Separation(client_custom_color_params_t * pparam, + gs_color_space * pcs, gs_state * pgs) +{ + const gs_separation_name name = pcs->params.separation.sep_name; + int pan_index; + byte * pname; + uint name_size; + gx_device * dev = pgs->device; + int num_pantone_colors = count_of(pantone_list); + bool use_custom_color_callback = false; + + /* Exit if we have already installed this color space. */ + if (pcs->pclient_color_space_data != NULL) + return true; + + /* + * Get the character string and length for the component name. + */ + pcs->params.separation.get_colorname_string(dev->memory, name, + &pname, &name_size); + /* + * Compare the colorant name to those in our PANTONE color list. + */ + for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) { + const char * pan_name = pantone_list[pan_index].name; + + if (compare_names(pname, name_size, pan_name, strlen(pan_name))) { + use_custom_color_callback = true; + break; + } + } + + if (use_custom_color_callback) { + demo_color_space_data_t * pclient_data = allocate_client_data_block(1); + + if (pclient_data == NULL) + return false; + pclient_data->color_index[0] = pan_index; + pcs->pclient_color_space_data = + (client_color_space_data_t *) pclient_data; + } + return use_custom_color_callback; +} + +/* + * Check if we want to use the PANTONE color processing logic for the given + * DeviceN color space. + */ +private bool +client_pantone_install_DeviceN(client_custom_color_params_t * pparam, + gs_color_space * pcs, gs_state * pgs) +{ + const gs_separation_name *names = pcs->params.device_n.names; + int num_comp = pcs->params.device_n.num_components; + int i; + int pan_index; + byte * pname; + uint name_size; + gx_device * dev = pgs->device; + int num_pantone_colors = count_of(pantone_list); + bool pantone_found = false; + bool other_separation_found = false; + bool use_pantone; + const char none_str[] = "None"; + const uint none_size = strlen(none_str); + const char cyan_str[] = "Cyan"; + const uint cyan_size = strlen(cyan_str); + const char magenta_str[] = "Magenta"; + const uint magenta_size = strlen(magenta_str); + const char yellow_str[] = "Yellow"; + const uint yellow_size = strlen(yellow_str); + const char black_str[] = "Black"; + const uint black_size = strlen(black_str); + int pantone_color_index[GS_CLIENT_COLOR_MAX_COMPONENTS]; + + /* Exit if we have already installed this color space. */ + if (pcs->pclient_color_space_data != NULL) + return true; + + /* + * Now check the names of the color components. + */ + for(i = 0; i < num_comp; i++ ) { + bool match = false; + + /* + * Get the character string and length for the component name. + */ + pcs->params.device_n.get_colorname_string(dev->memory, names[i], + &pname, &name_size); + /* + * Postscript does not include /None as a color component but it is + * allowed in PDF so we accept it. We simply skip components named + * 'None'. + */ + if (compare_names(none_str, none_size, pname, name_size)) { + pantone_color_index[i] = PANTONE_NONE; + continue; + } + /* + * Check if our color space includes the CMYK process colors. + */ + if (compare_names(cyan_str, cyan_size, pname, name_size)) { + pantone_color_index[i] = PANTONE_CYAN; + continue; + } + if (compare_names(magenta_str, magenta_size, pname, name_size)) { + pantone_color_index[i] = PANTONE_MAGENTA; + continue; + } + if (compare_names(yellow_str, yellow_size, pname, name_size)) { + pantone_color_index[i] = PANTONE_YELLOW; + continue; + } + if (compare_names(black_str, black_size, pname, name_size)) { + pantone_color_index[i] = PANTONE_BLACK; + continue; + } + /* + * Compare the colorant name to those in our Pantone color list. + */ + for (pan_index = 0; pan_index < num_pantone_colors ; pan_index++) { + const char * pan_name = pantone_list[pan_index].name; + + if (compare_names(pname, name_size, pan_name, strlen(pan_name))) { + pantone_color_index[i] = pan_index; + match = pantone_found = true; + break; + } + } + if (!match) { /* Exit if we find a non Pantone color */ + other_separation_found = true; + break; + } + } + /* + * Handle this color space as a 'pantone color space' if we have only + * PANTONE colors and CMYK. Any other separations will force us to + * use the normal Ghostscript processing for a DeviceN color space. + */ + use_pantone = pantone_found && !other_separation_found; + if (use_pantone) { + demo_color_space_data_t * pclient_data = allocate_client_data_block(1); + + if (pclient_data == NULL) + return false; + for(i = 0; i < num_comp; i++ ) + pclient_data->color_index[i] = pantone_color_index[i]; + pcs->pclient_color_space_data = + (client_color_space_data_t *) pclient_data; + } + return use_pantone; +} + + +/* + * Convert a set of color values in a 'PANTONE color space' into a device + * color values. + * + * This routine creates an equivalent CMYK color and then uses + * gx_remap_concrete_cmyk to convert this into device colorants. Note: It + * is possible to go directy to the output device colorants. However the + * pantone_install_xxx routines should verify that the expected device + * colorants match the actual device colorants. (For instance, Ghostscript + * can install temporary compositing devices for functions like handling + * PDF 1.4 transparency. The compositing devices may have a process color + * models which differ from the final output device.) + */ +private int +client_pantone_remap_color(client_custom_color_params_t * pparam, + const frac * pconc, const demo_color_space_data_t * pparams, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select, int num_comp) +{ + int i, pantone_index, cvalue; + int cyan = 0; + int magenta = 0; + int yellow = 0; + int black = 0; + frac cc, cm, cy, ck; + const pantone_list_t * plist; + + /* + * If the client color space data pointer is NULL then we are not processing + * this color space. The rangecheck error will indicate that GS should do + * its normal color space processing. + */ + if (pparams == NULL) + return_error(gs_error_rangecheck); + + /* + * Create a CMYK representation of the various colors in our color space. + * Note: If we have multiple components, then we do a simple sum of the + * CMYK equivalent for each color. If desired, a more complex handling is + * left to the user. + */ + for (i = 0; i < num_comp; i++) { + cvalue = pconc[i]; + pantone_index = pparams->color_index[i]; + switch (pantone_index) { + case PANTONE_NONE: + break; + case PANTONE_CYAN: + cyan += cvalue; + break; + case PANTONE_MAGENTA: + magenta += cvalue; + break; + case PANTONE_YELLOW: + yellow += cvalue; + break; + case PANTONE_BLACK: + black += cvalue; + break; + default: + plist = &(pantone_list[pantone_index]); + cyan += (int) floor(cvalue * plist->c); + magenta += (int) floor(cvalue * plist->m); + yellow += (int) floor(cvalue * plist->y); + black += (int) floor(cvalue * plist->k); + break; + } + } + /* Clamp our color values */ + cc = (cyan > frac_1) ? frac_1 : (cyan < frac_0) ? frac_0 : cyan; + cm = (magenta > frac_1) ? frac_1 : (magenta < frac_0) ? frac_0 : magenta; + cy = (yellow > frac_1) ? frac_1 : (yellow < frac_0) ? frac_0 : yellow; + ck = (black > frac_1) ? frac_1 : (black < frac_0) ? frac_0 : black; + gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pis, dev, select); + return 0; +} + +/* + * Convert a Separation color (with PANTONE colorants) into device color. + */ +private int +client_pantone_remap_Separation(client_custom_color_params_t * pparam, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + return client_pantone_remap_color(pparam, pconc, + (demo_color_space_data_t *)(pcs->pclient_color_space_data), + pdc, pis, dev, select, 1); +} + +/* + * Convert a DeviceN color (with PANTONE colorants) into device color. + */ +private int +client_pantone_remap_DeviceN(client_custom_color_params_t * pparam, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + return client_pantone_remap_color(pparam, pconc, + (demo_color_space_data_t *)(pcs->pclient_color_space_data), + pdc, pis, dev, select, gs_color_space_num_components(pcs)); +} + +#if OBJECT_TYPE_EXAMPLE +/* + * Install a DeviceGray color space. + */ +private bool +client_install_DeviceGray(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs) +{ + /* Nothing to do in our demo */ + return true; +} + +/* + * For demo and debug purposes, make our colors a function of the + * intensity of the given colors and the object type. + */ +private int +convert_intensity_into_device_color(const frac intensity, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac cc, cm, cy, ck; + + switch (pis->object_tag) { + case GS_TEXT_TAG: /* Make text red. */ + cc = ck = 0; + cm = cy = frac_1 - intensity; + break; + case GS_IMAGE_TAG: /* Make images green. */ + cm = ck = 0; + cc = cy = frac_1 - intensity; + break; + case GS_PATH_TAG: /* Make lines and fills blue. */ + default: + cy = ck = 0; + cc = cm = frac_1 - intensity; + break; + } + + /* Send CMYK colors to the device */ + gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pis, dev, select); + return 0; +} + +/* + * Convert a DeviceGray color into device color. + */ +private int +client_remap_DeviceGray(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given colors and the object type. + */ + frac intensity = pconc[0]; + + convert_intensity_into_device_color(intensity, pdc, pis, dev, select); + return 0; +} + +/* + * Install a DeviceRGB color space. + */ +private bool +client_install_DeviceRGB(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs) +{ + /* Nothing to do in our demo */ + dlprintf1("client_install_DeviceRGB ri = %d\n", pgs->renderingintent); + return true; +} + +/* + * Convert a DeviceRGB color into device color. + */ +private int +client_remap_DeviceRGB(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given colors and the object type. + */ + frac intensity = (frac)(pconc[0] * 0.30 + pconc[1] * 0.59 + pconc[2] * 0.11); + + convert_intensity_into_device_color(intensity, pdc, pis, dev, select); + return 0; +} + +/* + * Install a DeviceCMYK color space. + */ +private bool +client_install_DeviceCMYK(client_custom_color_params_t * pparams, + gs_color_space * pcs, gs_state * pgs) +{ + /* Nothing to do in our demo */ + return true; +} + +/* + * Convert a DeviceGray color into device color. + */ +private int +client_remap_DeviceCMYK(client_custom_color_params_t * pparams, + const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, + const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) +{ + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given colors and the object type. + */ + frac intensity = frac_1 - (frac)(pconc[0] * 0.30 + pconc[1] * 0.59 + + pconc[2] * 0.11 + pconc[3]); + + if (intensity < frac_0) + intensity = frac_0; + convert_intensity_into_device_color(intensity, pdc, pis, dev, select); + return 0; +} + +/* + * Convert a floating point color value into a fixed (frac) color value + * given a specified floating point range. + */ +#define convert2frac(color, range) \ + (color <= range.rmin) ? frac_0 \ + : (color >= range.rmax) ? frac_1 \ + : (frac) (frac_1 * \ + (color - range.rmin) / (range.rmax - range.rmin)) + +/* + * Convert a CIEBasedA color into device color. + */ +private int +client_remap_CIEBasedA(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac gray = convert2frac(pc->paint.values[0], pcs->params.a->RangeA); + + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given color value and the object type. + */ + return client_remap_DeviceGray(pparams, &gray, pcs, pdc, pis, dev, select); +} + +/* + * Convert a CIEBasedABC color into device color. + */ +private int +client_remap_CIEBasedABC(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac rgb[3]; + int i; + + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given color value and the object type. The color + * values could represent almost anything. However we are assuming + * that they are RGB values. + */ + for (i = 0; i < 3; i++) + rgb[i] = convert2frac(pc->paint.values[i], + pcs->params.abc->RangeABC.ranges[i]); + return client_remap_DeviceRGB(pparams, rgb, pcs, pdc, pis, dev, select); +} + +/* + * Convert a CIEBasedDEF color into device color. + */ +private int +client_remap_CIEBasedDEF(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac rgb[3]; + int i; + + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given color value and the object type. The color + * values could represent almost anything. However we are assuming + * that they are RGB values. + */ + for (i = 0; i < 3; i++) + rgb[i] = convert2frac(pc->paint.values[i], + pcs->params.def->RangeDEF.ranges[i]); + return client_remap_DeviceRGB(pparams, rgb, pcs, pdc, pis, dev, select); +} + +/* + * Convert a CIEBasedDEFG color into device color. + */ +private int +client_remap_CIEBasedDEFG(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac cmyk[4]; + int i; + + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given color value and the object type. The color + * values could represent almost anything. However we are assuming + * that they are CMYK values. + */ + for (i = 0; i < 4; i++) + cmyk[i] = convert2frac(pc->paint.values[i], + pcs->params.defg->RangeDEFG.ranges[i]); + return client_remap_DeviceRGB(pparams, cmyk, pcs, pdc, pis, dev, select); +} + +/* + * Convert a ICCBased color into device color. + */ +private int +client_remap_ICCBased(client_custom_color_params_t * pparams, + const gs_client_color * pc, const gs_color_space * pcs, + gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, + gs_color_select_t select) +{ + frac frac_color[GS_CLIENT_COLOR_MAX_COMPONENTS]; + int i, num_values = pcs->params.icc.picc_info->num_components; + + /* + * For demo and debug purposes, make our colors a function of the + * intensity of the given color value and the object type. The color + * values could represent almost anything. However based upon the + * number of color values, we are assuming that they are either + * gray, RGB, or CMYK values. + */ + for (i = 0; i < num_values; i++) + frac_color[i] = convert2frac(pc->paint.values[i], + pcs->params.icc.picc_info->Range.ranges[i]); + switch (num_values) { + case 0: + case 2: + return_error(e_rangecheck); + case 1: + return client_remap_DeviceGray(pparams, frac_color, pcs, + pdc, pis, dev, select); + case 3: + return client_remap_DeviceRGB(pparams, frac_color, pcs, + pdc, pis, dev, select); + case 4: + default: + return client_remap_DeviceCMYK(pparams, frac_color, pcs, + pdc, pis, dev, select); + } +} + +#undef convert2frac + +#endif /* OBJECT_TYPE_EXAMPLE */ + +#if OBJECT_TYPE_EXAMPLE +/* + * Client call back procedures for our demo which illustrates color + * processing based upon object type. + */ +client_custom_color_procs_t demo_procs = { + client_install_DeviceGray, /* DeviceGray */ + client_remap_DeviceGray, + client_install_DeviceRGB, /* DeviceRGB */ + client_remap_DeviceRGB, + client_install_DeviceCMYK, /* DeviceCMYK */ + client_remap_DeviceCMYK, + client_pantone_install_Separation, /* Separation */ + client_pantone_remap_Separation, + client_pantone_install_DeviceN, /* DeviceN */ + client_pantone_remap_DeviceN, + client_install_generic, /* CIEBasedA */ + client_remap_CIEBasedA, + client_install_generic, /* CIEBasedABC */ + client_remap_CIEBasedABC, + client_install_generic, /* CIEBasedDEF */ + client_remap_CIEBasedDEF, + client_install_generic, /* CIEBasedDEFG */ + client_remap_CIEBasedDEFG, + client_install_generic, /* ICCBased */ + client_remap_ICCBased +}; +#else /* Not OBJECT_TYPE_EXAMPLE special */ +/* + * For PANTONE colors, we only need to handle Separation and DeviceN + * color spaces. These are the only color spaces that can have PANTONE + * colors. + */ +client_custom_color_procs_t demo_procs = { + client_install_no_op, /* DeviceGray */ + client_remap_simple_no_op, + client_install_no_op, /* DeviceRGB */ + client_remap_simple_no_op, + client_install_no_op, /* DeviceCMYK */ + client_remap_simple_no_op, + client_pantone_install_Separation, /* Separation */ + client_pantone_remap_Separation, + client_pantone_install_DeviceN, /* DeviceN */ + client_pantone_remap_DeviceN, + client_install_no_op, /* CIEBasedA */ + client_remap_complex_no_op, + client_install_no_op, /* CIEBasedABC */ + client_remap_complex_no_op, + client_install_no_op, /* CIEBasedDEF */ + client_remap_complex_no_op, + client_install_no_op, /* CIEBasedDEFG */ + client_remap_complex_no_op, + client_install_no_op, /* ICCBased */ + client_remap_complex_no_op +}; +#endif /* OBJECT_TYPE_EXAMPLE */ + +/* + * Demo version of the PANTONE call back parameter structure. + */ +client_custom_color_params_t demo_callback = { + &demo_procs, + /* + * Use our 'list' of Pantone colors as an example data. + */ + (void *)(&pantone_list) +}; +#endif /* ENABLE_CUSTOM_COLOR_CALLBACK */ + +/* + * This procedure is here to simplify debugging. Normally one would expect the + * custom color callback structure to be set up by a calling application. + * Since I do not have a calling application, I need a simple way to setup the + * callback parameter. The callback parameter is passed as a string value. + * This routine puts the address of our demo callback structure into the + * provided string. + * + * This routine allows the demo version of the PANTONE logic to be enabled + * by adding the following to the command line: + * -c "<< /CustomColorCallback 32 string .pantonecallback >> setsystemparams" -f + */ + +/* <string> .pantonecallback <string> */ +private int +zpantonecallback(i_ctx_t *i_ctx_p) +{ +#if ENABLE_CUSTOM_COLOR_CALLBACK + os_ptr op = osp; + int val, idx, buf_pos = 3; + size_t iptr; +#define PTR_STRING_SIZE (2 * size_of(void *) + 3) + + /* Verify that the string size is big enough for our output */ + check_type(*op, t_string); + check_write(*op); + if (r_size(op) < PTR_STRING_SIZE) + return_error(e_rangecheck); + + /* Convert our call back parameter structure pointer into a string */ + op->value.bytes[0] = '1'; + op->value.bytes[1] = '6'; + op->value.bytes[2] = '#'; + iptr = (size_t)(&demo_callback); + for (idx = ((int)size_of(size_t)) * 8 - 4; idx >= 0; idx -= 4) { + val = (int)(iptr >> idx) & 0xf; + op->value.bytes[buf_pos++] = (byte)((val <= 9) ? '0' + val + : 'a' - 10 + val); + } + r_size(op) = PTR_STRING_SIZE; +#endif /* ENABLE_CUSTOM_COLOR_CALLBACK */ + return 0; +} + +/* ------ Initialization procedure ------ */ + +const op_def pantone_op_defs[] = +{ + {"1.pantonecallback", zpantonecallback}, + op_def_end(0) +}; + diff --git a/gs/src/gspaint.c b/gs/src/gspaint.c index 3d66d8dac..b9e2e7b7f 100644 --- a/gs/src/gspaint.c +++ b/gs/src/gspaint.c @@ -72,6 +72,9 @@ gs_fillpage(gs_state * pgs) gs_logical_operation_t save_lop; bool hl_color_available; + /* Processing a fill object operation */ + gs_set_object_tag(pgs, GS_PATH_TAG); + gx_set_dev_color(pgs); hl_color_available = gx_hld_is_hl_color_available((gs_imager_state *)pgs, pgs->dev_color); @@ -365,7 +368,8 @@ gs_stroke(gs_state * pgs) } code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path, pgs->in_charpath); - } if (gs_is_null_device(pgs->device)) { + } + if (gs_is_null_device(pgs->device)) { /* Handle separately to prevent gs_state_color_load. */ gs_newpath(pgs); code = 0; @@ -380,6 +384,38 @@ gs_stroke(gs_state * pgs) else gs_set_object_tag(pgs, GS_TEXT_TAG); + /* Here we need to distinguish text from vectors to compute the object tag. + Actually we need to know whether this function is called to rasterize a character, + or to rasterize a vector graphics to the output device. + Currently we assume it works for the bitrgbtags device only, + which is a low level device with a 4-component color model. + We use the fact that with printers a character is usually being rendered + to a 1bpp cache device rather than to the output device. + Therefore we hackly look whether the target device + "has a color" : either it's a multicomponent color model, + or it is not gray (such as a yellow separation). + + This check has several limitations : + 1. It doesn't work with -dNOCACHE. + 2. It doesn't work with large characters, + which cannot fit into a cache cell and thus they + render directly to the output device. + 3. It doesn't work for TextAlphaBits=2 or 4. + We don't care of this case because + text antialiasing usually usn't applied to printers. + 4. It doesn't work for things like with "(xyz) true charpath stroke". + That's unfortunate, we'd like to improve someday. + 5. It doesn't work for high level devices when a Type 3 character is being constructed. + This case is not important for low level devices + (which a printer is), because low level device doesn't accept + Type 3 charproc streams immediately. + */ + if (gx_device_has_color(gs_currentdevice(pgs))) { + gs_set_object_tag(pgs, GS_PATH_TAG); + } + else { + gs_set_object_tag(pgs, GS_TEXT_TAG); + } gx_set_dev_color(pgs); code = gs_state_color_load(pgs); if (code < 0) diff --git a/gs/src/gsstate.c b/gs/src/gsstate.c index 72ad3ff0b..022340863 100644 --- a/gs/src/gsstate.c +++ b/gs/src/gsstate.c @@ -699,6 +699,21 @@ gs_currentoverprintmode(const gs_state * pgs) return pgs->overprint_mode; } +/* setrenderingintent */ +int +gs_setrenderingintent(gs_state *pgs, int ri) { + if (ri < 0 || ri > 3) + return_error(gs_error_rangecheck); + pgs->renderingintent = ri; + return 0; +} + +/* currentrenderingintent */ +int +gs_currentrenderingintent(const gs_state * pgs) +{ + return pgs->renderingintent; +} /* * Reset most of the graphics state. diff --git a/gs/src/gsstate.h b/gs/src/gsstate.h index 3315d53bb..e6c5a0255 100644 --- a/gs/src/gsstate.h +++ b/gs/src/gsstate.h @@ -52,6 +52,9 @@ int gs_setoverprintmode(gs_state *, int); int gs_do_set_overprint(gs_state *); +int gs_currentrenderingintent(const gs_state *); +int gs_setrenderingintent(gs_state *, int); + int gs_initgraphics(gs_state *); /* Device control */ diff --git a/gs/src/gstext.c b/gs/src/gstext.c index ec9dc0c67..7d3adb6b1 100644 --- a/gs/src/gstext.c +++ b/gs/src/gstext.c @@ -256,6 +256,9 @@ gs_text_begin(gs_state * pgs, const gs_text_params_t * text, of a Type 3 font while stringwidth. Unfortunately we can't effectively know a leaf font type here, so we load the color unconditionally . */ + /* Processing a text object operation */ + gs_set_object_tag(pgs, GS_TEXT_TAG); + gx_set_dev_color(pgs); code = gs_state_color_load(pgs); if (code < 0) @@ -280,6 +283,9 @@ gs_text_update_dev_color(gs_state * pgs, gs_text_enum_t * pte) * update of the graphic state color will update the text color as * well. */ + /* Processing a text object operation */ + gs_set_object_tag(pgs, GS_TEXT_TAG); + if (pte->pdcolor != 0) gx_set_dev_color(pgs); return 0; diff --git a/gs/src/gstrans.c b/gs/src/gstrans.c index 865e4956b..6cf10ef21 100644 --- a/gs/src/gstrans.c +++ b/gs/src/gstrans.c @@ -21,6 +21,8 @@ #include "gsutil.h" #include "gzstate.h" #include "gxdevcli.h" +#include "gdevdevn.h" +#include "gxblend.h" #include "gdevp14.h" #define PUSH_TS 0 @@ -429,12 +431,45 @@ gx_init_transparency_mask(gs_imager_state * pis, 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. + */ +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; /* Other parameters not used */ + 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); } diff --git a/gs/src/gstrans.h b/gs/src/gstrans.h index 1d09a77ca..0ee2bba4f 100644 --- a/gs/src/gstrans.h +++ b/gs/src/gstrans.h @@ -65,6 +65,7 @@ typedef struct gs_transparency_source_s { struct gs_pdf14trans_params_s { /* The type of trasnparency operation */ pdf14_compositor_operations pdf14_op; + int num_spot_colors; /* Only for devices which support spot colors. */ /* Changed parameters flag */ int changed; /* Parameters from the gs_transparency_group_params_t structure */ @@ -90,7 +91,10 @@ struct gs_pdf14trans_params_s { bool mask_is_image; }; +#ifndef gs_pdf14trans_params_DEFINED +#define gs_pdf14trans_params_DEFINED typedef struct gs_pdf14trans_params_s gs_pdf14trans_params_t; +#endif /* * The PDF 1.4 transparency compositor structure. This is exactly analogous to diff --git a/gs/src/gsutil.c b/gs/src/gsutil.c index 3c807472c..614ca29d1 100644 --- a/gs/src/gsutil.c +++ b/gs/src/gsutil.c @@ -297,21 +297,21 @@ gs_enable_object_tagging() BITTAG = GS_UNKNOWN_TAG; } - void gs_set_object_tag(gs_state * pgs, const gs_object_tag_type_t tag) { if (BITTAG != GS_DEVICE_DOESNT_SUPPORT_TAGS) { - if ( BITTAG != tag ) { - /* mkromfs breaks this dependance - NB: needs to be fixed. - gx_unset_dev_color(pgs); - **/ - BITTAG = tag; - /* the assumption is made that the caller will: - * gx_set_dev_color(pgs); - */ - } + if ( pgs->object_tag != tag ) { + pgs->object_tag = tag; + /* mkromfs breaks this dependance + NB: needs to be fixed. + gx_unset_dev_color(pgs); + **/ + BITTAG = tag; + /* the assumption is made that the caller will: + * gx_set_dev_color(pgs); + */ + } } } diff --git a/gs/src/gxblend.c b/gs/src/gxblend.c index f546d1b5c..d58f5e5fa 100644 --- a/gs/src/gxblend.c +++ b/gs/src/gxblend.c @@ -16,12 +16,13 @@ #include "memory_.h" #include "gx.h" #include "gstparam.h" +#include "gxcindex.h" #include "gxblend.h" typedef int art_s32; -static void -art_blend_luminosity_rgb_8(byte *dst, const byte *backdrop, +void +art_blend_luminosity_rgb_8(int n_chan, byte *dst, const byte *backdrop, const byte *src) { int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2]; @@ -64,6 +65,59 @@ art_blend_luminosity_rgb_8(byte *dst, const byte *backdrop, dst[2] = b; } +void +art_blend_luminosity_custom_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src) +{ + int delta_y = 0, test = 0; + int r[ART_MAX_CHAN]; + int i; + + /* + * Since we do not know the details of the blending color space, we are + * simply using the average as the luminosity. First we need the + * delta luminosity values. + */ + for (i = 0; i < n_chan; i++) + delta_y += src[i] - backdrop[i]; + delta_y = (delta_y + n_chan / 2) / n_chan; + for (i = 0; i < n_chan; i++) { + r[i] = backdrop[i] + delta_y; + test |= r[i]; + } + + if (test & 0x100) { + int y; + int scale; + + /* Assume that the luminosity is simply the average of the backdrop. */ + y = src[0]; + for (i = 1; i < n_chan; i++) + y += src[i]; + y = (y + n_chan / 2) / n_chan; + + if (delta_y > 0) { + int max; + + max = r[0]; + for (i = 1; i < n_chan; i++) + max = max(max, r[i]); + scale = ((255 - y) << 16) / (max - y); + } else { + int min; + + min = r[0]; + for (i = 1; i < n_chan; i++) + min = min(min, r[i]); + scale = (y << 16) / (y - min); + } + for (i = 0; i < n_chan; i++) + r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16); + } + for (i = 0; i < n_chan; i++) + dst[i] = r[i]; +} + /* * The PDF 1.4 spec. does not give the details of the math involved in the * luminosity blending. All we are given is: @@ -83,17 +137,20 @@ art_blend_luminosity_rgb_8(byte *dst, const byte *backdrop, * * Our component values have already been complemented, i.e. (1 - X). */ -static void -art_blend_luminosity_cmyk_8(byte *dst, const byte *backdrop, +void +art_blend_luminosity_cmyk_8(int n_chan, byte *dst, const byte *backdrop, const byte *src) { + int i; + /* Treat CMY the same as RGB. */ - art_blend_luminosity_rgb_8(dst, backdrop, src); - dst[3] = src[3]; + art_blend_luminosity_rgb_8(3, dst, backdrop, src); + for (i = 3; i < n_chan; i++) + dst[i] = src[i]; } -static void -art_blend_saturation_rgb_8(byte *dst, const byte *backdrop, +void +art_blend_saturation_rgb_8(int n_chan, byte *dst, const byte *backdrop, const byte *src) { int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2]; @@ -157,14 +214,97 @@ art_blend_saturation_rgb_8(byte *dst, const byte *backdrop, dst[2] = b; } +void +art_blend_saturation_custom_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src) +{ + int minb, maxb; + int mins, maxs; + int y; + int scale; + int r[ART_MAX_CHAN]; + int test = 0; + int temp, i; + + /* Determine min and max of the backdrop */ + minb = maxb = temp = backdrop[0]; + for (i = 1; i < n_chan; i++) { + temp = backdrop[i]; + minb = min(minb, temp); + maxb = max(maxb, temp); + } + + if (minb == maxb) { + /* backdrop has zero saturation, avoid divide by 0 */ + for (i = 0; i < n_chan; i++) + dst[i] = temp; + return; + } + + /* Determine min and max of the source */ + mins = maxs = src[0]; + for (i = 1; i < n_chan; i++) { + temp = src[i]; + mins = min(minb, temp); + maxs = max(minb, temp); + } + + scale = ((maxs - mins) << 16) / (maxb - minb); + + /* Assume that the saturation is simply the average of the backdrop. */ + y = backdrop[0]; + for (i = 1; i < n_chan; i++) + y += backdrop[i]; + y = (y + n_chan / 2) / n_chan; + + /* Calculate the saturated values */ + for (i = 0; i < n_chan; i++) { + r[i] = y + ((((backdrop[i] - y) * scale) + 0x8000) >> 16); + test |= r[i]; + } + + if (test & 0x100) { + int scalemin, scalemax; + int min, max; + + /* Determine min and max of our blended values */ + min = max = temp = r[0]; + for (i = 1; i < n_chan; i++) { + temp = src[i]; + min = min(min, temp); + max = max(max, temp); + } + + if (min < 0) + scalemin = (y << 16) / (y - min); + else + scalemin = 0x10000; + + if (max > 255) + scalemax = ((255 - y) << 16) / (max - y); + else + scalemax = 0x10000; + + scale = scalemin < scalemax ? scalemin : scalemax; + for (i = 0; i < n_chan; i++) + r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16); + } + + for (i = 0; i < n_chan; i++) + dst[i] = r[i]; +} + /* Our component values have already been complemented, i.e. (1 - X). */ -static void -art_blend_saturation_cmyk_8(byte *dst, const byte *backdrop, +void +art_blend_saturation_cmyk_8(int n_chan, byte *dst, const byte *backdrop, const byte *src) { + int i; + /* Treat CMY the same as RGB */ - art_blend_saturation_rgb_8(dst, backdrop, src); - dst[3] = backdrop[3]; + art_blend_saturation_rgb_8(3, dst, backdrop, src); + for (i = 3; i < n_chan; i++) + dst[i] = backdrop[i]; } /* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 + @@ -231,7 +371,8 @@ const byte art_blend_soft_light_8[256] = { void art_blend_pixel_8(byte *dst, const byte *backdrop, - const byte *src, int n_chan, gs_blend_mode_t blend_mode) + const byte *src, int n_chan, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { int i; byte b, s; @@ -364,73 +505,20 @@ art_blend_pixel_8(byte *dst, const byte *backdrop, } break; case BLEND_MODE_Luminosity: - switch (n_chan) { - case 1: /* DeviceGray */ - dlprintf( - "art_blend_pixel_8: DeviceGray luminosity blend mode not implemented\n"); - break; - case 3: /* DeviceRGB */ - art_blend_luminosity_rgb_8(dst, backdrop, src); - break; - case 4: /* DeviceCMYK */ - art_blend_luminosity_cmyk_8(dst, backdrop, src); - break; - default: /* Should not happen */ - break; - } + pblend_procs->blend_luminosity(n_chan, dst, backdrop, src); break; case BLEND_MODE_Color: - switch (n_chan) { - case 1: /* DeviceGray */ - dlprintf( - "art_blend_pixel_8: DeviceGray color blend mode not implemented\n"); - break; - case 3: /* DeviceRGB */ - art_blend_luminosity_rgb_8(dst, src, backdrop); - break; - case 4: /* DeviceCMYK */ - art_blend_luminosity_cmyk_8(dst, src, backdrop); - break; - default: /* Should not happen */ - break; - } + pblend_procs->blend_luminosity(n_chan, dst, src, backdrop); break; case BLEND_MODE_Saturation: - switch (n_chan) { - case 1: /* DeviceGray */ - dlprintf( - "art_blend_pixel_8: DeviceGray saturation blend mode not implemented\n"); - break; - case 3: /* DeviceRGB */ - art_blend_saturation_rgb_8(dst, backdrop, src); - break; - case 4: /* DeviceCMYK */ - art_blend_saturation_cmyk_8(dst, backdrop, src); - break; - default: /* Should not happen */ - break; - } + pblend_procs->blend_saturation(n_chan, dst, backdrop, src); break; case BLEND_MODE_Hue: { byte tmp[4]; - switch (n_chan) { - case 1: /* DeviceGray */ - dlprintf( - "art_blend_pixel_8: DeviceGray hue blend mode not implemented\n"); - break; - case 3: /* DeviceRGB */ - art_blend_luminosity_rgb_8(tmp, src, backdrop); - art_blend_saturation_rgb_8(dst, tmp, backdrop); - break; - case 4: /* DeviceCMYK */ - art_blend_luminosity_cmyk_8(tmp, src, backdrop); - art_blend_saturation_cmyk_8(dst, tmp, backdrop); - break; - default: /* Should not happen */ - break; - } + pblend_procs->blend_luminosity(n_chan, tmp, src, backdrop); + pblend_procs->blend_saturation(n_chan, dst, tmp, backdrop); } break; default: @@ -592,7 +680,8 @@ art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask) void art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan, - gs_blend_mode_t blend_mode) + gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { byte a_b, a_s; unsigned int a_r; @@ -642,7 +731,7 @@ art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan, /* Do compositing with blending */ byte blend[ART_MAX_CHAN]; - art_blend_pixel_8(blend, dst, src, n_chan, blend_mode); + art_blend_pixel_8(blend, dst, src, n_chan, blend_mode, pblend_procs); for (i = 0; i < n_chan; i++) { int c_bl; /* Result of blend function */ int c_mix; /* Blend result mixed with source color */ @@ -739,7 +828,7 @@ art_pdf_composite_pixel_knockout_8(byte *dst, /* Do compositing with blending */ byte blend[ART_MAX_CHAN]; - art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode); + art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode, pblend_procs); for (i = 0; i < n_chan; i++) { int c_bl; /* Result of blend function */ int c_mix; /* Blend result mixed with source color */ @@ -803,9 +892,9 @@ art_pdf_uncomposite_group_8(byte *dst, void art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g, - const byte *src, byte src_alpha_g, - int n_chan, - byte alpha, gs_blend_mode_t blend_mode) + const byte *src, byte src_alpha_g, int n_chan, + byte alpha, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { byte dst_alpha; int i; @@ -869,15 +958,16 @@ art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g, tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80; *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8); } - art_pdf_composite_pixel_alpha_8(dst, ca, n_chan, blend_mode); + art_pdf_composite_pixel_alpha_8(dst, ca, n_chan, + blend_mode, pblend_procs); } /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */ } void art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g, - const byte *src, - int n_chan, byte alpha, gs_blend_mode_t blend_mode) + const byte *src, int n_chan, byte alpha, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { byte src_alpha; /* $\alpha g_n$ */ byte src_tmp[ART_MAX_CHAN + 1]; @@ -885,7 +975,8 @@ art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g, int tmp; if (alpha == 255) { - art_pdf_composite_pixel_alpha_8(dst, src, n_chan, blend_mode); + art_pdf_composite_pixel_alpha_8(dst, src, n_chan, + blend_mode, pblend_procs); if (dst_alpha_g != NULL) { tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80; *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8); @@ -898,7 +989,8 @@ art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g, ((bits32 *) src_tmp)[i] = ((const bits32 *)src)[i]; tmp = src_alpha * alpha + 0x80; src_tmp[n_chan] = (tmp + (tmp >> 8)) >> 8; - art_pdf_composite_pixel_alpha_8(dst, src_tmp, n_chan, blend_mode); + art_pdf_composite_pixel_alpha_8(dst, src_tmp, n_chan, + blend_mode, pblend_procs); if (dst_alpha_g != NULL) { tmp = (255 - *dst_alpha_g) * (255 - src_tmp[n_chan]) + 0x80; *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8); @@ -1009,13 +1101,10 @@ art_pdf_composite_knockout_isolated_8(byte *dst, void art_pdf_composite_knockout_8(byte *dst, - byte *dst_alpha_g, - const byte *backdrop, - const byte *src, - int n_chan, - byte shape, - byte alpha_mask, - byte shape_mask, gs_blend_mode_t blend_mode) + byte *dst_alpha_g, const byte *backdrop, const byte *src, + int n_chan, byte shape, byte alpha_mask, + byte shape_mask, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs) { /* This implementation follows the Adobe spec pretty closely, rather than trying to do anything clever. For example, in the case of a @@ -1073,7 +1162,8 @@ art_pdf_composite_knockout_8(byte *dst, } else { byte blend[ART_MAX_CHAN]; - art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode); + art_blend_pixel_8(blend, backdrop, src, n_chan, + blend_mode, pblend_procs); for (i = 0; i < n_chan; i++) { int c_s; int c_b; diff --git a/gs/src/gxblend.h b/gs/src/gxblend.h index 11d068aa7..045de8a2e 100644 --- a/gs/src/gxblend.h +++ b/gs/src/gxblend.h @@ -18,7 +18,32 @@ typedef bits16 ArtPixMaxDepth; -#define ART_MAX_CHAN 16 +#define ART_MAX_CHAN GX_DEVICE_COLOR_MAX_COMPONENTS + +/* + * This structure contains procedures for processing which differ + * between the different blending color spaces. + * + * The Luminosity, Color, Saturation, and Hue blend modes depend + * upon the blending color space. Currently the blending color space + * matches the process color model of the compositing device. We need + * two routines to implement the four 'non separable' blend modes. + */ +typedef struct { + /* + * Perform luminosity and color blending. (Also used for hue blending.) + */ + void (* blend_luminosity)(int n_chan, byte *dst, + const byte *backdrop, const byte *src); + /* + * Perform saturation blending. (Also used for hue blending.) + */ + void (* blend_saturation)(int n_chan, byte *dst, + const byte *backdrop, const byte *src); +} pdf14_nonseparable_blending_procs_s; + +typedef pdf14_nonseparable_blending_procs_s + pdf14_nonseparable_blending_procs_t; /** * art_blend_pixel: Compute PDF 1.4 blending function. @@ -57,6 +82,7 @@ art_blend_pixel(ArtPixMaxDepth * dst, const ArtPixMaxDepth * backdrop, * @src: Source pixel color. * @n_chan: Number of channels. * @blend_mode: Blend mode. + * @pblend_procs: Procs for handling non separable blending modes. * * Computes the blend of two pixels according the PDF 1.4 transparency * spec (section 3.2, Blend Mode). A few things to keep in mind about @@ -77,7 +103,8 @@ art_blend_pixel(ArtPixMaxDepth * dst, const ArtPixMaxDepth * backdrop, **/ void art_blend_pixel_8(byte *dst, const byte *backdrop, - const byte *src, int n_chan, gs_blend_mode_t blend_mode); + const byte *src, int n_chan, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs); /** * art_pdf_union_8: Union together two alpha values. @@ -104,6 +131,7 @@ byte art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask); * @src: Source pixel color. * @n_chan: Number of channels. * @blend_mode: Blend mode. + * @pblend_procs: Procs for handling non separable blending modes. * * Composites two pixels using the basic compositing operation. A few * things to keep in mind: @@ -120,8 +148,8 @@ byte art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask); **/ void art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan, - - gs_blend_mode_t blend_mode); + gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs); /** * art_pdf_uncomposite_group_8: Uncomposite group pixel. @@ -146,6 +174,7 @@ art_pdf_uncomposite_group_8(byte *dst, * @alpha: Alpha mask value. * @src_alpha_g: alpha_g value associated with @src. * @blend_mode: Blend mode for compositing. + * @pblend_procs: Procs for handling non separable blending modes. * * Note: this is only for non-isolated groups. This covers only the * single-alpha case. A separate function is needed for dual-alpha, @@ -157,16 +186,17 @@ art_pdf_uncomposite_group_8(byte *dst, **/ void art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g, - const byte *src, byte src_alpha_g, - int n_chan, - - byte alpha, gs_blend_mode_t blend_mode); + const byte *src, byte src_alpha_g, int n_chan, + byte alpha, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs); /** * art_pdf_composite_group_8: Composite group pixel. * @dst: Where to store pixel, also initial backdrop of group. * @dst_alpha_g: Optional pointer to alpha g value. * @alpha: Alpha mask value. + * @blend_mode: Blend mode for compositing. + * @pblend_procs: Procs for handling non separable blending modes. * * Note: this is only for isolated groups. This covers only the * single-alpha case. A separate function is needed for dual-alpha, @@ -175,10 +205,9 @@ art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g, * @alpha corresponds to $fk_i \cdot fm_i \cdot qk_i \cdot qm_i$. **/ void -art_pdf_composite_group_8(byte *dst, byte *alpha_g, - const byte *src, - - int n_chan, byte alpha, gs_blend_mode_t blend_mode); +art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g, + const byte *src, int n_chan, byte alpha, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs); /** * art_pdf_composite_knockout_simple_8: Simple knockout compositing. @@ -231,6 +260,7 @@ art_pdf_composite_knockout_isolated_8(byte *dst, * @alpha_mask: Alpha mask. * @shape_mask: Shape mask. * @blend_mode: Blend mode for compositing. + * @pblend_procs: Procs for handling non separable blending modes. * * This function handles compositing in the case where the knockout * group is non-isolated. If the @src pixels themselves come from a @@ -239,13 +269,28 @@ art_pdf_composite_knockout_isolated_8(byte *dst, **/ void art_pdf_composite_knockout_8(byte *dst, - byte *dst_alpha_g, - const byte *backdrop, - const byte *src, - int n_chan, - byte shape, - - byte alpha_mask, - byte shape_mask, gs_blend_mode_t blend_mode); + byte *dst_alpha_g, const byte *backdrop, const byte *src, + int n_chan, byte shape, byte alpha_mask, + byte shape_mask, gs_blend_mode_t blend_mode, + const pdf14_nonseparable_blending_procs_t * pblend_procs); + +/* + * Routines for handling the non separable blending modes. + */ +/* RGB blending color space */ +void art_blend_luminosity_rgb_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); +void art_blend_saturation_rgb_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); +/* CMYK and CMYK + spot blending color space */ +void art_blend_saturation_cmyk_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); +void art_blend_luminosity_cmyk_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); +/* 'Custom' i.e. unknown blending color space. */ +void art_blend_luminosity_custom_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); +void art_blend_saturation_custom_8(int n_chan, byte *dst, const byte *backdrop, + const byte *src); #endif /* gxblend_INCLUDED */ diff --git a/gs/src/gxcie.h b/gs/src/gxcie.h index 4b4a20c5e..c42f9540f 100644 --- a/gs/src/gxcie.h +++ b/gs/src/gxcie.h @@ -19,6 +19,7 @@ # define gxcie_INCLUDED #include "gscie.h" +#include "gsnamecl.h" /* * These color space implementation procedures are defined in gscie.c or @@ -99,6 +100,11 @@ extern GX_CIE_REMAP_FINISH_PROC(gx_cie_xyz_remap_finish); cs_proc_concretize_color(gx_concretize_CIEDEFG); cs_proc_concretize_color(gx_concretize_CIEDEF); cs_proc_concretize_color(gx_concretize_CIEABC); +#if ENABLE_CUSTOM_COLOR_CALLBACK +cs_proc_remap_color(gx_remap_CIEDEFG); +cs_proc_remap_color(gx_remap_CIEDEF); +cs_proc_remap_color(gx_remap_CIEA); +#endif cs_proc_remap_color(gx_remap_CIEABC); cs_proc_concretize_color(gx_concretize_CIEA); diff --git a/gs/src/gxclip.c b/gs/src/gxclip.c index 75300574e..6d7cac014 100644 --- a/gs/src/gxclip.c +++ b/gs/src/gxclip.c @@ -101,7 +101,8 @@ private const gx_device_clip gs_clip_device = gx_default_fill_linear_color_scanline, gx_default_fill_linear_color_trapezoid, gx_default_fill_linear_color_triangle, - gx_forward_update_spot_equivalent_colors + gx_forward_update_spot_equivalent_colors, + gx_forward_ret_devn_params } }; diff --git a/gs/src/gxclip2.c b/gs/src/gxclip2.c index 89b1d970b..e7e364166 100644 --- a/gs/src/gxclip2.c +++ b/gs/src/gxclip2.c @@ -93,7 +93,8 @@ private const gx_device_tile_clip gs_tile_clip_device = gx_forward_fill_linear_color_scanline, gx_forward_fill_linear_color_trapezoid, gx_forward_fill_linear_color_triangle, - gx_forward_update_spot_equivalent_colors + gx_forward_update_spot_equivalent_colors, + gx_forward_ret_devn_params } }; diff --git a/gs/src/gxclipm.c b/gs/src/gxclipm.c index 3ef0b0a54..17b04e67e 100644 --- a/gs/src/gxclipm.c +++ b/gs/src/gxclipm.c @@ -92,7 +92,8 @@ const gx_device_mask_clip gs_mask_clip_device = gx_forward_fill_linear_color_scanline, gx_forward_fill_linear_color_trapezoid, gx_forward_fill_linear_color_triangle, - gx_forward_update_spot_equivalent_colors + gx_forward_update_spot_equivalent_colors, + gx_forward_ret_devn_params } }; diff --git a/gs/src/gxclist.c b/gs/src/gxclist.c index 1c0408ae8..2075bae9f 100644 --- a/gs/src/gxclist.c +++ b/gs/src/gxclist.c @@ -135,7 +135,8 @@ const gx_device_procs gs_clist_device_procs = { gx_default_fill_linear_color_scanline, gx_default_fill_linear_color_trapezoid, /* fixme : write to clist. */ gx_default_fill_linear_color_triangle, - gx_forward_update_spot_equivalent_colors + gx_forward_update_spot_equivalent_colors, + gx_forward_ret_devn_params }; /* ------ Define the command set and syntax ------ */ diff --git a/gs/src/gxcmap.c b/gs/src/gxcmap.c index 9f2db1efa..30aae6eed 100644 --- a/gs/src/gxcmap.c +++ b/gs/src/gxcmap.c @@ -611,6 +611,21 @@ gx_remap_concrete_DGray(const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + int code = pcb->client_procs->remap_DeviceGray(pcb, pconc, + pcs, pdc, pis, dev, select); + + if (code == 0) + return 0; + } + } +#endif + if (pis->alpha == gx_max_color_value) (*pis->cmap_procs->map_gray) (pconc[0], pdc, pis, dev, select); @@ -632,6 +647,21 @@ gx_remap_DeviceGray(const gs_client_color * pc, const gs_color_space * pcs, pdc->ccolor.paint.values[0] = pc->paint.values[0]; pdc->ccolor_valid = true; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + int code = pcb->client_procs->remap_DeviceGray(pcb, &fgray, + pcs, pdc, pis, dev, select); + + if (code == 0) + return 0; + } + } +#endif + if (pis->alpha == gx_max_color_value) (*pis->cmap_procs->map_gray) (fgray, pdc, pis, dev, select); @@ -658,6 +688,20 @@ gx_remap_concrete_DRGB(const frac * pconc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + int code = pcb->client_procs->remap_DeviceRGB(pcb, pconc, + pcs, pdc, pis, dev, select); + + if (code == 0) + return 0; + } + } +#endif if (pis->alpha == gx_max_color_value) gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2], pdc, pis, dev, select); @@ -682,6 +726,25 @@ gx_remap_DeviceRGB(const gs_client_color * pc, const gs_color_space * pcs, pdc->ccolor.paint.values[2] = pc->paint.values[2]; pdc->ccolor_valid = true; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + frac conc[3]; + int code; + + conc[0] = fred; + conc[1] = fgreen; + conc[2] = fblue; + code = pcb->client_procs->remap_DeviceRGB(pcb, conc, + pcs, pdc, pis, dev, select); + if (code == 0) + return 0; + } + } +#endif if (pis->alpha == gx_max_color_value) gx_remap_concrete_rgb(fred, fgreen, fblue, pdc, pis, dev, select); @@ -710,6 +773,20 @@ gx_remap_concrete_DCMYK(const frac * pconc, const gs_color_space * pcs, gs_color_select_t select) { /****** IGNORE alpha ******/ +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + int code = pcb->client_procs->remap_DeviceCMYK(pcb, pconc, + pcs, pdc, pis, dev, select); + + if (code == 0) + return 0; + } + } +#endif gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3], pdc, pis, dev, select); return 0; @@ -729,6 +806,26 @@ gx_remap_DeviceCMYK(const gs_client_color * pc, const gs_color_space * pcs, pdc->ccolor.paint.values[3] = pc->paint.values[3]; pdc->ccolor_valid = true; +#if ENABLE_CUSTOM_COLOR_CALLBACK + { + client_custom_color_params_t * pcb = + (client_custom_color_params_t *) (pis->custom_color_callback); + + if (pcb != NULL) { + frac conc[4]; + int code; + + conc[0] = (frac)unit_frac(pc->paint.values[0], ft0); + conc[1] = (frac)unit_frac(pc->paint.values[1], ft1); + conc[2] = (frac)unit_frac(pc->paint.values[2], ft2); + conc[3] = (frac)unit_frac(pc->paint.values[3], ft3); + code = pcb->client_procs->remap_DeviceCMYK(pcb, conc, + pcs, pdc, pis, dev, select); + if (code == 0) + return 0; + } + } +#endif gx_remap_concrete_cmyk((frac)unit_frac(pc->paint.values[0], ft0), (frac)unit_frac(pc->paint.values[1], ft1), (frac)unit_frac(pc->paint.values[2], ft2), diff --git a/gs/src/gxdcolor.h b/gs/src/gxdcolor.h index 4ce260917..ccf291c0c 100644 --- a/gs/src/gxdcolor.h +++ b/gs/src/gxdcolor.h @@ -27,7 +27,11 @@ #ifndef gx_device_DEFINED # define gx_device_DEFINED typedef struct gx_device_s gx_device; +#endif +#ifndef gs_imager_state_DEFINED +# define gs_imager_state_DEFINED +typedef struct gs_imager_state_s gs_imager_state; #endif /* diff --git a/gs/src/gxdevcli.h b/gs/src/gxdevcli.h index eee76746f..84cb057dc 100644 --- a/gs/src/gxdevcli.h +++ b/gs/src/gxdevcli.h @@ -494,7 +494,7 @@ typedef struct gx_device_color_info_s { : "DeviceCMYK") ) #define dci_std_polarity(nc) \ - ( (nc) == 4 ? GX_CINFO_POLARITY_SUBTRACTIVE \ + ( (nc) >= 4 ? GX_CINFO_POLARITY_SUBTRACTIVE \ : GX_CINFO_POLARITY_ADDITIVE ) /* @@ -632,15 +632,6 @@ dev_page_proc_install(gx_default_install); dev_page_proc_begin_page(gx_default_begin_page); dev_page_proc_end_page(gx_default_end_page); -#if ENABLE_NAMED_COLOR_CALLBACK -/* Ptr to named color callback struct */ -#define NAMED_COLOR_PTR void * named_color_callback; -#define INIT_NAMED_COLOR_PTR NULL, /* Initial value */ -#else -#define NAMED_COLOR_PTR -#define INIT_NAMED_COLOR_PTR -#endif - /* ---------------- Device structure ---------------- */ /* @@ -713,7 +704,6 @@ typedef struct gx_device_cached_colors_s { bool IgnoreNumCopies; /* if true, force num_copies = 1 */\ bool UseCIEColor; /* for PS LL3 */\ bool LockSafetyParams; /* If true, prevent unsafe changes */\ - NAMED_COLOR_PTR /* Pointer to named color callback struct */\ gx_page_device_procs page_procs; /* must be last */\ /* end of std_device_body */\ gx_device_procs procs /* object procedures */ @@ -1348,6 +1338,20 @@ typedef struct gs_fill_attributes_s { #define dev_proc_update_spot_equivalent_colors(proc)\ dev_t_proc_update_spot_equivalent_colors(proc, gx_device) +/* + * return a pointer to the devn_params section of a device. Return NULL + * if this field is not present within the device. + */ +#ifndef gs_devn_params_DEFINED +#define gs_devn_params_DEFINED +typedef struct gs_devn_params_s gs_devn_params; +#endif + +#define dev_t_proc_ret_devn_params(proc, dev_t)\ + gs_devn_params * proc(dev_t *dev) +#define dev_proc_ret_devn_params(proc)\ + dev_t_proc_ret_devn_params(proc, gx_device) + /* Define the device procedure vector template proper. */ #define gx_device_proc_struct(dev_t)\ @@ -1411,6 +1415,7 @@ typedef struct gs_fill_attributes_s { dev_t_proc_fill_linear_color_trapezoid((*fill_linear_color_trapezoid), dev_t); \ dev_t_proc_fill_linear_color_triangle((*fill_linear_color_triangle), dev_t); \ dev_t_proc_update_spot_equivalent_colors((*update_spot_equivalent_colors), dev_t); \ + dev_t_proc_ret_devn_params((*ret_devn_params), dev_t); \ } diff --git a/gs/src/gxdevice.h b/gs/src/gxdevice.h index 7671f756a..086476b00 100644 --- a/gs/src/gxdevice.h +++ b/gs/src/gxdevice.h @@ -102,7 +102,6 @@ #define std_device_part3_()\ 0/*PageCount*/, 0/*ShowpageCount*/, 1/*NumCopies*/, 0/*NumCopies_set*/,\ 0/*IgnoreNumCopies*/, 0/*UseCIEColor*/, 0/*LockSafetyParams*/,\ - INIT_NAMED_COLOR_PTR /* 'Named color' callback pointer */\ { gx_default_install, gx_default_begin_page, gx_default_end_page } /* * We need a number of different variants of the std_device_ macro simply @@ -274,6 +273,7 @@ dev_proc_fill_linear_color_scanline(gx_default_fill_linear_color_scanline); dev_proc_fill_linear_color_trapezoid(gx_default_fill_linear_color_trapezoid); dev_proc_fill_linear_color_triangle(gx_default_fill_linear_color_triangle); dev_proc_update_spot_equivalent_colors(gx_default_update_spot_equivalent_colors); +dev_proc_ret_devn_params(gx_default_ret_devn_params); /* BACKWARD COMPATIBILITY */ #define gx_non_imaging_create_compositor gx_null_create_compositor @@ -353,6 +353,7 @@ dev_proc_fill_linear_color_scanline(gx_forward_fill_linear_color_scanline); dev_proc_fill_linear_color_trapezoid(gx_forward_fill_linear_color_trapezoid); dev_proc_fill_linear_color_triangle(gx_forward_fill_linear_color_triangle); dev_proc_update_spot_equivalent_colors(gx_forward_update_spot_equivalent_colors); +dev_proc_ret_devn_params(gx_forward_ret_devn_params); /* ---------------- Implementation utilities ---------------- */ diff --git a/gs/src/gxistate.h b/gs/src/gxistate.h index 33ff7612e..826cd49d9 100644 --- a/gs/src/gxistate.h +++ b/gs/src/gxistate.h @@ -142,6 +142,7 @@ typedef struct gx_transfer_s { /* effective_transfer are always the same.) */\ gx_transfer set_transfer; /* members are (RC) */\ gx_transfer_map *effective_transfer[GX_DEVICE_COLOR_MAX_COMPONENTS]; /* see below */\ + int object_tag; /* */\ \ /* Color caches: */\ \ @@ -197,9 +198,6 @@ typedef struct gx_transfer_s { typedef struct gs_devicen_color_map_s { bool use_alt_cspace; -#if ENABLE_NAMED_COLOR_CALLBACK - bool use_named_color_callback; -#endif separation_type sep_type; uint num_components; /* Input - Duplicate of value in gs_device_n_params */ uint num_colorants; /* Number of colorants - output */ @@ -241,6 +239,8 @@ typedef struct gs_devicen_color_map_s { bool accurate_curves;\ bool have_pattern_streams;\ float smoothness;\ + int renderingintent;\ + CUSTOM_COLOR_PTR /* Pointer to custom color callback struct */\ const gx_color_map_procs *\ (*get_cmap_procs)(const gs_imager_state *, const gx_device *);\ gs_color_rendering_state_common @@ -271,8 +271,9 @@ struct gs_imager_state_s { { (float)(scale), 0.0, 0.0, (float)(-(scale)), 0.0, 0.0 },\ false, {0, 0}, {0, 0}, false, \ lop_default, gx_max_color_value, BLEND_MODE_Compatible,\ - { 1.0, 0 }, { 1.0, 0 }, 0, 0/*false*/, 0, 0, 0/*false*/, 0, 0, 1.0,\ + { 1.0, 0 }, { 1.0, 0 }, 0, 0/*false*/, 0, 0, 0/*false*/, 0, 0, 1.0, \ { fixed_half, fixed_half }, 0/*false*/, 0/*false*/, 0/*false*/, 1.0,\ + 1, INIT_CUSTOM_COLOR_PTR /* 'Custom color' callback pointer */ \ gx_default_get_cmap_procs /* The imager state structure is public only for subclassing. */ diff --git a/gs/src/iparam.c b/gs/src/iparam.c index 9f36b1b86..ec8d402e8 100644 --- a/gs/src/iparam.c +++ b/gs/src/iparam.c @@ -28,6 +28,7 @@ #include "iutil.h" /* for num_params */ #include "ivmspace.h" #include "store.h" +#include "gsstruct.h" /* for st_bytes */ /* ================ Utilities ================ */ @@ -517,7 +518,7 @@ private const gs_param_list_procs ref_read_procs = }; private int ref_param_read(iparam_list *, gs_param_name, iparam_loc *, int); -private int ref_param_read_string_value(const gs_memory_t *mem, +private int ref_param_read_string_value(gs_memory_t *mem, const iparam_loc *, gs_param_string *); private int ref_param_read_array(iparam_list *, gs_param_name, @@ -797,6 +798,7 @@ ref_param_read_typed(gs_param_list * plist, gs_param_name pkey, pvalue->type = gs_param_type_float; return 0; case t_string: + case t_astruct: pvalue->type = gs_param_type_string; return ref_param_read_string_value(plist->memory, &loc, &pvalue->value.s); default: @@ -864,7 +866,7 @@ ref_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum, /* Read a string value. */ private int -ref_param_read_string_value(const gs_memory_t *mem, const iparam_loc * ploc, gs_param_string * pvalue) +ref_param_read_string_value(gs_memory_t *mem, const iparam_loc * ploc, gs_param_string * pvalue) { const ref *pref = ploc->pvalue; @@ -884,6 +886,17 @@ ref_param_read_string_value(const gs_memory_t *mem, const iparam_loc * ploc, gs_ pvalue->size = r_size(pref); pvalue->persistent = false; break; + case t_astruct: + /* Note: technically, instead of the "mem" argument, we + should be using the plists's ref_memory. However, in a + simple call to .putdeviceparams, they are identical. */ + iparam_check_read(*ploc); + if (gs_object_type(mem, pref->value.pstruct) != &st_bytes) + return iparam_note_error(*ploc, e_typecheck); + pvalue->data = r_ptr(pref, byte); + pvalue->size = gs_object_size(mem, pref->value.pstruct); + pvalue->persistent = false; + break; default: return iparam_note_error(*ploc, e_typecheck); } diff --git a/gs/src/lib.mak b/gs/src/lib.mak index 6dfdb6bc9..d6337f264 100644 --- a/gs/src/lib.mak +++ b/gs/src/lib.mak @@ -392,7 +392,7 @@ gsdcolor_h=$(GLSRC)gsdcolor.h $(gsccolor_h)\ gxdcolor_h=$(GLSRC)gxdcolor.h\ $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h) gsnamecl_h=$(GLSRC)gsnamecl.h -gscspace_h=$(GLSRC)gscspace.h $(gsmemory_h) $(gsnamecl_h) $(gsrefct_h) +gscspace_h=$(GLSRC)gscspace.h $(gsmemory_h) $(gsrefct_h) gscssub_h=$(GLSRC)gscssub.h $(gscspace_h) gxdevcli_h=$(GLSRC)gxdevcli.h $(std_h) $(stdint__h)\ $(gscompt_h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h)\ @@ -2446,13 +2446,16 @@ $(GLD)seprlib.dev : $(LIB_MAK) $(ECHOGS_XE) $(seprlib_) $(GLOBJ)gscsepr.$(OBJ) : $(GLSRC)gscsepr.c $(GXERR) $(memory__h)\ $(gsfunc_h) $(gsrefct_h) $(gsmatrix_h) $(gscsepr_h) $(gxcspace_h)\ $(gxfixed_h) $(gxcolor2_h) $(gzstate_h) $(gscdevn_h) $(gxcdevn_h)\ - $(gxcmap_h) $(gxdevcli_h) $(gsovrc_h) $(stream_h) + $(gxcmap_h) $(gxdevcli_h) $(gsovrc_h) $(stream_h) $(gsnamecl_h) $(GLCC) $(GLO_)gscsepr.$(OBJ) $(C_) $(GLSRC)gscsepr.c -$(GLOBJ)gsnamecl.$(OBJ) : $(GLSRC)gsnamecl.c $(GXERR) $(memory__h) +$(GLOBJ)gsnamecl.$(OBJ) : $(GLSRC)gsnamecl.c $(GXERR) $(memory__h) $(gxcspace_h)\ + $(gscdefs_h) $(gxdevice_h) $(gzstate_h) $(GLCC) $(GLO_)gsnamecl.$(OBJ) $(C_) $(GLSRC)gsnamecl.c -$(GLOBJ)gsncdemo.$(OBJ) : $(GLSRC)gsncdemo.c $(GXERR) $(memory__h) +$(GLOBJ)gsncdemo.$(OBJ) : $(GLSRC)gsncdemo.c $(GXERR) $(stdpre_h) $(math_h)\ + $(memory__h) $(gscdefs_h) $(gscspace_h) $(gxdevice_h) $(gzstate_h)\ + $(malloc__h) $(GLCC) $(GLO_)gsncdemo.$(OBJ) $(C_) $(GLSRC)gsncdemo.c # ================ Display Postscript extensions ================ # diff --git a/gs/src/zcolor3.c b/gs/src/zcolor3.c index 38cbde0cd..b218c7fac 100644 --- a/gs/src/zcolor3.c +++ b/gs/src/zcolor3.c @@ -16,6 +16,7 @@ #include "ghost.h" #include "oper.h" #include "igstate.h" +#include "store.h" /* @@ -43,6 +44,30 @@ zsetuseciecolor(i_ctx_t * i_ctx_p) return 0; } +/* - .currentrenderingintent <int> */ +private int +zcurrentrenderingintent(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + + push(1); + make_int(op, gs_currentrenderingintent(igs)); + return 0; +} + +/* <int> .setrenderingintent - */ +private int +zsetrenderingintent(i_ctx_t * i_ctx_p) +{ + os_ptr op = osp; + int param; + int code = int_param(op, max_int, ¶m); + + if (code < 0 || (code = gs_setrenderingintent(igs, param)) < 0) + return code; + pop(1); + return 0; +} /* * Initialization procedure @@ -51,5 +76,7 @@ zsetuseciecolor(i_ctx_t * i_ctx_p) const op_def zcolor3_l3_op_defs[] = { op_def_begin_ll3(), { "0.setuseciecolor", zsetuseciecolor }, + { "0.currentrenderintent", zcurrentrenderingintent }, + { "1.setrenderingintent", zsetrenderingintent }, op_def_end(0) }; diff --git a/gs/src/zfapi.c b/gs/src/zfapi.c index cfd0c274b..92bb45518 100644 --- a/gs/src/zfapi.c +++ b/gs/src/zfapi.c @@ -1878,7 +1878,7 @@ private int do_FAPIpassfont(i_ctx_t *i_ctx_p, char *font_file_path, bool *succes private int zFAPIpassfont(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; - bool found; + bool found = false; char *font_file_path = NULL; ref *v; diff --git a/gs/src/ztrans.c b/gs/src/ztrans.c index a8997c14b..115df9cb4 100644 --- a/gs/src/ztrans.c +++ b/gs/src/ztrans.c @@ -31,6 +31,8 @@ #include "iname.h" #include "store.h" #include "gsdfilt.h" +#include "gdevdevn.h" +#include "gxblend.h" #include "gdevp14.h" /* ------ Utilities ------ */ diff --git a/gs/src/zusparam.c b/gs/src/zusparam.c index af9f71f48..0d84a6e21 100644 --- a/gs/src/zusparam.c +++ b/gs/src/zusparam.c @@ -34,6 +34,7 @@ #include "iutil2.h" #include "ivmem2.h" #include "store.h" +#include "gsnamecl.h" /* The (global) font directory */ extern gs_font_dir *ifont_dir; /* in zfont.c */ @@ -268,6 +269,13 @@ zsetsystemparams(i_ctx_t *i_ctx_p) if (code < 0) goto out; } +#if ENABLE_CUSTOM_COLOR_CALLBACK + /* The custom color callback pointer */ + code = custom_color_callback_put_params(i_ctx_p->pgs, plist); + if (code < 0) + goto out; +#endif + code = setparams(i_ctx_p, plist, &system_param_set); out: iparam_list_release(&list); @@ -639,7 +647,7 @@ current_param_list(i_ctx_t *i_ctx_p, const param_set * pset, { stack_param_list list; gs_param_list *const plist = (gs_param_list *)&list; - int i; + int i, code = 0; stack_param_list_write(&list, &o_stack, NULL, iimemory); for (i = 0; i < pset->long_count; i++) { @@ -647,8 +655,8 @@ current_param_list(i_ctx_t *i_ctx_p, const param_set * pset, if (pname_matches(pname, psref)) { long val = (*pset->long_defs[i].current)(i_ctx_p); - int code = param_write_long(plist, pname, &val); + code = param_write_long(plist, pname, &val); if (code < 0) return code; } @@ -658,8 +666,8 @@ current_param_list(i_ctx_t *i_ctx_p, const param_set * pset, if (pname_matches(pname, psref)) { bool val = (*pset->bool_defs[i].current)(i_ctx_p); - int code = param_write_bool(plist, pname, &val); + code = param_write_bool(plist, pname, &val); if (code < 0) return code; } @@ -669,7 +677,6 @@ current_param_list(i_ctx_t *i_ctx_p, const param_set * pset, if (pname_matches(pname, psref)) { gs_param_string val; - int code; (*pset->string_defs[i].current)(i_ctx_p, &val); code = param_write_string(plist, pname, &val); @@ -677,7 +684,14 @@ current_param_list(i_ctx_t *i_ctx_p, const param_set * pset, return code; } } - return 0; +#if ENABLE_CUSTOM_COLOR_CALLBACK + if (pset == &system_param_set) { + /* The custom_color callback pointer */ + if (pname_matches(CustomColorCallbackParamName, psref)) + code = custom_color_callback_get_params(i_ctx_p->pgs, plist); + } +#endif + return code; } /* Get the current values of a parameter set to the stack. */ |