summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Osborn <timothy.osborn@artifex.com>2007-03-23 13:56:11 +0000
committerTimothy Osborn <timothy.osborn@artifex.com>2007-03-23 13:56:11 +0000
commita735c9f699f7c1121276a2c8761a06d3770928ce (patch)
tree5e3cc3167c9bde6d313ff857cf2c5cf0e0ae8e88
parentbbf19d56ef91433e6997998101eed6e584afb354 (diff)
Custom color hooks code merge
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@7795 a1074d23-0009-0410-80fe-cf8c14f379e6
-rw-r--r--gs/lib/pdf_main.ps163
-rw-r--r--gs/lib/pdf_ops.ps9
-rw-r--r--gs/src/gdevbbox.c1
-rw-r--r--gs/src/gdevdevn.c126
-rw-r--r--gs/src/gdevdevn.h69
-rw-r--r--gs/src/gdevdflt.c13
-rw-r--r--gs/src/gdevdsp.c16
-rw-r--r--gs/src/gdevnfwd.c12
-rw-r--r--gs/src/gdevp14.c1516
-rw-r--r--gs/src/gdevp14.h100
-rw-r--r--gs/src/gdevpbm.c24
-rw-r--r--gs/src/gdevpnga.c1
-rw-r--r--gs/src/gdevprn.c1
-rw-r--r--gs/src/gdevpsd.c2
-rw-r--r--gs/src/gdevrops.c3
-rw-r--r--gs/src/gdevtsep.c16
-rw-r--r--gs/src/gscdevn.c22
-rw-r--r--gs/src/gscie.c64
-rw-r--r--gs/src/gsciemap.c87
-rw-r--r--gs/src/gscolor2.c2
-rw-r--r--gs/src/gscscie.c21
-rw-r--r--gs/src/gscsepr.c22
-rw-r--r--gs/src/gscspace.c77
-rw-r--r--gs/src/gscspace.h11
-rw-r--r--gs/src/gsdparam.c12
-rw-r--r--gs/src/gsdps1.c4
-rw-r--r--gs/src/gsicc.c49
-rw-r--r--gs/src/gsimage.c5
-rw-r--r--gs/src/gsnamecl.c158
-rw-r--r--gs/src/gsnamecl.h466
-rw-r--r--gs/src/gsncdemo.c1319
-rw-r--r--gs/src/gspaint.c38
-rw-r--r--gs/src/gsstate.c15
-rw-r--r--gs/src/gsstate.h3
-rw-r--r--gs/src/gstext.c6
-rw-r--r--gs/src/gstrans.c37
-rw-r--r--gs/src/gstrans.h4
-rw-r--r--gs/src/gsutil.c22
-rw-r--r--gs/src/gxblend.c270
-rw-r--r--gs/src/gxblend.h85
-rw-r--r--gs/src/gxcie.h6
-rw-r--r--gs/src/gxclip.c3
-rw-r--r--gs/src/gxclip2.c3
-rw-r--r--gs/src/gxclipm.c3
-rw-r--r--gs/src/gxclist.c3
-rw-r--r--gs/src/gxcmap.c97
-rw-r--r--gs/src/gxdcolor.h4
-rw-r--r--gs/src/gxdevcli.h27
-rw-r--r--gs/src/gxdevice.h3
-rw-r--r--gs/src/gxistate.h9
-rw-r--r--gs/src/iparam.c17
-rw-r--r--gs/src/lib.mak11
-rw-r--r--gs/src/zcolor3.c27
-rw-r--r--gs/src/zfapi.c2
-rw-r--r--gs/src/ztrans.c2
-rw-r--r--gs/src/zusparam.c24
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(&param_list, p14dev->memory);
+ code = get_param_compressed_color_list_elem(p14dev,
+ (gs_param_list *)&param_list,
+ p14dev->devn_params.compressed_color_list,
+ PDF14CompressedColorListParamName, &pkeyname_list_head);
+ get_param_spot_color_names(p14dev, (gs_param_list *)&param_list,
+ &pkeyname_list_head);
+ if (code >= 0) {
+ gx_device * tdev = p14dev->target;
+
+ gs_c_param_list_read(&param_list);
+ // put_param_compressed_color_list_elem(p14dev,
+ // (gs_param_list *)&param_list,
+ // &pret_comp_list, "PDF14CompressedColorList",
+ // TOP_ENCODED_LEVEL);
+ // put_param_pdf14_spot_names(p14dev, (gs_param_list *)&param_list);
+#if 1
+ code = dev_proc(tdev, put_params)(tdev, (gs_param_list *)&param_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 *)&param_list );
+#endif
+ }
+ gs_c_param_list_release(&param_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, &params);
}
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, &param);
+
+ 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. */