summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Sharp <ken.sharp@artifex.com>2008-08-11 14:16:18 +0000
committerKen Sharp <ken.sharp@artifex.com>2008-08-11 14:16:18 +0000
commitcecbdfcd156a190dfe3bc7ed07e2179cf45dbbb4 (patch)
treea1e8539ea070d84fcd924b0c27b069c5bbe67d0f
parent91d8f890b4429c3d73f7c28bb1b1ac7a6c3a9751 (diff)
Move the interpretation of PostScript (and PDF) color spaces from PostScript into C.
DETAILS: This has required a large number of changes, there are a few new .c or .h files, a number of PostScript files have been removed, and a few others simplified. A few documentation '.htm' files have also been modified to reflect these changes. EXPECTED DIFFERENCES None git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@8962 a1074d23-0009-0410-80fe-cf8c14f379e6
-rw-r--r--gs/Resource/Init/gs_ciecs2.ps147
-rw-r--r--gs/Resource/Init/gs_ciecs3.ps137
-rw-r--r--gs/Resource/Init/gs_cspace.ps1146
-rw-r--r--gs/Resource/Init/gs_devcs.ps250
-rw-r--r--gs/Resource/Init/gs_devn.ps218
-rw-r--r--gs/Resource/Init/gs_devpxl.ps78
-rw-r--r--gs/Resource/Init/gs_icc.ps259
-rw-r--r--gs/Resource/Init/gs_indxd.ps205
-rw-r--r--gs/Resource/Init/gs_init.ps8
-rw-r--r--gs/Resource/Init/gs_lev2.ps35
-rw-r--r--gs/Resource/Init/gs_ll3.ps15
-rw-r--r--gs/Resource/Init/gs_patrn.ps309
-rw-r--r--gs/Resource/Init/gs_sepr.ps268
-rw-r--r--gs/doc/Develop.htm8
-rw-r--r--gs/doc/Psfiles.htm46
-rw-r--r--gs/src/gscolor2.h2
-rw-r--r--gs/src/ifunc.h6
-rw-r--r--gs/src/int.mak19
-rw-r--r--gs/src/zcie.c83
-rw-r--r--gs/src/zcie.h25
-rw-r--r--gs/src/zcolor.c5466
-rw-r--r--gs/src/zcolor.h97
-rw-r--r--gs/src/zcsdevn.c5
-rw-r--r--gs/src/zcsindex.c129
-rw-r--r--gs/src/zcspixel.c32
-rw-r--r--gs/src/zcssepr.c84
-rw-r--r--gs/src/zfsample.c145
-rw-r--r--gs/src/zfunc.c26
-rw-r--r--gs/src/zfunc4.c78
-rw-r--r--gs/src/zicc.c148
-rw-r--r--gs/src/zicc.h22
-rw-r--r--gs/src/zpcolor.c44
32 files changed, 6100 insertions, 3440 deletions
diff --git a/gs/Resource/Init/gs_ciecs2.ps b/gs/Resource/Init/gs_ciecs2.ps
deleted file mode 100644
index 6c1756d83..000000000
--- a/gs/Resource/Init/gs_ciecs2.ps
+++ /dev/null
@@ -1,147 +0,0 @@
-% Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Level 2 CIEBased color space method dictionaries.
-
-%
-% The validation routines in these method dictionaries perform only
-% partial validations; the .setcie* operators will perform the rest.
-%
-
-% verify that at least one of the CIEBased color spaces is supported
-true
- { /.setcieaspace /.setcieabcspace /.setciedefspace /.setciedefgspace }
- {
- where
- { pop not exit }
- if
- }
-forall
- { currentfile closefile }
-if
-
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-%
-% <obj> check_cie_cspace <obj>
-%
-% Perform a very basic check that an object is a CIEBased color space
-% array.
-%
-/check_cie_cspace
- {
- //check_array exec
- dup 1 get type /dicttype ne
- //setcspace_typecheck
- if
- }
-bind def
-
-
-
-/.setcieaspace where
- {
- pop
- colorspacedict
- /CIEBasedA
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_1
-
- /cs_get_range
- {
- 1 get /RangeA .knownget not
- { //dflt_range_1 }
- if
- }
- bind
-
- /cs_get_default_color { pop 0 } bind
- /cs_get_currentgray //no_currentgray
- /cs_get_currentrgb //no_currentrgb
- /cs_get_currentcmyk //no_currentcmyk
- /cs_validate //check_cie_cspace
- /cs_substitute //dup_1
- /cs_prepare {}
-
- /cs_install
- {
- NOCIE
- { pop /DeviceGray //.cs_install exec }
- { 1 get .setcieaspace }
- ifelse
- }
- bind
-
- /cs_prepare_color //validate_1
- /cs_complete_setcolor //pop_1
- .dicttomark
- put
- }
-if
-
-/.setcieabcspace where
- {
- pop
- colorspacedict
- /CIEBasedABC
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_3
-
- /cs_get_range
- {
- 1 get /RangeABC .knownget not
- { //dflt_range_3 }
- if
- }
- bind
-
- /cs_get_default_color { pop 0 0 0 } bind
- /cs_get_currentgray //no_currentgray
- /cs_get_currentrgb //no_currentrgb
- /cs_get_currentcmyk //no_currentcmyk
- /cs_validate //check_cie_cspace
- /cs_substitute //dup_1
- /cs_prepare {}
-
- /cs_install
- {
- NOCIE
- { pop /DeviceRGB //.cs_install exec }
- { 1 get .setcieabcspace }
- ifelse
- }
- bind
-
- /cs_prepare_color //validate_3
- /cs_complete_setcolor //pop_1
- .dicttomark
- put
- }
-if
-
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_ciecs3.ps b/gs/Resource/Init/gs_ciecs3.ps
deleted file mode 100644
index f713825e5..000000000
--- a/gs/Resource/Init/gs_ciecs3.ps
+++ /dev/null
@@ -1,137 +0,0 @@
-% Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Level 3 CIEBased color space method dictionaries.
-% This assumes gs_ciecs2.ps has already been processed.
-
-%
-% The validation routines in these method dictionaries perform only
-% partial validations; the .setcie* operators will perform the rest.
-%
-
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-
-/.setciedefspace where
- {
- pop
- colorspacedict
- /CIEBasedDEF
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_3
-
- /cs_get_range
- {
- 1 get /RangeDEF .knownget not
- { //dflt_range_3 }
- if
- }
- bind
-
- % per Page 233 of the PLRM, default color should be as close to 0.0 as possible
- % within the RangeDEF
- /cs_get_default_color { 1 get /RangeDEF .knownget {
- aload pop pop 5 1 roll pop 4 1 roll pop 3 1 roll
- } {
- 0.0 0.0 0.0
- } ifelse
- } bind
- /cs_get_currentgray //no_currentgray
- /cs_get_currentrgb //no_currentrgb
- /cs_get_currentcmyk //no_currentcmyk
- /cs_validate //check_cie_cspace
- /cs_substitute //dup_1
- /cs_prepare {}
-
- /cs_install
- {
- NOCIE
- { pop /DeviceRGB //.cs_install exec }
- { 1 get .setciedefspace }
- ifelse
- }
- bind
-
- /cs_prepare_color //validate_3
- /cs_complete_setcolor //pop_1
- .dicttomark
- put
- }
-if
-
-
-/.setciedefgspace where
- {
- pop
- colorspacedict
- /CIEBasedDEFG
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_4
-
- /cs_get_range
- {
- 1 get /RangeDEFG .knownget not
- { //dflt_range_4 }
- if
- }
- bind
-
- % per Page 233 of the PLRM, default color should be as close to 0.0 as possible
- % within the RangeDEFG
- /cs_get_default_color { 1 get /RangeDEFG .knownget {
- aload pop pop 7 1 roll pop 6 1 roll pop 5 1 roll pop 4 1 roll
- } {
- 0.0 0.0 0.0 0.0
- } ifelse
- } bind
- /cs_get_currentgray //no_currentgray
- /cs_get_currentrgb //no_currentrgb
- /cs_get_currentcmyk //no_currentcmyk
- /cs_validate //check_cie_cspace
- /cs_substitute //dup_1
- /cs_prepare {}
-
- % the use of the DeviceCMYK color space is questionable:
- % it will likely have the wrong polarity
- /cs_install
- {
- NOCIE
- { pop /DeviceCMYK //.cs_install exec }
- { 1 get .setciedefgspace }
- ifelse
- }
- bind
-
- /cs_prepare_color //validate_4
- /cs_complete_setcolor //pop_1
- .dicttomark
- put
- }
-if
-
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_cspace.ps b/gs/Resource/Init/gs_cspace.ps
index 8199f3389..9ec3336c3 100644
--- a/gs/Resource/Init/gs_cspace.ps
+++ b/gs/Resource/Init/gs_cspace.ps
@@ -17,1006 +17,212 @@
% basic colorspace mechanism
%
-% This new implementation of color spaces extends the color space
-% formalism to all PostScript levels. Level specific features and
-% operators continue to be accessible only in the appropriate level,
-% but the colorspace concept and associated mechanisms are used
-% throughout.
+% There have been some major changes to the PostScript colour handling.
+% In particular, the vast majority of the colour space code has been
+% converted from PostScript to C. This file has been extensively
+% modified, as has gs_icc.ps. The remaining PostScript files which
+% previously implemented colour space handling; gs_ciecs2.ps, gs_ciecs3.ps
+% gs_devcs.ps, gs_devn.ps, gs_devpxl.ps, gs_indxd.ps, gs_patrn.ps and
+% gs_sepr.ps have been superceded by the C code and removed.
%
-% The color space mechanism is built around two dictionaries:
+% gs_lev2.ps and gs_ll3.ps have also been modified so that they no longer
+% attempt to execute these PostScript files.
%
-% .cspace_util
-% A dictionary in global VM that is accessible in userdict only
-% during initialization. This dictionary is intended for various
-% utility procedures that are used in implementing the individual
-% color spaces.
-%
-% colorspacedict
-% A dictionary of methods for each color space type. The keys
-% in this dictionary are color space type names (e.g.: /DeviceGray,
-% /Separation, etc.), and the values are dictionaries of methods.
-% The set of methods is the same for each color space type, and
-% provides a complete implementation for the corresponding color
-% space type. This dictionary is in global VM.
-%
-% The information specific to a color space type is created in a file
-% for that type or group of types (e.g.: gs_csdev.ps, gs_csindx.ps,
-% etc.). These files will generally adhere to the template:
-%
-% .currentglobal true .setglobal
-% <level-specific dictionary> begin
-% ...
-% .cspace_util begin
-% colorspacedict
-% /<color space type name>
-% mark
-% /cs_validate
-% {
-% ...
-% }
-% bind
-% ...
-% .dicttomark
-% put
-% end % .cspace_util
-% end ... % level-specific dictionary
-% .setglobal
-%
-% The methods associated with a color space are listed below (along with
-% their stack handling), followed by descriptions.
-%
-% - cs_potential_indexed_base <bool>
-%
-% - cs_potential_pattern_base <bool>
-%
-% - cs_potential_alternate <bool>
-%
-% - cs_potential_icc_alternate <bool>
-%
-%
-% <name | array> cs_get_ncomps <int>
-%
-% <name | array> cs_get_range <range_array>
-%
-% <name | array> cs_get_default_color <c1> ... <cn>
-%
-%
-% <c1> ... <cn> <name | array> cs_get_currentgray <gray>
-%
-% <c1> ... <cn> <name | array> cs_get_currentrgb <red> <green> <blue>
-%
-% <c1> ... <cn> <name | array> cs_get_currentcmyk
-% <cyan> <magenta> <yellow> <black>
-%
-%
-% <name | array> cs_validate <name | array>
-%
-% <name1 | array1> cs_substitute <name1 | array1> <array2>
-%
-% <name1 | array1> <array2> cs_prepare <name1 | array1> <array2>
-%
-% <name | array> cs_install -
-%
-%
-% <c1> ... <cn> <array> cs_verify_color <c1> ... <cn>
-%
-% <array> cs_complete_color -
-%
-%
-% cs_potential_indexed_base, cs_potential_pattern_base,
-% cs_potential_alternate, cs_potential_icc_alternate
-% These are booleans rather than procedures. They indicate if the color
-% space can be a base space of an Indexed color space (anything except
-% Indexed and Pattern), a Pattern color space (anything except Pattern),
-% the alternative color space of a Separation or DeviceN color space, or
-% the alternative color space of an ICCBased color space. The two
-% parameters are distinct only because of a Ghostscript-specific
-% implementation problem; in principle, there is nothing special about
-% ICCBased color spaces in this regard.
-%
-% cs_get_ncomps
-% Return the number of color components for the color spaces. For Pattern
-% color spaces, the value is -1 if there is no base space, or -(n + 1) if
-% the base space has n components.
-%
-% cs_get_range
-% Return the input Range array appropriate for this color space. This is
-% defined for all color spaces, though it is of interest primarily for
-% CIEBased and ICCBased color spaces. For Indexed color spaces this is
-% [ 0 hival ], where hival is the maximum support index value. For all
-% other non-CIEBased, non-ICCBased color spaces, the range is an array
-% of ncomps elements, all of which are [ 0 1 ], where ncomps is the
-% number of color space components.
-%
-% cs_get_default_color
-% Generates the default color for the current color space. Under normal
-% circumstances this is done internally. It is provided in PostScript
-% only to support an optimization that doesn't change the current color
-% space more often than necessary.
-%
-% cs_get_currentgray, cs_get_currentrgb, cs_get_currentcmyk
-% These procedures are used to implement the currentgray, currentrgb,
-% and currentcmyk operators (which are pseudo-operators in the current
-% implementation).
-%
-% cs_validate
-% Validate the operand color space. Because color spaces are extensively
-% manipulated in PostScript in this implementation, error handling can
-% become burdensome. To make the code somewhat simpler, it is useful to
-% be able to validate a color space prior to manipulation, so as to
-% ensure that errors are not discovered in awkward places.
-%
-% cs_substitute
-% Substitute a device-independent color space for device specific color
-% space. This applies directly to the device-specific color spaces
-% (DeviceGray, DeviceRGB, DeviceCMYK), and indirectly when these color
-% spaces are used as base/alternative color spaces. The mechanism for
-% color substitution is included in all language levels, though it may
-% only be accessed for Language Level 3.
-%
-% The substituted color space is the topmost of the operands pushed.
-% this may or may not be the same as the original color space, which
-% is immediately below it on the operand stack. If the two differ,
-% the substituted space will always be in local VM (and will be
-% writable).
-%
-% Substitution is applied recursively to the base/alternate color
-% space of ICCBased, Indexed, Separation, DeviceN, or Pattern
-% color spaces. Because Ghostscript currently requires that any
-% base or alternative color space be the current color space when
-% the enclosing color space is set, this substitution effectively
-% occurs twice: once in the original color space, and once when the
-% base/alternative color space is made the current color space.
-% We retain the first substitution as we would eventually like to
-% remove the restriction on making the base/alternative color space
-% the current color space.
-%
-% cs_prepare
-% Perform any operations required on the color space for installation.
-% This method exists primarily to allow conversion of PostScript
-% procedures to functions for CIEBased color spaces. Two operands are
-% provided: the original and the substituted color space. If the two
-% differ and the latter is writable, required modifications can
-% be made "in place". Otherwise, a new instance of the second color
-% space must be built.
-%
-% Currently, cs_prepare is not explicitly recursive. Because
-% Ghostscript requires a base/alternate color space to be installed
-% as the current color space prior to installing the enclosing color
-% space, the cs_prepare method will implicitly be called recursively.
-% The reason for not making this explicit is that color space
-% preparation may involve a considerable amount of work, which could
-% be avoided if, for example, an alternative color space will not
-% be used because the enclosing Separation/DeviceN color space is
-% supported in native mode by the process color model. We would
-% eventually like to remove the need to prepare color spaces that
-% will not be used.
-%
-% cs_install
-% This method actually installs the color space in the graphic state.
-% Only the substituted/prepared space (which may be the same as the
-% original space) is passed as an operand; the original space is handled
-% directly by the .setcolorspace operator.
-%
-% The provision of a separate method for this tasks reflects the
-% historical implementation of color spaces in the Ghostscript
-% interpreter. This implementation provides a unique operator for each
-% color space type.
-%
-% cs_prepare_color
-% Modify a set of color operands as required by a color space. This
-% is used primarily to verify the color operands, as this is most
-% conveniently done in PostScript.
-%
-% cs_complete_setcolor
-% This method is invoked immediately after a (successful) invocation
-% of setcolor. Ii is provided as a separate method for compatibility
-% with Adobe implementations. These implementations invoke the lookup
-% (Indexed) or tint procedure each time setcolor is invoked (only if
-% the alternative color space is used in the case of the tint
-% transform). Because Ghostscript may convert these procedures to
-% functions (or pre-sample them), the procedures may not always be
-% called when expected. There are applications that depend on this
-% behavior (e.g.: Adobe PhotoShop 5+), so this method provides a way
-% to emulate it.
-%
-% In principle, a cs_complete_setcolor procedure for an Indexed color
-% space whose base space should invoke cs_complete_setcolor on its
-% base space. Currently we don't do this, because it has not been
-% shown to be necessary. It would be simple to add if it is every
-% needed.
-%
-% All of these methods are procedures.
-%
-% For each of these methods, there is a procedure in .cspace_util with
-% a dot ('.') prefix that will invoke the appropriate procedure for the
-% operand array.
-%
-
.currentglobal true .setglobal
-userdict /.cspace_util 80 dict put
-.cspace_util begin
-
-
-% Global, read-only, unpacked, array-form device color spaces
-%
-/DeviceGray_array /DeviceGray 1 array astore readonly def
-/DeviceRGB_array /DeviceRGB 1 array astore readonly def
-/DeviceCMYK_array /DeviceCMYK 1 array astore readonly def
-
-%
-% Colorspacedict is initially in .cspace_util; it is copied to level2dict
-% in the Level 2 initialization code to retain compatibility with
-% earlier implementations.
-%
-/colorspacedict 20 dict def
-
-
-%
-% <obj> make_array1 <array>
-%
-% procedure for conditionally converting a named color space to a
-% 1-element array. Since names are always global, the array will be
-% as well.
-%
-/make_array1
- {
- dup type /nametype eq
- { currentglobal true setglobal exch 1 array astore exch setglobal }
- if
- }
-bind def
-
-%
-% <name|array> .get_cspace_type name
-%
-% Provide generic routine for retrieving the color space type.
-%
-/.get_cspace_type
- {
- dup type dup /arraytype eq exch /packedarraytype eq or
- { 0 get }
- if
- }
-bind def
-
-%
-% <name|array> .get_method_dict <dict>
-%
-% Get the method dictionary for a specific color space. Note that the
-% color space is left on the stack.
-%
-/.get_method_dict
- { //colorspacedict exch //.get_cspace_type exec get }
-bind def
+systemdict begin
%
-% <name|array> <proc_name> .get_method <name|array> <proc | bool>
-%
-% Get the named method for the operand color space.
+% gs_res.ps, and possibly other files, use this dictionary. Formerly
+% in cspace_util, moved to systemdict.
%
-/.get_method
- { exch //.get_method_dict exec exch get }
-bind def
+20 dict dup /colorspacedict exch def
+begin % colorspacedict
%
-% <name_array> .cs_potential_indexed_base <bool>
-% <name_array> .cs_potential_pattern_base <bool>
-% <name_array> .cs_potential_alternate <bool>
-% <name_array> .cs_potential_icc_alternate <bool>
-% <name | array> .cs_get_ncomps <int>
-% <name | array> .cs_get_range <range_array>
-% <name | array> .cs_get_default_color <c1> ... <cn>
-% <c1> ... <cn> <name | array> .cs_get_currentgray <gray>
-% <c1> ... <cn> <name | array> .cs_get_currentrgb <r> <g> <b>
-% <c1> ... <cn> <name | array> .cs_get_currentcmyk <c> <m> <y> <k>
-% <name | array> .cs_validate <name | array>
-% <name1 | array1> .cs_substitute <name1 | array1> <array2>
-% <name1 | array1> <array2> .cs_prepare <name1 | array1> <array2>
-% <name | array> .cs_install -
-% <c1> ... <cn> <array> .cs_prepare_color <c1> ... <cn>
-% <array> .cs_complete_setcolor -
-%
-% These procedures provide access to the corresponding methods of the
-% operand color space.
+% gs_res.ps uses these entries in colorspacedict
+% to populate the ColorSpaceFamily resource, so we need
+% to add the supported spaces.
%
-/.cs_potential_indexed_base
- { /cs_potential_indexed_base //.get_method exec }
-bind def
-
-/.cs_potential_pattern_base
- { /cs_potential_pattern_base //.get_method exec }
-bind def
-
-/.cs_potential_alternate
- { /cs_potential_alternate //.get_method exec }
-bind def
-
-/.cs_potential_icc_alternate
- { /cs_potential_icc_alternate //.get_method exec }
-bind def
-
-/.cs_get_ncomps
- { dup /cs_get_ncomps //.get_method exec exec }
-bind def
-
-/.cs_get_range
- { dup /cs_get_range //.get_method exec exec }
-bind def
-
-/.cs_get_default_color
- { dup /cs_get_default_color //.get_method exec exec }
-bind def
-
-/.cs_get_currentgray
- { dup /cs_get_currentgray //.get_method exec exec }
-bind def
-
-/.cs_get_currentrgb
- { dup /cs_get_currentrgb //.get_method exec exec }
-bind def
-
-/.cs_get_currentcmyk
- { dup /cs_get_currentcmyk //.get_method exec exec }
-bind def
+/DeviceGray [] def
+/DeviceRGB [] def
+/DeviceCMYK [] def
+end % colorspacedict
-/.cs_validate
- { dup /cs_validate //.get_method exec exec }
-bind def
-
-/.cs_substitute
- { dup /cs_substitute //.get_method exec exec }
-bind def
-
-/.cs_prepare
- { dup /cs_prepare //.get_method exec exec }
-bind def
-
-/.cs_install
- { dup /cs_install //.get_method exec exec }
-bind def
-
-/.cs_prepare_color
- { dup /cs_prepare_color //.get_method exec exec }
-bind def
-
-/.cs_complete_setcolor
- { dup /cs_complete_setcolor //.get_method exec exec }
-bind def
-
-
-%
-% Make sure we have an interpreter color space before redefining
-% setcolorspace. The interpreter internal code only sets the effective
-% color space; the interpreters color spaces begins as a null object.
%
-% NB: This should come prior to the redefinition of setcolorspace, and
-% must use an array operand.
-%
-//DeviceGray_array setcolorspace
-
-%
-% <c1> ... <cn> setcolor -
-%
-% As with setcolorspace, setcolor is initially placed in .cspace_util,
-% and is copied to level2dict by the Level 2 initialization code. The
-% internal definition of setcolor is removed from systemdict as soon
-% as this procedure is defined.
-%
-/setcolor
- {
- {
- currentcolorspace //.cs_prepare_color exec //setcolor
- currentcolorspace //.cs_complete_setcolor exec
- }
- stopped
- { //.cspace_util /setcolor get $error /errorname get signalerror }
- if
- }
-bind odef
-
-systemdict /setcolor .undef
-
-
-%
-% <name|array> <bool> _setcolorspace -
-% <name|array> _setcolorspace_nosub -
-%
-% <name|array> setcolorspace -
-% <name|array> forcesetcolorspace -
-%
-% setcolorspace is initially placed in .cspace_util. It is copied to
-% level2dict by the Level 2 initialization code. The internal
-% setcolorspace operator is removed from systemdict as soon as this
-% procedure is defined.
-%
-% Because some jobs, in particular PDF jobs, repeatedly set the same
-% color space, this procedure will check if the operand and current
-% color spaces are the same. The check is absolute for parameterless
-% color spaces, conservative for others. For PostScript, this
-% optimization can only be employed if color space substitution is
-% disabled, as otherwise there is no way to account for possible changes
-% in the /Default* instances of the ColorSpace resource category. For PDF
-% jobs, resource category instances can only be changed at very specific
-% times (typically page boundaries), so the "operand color space is the
-% same as current color space" optimization may be used even if color
-% space substitution is in effect. The optimization is also highly
-% desirable in such cases, as it greatly improves performance.
-%
-% In certain situations, it is critical that a color space be set,
-% even if it is the same as the current color space. This is the case
-% when a CIEBased color space is used as a base or alternative color
-% space, due to some long-standing problems with the graphics libraries
-% handling of sampled information from the procedures in CIE color
-% spaces and the color rendering dictionary. The forcesetcolorspace
-% operator is provided for those situations.
-%
-% Note also that, if the current color space is not reset, at least
-% the current color must be reset to its default value.
-%
-% Another problem arises in the case of ICCBased color spaces. These
-% color spaces may be used to substitute for a DeviceGray/DeviceRGB/
-% DeviceCMYK color space, and may themselves require such a color
-% space as an alternate. Obviously, when this is the case the normal
-% setcolorspace mechanism would encounter and infinite loop if the
-% alternate colro space needed to be used. For this particular case,
-% the special _setcolorspace_nosub is provided, which suppresses
-% color space substitution. This routine does not bother to check if
-% the operand and current color space are the same.
+% Global, read-only, unpacked, array-form device color spaces
+% We need to return an array argument in response to currentcolorspace
+% even if the argument presented to setcolorspace was a simple device
+% space name. Not only that, but in order to satisfy some Adobe
+% applications, it must be the *same* array every time. The only way
+% to do that is to define an appropriate set initial arrays and always return
+% one of those. These arrays are defined here.
%
-/_setcolorspace
- {
- { % Early validation the argument. The code below fails in unpredictable ways
- % when it is exposed to the garbage.
- 1 index
- dup type dup /arraytype eq exch /packedarraytype eq or { 0 get } if
- dup type /nametype ne {
- //.cspace_util /setcolorspace get /typecheck signalerror
- } if
- //colorspacedict exch known not {
- //.cspace_util /setcolorspace get /undefined signalerror
- } if
-
- % See if the operand space is the same as the current space.
- % The test is intentionaly conservative to meet CET 09-06.
- 1 index % [/new] bool [/new]
- type /nametype eq
- { currentcolorspace 0 get % [/new] bool /old
- 2 index eq % [/new] bool bool
- }
- { currentcolorspace % [/new] bool [/old]
- 2 index eq % [/new] bool eq
- }
- ifelse
- and dup
- {
- %
- % If PDFfile is defined on the dictionary stack, this is a
- % PDF job. No additional check is required in this case (see
- % comment above).
- %
- /PDFfile where
- { pop }
- { .getuseciecolor not and } % check that UseCIEColor is off
- ifelse
- }
- if
- {
- % Some versions of PhotoShop generate documents
- % that place an extra value on the operand stack
- % and tintTransform replaces it - see bug 549307
- % for details. Also see the test case of bug 689263.
- % Here we use mark...cleartomark to restore the stack
- % to its normal state.
- mark
- true % An extra value for bogus Adobe tintTransform
- 3 -1 roll
- //.cs_get_default_color exec setcolor
- cleartomark
- }
- {
- //.cs_validate exec
- //.cs_substitute exec
- //.cs_prepare exec
- //.cs_install exec
- dup //make_array1 exec //setcolorspace
- mark %See comments above
- true
- 3 -1 roll
- //.cs_get_default_color exec setcolor
- cleartomark
- }
- ifelse
- }
- stopped
- { //.cspace_util /setcolorspace get $error /errorname get signalerror }
- if
- }
-bind def
-
-/_setcolorspace_nosub
- {
- {
- //.cs_validate exec
- dup
- //.cs_prepare exec
- //.cs_install exec
- //make_array1 exec //setcolorspace
- }
- stopped
- { //.cspace_util /setcolorspace get $error /errorname get signalerror }
- if
- }
-bind def
-
-/setcolorspace { //true //_setcolorspace exec } bind odef
-/forcesetcolorspace { //false //_setcolorspace exec } bind odef
+/DeviceGray_array /DeviceGray 1 array astore readonly def
+/DeviceRGB_array /DeviceRGB 1 array astore readonly def
+/DeviceCMYK_array /DeviceCMYK 1 array astore readonly def
%
% - initgraphics -
%
-% The initgraphics operator must be redefined create a real color space.
-% Previously this was unnecessary, as .currentcolorspace could return
-% an integer.
+% The internal routine gs_initgraphics doesn't (re)set the color space,
+% so we must redefine the operation to do it here.
%
%
/initgraphics
- { initgraphics //DeviceGray_array forcesetcolorspace }
-.bind systemdict begin odef end
-
-systemdict /setcolorspace .undef
-
-
-%
-% <gray> setgray -
-%
-% <r> <g> <b> setrgbcolor -
-%
-% <c> <m> <y> <b> setcmykcolor -
-%
-% The Level 1 color setting operators. setcmykcolor is created only if
-% setcolorscreen is present. These operators are always defined in
-% systemdict.
-%
-/setgray
- {
- { //DeviceGray_array //setcolorspace //setcolor }
- stopped
- { /setgray .systemvar $error /errorname get signalerror }
- if
- }
-bind systemdict begin odef end
-
-/setrgbcolor
- {
- { //DeviceRGB_array //setcolorspace //setcolor }
- stopped
- { /setrgbcolor .systemvar $error /errorname get signalerror }
- if
- }
-bind systemdict begin odef end
-
-/setcolorscreen where
- {
- pop
- /setcmykcolor
- {
- { //DeviceCMYK_array //setcolorspace //setcolor }
- stopped
- { /setcmykcolor .systemvar $error /errorname get signalerror }
- if
- }
- bind systemdict begin odef end
- }
-if
-
-
-%
-% - currentgray <gray>
-%
-% - currentrgbcolor <r> <g> <b>
-%
-% - currentcmykcolor <c> <m> <y> <k>
-%
-% Return the current color, mapped to a DeviceGray, DeviceRGB, or
-% DeviceCMYK color space. The latter is only created if setcolorscreen
-% is present.
-/currentgray
- { currentcolor currentcolorspace //.cs_get_currentgray exec }
-bind systemdict begin odef end
-
-/currentrgbcolor
- { currentcolor currentcolorspace //.cs_get_currentrgb exec }
-bind systemdict begin odef end
-
-/setcolorscreen where
- {
+ { initgraphics systemdict /DeviceGray_array get setcolorspace }
+.bind odef
+
+
+%
+% These routines used for the NOSUBSTDEVICECOLORS switch. This prevents
+% substitution of DeviceGray, DeviceRGB and DeviceCMYK with a Default*
+% colour space when /UseCIEColors is true. If the job includes a
+% definition of /DefaltGray, DefaultRGB or DefaultCMYK then it also executes
+% .includecolorspace to allow the device to record the substitute space.
+%
+/..page_default_spaces 3 dict def
+
+%
+% Used internally to retrieve any relevant default colour space.
+%
+% <Default space name> ..nosubstdevicetest false
+% <Default space name> [space] true
+%
+% If the boolean is true then the C code must set the additional colour space
+% and execute .includecolorspace before finally setting a DeviceGray space.
+%
+/..nosubstdevicetest
+{
+ false mark 3 -1 roll
+ % If we have already recorded this space, don't repeat it.
+ systemdict /..page_default_spaces get 1 index known {
+ cleartomark
+ } {
+ {
+ % Check to see if this space was defined by defineresource, if so then
+ % the job defined it, otherwise its the usual default, so ignore it.
+ dup /ColorSpace resourcestatus {
+ pop 0 eq {
+ % Default* defined by defineresource
+ systemdict /..page_default_spaces get 1 index //true put
+ dup /ColorSpace findresource 4 2 roll pop pop true
+ }{
+ cleartomark
+ } ifelse
+ }{
+ cleartomark
+ } ifelse
+ } stopped
+ {cleartomark}if
+ } ifelse
+}bind def
+
+%
+% <color_space_name> ..includecolorspace -
+%
+/..includecolorspace
+{
+ % If we have already recorded this space, don't repeat it.
+ systemdict /..page_default_spaces get 1 index known {
pop
- /currentcmykcolor
- { currentcolor currentcolorspace //.cs_get_currentcmyk exec }
- bind systemdict begin odef end
- }
-if
-
-
-
-%
-% Add some generically useful structures and procedures to .cspace_util.
-%
-
-%
-% Some common errors. The command for these errors will normally be
-% overwritten by the invoking operator. We cannot "load" the secolorspace
-% or setcolor operators, as they are not present in Level 1 systems.
-%
-/setcspace_typecheck
- { /setcolorspace cvx /typecheck signalerror }
-bind def
-
-/setcspace_rangecheck
- { /setcolorspace cvx /rangecheck signalerror }
-bind def
-
-/setcspace_invalidaccess
- { /setcolorspace cvx /invalidaccess signalerror }
-bind def
-
-/setcspace_undefined
- { /setcolorspace cvx /undefined signalerror }
-bind def
-
-/setcolor_typecheck
- { /setcolor cvx /typecheck signalerror }
-bind def
-
-/setcolor_invalidaccess
- { /setcolor cvx /invalidaccess signalerror }
-bind def
-
-
-%
-% <obj> check_array <obj>
-%
-% Check that an object is an array. Currently we don't check for
-% readability, as a failing get or length operator should generate
-% the appropriate invalidaccess error.
-/check_array
- {
- dup type dup /arraytype ne exch /packedarraytype ne and
- { /setcolorspace cvx /typecheck signalerror }
+ } {
+ mark exch
+ {
+ % Check to see if this space was defined by defineresource, if so then
+ % the job defined it, otherwise its the usual default, so ignore it.
+ dup /ColorSpace resourcestatus {
+ pop 0 eq {
+ % Job defined /Default*, so record it and allow the device access to it
+ systemdict /..page_default_spaces get 1 index //true put
+ gsave
+ { dup /ColorSpace findresource //setcolorspace exec .includecolorspace
+ } stopped pop
+ grestore
+ } if
+ } if
+ } stopped pop
+ cleartomark
+ } ifelse
+} bind def
+
+%
+% <color_space> <color_space_name> cs_substitute_generic <color_space1> <color_space2>
+%
+/cs_substitute_generic
+{ .getuseciecolor
+ {NOSUBSTDEVICECOLORS
+ { //..includecolorspace exec dup }
+ { /ColorSpace findresource }
+ ifelse
+ }
+ { pop dup }
+ ifelse
+}
+bind def
+
+%
+% <color_space> <color_space_name> cs_substitute_DeviceRGB_for_PDFX_or_PDFA <color_space1> <color_space2>
+%
+/cs_substitute_DeviceRGB_for_PDFX_or_PDFA
+{ systemdict /PDFX .knownget not { false } if
+ systemdict /PDFA .knownget not { false } if
+ or {
+ dup /ColorSpace resourcestatus {
+ pop pop
+ } {
+ (Error: Need a /DefaultRGB /ColorSpace resource for generating a PDF/X or PDF/A document.) =
+ /cs_substitute_DeviceRGB_for_PDFX_or_PDFA cvx /undefined signalerror
+ } ifelse
+ /ColorSpace findresource
+ } {
+ //cs_substitute_generic exec
+ } ifelse
+} bind def
+end
+
+%
+% used to convert the DataSource of an ICCBased colour space into a
+% file, if it isn't one already. This is required because the current
+% implementation of ICC spaces requires the data source to be a file.
+% This routine is *only* called from the PostScript interpreter when
+% setting an ICCBased space with a string data source.
+%
+/.convertICCSource
+{
+ % make DataSource a file
+ dup 1 get /DataSource get type /stringtype eq
+ {
+ % build all new structures in local VM
+ .currentglobal exch //false .setglobal
+
+ % check if we need to copy the color space and dictionary
+ 2 copy eq
+ {
+ dup length array copy
+ dup 1 2 copy get dup length dict copy put
+ }
if
- }
-bind def
-
-
-% pre-defined procedures for cs_ncomps and cs_get_range
-/ncomps_1 { pop 1 } bind def
-/ncomps_3 { pop 3 } bind def
-/ncomps_4 { pop 4 } bind def
-
-/dflt_range_4 [ 0 1 0 1 0 1 0 1 ] readonly def
-/dflt_range_3 dflt_range_4 0 6 getinterval def
-/dflt_range_1 dflt_range_4 0 2 getinterval def
-
-% <obj> get_range_[1|3|4] <range>
-/get_range_1 { pop //dflt_range_1 } bind def
-/get_range_3 { pop //dflt_range_3 } bind def
-/get_range_4 { pop //dflt_range_4 } bind def
-
-
-%
-% <c1> ... <cn> <name | array> <n>
-% check_num_stack
-% <c1> ... <cn> <array | array>
-%
-% <c1> <array> validate_color_1 <c1>
-% <c1> <c2> <c3> <arraY> validate_color_3 <c1> <c2> <c3>
-% <c1> <c2> <c3> <c4> <arraY> validate_color_4 <c1> <c2> <c3> <c4>
-%
-% check_num_stack verifies that the stack consists of a color space array and
-% n numbers. This is used by most of the cs_prepare_color procedures. The
-% validate_color_[1|3|4] procedures can be used as the cs_prepare_color
-% procedure for Device specific, CIEBased, and Indexed color spaces.
-%
-% Note that the pseudo-operator that (indirectly) invokes this routine will
-% handle resetting the stacks.
-%
-/check_num_stack
- { % c1 .. cn [] n
- 1 1 3 2 roll % c1 .. cn [] 1 1 n
- { index
- type dup /integertype ne exch /realtype ne and
- //setcolor_typecheck
- if
- }
- for
- } bind def
-
-% <c1> <array> validate_1 <c1>
-/validate_1 { 1 //check_num_stack exec pop } bind def
-
-% <c1> <c2> <c3> <array> validate_3 <c1> <c2> <c3>
-/validate_3 { 3 //check_num_stack exec pop } bind def
-
-% <c1> <c2> <c3> <c4> <array> validate_4 <c1> <c2> <c3> <c4>
-/validate_4 { 4 //check_num_stack exec pop } bind def
-
-
-%
-% <obj> pop_1 -
-%
-% This is a procedure form of pop. It may be used where a procedure is
-% expected, but the function of the procedure is the same as the pop
-% operator.
-/pop_1 { pop } bind def
-
-%
-% <obj> dup_1 <obj> <obj>
-%
-% An analog to pop_1, this one for dup.
-%
-/dup_1 { dup } bind def
-
-%
-% <obj1> ... <objn> <n> clear_n_objs -
-%
-% Clear n objects from the operand stack.
-%
-/clear_n_objs { //pop_1 repeat } bind def
-
-%
-% <obj1> ... <objn> <array> clear_setcolor_operands -
-%
-% Clear the setcolor operands for a color space.
-%
-/clear_setcolor_operands
- { //.cs_get_ncomps exec //clear_n_objs exec }
-bind def
-
-%
-% Return 1, 3, or 4 zeros. These routines are used primarily for the
-% CIEBased color spaces, for which currentgray and currentrgb
-% should return 0 for all components, and currentcmyk should return
-% 0 0 0 1.0 (this varies from Adobe's documentation but is consistent
-% with their impelementations).
-%
-/no_currentgray { //.cs_get_ncomps exec //clear_n_objs exec 0. } bind def
-/no_currentrgb { //.cs_get_ncomps exec //clear_n_objs exec 0. 0. 0. } bind def
-/no_currentcmyk { //.cs_get_ncomps exec //clear_n_objs exec 0. 0. 0. 1.} bind def
-
-
-%
-% <num> bound_0_1 <num>
-%
-% Bound a number to the range [0.0, 1.0]
-%
-/bound_0_1
- {
- dup 0 lt
- { pop 0.0 }
- {
- dup 1 gt
- { pop 1.0 }
- if
- }
- ifelse
- }
-bind def
+ % fetch DataSource, setting up stack for multiple puts
+ dup 1 2 copy get dup /DataSource 2 copy get
-%
-% Provide pseudo-operators for sethsbcolor and currenthsbcolor. These are
-% alternate versions of the setrgbcolor and currentrgbcolor operators, which
-% make use of a hue/staturation/brightness color description.
-%
+ % convert the string into a file
+ /ReusableStreamDecode filter
-%
-% <num_1> ... <num_n> n max_n <num>
-% <num_1> ... <num_n> n min_n <num>
-%
-% Find the maximum and minum of 3 color component intensities.
-%
-/max_n
- {
- 1 sub
- { 2 copy lt { exch } if pop }
- repeat
- }
-bind def
+ % put the file into the dictioary, the dictionary into the array
+ put put
-/min_n
- {
- 1 sub
- { 2 copy gt { exch } if pop }
- repeat
+ % restore the VM mode
+ exch .setglobal
}
-bind def
-
+ if
+} bind def
%
-% <r> <g> <b> .rgb_2_hsb <h> <s> <br>
-% <h> <s> <br> .hsb_2_rgb <r> <g> <b>
-%
-% Convert between RGB and HSB colors, using the hexcone approach (see
-% Rogers, David, "Procedureal Elements For Computer Graphics",
-% (McGraw-Hill, 1985), pp. 402 - 3).
-%
-% The rgb ==> hsb calculation is:
-%
-% br = max(r, g, b)
-%
-% if (br == 0)
-% h = 0, s = 0;
-% else {
-% v = min(r, g, b)
-% diff = br - v;
-% sat = diff / br;
-% if (r == br)
-% h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
-% else if (g == br)
-% h = 1/3 + (b - r) / (6 * diff);
-% else /* b == br */
-% h = 2/3 + (r - g) / (6 * diff);
-% }
-%
-% The hsb ==> rgb conversion is:
-%
-% mn = (1 - s) * br, md = 6 * s * br;
+% Set the initial device space
%
-% switch ((int)floor(6 * h)) {
-% case 0: /* r >= g >= b */
-% r = br;
-% g = mn + h * md;
-% b = mn;
-% break;
-%
-% case 1: /* g >= r >= b */
-% r = mn + md * (1/3 - h);
-% g = br;
-% b = mn;
-% break;
-%
-% case 2: /* g >= b >= r */
-% r = mn;
-% g = br;
-% b = mn + (h - 1/3) * md;
-% break;
-%
-% case 3: /* b >= g >= r */
-% r = mn;
-% g = mn + (2/3 - h) * md;
-% b = br;
-% break;
-%
-% case 4: /* b >= r >= g */
-% r = mn + (h - 2/3) * md;
-% g = mn;
-% b = br;
-% break;
-%
-% case 5: /* r >= b >= g */
-% r = br;
-% g = mn;
-% b = mn + (1 - h) * md;
-% break;
-%
-% case 6: /* We have wrapped around the hexcone. Thus this case is
-% the same as case 0 with h = 0 */
-% h = 0;
-% r = br;
-% g = mn + h * md = mn;
-% b = mn;
-% break;
-% }
-%
-
-
-% Define 1/3 and 2/3 accurately (don't use literals like 0.333333).
-/.f1_3 1.0 3 div def
-/.f2_3 2.0 3 div def
-
-/.rgb_2_hsb
- {
- % find the largest and smallest components
- 3 copy 3 //max_n exec dup 5 1 roll
- dup 0.0 eq
- { pop pop pop pop 0.0 0.0 }
- {
- 4 copy pop 3 //min_n exec 1 index exch sub
- dup 2 index div 7 1 roll
- dup 0.0 eq
- { 5 { pop } repeat 0.0 3 1 roll }
- {
- 6.0 mul 5 1 roll
- 2 copy eq % blue == brightness
- { pop pop sub exch div //.f2_3 add }
- {
- 2 index eq % green == brightness
- { exch pop exch sub exch div //.f1_3 add }
- {
- % red == brightness
- sub exch pop exch div
- dup 0.0 lt
- { 1.0 add }
- if
- }
- ifelse
- }
- ifelse
- 3 1 roll
- }
- ifelse
- }
- ifelse
- }
-bind def
-
-
-/.hsb_2_rgb
- {
- 3 { 0.0 max 1.0 min 3 1 roll } repeat % h s b
- 1.0 2 index sub 1 index mul % h s b (1-s)*b
- 3 -1 roll 2 index mul 6.0 mul % h b (1-s)*b 6*s*b
- 4 -1 roll % b (1-s)*b=nm 6*s*b=md h
-
- % array of procedures for the 7 hue cases
- {
- % 0 ==> r >= g >= b % b nm md h
- { mul 1 index add exch }
-
- % 1 ==> g >= r >= b
- { //.f1_3 exch sub mul 1 index add 3 1 roll }
-
- % 2 ==> g >= b >= r
- { //.f1_3 sub mul 1 index add 3 1 roll exch 3 -1 roll }
-
- % 3 ==> b >= g >= r
- { //.f2_3 exch sub mul 1 index add 3 -1 roll }
-
- % 4 ==> b >= r >= g
- { //.f2_3 sub mul 1 index add 3 1 roll exch }
-
- % 5 ==> r >= b >= g
- { 1.0 exch sub mul 1 index add }
-
- % 6 ==> r = br, g = b = mn
- % Case 6 is the same as case 0 with h = 0. This also simplifies
- % the calculations.
- { pop pop dup }
- }
- 1 index 6.0 mul cvi % b (1-s)*b 6*s*b h {} int(6*h)
- get exec
- }
-bind def
-
-
-%
-% <hue> <saturation> <brightness sethsbcolor -
-%
-% - currenthsbcolor <hue> <saturation> <brightness>
-%
-/sethsbcolor
- {
- { //.hsb_2_rgb exec setrgbcolor }
- stopped
- { /sethsbcolor .systemvar $error /errorname get signalerror }
- if
- }
-bind systemdict begin odef end
-
-/currenthsbcolor
- {
- { currentrgbcolor //.rgb_2_hsb exec }
- stopped
- { /currenthsbcolor .systemvar $error /errorname get signalerror }
- if
- }
-bind systemdict begin odef end
+systemdict /DeviceGray_array get setcolorspace
-currentdict /DeviceGray_array .undef
-currentdict /DeviceRGB_array .undef
-currentdict /DeviceCMYK_array .undef
-end % .cspace_util
.setglobal
diff --git a/gs/Resource/Init/gs_devcs.ps b/gs/Resource/Init/gs_devcs.ps
deleted file mode 100644
index 1d7557942..000000000
--- a/gs/Resource/Init/gs_devcs.ps
+++ /dev/null
@@ -1,250 +0,0 @@
-% Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Device-specific color space method dictionaries.
-
-%
-% This file implements the method dictionaries for the Device-specific
-% color spaces. See gs_cspace.ps for information.
-%
-% Note that, because these color spaces are parameter-less, no color
-% space validation is required: if we can get to the color space methods,
-% we know the color space is legitimate.
-%
-% The colorspace substitution routines for these color spaces
-% (cs_substitute) will fail in a Level 1 system, but this is not a
-% problem as .getuseciecolor will always return false for such systems.
-%
-.currentglobal true .setglobal
-.cspace_util begin
-
-%
-% <r> <g> <b> rgb_2_gray <gray>
-%
-% Convert RGB colors to gray. This includes a special check for
-% r == g == b, and avoids roundoff error if this is the case.
-%
-/rgb_2_gray
- {
- 3 copy 1 index eq 3 1 roll eq and
- { pop pop }
- { .11 mul exch .59 mul add exch .3 mul add }
- ifelse
- }
-bind def
-
-systemdict /..page_default_spaces 3 dict put
-
-% <color_space_name> ..includecolorspace -
-/..includecolorspace
-{ % Only includes ones explicitly defined by the document.
- systemdict /..page_default_spaces get 1 index known {
- pop
- } {
- mark exch
- { dup /ColorSpace resourcestatus {
- pop 0 eq {
- systemdict /..page_default_spaces get 1 index //true put
- gsave
- { dup /ColorSpace findresource //_setcolorspace_nosub exec .includecolorspace
- } stopped pop
- grestore
- } if
- } if
- } stopped pop
- cleartomark
- } ifelse
-} bind def
-
-% <color_space> <color_space_name> cs_substitute_generic <color_space1> <color_space2>
-/cs_substitute_generic
-{ .getuseciecolor
- { NOSUBSTDEVICECOLORS
- { //..includecolorspace exec dup }
- { /ColorSpace findresource }
- ifelse
- }
- { pop dup }
- ifelse
-}
-bind def
-
-% <color_space> <color_space_name> cs_substitute_DeviceRGB_for_PDFX_or_PDFA <color_space1> <color_space2>
-/cs_substitute_DeviceRGB_for_PDFX_or_PDFA
-{ systemdict /PDFX .knownget not { false } if
- systemdict /PDFA .knownget not { false } if
- or {
- dup /ColorSpace resourcestatus {
- pop pop
- } {
- (Error: Need a /DefaultRGB /ColorSpace resource for generating a PDF/X or PDF/A document.) =
- /cs_substitute_DeviceRGB_for_PDFX_or_PDFA cvx /undefined signalerror
- } ifelse
- /ColorSpace findresource
- } {
- //cs_substitute_generic exec
- } ifelse
-} bind def
-
-colorspacedict
-
-dup
-/DeviceGray
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_1
- /cs_get_range //get_range_1
- /cs_get_default_color { pop 0.0 } bind
- /cs_get_currentgray //pop_1
- /cs_get_currentrgb { pop dup dup } bind
- /cs_get_currentcmyk { pop 1.0 exch sub 0.0 0.0 0.0 4 -1 roll } bind
- /cs_validate {}
-
- /cs_substitute
- { /DefaultGray //cs_substitute_generic exec
- }
- bind
-
- /cs_prepare {}
- /cs_install { pop 0 .setdevcspace } bind
- /cs_prepare_color //validate_1
- /cs_complete_setcolor //pop_1
- .dicttomark
-put
-
-
-/DeviceRGB
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_3
- /cs_get_range //get_range_3
- /cs_get_default_color { pop 0.0 0.0 0.0 } bind
- /cs_get_currentgray { pop //rgb_2_gray exec } bind
- /cs_get_currentrgb //pop_1
-
- % to convert to cmyk use blackgeneration and undercolorremoval
- /cs_get_currentcmyk
- {
- pop
-
- % convert to subtractive (CMY) color space
- 3
- { 1.0 exch sub 3 1 roll }
- repeat
-
- % find the minimum (initial k component)
- 3 copy
- 2
- {
- 2 copy gt
- { exch }
- if
- pop
- }
- repeat
-
- % apply undercolorremoval
- dup 5 1 roll currentundercolorremoval exec cvr 4 1 roll
- 3
- { 3 index sub //bound_0_1 exec 3 1 roll }
- repeat
-
- % apply blackgeneration
- 5 3 roll pop currentblackgeneration exec cvr //bound_0_1 exec
- }
- bind
-
- /cs_validate {}
-
- /cs_substitute
- { /DefaultRGB //cs_substitute_DeviceRGB_for_PDFX_or_PDFA exec
- }
- bind
-
- /cs_prepare {}
- /cs_install { pop 1 .setdevcspace } bind
- /cs_prepare_color //validate_3
- /cs_complete_setcolor //pop_1
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
-
-
-% Only create the DeviceCMYK color space if setcolorscreen is present
-/setcolorscreen where
- { pop }
- { currentfile closefile }
-ifelse
-
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-colorspacedict
-/DeviceCMYK
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_4
- /cs_get_range //get_range_4
- /cs_get_default_color { pop 0.0 0.0 0.0 1.0 } bind
-
- /cs_get_currentgray
- { pop 4 1 roll //rgb_2_gray exec add 1.0 exch sub //bound_0_1 exec }
- bind
-
- /cs_get_currentrgb
- {
- pop
- 4 1 roll 3
- { 3 index add 1.0 exch sub //bound_0_1 exec 3 1 roll }
- repeat
- 4 -1 roll pop
- }
- bind
-
- /cs_get_currentcmyk //pop_1
-
- /cs_validate {}
-
- /cs_substitute
- { /DefaultCMYK //cs_substitute_generic exec
- }
- bind
-
- /cs_prepare {}
- /cs_install { pop 2 .setdevcspace } bind
- /cs_prepare_color //validate_4
- /cs_complete_setcolor //pop_1
- .dicttomark
-put
-
-currentdict /..includecolorspace .undef
-currentdict /cs_substitute_generic .undef
-
-end % .cspace_util
-.setglobal
-
diff --git a/gs/Resource/Init/gs_devn.ps b/gs/Resource/Init/gs_devn.ps
deleted file mode 100644
index 5b679aedd..000000000
--- a/gs/Resource/Init/gs_devn.ps
+++ /dev/null
@@ -1,218 +0,0 @@
-% Copyright (C) 2001, 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% DeviceN color space method dictionary; this depends on gs_sepr.ps
-
-
-% verify that DeviceN and Separation color spaces are supported
-/.setdevicenspace where
- {
- pop
- /.setseparationspace where
- { pop //false }
- { //true }
- ifelse
- }
- { //true }
-ifelse
- { currentfile closefile }
-if
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-
-%
-% <c1> ... <cm> <array> apply_devn_tint_xform <c1>' ... <cn>' <array>
-%
-% Apply the tint transformation for the DeviceN color intensity values.
-/apply_devn_tint_xform
- {
- dup 1 get length 1 add exch
- mark 2 index 2 add 2 roll
- index 3 get exec
- counttomark 2 add -2 roll pop
- }
-bind def
-
-
-
-colorspacedict
-/DeviceN
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate false
- /cs_potential_icc_alternate false
- /cs_get_ncomps { 1 get length } bind
- /cs_get_range { 1 get length [ exch { 0 1 } repeat ] } bind
- /cs_get_default_color { 1 get length { 1 } repeat } bind
-
- /cs_get_currentgray
- { //apply_devn_tint_xform exec 2 get //.cs_get_currentgray exec }
- bind
- /cs_get_currentrgb
- { //apply_devn_tint_xform exec 2 get //.cs_get_currentrgb exec }
- bind
- /cs_get_currentcmyk
- { //apply_devn_tint_xform exec 2 get //.cs_get_currentcmyk exec }
- bind
-
- % a lot of validation is done by the cs_validate method
- /cs_validate
- {
- //check_array exec
- dup 1 get //check_array exec
- {
- type dup /nametype ne exch /stringtype ne and
- //setcspace_typecheck
- if
- }
- forall
- dup 2 get //.cs_validate exec //.cs_potential_alternate exec not
- //setcspace_rangecheck
- if
- dup 3 get //check_array exec xcheck not
- //setcspace_typecheck
- if
- }
- bind
-
- % substitute the base space if appropriate
- /cs_substitute
- {
- dup 2 get //.cs_substitute exec 2 copy eq
- { pop pop dup }
- {
- % retain only the new alternate space
- exch pop
-
- % build all new structures in local VM
- .currentglobal 3 1 roll //false .setglobal
-
- % construct a new array and insert the new base color space
- 1 index dup length array copy dup 2 4 -1 roll put
-
- % restore VM mode
- 3 -1 roll .setglobal
- }
- ifelse
- }
- bind
-
- %
- % The Ghostscript interpreter works better when tinttransform procedures
- % are translated into functions. Attempt to do that here.
- %
- /cs_prepare //converttinttransform
-
- %
- % Install the current color space.
- %
- % The current Ghostscript color space implementation requires that
- % color spaces that provide a base or alternative color space set
- % that base/alternative color space to be the current color space
- % before attempting to set the original color space.
- %
- % Beginning with Acrobat 5, PDF apparently supports 1-component
- % DeviceN color spaces with the single component "All" (the "PDF
- % Reference", 3rd ed., p. 206 still describes this as illegal).
- % We translate such calls to Separation color spaces.
- %
- /cs_install
- {
- % save the current color space
- currentcolorspace
-
- % set the base color space as the current color space
- 1 index 2 get //forcesetcolorspace
-
- % set the indexed color space; restore the earlier space on error
- mark 2 index
- dup 1 get dup length 1 eq exch 0 get /All eq and
- {
- dup length array copy
- dup 0 /Separation put
- dup 1 /All put
- { .setseparationspace }
- } {
- {
- dup .setdevicenspace
- % Check if the DeviceN color space includes an 'attributes'
- % dict with a Colorants dict. If present then we want to
- % attach the separation colorspace in the Colorants dict to
- % the DeviceN color space description within the graphics
- % library. To do this we are creating a temp gstate, building
- % each of the Colorants color spaces in the temp gstate and
- % then attaching the temp color space to the DeviceN color
- % space. This round about procedure is done to create
- % descriptions of the Colorants color spaces which are
- % equivalent to any other color space (i.e. with color space
- % substitution performed on the alternate color space and the
- % tint transform function sampled).
- dup length 4 gt {
- dup 4 get /Colorants .knownget {
- { gsave
- { % Ignore any problems with the Colorants color spaces
- //forcesetcolorspace .attachdevicenattributespace
- } stopped pop
- grestore
- } forall
- } if
- } if
- pop
- }
- }
- ifelse
- stopped
- { cleartomark setcolorspace stop }
- { pop pop pop }
- ifelse
- }
- bind
-
- /cs_prepare_color { dup 1 get length //check_num_stack exec pop } bind
-
- %
- % If a DeviceN color space is not supported in native mode by
- % the current process color model, Adobe implementations will always
- % execute the tint transform procedure when setcolor is invoked.
- % Ghostscript may have turned this transform into a sampled function,
- % and even if this is not the case, will have sampled the transform
- % when the color space is first set. Some applications depend on
- % the Adobe behavior, so we implement it via the cs_complete_setcolor
- % method.
- %
- /cs_complete_setcolor
- {
- .usealternate
- {
- pop
- currentcolor
- currentcolorspace 3 get exec
- currentcolorspace 2 get
- //clear_setcolor_operands exec
- }
- { pop }
- ifelse
- }
- bind
-
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_devpxl.ps b/gs/Resource/Init/gs_devpxl.ps
deleted file mode 100644
index 0bc0cee12..000000000
--- a/gs/Resource/Init/gs_devpxl.ps
+++ /dev/null
@@ -1,78 +0,0 @@
-% Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% DevicePixel color space method dictionaries.
-
-%
-% This file implements the DevicePixel color space. See gs_cspace.ps
-% for information.
-%
-% The DevicePixel color space includes a single parameter, the bit
-% depth of the device color representation. Color is expressed as
-% single integers in an opaque, device-specific format.
-%
-
-% verify that the DevicePixel color space is supported
-/.setdevicepixelspace where
- { pop }
- { currentfile closefile }
-ifelse
-
-
-.currentglobal true .setglobal
-
-.cspace_util begin
-
-
-colorspacedict
-/DevicePixel
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate true
- /cs_get_ncomps //ncomps_1
- /cs_get_range { [ exch 1 get 1 exch bitshift 1 sub ] } bind
- /cs_get_default_color { pop 0 } bind % no good default
- /cs_get_currentgray //no_currentgray
- /cs_get_currentrgb //no_currentrgb
- /cs_get_currentcmyk //no_currentcmyk
-
- /cs_validate
- {
- //check_array exec
- dup 1 get dup type /integertype ne
- //setcspace_typecheck
- if
- dup 0 lt
- //setcspace_rangecheck
- if
- 31 gt % 31 bits is an implementation limit
- { /setcolorspace .systemvar /limitcheck signalerror }
- if
- }
- bind
-
- /cs_substitute //dup_1
- /cs_prepare {}
- /cs_install { .setdevicepixelspace } bind
- /cs_prepare_color //validate_1
- /cs_complete_setcolor //pop_1
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_icc.ps b/gs/Resource/Init/gs_icc.ps
index 28d345e8a..c179ea9ed 100644
--- a/gs/Resource/Init/gs_icc.ps
+++ b/gs/Resource/Init/gs_icc.ps
@@ -17,262 +17,15 @@
% ICCBased color space method dictionaries.
% This assumes gs_ciecs2.ps has already been processed.
-%
-% Note that the substitution procedure in this routine will dynamically
-% check for support of ICCBased color space. If such support is not
-% provided, the alternative color space will be used.
-%
-% The validation routine in dictionary (cs_validate) performs a more
-% extensive validation than is done for other color spaces, because
-% .seticcspace does less checking than most other color space setting
-% operators.
-%
-
-
.currentglobal true .setglobal
-.cspace_util begin
+% gs_res.ps uses these entries in colorspacedict
+% to populate the ColorSpaceFamily resource, so we need
+% to add the supported spaces.
%
-% A dictionary for mapping the number of components of an ICCBased color
-% space to the appropriate alternative color space. This is used only
-% if an alternative color space is not specifically provided.
-%
-/icc_comp_map_dict
- mark 1 /DeviceGray 3 /DeviceRGB 4 /DeviceCMYK .dicttomark
-def
-
-%
-% <array1> get_icc_alternative_space <name | array2>
-%
-% Get the alternative color space for an ICCBased color space.
-%
-/get_icc_alternative_space
- {
- 1 get dup /Alternate .knownget
- { exch pop }
- { /N get //icc_comp_map_dict exch get }
- ifelse
- }
-bind def
-
-
-colorspacedict
-/ICCBased
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate true
- /cs_potential_icc_alternate false
- /cs_get_ncomps { 1 get /N get } bind
-
- /cs_get_range
- {
- 1 get dup /Range .knownget
- { exch pop }
- { /N get 2 mul //dflt_range_4 exch 0 exch getinterval }
- ifelse
- }
- bind
-
- /cs_get_default_color { 1 get /N get { 0 } repeat } bind
-
- %
- % For generating a gray, RGB, or CMYK equivalent color, we will
- % assume that the alternative color space provides reasonable
- % mapping.
- /cs_get_currentgray
- { //get_icc_alternative_space exec //.cs_get_currentgray exec }
- bind
- /cs_get_currentrgb
- { //get_icc_alternative_space exec //.cs_get_currentrgb exec }
- bind
- /cs_get_currentcmyk
- { //get_icc_alternative_space exec //.cs_get_currentcmyk exec }
- bind
-
- % a lot of validation is done by the cs_validate method
- /cs_validate
- {
- //check_cie_cspace exec
- dup 1 get
- dup /N get
- dup type /integertype ne
- //setcspace_typecheck
- if
- //icc_comp_map_dict exch known not
- //setcspace_rangecheck
- if
- dup /DataSource get
- dup type dup /stringtype ne exch /filetype ne and
- //setcspace_typecheck
- if
- rcheck not
- //setcspace_invalidaccess
- if
- dup /Range .knownget
- {
- //check_array exec
- {
- type dup /integertype ne exch /realtype ne and
- //setcspace_typecheck
- if
- }
- forall
- }
- if
- /Alternate .knownget
- {
- //.cs_validate exec
- dup //.cs_potential_icc_alternate exec not
- {
- 0 get /ICCBased ne
- //setcspace_rangecheck
- if
- }
- { pop }
- ifelse
- }
- if
- }
- bind
-
- % substitute the Alternate space, if appropriate
- /cs_substitute
- {
- %
- % A design problem in the Ghostscript graphic library color
- % space code prevents an ICCBased color space from having an
- % ICCBased alternative color space. This situation actually
- % arises fairly frequently in PDF, as an ICCBased color space
- % is used as the substitute color for a Device{Gray|RGB|CMYK}
- % color space, which in turn are used as the alternative color
- % space to another (or possibly even the same) ICCBased color
- % space.
- %
- % This situation causes no fundamental problems, as
- % Ghostscript nominally supports ICCBased color spaces, so the
- % Alternate color space is not used. Where this is not true
- % (primarily because the NOCIE option is selected), the code
- % would (except for the design flaw noted above) select the
- % Alternate of the Alternate color space.
- %
- % The code below works around this problem by suprressing
- % color space substitution for alternative color spaces if
- % the substituting space is an ICCBased color space.
- %
- dup //get_icc_alternative_space exec
- //.cs_substitute exec
- 2 copy eq
- 1 index //.cs_potential_icc_alternate exec not
- or
- { pop pop dup }
- {
- % retain just the new Alternate space
- exch pop
-
- % build all new structures in local VM
- .currentglobal 3 1 roll //false .setglobal
-
- % copy the original ICCBased color space array
- 1 index dup length array copy
-
- % copy the ICCBased dictionary
- dup 1 2 copy get dup length dict copy
-
- % insert the new alterante color space
- dup /Alternate 7 -1 roll put
-
- % insert the new dictionary into the arra
- put
-
- % restore the VM mode
- 3 -1 roll .setglobal
- }
- ifelse
- }
- bind
-
- %
- % The current implementation of ICCBased color spaces requires the
- % DataSource to be a file.
- %
- /cs_prepare
- {
- % make DataSource a file
- dup 1 get /DataSource get type /stringtype eq
- {
- % build all new structures in local VM
- .currentglobal exch //false .setglobal
-
- % check if we need to copy the color space and dictionary
- 2 copy eq
- {
- dup length array copy
- dup 1 2 copy get dup length dict copy put
- }
- if
-
- % fetch DataSource, setting up stack for multiple puts
- dup 1 2 copy get dup /DataSource 2 copy get
-
- % convert the string into a file
- /ReusableStreamDecode filter
-
- % put the file into the dictioary, the dictionary into the array
- put put
-
- % restore the VM mode
- exch .setglobal
- }
- if
- }
- bind
-
- %
- % Install the current color space.
- %
- % The current Ghostscript color space implementation requires that
- % color spaces that provide a base or alternative color space set
- % that base/alternative color space to be the current color space
- % before attempting to set the original color space. This can cause
- % difficulty if an ICCBased color space is being used as a substitute
- % color space for a device-specific color space, and uses that same
- % device-specific color space as an alternative space. For this
- % reason, a special _setcolorspace_nosub operator is provided.
- %
- /cs_install
- {
- % set the alternative color space to be the current color space
- dup //get_icc_alternative_space exec //_setcolorspace_nosub exec
-
- % check for native support
- /.seticcspace where
- { pop //false }
- { //true }
- ifelse
- NOCIE or
- //pop_1 % do nothing
- {
- % Acrobat Reader silently ignores errors with ICC profiles
- % and uses the alternate color space -- do the same.
- mark exch 1 get
- { .seticcspace }
- .internalstopped
- cleartomark
- }
- ifelse
- }
- bind
-
- % for now, the alternative spaces for an ICCBased color space do
- % not require special preparation
- /cs_prepare_color { dup 1 get /N get //check_num_stack exec pop } bind
- /cs_complete_setcolor //pop_1
-
- .dicttomark
-put
-
-end % .cspace_util
+systemdict /colorspacedict get begin
+/ICCBased [] def
+end
NOPSICC { (%END PSICC) .skipeof } if
% Now set up ICC profile loading for PostScript %%BeginICCProfile sections.
diff --git a/gs/Resource/Init/gs_indxd.ps b/gs/Resource/Init/gs_indxd.ps
deleted file mode 100644
index 5b93532e4..000000000
--- a/gs/Resource/Init/gs_indxd.ps
+++ /dev/null
@@ -1,205 +0,0 @@
-% Copyright (C) 2001, 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Indexed color space method dictionary
-
-
-% verify that Indexed color spaces are supported
-/.setindexedspace where
- { pop }
- { currentfile closefile }
-ifelse
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-%
-% <num> <array> restrict_index <int> <array>
-%
-% Restrict the operand to setcolor for an Indexed color space to be an
-% integer in the applicable range.
-%
-/restrict_index
- {
- exch round cvi
- dup 0 lt
- { pop 0 }
- {
- 1 index 2 get 2 copy gt
- { exch }
- if
- pop
- }
- ifelse
- exch
- }
-bind def
-
-%
-% <num> <array> get_indexed_base_color <c1> ... <cn> <array>
-%
-% Get the base color corresponding to an indexed color value.
-%
-/get_indexed_base_color
- {
- % just in case, set the index into the appropriate range
- //restrict_index exec
-
- % lookup in the string or use the lookup proc
- mark 1 index 3 get dup type /stringtype eq
- {
- 2 index 1 get //.cs_get_ncomps exec dup 6 -1 roll mul exch getinterval
- { 255 div }
- forall
- }
- { 4 -1 roll exch exec }
- ifelse
- counttomark 2 add -2 roll pop
- }
-bind def
-
-
-colorspacedict
-/Indexed
- mark
- /cs_potential_indexed_base false
- /cs_potential_pattern_base true
- /cs_potential_alternate false
- /cs_potential_icc_alternate false
- /cs_get_ncomps //ncomps_1
- /cs_get_range { 0 exch 2 get 2 array astore } bind
- /cs_get_default_color { pop 0 } bind
-
- /cs_get_currentgray
- { //get_indexed_base_color exec 1 get //.cs_get_currentgray exec }
- bind
- /cs_get_currentrgb
- { //get_indexed_base_color exec 1 get //.cs_get_currentrgb exec }
- bind
- /cs_get_currentcmyk
- { //get_indexed_base_color exec 1 get //.cs_get_currentcmyk exec }
- bind
-
- % a lot of validation is done by the cs_validate method
- /cs_validate
- {
- //check_array exec
- dup 1 get //.cs_validate exec //.cs_potential_indexed_base exec not
- //setcspace_rangecheck
- if
- dup 2 get dup type /integertype ne
- //setcspace_typecheck
- {
- dup 0 lt exch 4095 gt or
- //setcspace_rangecheck
- if
- }
- ifelse
- dup 3 get dup type /stringtype eq
- {
- length
- 1 index dup 2 get 1 add exch 1 get //.cs_get_ncomps exec mul
- lt
- //setcspace_rangecheck
- if
- }
- {
- //check_array exec xcheck not
- //setcspace_typecheck
- if
- }
- ifelse
- }
- bind
-
- % substitute the base space if appropriate
- /cs_substitute
- {
- dup 1 get //.cs_substitute exec 2 copy eq
- { pop pop dup }
- {
- % retain only the new base space
- exch pop
-
- % build all new structures in local VM
- .currentglobal 3 1 roll //false .setglobal
-
- % construct a new array and insert the new base color space
- 1 index dup length array copy dup 1 4 -1 roll put
-
- % restore VM mode
- 3 -1 roll .setglobal
- }
- ifelse
- }
- bind
-
- /cs_prepare {}
-
- %
- % Install the current color space. Note that the alternative color
- % space will already have been set as the current color space.
- %
- % The current Ghostscript color space implementation requires that
- % color spaces that provide a base or alternative color space set
- % that base/alternative color space to be the current color space
- % before attempting to set the original color space.
- %
- /cs_install
- {
- % save the current color space
- currentcolorspace
-
- % set the base color space as the current color space
- 1 index 1 get //forcesetcolorspace
-
- % set the indexed color space; restore the earlier space on error
- mark 2 index
- { .setindexedspace }
- stopped
- { cleartomark setcolorspace stop }
- { pop pop pop }
- ifelse
- }
- bind
-
- % Adobe implementations accept floating point values
- /cs_prepare_color { //validate_1 exec cvi } bind
-
- %
- % Adobe implementations always execute a lookup procedure when setcolor
- % is invoked. Ghostscript samples the lookup procedure when
- % setcolorspace is invoked, and then does not access it again. In the
- % unlikely event that an application depends on the Adobe-specific
- % behavior, it is replicated in this method.
- %
- /cs_complete_setcolor
- {
- 3 get dup type /stringtype eq
- { pop }
- {
- currentcolor exch exec
- currentcolorspace 1 get //clear_setcolor_operands exec
- }
- ifelse
- }
- bind
-
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_init.ps b/gs/Resource/Init/gs_init.ps
index 6c76f5b8b..88041f46e 100644
--- a/gs/Resource/Init/gs_init.ps
+++ b/gs/Resource/Init/gs_init.ps
@@ -666,7 +666,7 @@ systemdict /internaldict dup .makeinternaldict .makeoperator
{ 0 1 count 3 sub { index === } for } bind def
/runlibfile
{ % We don't want to bind 'run' into this procedure,
- % since run may get redefined.
+ % since run may get redefined.
findlibfile
{ exch pop /run .systemvar exec }
{ /undefinedfilename signalerror }
@@ -732,7 +732,7 @@ userdict /.currentresourcefile //null put
{ stop } if
} bind def
/.runresource { % <file> .runresource -
- { //run } .execasresource % immediately bind run to ignore redefinitions
+ { /run .systemvar exec } .execasresource
} bind def
% Define procedures for getting and setting the current device resolution.
@@ -1534,10 +1534,6 @@ setpacking
(END BASIC COLOR) VMDEBUG
-%% Replace 1 (gs_devcs.ps)
-(gs_devcs.ps) runlibfile
-
-(END LEVEL 1 COLOR) VMDEBUG
% Load image support
%% Replace 1 (gs_img.ps)
diff --git a/gs/Resource/Init/gs_lev2.ps b/gs/Resource/Init/gs_lev2.ps
index 4509ad242..1f143bf78 100644
--- a/gs/Resource/Init/gs_lev2.ps
+++ b/gs/Resource/Init/gs_lev2.ps
@@ -680,29 +680,18 @@ currentdict end
} odef
% ------ Color spaces ------ %
-
-% Move setcolorspace, setcolor, and colorspacedict to level2dict
-level2dict /setcolorspace .cspace_util 1 index get put
-level2dict /setcolor .cspace_util 1 index get put
-level2dict /colorspacedict .cspace_util 1 index get put
-
-% Add the level 2 color spaces
-% DevicePixel is actually a LanguageLevel 3 feature; it is here for
-% historical reasons.
-%% Replace 1 (gs_devpxl.ps)
-(gs_devpxl.ps) runlibfile
-
-%% Replace 1 (gs_ciecs2.ps)
-(gs_ciecs2.ps) runlibfile
-
-%% Replace 1 (gs_indxd.ps)
-(gs_indxd.ps) runlibfile
-
-%% Replace 1 (gs_sepr.ps)
-(gs_sepr.ps) runlibfile
-
-%% Replace 1 (gs_patrn.ps)
-(gs_patrn.ps) runlibfile
+% gs_res.ps uses these entries in colorspacedict
+% to populate the ColorSpaceFamily resource, so we need
+% to add the supported spaces.
+%
+systemdict /colorspacedict get begin
+/CIEBasedA [] def
+/CIEBasedABC [] def
+/DevicePixel [] def
+/Indexed [] def
+/Pattern [] def
+/Separation [] def
+end
diff --git a/gs/Resource/Init/gs_ll3.ps b/gs/Resource/Init/gs_ll3.ps
index dba186eb1..b6c71e5ef 100644
--- a/gs/Resource/Init/gs_ll3.ps
+++ b/gs/Resource/Init/gs_ll3.ps
@@ -329,12 +329,15 @@ systemdict /.reuseparamdict undef
0.02 setsmoothness
% ------ DeviceN color space ------ %
-
-%% Replace 1 (gs_ciecs3.ps)
-(gs_ciecs3.ps) runlibfile
-
-%% Replace 1 (gs_devn.ps)
-(gs_devn.ps) runlibfile
+% gs_res.ps uses these entries in colorspacedict
+% to populate the ColorSpaceFamily resource, so we need
+% to add the supported spaces.
+%
+systemdict /colorspacedict get begin
+/CIEBasedDEF [] def
+/CIEBasedDEFG [] def
+/DeviceN [] def
+end
% ------ Miscellaneous ------ %
diff --git a/gs/Resource/Init/gs_patrn.ps b/gs/Resource/Init/gs_patrn.ps
deleted file mode 100644
index d41f25573..000000000
--- a/gs/Resource/Init/gs_patrn.ps
+++ /dev/null
@@ -1,309 +0,0 @@
-% Copyright (C) 2001, 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Pattern color space method dictionary.
-
-
-% verify that Pattern color spaces are supported
-/.setpatternspace where
- { pop }
- { currentfile closefile }
-ifelse
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-%
-% <name1 | array1> get_pattern_base_cspace <null | name2 | array2>
-%
-% If the Pattern color space has a base color space, push that base
-% color space onto the stack. Otherwise, push a null object.
-%
-/get_pattern_base_cspace
- {
- dup type /nametype eq
- { pop //null }
- {
- dup length 1 gt
- { 1 get }
- { pop //null }
- ifelse
- }
- ifelse
- }
-bind def
-
-
-%
-% <dict> has_base_color <bool>
-%
-% Determine if a Pattern "color" includes a base color. This is the case
-% if the pattern dictionary has PatternType 1 and PaintType 2.
-%
-/has_base_color
- {
- dup //null eq
- { pop //false }
- {
- dup /PatternType get 1 eq
- { /PaintType get 2 eq }
- { pop //false }
- ifelse
- }
- ifelse
- }
-bind def
-
-%
-% <c1> ... <cn> <pattern_dict> <pattern_cspace>
-% get_pattern_base_color
-% <c1> ... <cn> <base_cspace> true
-% or
-% <?c1?> ... <?cn?> <dict> <pattern>
-% get_pattern_base_color
-% false
-%
-% If a pattern dictionary has a base color, set up that base color and
-% color space, and push true. Otherwise, just push false. It is assumed
-% that if the pattern includes a base color, the Pattern color space
-% has a base color space.
-%
-/get_pattern_base_color
- {
- exch //has_base_color exec
- { 1 get //true }
- { pop //false }
- ifelse
- }
-bind def
-
-
-colorspacedict
-/Pattern
- mark
- /cs_potential_indexed_base false
- /cs_potential_pattern_base false
- /cs_potential_alternate false
- /cs_potential_icc_alternate false
-
- %
- % We employ the same convention for describing the number of
- % components in a Pattern color space as is used by the graphic
- % library. For pattern spaces with no underlying color space,
- % the result is -1. If a Pattern space has an underlying color
- % space with n components, the result is -(n + 1).
- %
- /cs_get_ncomps
- {
- //get_pattern_base_cspace exec dup //null eq
- { pop 0 }
- //.cs_get_ncomps
- ifelse
- 1 add neg
- }
- bind
-
- % there is no "range" for a Pattern color space
- /cs_get_range { {} cvlit } bind
-
- /cs_get_default_color { pop //null } bind
-
- /cs_get_currentgray
- {
- //get_pattern_base_color exec
- //.cs_get_currentgray
- { 0. }
- ifelse
- }
- bind
-
- /cs_get_currentrgb
- {
- //get_pattern_base_color exec
- //.cs_get_currentrgb
- { 0. 0. 0. }
- ifelse
- }
- bind
-
- /cs_get_currentcmyk
- {
- //get_pattern_base_color exec
- //.cs_get_currentcmyk
- { 0. 0. 0. 1. }
- ifelse
- }
- bind
-
- /cs_validate
- {
- dup //get_pattern_base_cspace exec dup //null eq
- { pop }
- {
- //.cs_validate exec //.cs_potential_pattern_base exec not
- //setcspace_rangecheck
- if
- }
- ifelse
- }
- bind
-
- % substitute the base space if appropriate
- /cs_substitute
- {
- dup //get_pattern_base_cspace exec dup //null eq
- { pop dup }
- {
- //.cs_substitute exec 2 copy eq
- { pop pop dup }
- {
- % retain only the new alternate space
- exch pop
-
- % build all new structures in local VM
- .currentglobal 3 1 roll //false .setglobal
-
- % construct a new array and insert the new base color space
- 1 index dup length array copy dup 1 4 -1 roll put
-
- % restore VM mode
- 3 -1 roll .setglobal
- }
- ifelse
- }
- ifelse
- }
- bind
-
- /cs_prepare {}
-
- %
- % Install the current color space.
- %
- % The current Ghostscript color space implementation requires that
- % color spaces that provide a base or alternative color space set
- % that base/alternative color space to be the current color space
- % before attempting to set the original color space.
- %
- % In principle, the only errors that are possible for .setpatternspace
- % (given that setcolorspace itself is legal) are limitcheck and/or
- % VMerror. The Ghostscript implementation allows a few others, so
- % we go through the full code to restore the current color space in
- % the event of an error.
- %
- /cs_install
- {
- dup //get_pattern_base_cspace exec dup //null eq
- {
- pop
- dup type /nametype eq
- { pop { /Pattern } cvlit }
- if
- .setpatternspace
- }
- {
- % save the current color space
- currentcolorspace
-
- % set the base color space as the current color space
- exch //forcesetcolorspace
-
- % set the pattern color space; restore the earlier space on error
- mark 2 index
- { .setpatternspace }
- stopped
- { cleartomark setcolorspace stop }
- { pop pop pop }
- ifelse
- }
- ifelse
- }
- bind
-
-
- %
- % Pattern dictionaries generated by makepattern will include an
- % Implementation entry whose value is an internal data structure.
- % Such structures are given executable type names that match their
- % internal structure names. The names used for pattern
- % implementations are gs_pattern1_instance_t and
- % gs_pattern2_instance_t. It is unfortunate to have to expose such
- % internal names at this level, but not easily avoided.
- % For CPSI/CET compatibility we 'hide' this inside an array
- %
- /cs_prepare_color
- {
- % verify that the topmost operand is a pattern dictionary
- 1 index dup type /dicttype ne
- {
- //null ne
- //setcspace_typecheck
- if
- pop
- }
- {
- dup /Implementation .knownget
- { 0 get type dup dup
- /gs_pattern1_instance_t ne exch /gs_pattern2_instance_t ne and
- exch xcheck not
- or
- //setcspace_typecheck
- if
- }
- //setcspace_typecheck
- ifelse
-
- % check if base color space operands are present
- dup /PatternType get 1 eq
- {
- /PaintType get 2 eq
- {
- % verify that a base color space exists
- //get_pattern_base_cspace exec dup //null eq
- //setcspace_rangecheck
- if
- //.cs_get_ncomps exec
- % We cannot use check_num_stack since it does not
- % properly clean the stack. The CET test 09-47n.ps has
- % a very bad test case with a faulty setpattern call with
- % no color values. To properly handle that case and to
- % ensure that the stack is properly cleaned, we are
- % testing the type of the color values inline.
- 1 exch 1 exch
- {
- index type dup /integertype ne exch /realtype ne and
- //setcolor_typecheck
- if
- }
- for
- }
- { pop }
- ifelse
- }
- { pop pop }
- ifelse
- }
- ifelse
- }
- bind
-
- /cs_complete_setcolor //pop_1
-
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
diff --git a/gs/Resource/Init/gs_sepr.ps b/gs/Resource/Init/gs_sepr.ps
deleted file mode 100644
index e417adb3d..000000000
--- a/gs/Resource/Init/gs_sepr.ps
+++ /dev/null
@@ -1,268 +0,0 @@
-% Copyright (C) 2001, 2002 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id$
-% Separation color space method dictionary
-
-
-% verify that Separation color spaces are supported
-/.setseparationspace where
- { pop }
- { currentfile closefile }
-ifelse
-
-.currentglobal true .setglobal
-.cspace_util begin
-
-
-%
-% <c1> <array> apply_sepr_tint_xform <c1>' ... <cn>' <array>
-%
-% Apply the tint transform for a Separation color space color intensity
-% value.
-%
-/apply_sepr_tint_xform
- {
- exch //bound_0_1 exec
- mark exch 2 index 3 get exec
- counttomark { cvr counttomark -1 roll } repeat % for CET, make all tints real.
- counttomark 2 add -2 roll pop
- }
-bind def
-
-
-%
-% <cspace_array> build_tintxform_function <cspace_array> <proc>
-%
-% Convert a tint transformation into a function, if possible. If this is
-% successful, <proc> will be a function procedure (a two-element,
-% execute-only, executable array whose first element is the function
-% data structure and whose second element is the operator %execfunction.
-% If it is not successful, <proc> will be the same as the tint transform
-% in <cspace_array>.
-%
-% Note that, for PDF files, the tint transform will likely already be a
-% function-array. In this case, <proc> will be this array, and thus will
-% also be identical to the original tint transform.
-%
-% This procedure is used for both Separation and DeviceN color spaces.
-%
-/build_tintxform_function
- {
- dup 3 get dup .isencapfunction not
- {
- % Try a FunctionType 4 function first; build the function dictionary
- % in local VM.
- .currentglobal exch //false .setglobal
- % Make the dictionary a couple of elements large in case this fails
- % and we need the dictionary to build a sampled function.
- 6 dict begin
- /FunctionType 4 def
- /Function exch def
- /Domain 2 index //.cs_get_range exec def
- /Range 2 index 2 get //.cs_get_range exec def
- currentdict end
- { .buildfunction }
- .internalstopped % If .buildfunction fails then not type 4 func.
- { % If not then try building a sampled (type 0) func.
- % We are using the dictionary which was created before .buildfunction
- dup /Order 3 put
- dup /BitsPerSample 16 put
- { .buildsampledfunction }
- .internalstopped % If .buildsamplefunction fails then invalid func.
- { % Failed - Create a dummy tint transform function
- % We are using the dictionary which was created before .buildfunction
- dup /Function {} put % Replace invalid tint transform with dummy
- .buildfunction
- }
- if % Check status from .buildsamplefunction/.internalstopped
- }
- if % check status from .buildfunction/.intermalstopped
- % restore the VM mode
- exch .setglobal
- }
- if
- }
-bind def
-
-%
-% <array1> <array2> converttinttransform <array1> <array2'>
-%
-% Convert a Separation/DeviceN color space to use a function as a tint
-% transformation, if this is possible. Possible outcomes are:
-%
-% 1. The tint transform already is a function, or is a procedure that
-% cannot be converted to a function. In either case, <array2> is
-% left unchanged (<array2> == <array2'>).
-%
-% 2. The tint transform is not already a function but can be converted
-% to a function, and <array1> != <array2>. In this case, <array2>
-% is modified directly.
-%
-% 3. The tint transform is not already a function but can be converted
-% to a function, and <array1> == <array2>. In this case, <array2>
-% is copied, and the copy is modified (i.e., after the operation
-% <array1> != <array2>
-%
-% This slightly complex approach avoids creating an extra color space
-% array unnecessarily.
-%
-/converttinttransform
- {
- % convert the tint transform to a fucntion
- //build_tintxform_function exec
-
- % see if anything needs to be modified
- 1 index 3 get 2 copy eq
- { pop pop }
- {
- pop
-
- % see if the color space must be copied
- 3 copy pop eq
- {
- % copy the array into local VM
- .currentglobal //false .setglobal
- 3 -1 roll dup length array copy 3 1 roll
- .setglobal
- }
- if
- 1 index exch 3 exch put
- }
- ifelse
- }
-bind def
-
-
-colorspacedict
-/Separation
- mark
- /cs_potential_indexed_base true
- /cs_potential_pattern_base true
- /cs_potential_alternate false
- /cs_potential_icc_alternate false
- /cs_get_ncomps //ncomps_1
- /cs_get_range //get_range_1
- /cs_get_default_color { pop 1 } bind
-
- /cs_get_currentgray
- { //apply_sepr_tint_xform exec 2 get //.cs_get_currentgray exec }
- bind
- /cs_get_currentrgb
- { //apply_sepr_tint_xform exec 2 get //.cs_get_currentrgb exec }
- bind
- /cs_get_currentcmyk
- { //apply_sepr_tint_xform exec 2 get //.cs_get_currentcmyk exec }
- bind
-
- % a lot of validation is done by the cs_validate method
- /cs_validate
- {
- //check_array exec
- dup 1 get type dup /nametype ne exch /stringtype ne and
- //setcspace_typecheck
- if
- dup 2 get //.cs_validate exec //.cs_potential_alternate exec not
- //setcspace_rangecheck
- if
- dup 3 get //check_array exec xcheck not
- //setcspace_typecheck
- if
- }
- bind
-
- % substitute the base space if appropriate
- /cs_substitute
- {
- dup 2 get //.cs_substitute exec 2 copy eq
- { pop pop dup }
- {
- % retain only the new alternate space
- exch pop
-
- % build all new structures in local VM
- .currentglobal 3 1 roll //false .setglobal
-
- % construct a new array and insert the new base color space
- 1 index dup length array copy dup 2 4 -1 roll put
-
- % restore VM mode
- 3 -1 roll .setglobal
- }
- ifelse
- }
- bind
-
- %
- % The Ghostscript interpreter works better when tinttransform procedures
- % are translated into functions. Attempt to do that here.
- %
- /cs_prepare //converttinttransform
-
- %
- % Install the current color space.
- %
- % The current Ghostscript color space implementation requires that
- % color spaces that provide a base or alternative color space set
- % that base/alternative color space to be the current color space
- % before attempting to set the original color space.
- %
- /cs_install
- {
- % save the current color space
- currentcolorspace
-
- % set the base color space as the current color space
- 1 index 2 get //forcesetcolorspace
-
- % set the indexed color space; restore the earlier space on error
- mark 2 index
- { .setseparationspace }
- stopped
- { cleartomark setcolorspace stop }
- { pop pop pop }
- ifelse
- }
- bind
-
- /cs_prepare_color //validate_1
-
- %
- % If a Separation color space is not supported in native mode by
- % the current process color model, Adobe implementations will always
- % execute the tint transform procedure when setcolor is invoked.
- % Ghostscript may have turned this transform into a sampled function,
- % and even if this is not the case, will have sampled the transform
- % when the color space is first set. Some applications may depend
- % on the Adobe behavior, so we implement it via the
- % cs_complete_setcolor method.
- %
- /cs_complete_setcolor
- {
- .usealternate
- {
- currentcolor exch 3 get exec
- currentcolorspace 2 get //clear_setcolor_operands exec
- }
- { pop }
- ifelse
- }
- bind
-
- .dicttomark
-put
-
-end % .cspace_util
-.setglobal
diff --git a/gs/doc/Develop.htm b/gs/doc/Develop.htm
index de0ab6023..957b74940 100644
--- a/gs/doc/Develop.htm
+++ b/gs/doc/Develop.htm
@@ -2761,15 +2761,7 @@ Color Spaces and support:
<dt>
Color Space Loading:
<dd>
-<a href="../lib/gs_ciecs2.ps">lib/gs_ciecs2.ps</a>,
-<a href="../lib/gs_ciecs3.ps">lib/gs_ciecs3.ps</a>,
<a href="../lib/gs_cspace.ps">lib/gs_cspace.ps</a>,
-<a href="../lib/gs_devcs.ps">lib/gs_devcs.ps</a>,
-<a href="../lib/gs_devn.ps">lib/gs_devn.ps</a>,
-<a href="../lib/gs_devpxl.ps">lib/gs_devpxl.ps</a>,
-<a href="../lib/gs_indxd.ps">lib/gs_indxd.ps</a>,
-<a href="../lib/gs_patrn.ps">lib/gs_patrn.ps</a>,
-<a href="../lib/gs_sepr.ps">lib/gs_sepr.ps</a>.
<dt>
ICC color profiles:
diff --git a/gs/doc/Psfiles.htm b/gs/doc/Psfiles.htm
index 4f518e51e..cfc94a707 100644
--- a/gs/doc/Psfiles.htm
+++ b/gs/doc/Psfiles.htm
@@ -152,16 +152,6 @@ Used for for emulating PostScript fonts with non-PostScript font technologies.
</dl>
<dl>
-<dt><a href="../lib/gs_ciecs2.ps"><tt>gs_ciecs2.ps</tt></a>
-<dd>Implementation of the LangaugeLevel 2 CIEBased color spaces: CIEBasedA and CIEBasedABC.
-</dl>
-
-<dl>
-<dt><a href="../lib/gs_ciecs3.ps"><tt>gs_ciecs3.ps</tt></a>
-<dd>Implementation of the LangaugeLevel 3 CIEBased color spaces: CIEBasedA and CIEBasedABC.
-</dl>
-
-<dl>
<dt><a href="../lib/gs_cmap.ps"><tt>gs_cmap.ps</tt></a>
<dd><b><tt>ProcSet</tt></b> for implementing <b><tt>CMap</tt></b> resources.
</dl>
@@ -170,26 +160,7 @@ Used for for emulating PostScript fonts with non-PostScript font technologies.
<dt><a href="../lib/gs_cspace.ps"><tt>gs_cspace.ps</tt></a>
<dd> PostScript portion of the basic color space handling;
see the extensive comment at the head of the file
-for information. Note that color space substitution
-and the hue-saturation-brightness (HSB) color space
-are now fully implemented in the PostScript code;
-the interpreter and the graphic library are no longer
-involved in or even aware of these features.
-</dl>
-
-<dl>
-<dt><a href="../lib/gs_devcs.ps"><tt>gs_devcs.ps</tt></a>
-<dd>Implementation of the DeviceGray, DeviceRGB, and DeviceCMYK color spaces.
-</dl>
-
-<dl>
- <dt><a href="../lib/gs_devn.ps"><tt>gs_devn.ps</tt></a>
- <dd>Implementation of the DeviceN color space.
-</dl>
-
-<dl>
- <dt><a href="../lib/gs_devpxl.ps"><tt>gs_devpxl.ps</tt></a>
- <dd>Implementation of the DevicePixel color space.
+for information.
</dl>
<dl>
@@ -230,11 +201,6 @@ facility).
</dl>
<dl>
-<dt><a href="../lib/gs_indxd.ps"><tt>gs_indxd.ps</tt></a>
-<dd>Implementation of the Indexed color space.
-</dl>
-
-<dl>
<dt><a href="../lib/gs_init.ps"><tt>gs_init.ps</tt></a>
<dd>Ghostscript reads this automatically when it starts up. It contains
definitions of many standard procedures and initialization for a wide
@@ -254,11 +220,6 @@ procedures and miscellaneous initialization for the Level 2 functions.
</dl>
<dl>
-<dt><a href="../lib/gs_patrn.ps"><tt>gs_patrn.ps</tt></a>
-<dd>Implementation of the Pattern color space.
-</dl>
-
-<dl>
<dt><a href="../lib/gs_resmp.ps"><tt>gs_resmp.ps</tt></a>
<dd>A procset for redefining resource categories with a resource map.
</dl>
@@ -283,11 +244,6 @@ configurations.
</dl>
<dl>
-<dt><a href="../lib/gs_sepr.ps"><tt>gs_sepr.ps</tt></a>
-<dd>Implementaton of the Separation color space.
-</dl>
-
-<dl>
<dt><a href="../lib/gs_setpd.ps"><tt>gs_setpd.ps</tt></a>
<dd>Implementation of the <b><tt>setpagedevice</tt></b> operator.
</dl>
diff --git a/gs/src/gscolor2.h b/gs/src/gscolor2.h
index ad3782d1e..1730ddfef 100644
--- a/gs/src/gscolor2.h
+++ b/gs/src/gscolor2.h
@@ -40,6 +40,8 @@ int
gs_indexed_limit_and_lookup(const gs_client_color * pc,const gs_color_space *pcs,
gs_client_color *pcc);
+/* Declare the Indexed color space type. */
+extern const gs_color_space_type gs_color_space_type_Indexed;
/* CIE-specific routines */
#ifndef gs_cie_render_DEFINED
diff --git a/gs/src/ifunc.h b/gs/src/ifunc.h
index 16378efe4..171b302f9 100644
--- a/gs/src/ifunc.h
+++ b/gs/src/ifunc.h
@@ -39,6 +39,12 @@ int fn_build_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn,
int fn_build_sub_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn,
int depth, gs_memory_t *mem, const float *shading_domain, const int num_inputs);
+/* Called only from the routines in zcolor.c, in order to convert a tint-transform
+ * procedure to a function. Little more than a place-holder to avoid making a number
+ * of functions non-static
+ */
+int buildfunction(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, int type);
+
/*
* Collect a heap-allocated array of floats. If the key is missing, set
* *pparray = 0 and return 0; otherwise set *pparray and return the number
diff --git a/gs/src/int.mak b/gs/src/int.mak
index 10a6f70a4..41ec537ef 100644
--- a/gs/src/int.mak
+++ b/gs/src/int.mak
@@ -451,8 +451,9 @@ $(PSOBJ)zcolor.$(OBJ) : $(PSSRC)zcolor.c $(OP)\
$(igstate_h) $(iutil_h) $(store_h) $(gxfixed_h) $(gxmatrix_h)\
$(gzstate_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxcmap_h)\
$(gxcspace_h) $(gxcolor2_h) $(gxpcolor_h)\
- $(idict_h) $(icolor_h) $(idparam_h) $(iname_h)
- $(PSCC) $(PSO_)zcolor.$(OBJ) $(C_) $(PSSRC)zcolor.c
+ $(idict_h) $(icolor_h) $(idparam_h) $(iname_h) $(iutil_h) $(icsmap_h)\
+ $(zht2_h) $(dstack_h)
+ $(PSCC) $(PSO_)zcolor.$(OBJ) $(C_) $(PSSRC)zcolor.c
$(PSOBJ)zdevice.$(OBJ) : $(PSSRC)zdevice.c $(OP) $(string__h)\
$(ialloc_h) $(idict_h) $(igstate_h) $(iname_h) $(interp_h) $(iparam_h) $(ivmspace_h)\
@@ -530,7 +531,7 @@ Z1OPS=zarith zarray zcontrol1 zcontrol2 zcontrol3
Z2OPS=zdict1 zdict2 zfile zfile1 zfileio1 zfileio2
Z3_4OPS=zfilter zfproc zgeneric ziodev zmath zalg
Z5_6OPS=zmisc zpacked zrelbit zstack zstring zsysvm
-Z7_8OPS=ztoken ztype zvmem zbfont zchar_a zchar_b zcolor
+Z7_8OPS=ztoken ztype zvmem zbfont zchar_a zchar_b zcolor zcolor_ext
Z9OPS=zdevice zfont zfontenum zgstate1 zgstate2 zgstate3
Z10OPS=zdfilter zht zimage zmatrix
Z11OPS=zpaint zpath pantone
@@ -998,7 +999,6 @@ $(PSD)psl2read.dev : $(INT_MAK) $(ECHOGS_XE) $(psl2read_)\
$(PSD)psl2int.dev $(PSD)dps2read.dev
$(SETMOD) $(PSD)psl2read $(psl2read_)
$(ADDMOD) $(PSD)psl2read -include $(PSD)psl2int $(PSD)dps2read
- $(ADDMOD) $(PSD)psl2read -oper zcolor2_l2 zcsindex_l2
$(ADDMOD) $(PSD)psl2read -oper zht2_l2
$(PSOBJ)zcolor2.$(OBJ) : $(PSSRC)zcolor2.c $(OP) $(string__h)\
@@ -1400,7 +1400,7 @@ $(PSOBJ)zcidtest.$(OBJ) : $(PSSRC)zcidtest.c $(string__h) $(OP)\
cieread_=$(PSOBJ)zcie.$(OBJ) $(PSOBJ)zcrd.$(OBJ)
$(PSD)cie.dev : $(INT_MAK) $(ECHOGS_XE) $(cieread_) $(GLD)cielib.dev
$(SETMOD) $(PSD)cie $(cieread_)
- $(ADDMOD) $(PSD)cie -oper zcie_l2 zcrd_l2
+ $(ADDMOD) $(PSD)cie -oper zcrd_l2
$(ADDMOD) $(PSD)cie -include $(GLD)cielib
icie_h=$(PSSRC)icie.h
@@ -1540,7 +1540,6 @@ $(PSOBJ)zdpnext.$(OBJ) : $(PSSRC)zdpnext.c $(math__h) $(OP)\
cspixint_=$(PSOBJ)zcspixel.$(OBJ)
$(PSD)cspixel.dev : $(INT_MAK) $(ECHOGS_XE) $(cspixint_) $(GLD)cspixlib.dev
$(SETMOD) $(PSD)cspixel $(cspixint_)
- $(ADDMOD) $(PSD)cspixel -oper zcspixel
$(ADDMOD) $(PSD)cspixel -include $(GLD)cspixlib
$(PSOBJ)zcspixel.$(OBJ) : $(PSSRC)zcspixel.c $(OP)\
@@ -1557,11 +1556,6 @@ $(PSD)psl3.dev : $(INT_MAK) $(ECHOGS_XE)\
$(ADDMOD) $(PSD)psl3 -include $(GLD)psl3lib $(PSD)psl3read
$(ADDMOD) $(PSD)psl3 -emulator PostScript PostScriptLevel2 PostScriptLevel3
-$(PSOBJ)zcsdevn.$(OBJ) : $(PSSRC)zcsdevn.c $(OP) $(memory__h)\
- $(gscolor2_h) $(gscdevn_h) $(gxcdevn_h) $(gxcspace_h) $(zht2_h)\
- $(estack_h) $(ialloc_h) $(icremap_h) $(ifunc_h) $(igstate_h) $(iname_h)
- $(PSCC) $(PSO_)zcsdevn.$(OBJ) $(C_) $(PSSRC)zcsdevn.c
-
$(PSOBJ)zfunc3.$(OBJ) : $(PSSRC)zfunc3.c $(memory__h) $(OP)\
$(gsfunc3_h) $(gsstruct_h)\
$(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifunc_h)\
@@ -1609,7 +1603,7 @@ $(PSOBJ)zshade.$(OBJ) : $(PSSRC)zshade.c $(memory__h) $(OP)\
$(store_h)
$(PSCC) $(PSO_)zshade.$(OBJ) $(C_) $(PSSRC)zshade.c
-psl3read_1=$(PSOBJ)zcsdevn.$(OBJ) $(PSOBJ)zfunc3.$(OBJ) $(PSOBJ)zfsample.$(OBJ)
+psl3read_1=$(PSOBJ)zfunc3.$(OBJ) $(PSOBJ)zfsample.$(OBJ)
psl3read_2=$(PSOBJ)zimage3.$(OBJ) $(PSOBJ)zmisc3.$(OBJ) $(PSOBJ)zcolor3.$(OBJ)\
$(PSOBJ)zshade.$(OBJ)
psl3read_=$(psl3read_1) $(psl3read_2)
@@ -1619,7 +1613,6 @@ $(PSD)psl3read.dev : $(INT_MAK) $(ECHOGS_XE) $(psl3read_)\
$(PSD)frsd.dev $(PSD)fzlib.dev
$(SETMOD) $(PSD)psl3read $(psl3read_1)
$(ADDMOD) $(PSD)psl3read $(psl3read_2)
- $(ADDMOD) $(PSD)psl3read -oper zcsdevn
$(ADDMOD) $(PSD)psl3read -oper zfsample
$(ADDMOD) $(PSD)psl3read -oper zimage3 zmisc3 zcolor3_l3 zshade
$(ADDMOD) $(PSD)psl3read -functiontype 2 3
diff --git a/gs/src/zcie.c b/gs/src/zcie.c
index f4252728b..81d8ba6c4 100644
--- a/gs/src/zcie.c
+++ b/gs/src/zcie.c
@@ -30,6 +30,7 @@
#include "isave.h"
#include "ivmspace.h"
#include "store.h" /* for make_null */
+#include "zcie.h"
/* Empty procedures */
static const ref empty_procs[4] =
@@ -295,10 +296,9 @@ static int cache_common(i_ctx_t *, gs_cie_common *, const ref_cie_procs *,
static int cache_abc_common(i_ctx_t *, gs_cie_abc *, const ref_cie_procs *,
void *, gs_ref_memory_t *);
-/* <dict> .setciedefgspace - */
static int cie_defg_finish(i_ctx_t *);
-static int
-zsetciedefgspace(i_ctx_t *i_ctx_p)
+int
+ciedefgspace(i_ctx_t *i_ctx_p, ref *CIEDict)
{
os_ptr op = osp;
int edepth = ref_stack_count(&e_stack);
@@ -310,9 +310,8 @@ zsetciedefgspace(i_ctx_t *i_ctx_p)
int code;
ref *ptref;
- check_type(*op, t_dictionary);
- check_dict_read(*op);
- if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
+ push(1);
+ if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0)
return (code < 0 ? code : gs_note_error(e_rangecheck));
check_read_type(*ptref, t_array);
if (r_size(ptref) != 5)
@@ -324,11 +323,11 @@ zsetciedefgspace(i_ctx_t *i_ctx_p)
pcie = pcs->params.defg;
pcie->Table.n = 4;
pcie->Table.m = 3;
- if ((code = dict_ranges_param(mem, op, "RangeDEFG", 4, pcie->RangeDEFG.ranges)) < 0 ||
- (code = dict_proc_array_param(mem, op, "DecodeDEFG", 4, &procs.PreDecode.DEFG)) < 0 ||
- (code = dict_ranges_param(mem, op, "RangeHIJK", 4, pcie->RangeHIJK.ranges)) < 0 ||
+ if ((code = dict_ranges_param(mem, CIEDict, "RangeDEFG", 4, pcie->RangeDEFG.ranges)) < 0 ||
+ (code = dict_proc_array_param(mem, CIEDict, "DecodeDEFG", 4, &procs.PreDecode.DEFG)) < 0 ||
+ (code = dict_ranges_param(mem, CIEDict, "RangeHIJK", 4, pcie->RangeHIJK.ranges)) < 0 ||
(code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
- (code = cie_abc_param(imemory, op, (gs_cie_abc *) pcie, &procs)) < 0 ||
+ (code = cie_abc_param(imemory, CIEDict, (gs_cie_abc *) pcie, &procs)) < 0 ||
(code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
(code = cie_cache_push_finish(i_ctx_p, cie_defg_finish, imem, pcie)) < 0 ||
(code = cie_prepare_cache4(i_ctx_p, &pcie->RangeDEFG,
@@ -354,10 +353,9 @@ cie_defg_finish(i_ctx_t *i_ctx_p)
return 0;
}
-/* <dict> .setciedefspace - */
static int cie_def_finish(i_ctx_t *);
-static int
-zsetciedefspace(i_ctx_t *i_ctx_p)
+int
+ciedefspace(i_ctx_t *i_ctx_p, ref *CIEDict)
{
os_ptr op = osp;
int edepth = ref_stack_count(&e_stack);
@@ -369,9 +367,8 @@ zsetciedefspace(i_ctx_t *i_ctx_p)
int code;
ref *ptref;
- check_type(*op, t_dictionary);
- check_dict_read(*op);
- if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
+ push(1);
+ if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0)
return (code < 0 ? code : gs_note_error(e_rangecheck));
check_read_type(*ptref, t_array);
if (r_size(ptref) != 4)
@@ -383,11 +380,11 @@ zsetciedefspace(i_ctx_t *i_ctx_p)
pcie = pcs->params.def;
pcie->Table.n = 3;
pcie->Table.m = 3;
- if ((code = dict_range3_param(mem, op, "RangeDEF", &pcie->RangeDEF)) < 0 ||
- (code = dict_proc3_param(mem, op, "DecodeDEF", &procs.PreDecode.DEF)) < 0 ||
- (code = dict_range3_param(mem, op, "RangeHIJ", &pcie->RangeHIJ)) < 0 ||
+ if ((code = dict_range3_param(mem, CIEDict, "RangeDEF", &pcie->RangeDEF)) < 0 ||
+ (code = dict_proc3_param(mem, CIEDict, "DecodeDEF", &procs.PreDecode.DEF)) < 0 ||
+ (code = dict_range3_param(mem, CIEDict, "RangeHIJ", &pcie->RangeHIJ)) < 0 ||
(code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
- (code = cie_abc_param(imemory, op, (gs_cie_abc *) pcie, &procs)) < 0 ||
+ (code = cie_abc_param(imemory, CIEDict, (gs_cie_abc *) pcie, &procs)) < 0 ||
(code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
(code = cie_cache_push_finish(i_ctx_p, cie_def_finish, imem, pcie)) < 0 ||
(code = cie_prepare_cache3(i_ctx_p, &pcie->RangeDEF,
@@ -413,10 +410,10 @@ cie_def_finish(i_ctx_t *i_ctx_p)
return 0;
}
-/* <dict> .setcieabcspace - */
static int cie_abc_finish(i_ctx_t *);
-static int
-zsetcieabcspace(i_ctx_t *i_ctx_p)
+
+int
+cieabcspace(i_ctx_t *i_ctx_p, ref *CIEDict)
{
os_ptr op = osp;
int edepth = ref_stack_count(&e_stack);
@@ -427,14 +424,13 @@ zsetcieabcspace(i_ctx_t *i_ctx_p)
gs_cie_abc *pcie;
int code;
- check_type(*op, t_dictionary);
- check_dict_read(*op);
+ push(1); /* Sacrificial */
procs = istate->colorspace.procs.cie;
code = gs_cspace_build_CIEABC(&pcs, NULL, mem);
if (code < 0)
return code;
pcie = pcs->params.abc;
- code = cie_abc_param(imemory, op, pcie, &procs);
+ code = cie_abc_param(imemory, CIEDict, pcie, &procs);
if (code < 0 ||
(code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
(code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie)) < 0 ||
@@ -456,10 +452,10 @@ cie_abc_finish(i_ctx_t *i_ctx_p)
return 0;
}
-/* <dict> .setcieaspace - */
static int cie_a_finish(i_ctx_t *);
-static int
-zsetcieaspace(i_ctx_t *i_ctx_p)
+
+int
+cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict)
{
os_ptr op = osp;
int edepth = ref_stack_count(&e_stack);
@@ -470,18 +466,17 @@ zsetcieaspace(i_ctx_t *i_ctx_p)
gs_cie_a *pcie;
int code;
- check_type(*op, t_dictionary);
- check_dict_read(*op);
+ push(1); /* Sacrificial. cie_a_finish does a pop... */
procs = istate->colorspace.procs.cie;
- if ((code = dict_proc_param(op, "DecodeA", &procs.Decode.A, true)) < 0)
+ if ((code = dict_proc_param(CIEdict, "DecodeA", &procs.Decode.A, true)) < 0)
return code;
code = gs_cspace_build_CIEA(&pcs, NULL, mem);
if (code < 0)
return code;
pcie = pcs->params.a;
- if ((code = dict_floats_param(imemory, op, "RangeA", 2, (float *)&pcie->RangeA, (const float *)&RangeA_default)) < 0 ||
- (code = dict_floats_param(imemory, op, "MatrixA", 3, (float *)&pcie->MatrixA, (const float *)&MatrixA_default)) < 0 ||
- (code = cie_lmnp_param(imemory, op, &pcie->common, &procs)) < 0 ||
+ if ((code = dict_floats_param(imemory, CIEdict, "RangeA", 2, (float *)&pcie->RangeA, (const float *)&RangeA_default)) < 0 ||
+ (code = dict_floats_param(imemory, CIEdict, "MatrixA", 3, (float *)&pcie->MatrixA, (const float *)&MatrixA_default)) < 0 ||
+ (code = cie_lmnp_param(imemory, CIEdict, &pcie->common, &procs)) < 0 ||
(code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
(code = cie_cache_push_finish(i_ctx_p, cie_a_finish, imem, pcie)) < 0 ||
(code = cie_prepare_cache(i_ctx_p, &pcie->RangeA, &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A")) < 0 ||
@@ -660,21 +655,3 @@ cie_cache_push_finish(i_ctx_t *i_ctx_p, op_proc_t finish_proc,
return o_push_estack;
}
-/* ------ Initialization procedure ------ */
-
-const op_def zcie_l2_op_defs[] =
-{
- op_def_begin_level2(),
- {"1.setcieaspace", zsetcieaspace},
- {"1.setcieabcspace", zsetcieabcspace},
- {"1.setciedefspace", zsetciedefspace},
- {"1.setciedefgspace", zsetciedefgspace},
- /* Internal operators */
- {"1%cie_defg_finish", cie_defg_finish},
- {"1%cie_def_finish", cie_def_finish},
- {"1%cie_abc_finish", cie_abc_finish},
- {"1%cie_a_finish", cie_a_finish},
- {"0%cie_cache_finish", cie_cache_finish},
- {"1%cie_cache_finish1", cie_cache_finish1},
- op_def_end(0)
-};
diff --git a/gs/src/zcie.h b/gs/src/zcie.h
new file mode 100644
index 000000000..5d0d870a0
--- /dev/null
+++ b/gs/src/zcie.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2001-2006 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/
+ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* $Id: zcie.h $ */
+/* Definitions for CIEBased color spaces */
+
+#ifndef zcie_INCLUDED
+# define zcie_INCLUDED
+
+int cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict);
+int cieabcspace(i_ctx_t *i_ctx_p, ref *CIEDict);
+int ciedefspace(i_ctx_t *i_ctx_p, ref *CIEDict);
+int ciedefgspace(i_ctx_t *i_ctx_p, ref *CIEDict);
+
+#endif /* zcie_INCLUDED */
diff --git a/gs/src/zcolor.c b/gs/src/zcolor.c
index 9c95f56ac..2add173f5 100644
--- a/gs/src/zcolor.c
+++ b/gs/src/zcolor.c
@@ -13,14 +13,21 @@
/* $Id$ */
/* Color operators */
+#include "math.h"
#include "memory_.h"
#include "ghost.h"
#include "oper.h"
+#include "dstack.h" /* for systemdict */
#include "estack.h"
#include "ialloc.h"
#include "igstate.h"
#include "iutil.h"
#include "store.h"
+#include "gscolor.h" /* for gs_setgray and gs_setrgbcolor */
+#include "gscolor1.h" /* for gs_setcmykcolor */
+#include "gscsepr.h" /* For declarartion of Separation functions */
+#include "gscdevn.h" /* For declarartion of DeviceN functions */
+#include "gscpixel.h" /* For declarartion of DevicePixel functions */
#include "gxfixed.h"
#include "gxmatrix.h"
#include "gzstate.h"
@@ -36,10 +43,22 @@
#include "idparam.h"
#include "iname.h"
#include "iutil.h"
+#include "ifunc.h" /* For declaration of buildfunction */
+#include "icsmap.h"
+#include "ifunc.h"
+#include "zht2.h"
+#include "zcolor.h" /* For the PS_colour_space_t structure */
+#include "zcie.h" /* For CIE space function declarations */
+#include "zicc.h" /* For declaration of seticc */
/* imported from gsht.c */
extern void gx_set_effective_transfer(gs_state *);
+/* Essential forward declarations */
+static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth);
+static int setcolorspace_cont(i_ctx_t *i_ctx_p);
+static int setcolor_cont(i_ctx_t *i_ctx_p);
+
/* define the number of stack slots needed for zcolor_remap_one */
const int zcolor_remap_one_ostack = 4;
const int zcolor_remap_one_estack = 3;
@@ -124,26 +143,63 @@ static int
zcurrentcolorspace(i_ctx_t * i_ctx_p)
{
os_ptr op = osp; /* required by "push" macro */
+ int code;
+ ref namestr,stref;
+ byte *body;
- push(1);
- if ( gs_color_space_get_index(igs->color_space) == gs_color_space_index_DeviceGray ) {
- ref gray, graystr;
- ref csa = istate->colorspace.array;
- if (array_get(imemory, &csa, 0, &gray) >= 0 &&
- r_has_type(&gray, t_name) &&
- (name_string_ref(imemory, &gray, &graystr),
- r_size(&graystr) == 10 &&
- !memcmp(graystr.value.bytes, "DeviceGray", 10))) {
-
- *op = istate->colorspace.array;
- } else {
- int code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
- if (code < 0)
- return code;
- return name_enter_string(imemory, "DeviceGray", op->value.refs);
- }
- } else
- *op = istate->colorspace.array;
+ /* Adobe applications expect that the Device spaces (DeviceGray
+ * DeviceRGB and DeviceCMYK) will always return the same array.
+ * Not merely the same content but the same actual array. To do
+ * this we define the arrays at startup (see gs_cspace.ps), and
+ * recover them here by executing PostScript.
+ */
+ if (r_has_type(&istate->colorspace.array, t_name)) {
+ name_string_ref(imemory, &istate->colorspace.array, &namestr);
+ if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceGray", 10)) {
+ body = ialloc_string(32, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "systemdict /DeviceGray_array get", 32);
+ make_string(&stref, a_all | icurrent_space, 32, body);
+ } else {
+ if (r_size(&namestr) == 9 && !memcmp(namestr.value.bytes, "DeviceRGB", 9)) {
+ body = ialloc_string(31, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "systemdict /DeviceRGB_array get", 31);
+ make_string(&stref, a_all | icurrent_space, 31, body);
+ } else {
+ if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceCMYK", 10)) {
+ body = ialloc_string(32, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "systemdict /DeviceCMYK_array get", 32);
+ make_string(&stref, a_all | icurrent_space, 32, body);
+ } else {
+ /* Not one of the Device spaces, but still just a name. Give
+ * up and return the name on the stack.
+ */
+ push(1);
+ code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
+ if (code < 0)
+ return code;
+ refset_null(op->value.refs, 1);
+ ref_assign_old(op, op->value.refs, &istate->colorspace.array, "currentcolorspace");
+ return 0;
+ }
+ }
+ }
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ } else {
+ /* If the space isn't a simple name, then we don't need any special
+ * action and can simply use it.
+ */
+ push(1);
+ *op = istate->colorspace.array;
+ }
return 0;
}
@@ -192,13 +248,15 @@ static int
zsetcolor(i_ctx_t * i_ctx_p)
{
os_ptr op = osp;
+ es_ptr ep = esp;
const gs_color_space * pcs = gs_currentcolorspace(igs);
gs_client_color cc;
- int n_comps, n_numeric_comps, num_offset = 0, code;
+ int n_comps, n_numeric_comps, num_offset = 0, code, depth;
bool is_ptype2 = 0;
+ PS_colour_space_t *space;
/* initialize the client color pattern pointer for GC */
- cc.pattern = 0;
+ cc.pattern = 0;
/* check for a pattern color space */
if ((n_comps = cs_num_components(pcs)) < 0) {
@@ -207,8 +265,12 @@ zsetcolor(i_ctx_t * i_ctx_p)
ref *pImpl, pPatInst;
int ptype;
- dict_find_string(op, "Implementation", &pImpl);
+ code = dict_find_string(op, "Implementation", &pImpl);
+ if (code < 0)
+ return code;
code = array_get(imemory, pImpl, 0, &pPatInst);
+ if (code < 0)
+ return code;
cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
? n_comps - 1
@@ -222,8 +284,19 @@ zsetcolor(i_ctx_t * i_ctx_p)
n_numeric_comps = n_comps;
/* gather the numeric operands */
- float_params(op - num_offset, n_numeric_comps, cc.paint.values);
-
+ code = float_params(op - num_offset, n_numeric_comps, cc.paint.values);
+ if (code < 0)
+ return code;
+
+ code = get_space_object(i_ctx_p, &istate->colorspace.array, &space);
+ if (code < 0)
+ return code;
+ if (space->validatecomponents) {
+ code = space->validatecomponents(i_ctx_p, &istate->colorspace.array, cc.paint.values, n_numeric_comps);
+ if (code < 0)
+ return code;
+ }
+
/* pass the color to the graphic library */
if ((code = gs_setcolor(igs, &cc)) >= 0) {
@@ -231,10 +304,99 @@ zsetcolor(i_ctx_t * i_ctx_p)
istate->pattern = *op; /* save pattern dict or null */
n_comps = n_numeric_comps + 1;
}
- pop(n_comps);
}
- return code;
+ /* Check the color spaces, to see if we need to run any tint transform
+ * procedures. Some Adobe applications *eg Photoshop) expect that the
+ * tint transform will be run and use this to set up duotone DeviceN
+ * spaces.
+ */
+ code = validate_spaces(i_ctx_p, &istate->colorspace.array, &depth);
+ if (code < 0)
+ return code;
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ /* A place holder for data potentially used by transform functions */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store the 'depth' of the space returned during checking above */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store the 'stage' of processing (initially 0) */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ ep = esp += 1;
+ *ep = istate->colorspace.array;
+ /* Finally, the actual continuation routine */
+ push_op_estack(setcolor_cont);
+ return o_push_estack;
+}
+
+/*
+ * Given two color space arrays, attempts to determine if they are the
+ * same space by comparing their contents recursively. For some spaces,
+ * especially CIE based color spaces, it can significantly improve
+ * performance if the same space is frequently re-used.
+ */
+static int is_same_colorspace(i_ctx_t * i_ctx_p, ref *space1, ref *space2)
+{
+ PS_colour_space_t *oldcspace = 0, *newcspace = 0;
+ ref oldspace, *poldspace = &oldspace, newspace, *pnewspace = &newspace;
+ int code;
+
+ /* Silence compiler warnings */
+ oldspace.tas.type_attrs = 0;
+ oldspace.tas.type_attrs = 0;
+
+ ref_assign(poldspace, space1);
+ ref_assign(pnewspace, space2);
+ do {
+ if (r_type(poldspace) != r_type(pnewspace))
+ return 0;
+
+ code = get_space_object(i_ctx_p, poldspace, &oldcspace);
+ if (code < 0)
+ return 0;
+
+ code = get_space_object(i_ctx_p, pnewspace, &newcspace);
+ if (code < 0)
+ return 0;
+
+ /* Check the two color space types are the same
+ * (Indexed, Separation, DeviceCMYK etc).
+ */
+ if (strcmp(oldcspace->name, newcspace->name) != 0)
+ return 0;
+
+ /* Call the space-specific comparison routine */
+ if (!oldcspace->compareproc(i_ctx_p, poldspace, pnewspace))
+ return 0;
+
+ /* The current space is OK, if there is no alternate, then that's
+ * good enough.
+ */
+ if (!oldcspace->alternateproc)
+ break;
+
+ /* Otherwise, retrieve the alternate space for each, and continue
+ * round the loop, checking those.
+ */
+ code = oldcspace->alternateproc(i_ctx_p, poldspace, &poldspace);
+ if (code < 0)
+ return 0;
+
+ code = newcspace->alternateproc(i_ctx_p, pnewspace, &pnewspace);
+ if (code < 0)
+ return 0;
+ }
+ while(1);
+
+ return 1;
}
/*
@@ -244,19 +406,109 @@ zsetcolor(i_ctx_t * i_ctx_p)
* currentcolorspace operator, but is not directly used to pass color
* space information to the graphic library.
*
- * This operator can only be called from within the setcolorspace
- * pseudo-operator; the definition of the latter will override this
- * definition. Because error cheching is performed by the pseudo-
- * operator, it need not be repeated here.
*/
static int
zsetcolorspace(i_ctx_t * i_ctx_p)
{
os_ptr op = osp;
+ es_ptr ep = esp;
+ int code, depth;
- istate->colorspace.array = *op;
- pop(1);
- return 0;
+ /* Make sure we have an operand... */
+ check_op(1);
+ /* Check its either a name (base space) or an array */
+ if (!r_has_type(op, t_name))
+ if (!r_is_array(op))
+ return_error(e_typecheck);
+
+ code = validate_spaces(i_ctx_p, op, &depth);
+ if (code < 0)
+ return code;
+
+ /* See if its the same as the current space */
+ if (is_same_colorspace(i_ctx_p, op, &istate->colorspace.array)) {
+ PS_colour_space_t *cspace;
+
+ /* Even if its the same space, we still need to set the correct
+ * initial color value.
+ */
+ code = get_space_object(i_ctx_p, &istate->colorspace.array, &cspace);
+ if (code < 0)
+ return 0;
+ if (cspace->initialcolorproc) {
+ cspace->initialcolorproc(i_ctx_p, &istate->colorspace.array);
+ }
+ /* Pop the space off the stack */
+ pop(1);
+ return 0;
+ }
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ /* Store the initial value of CIE substitution (not substituting) */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store the 'depth' of the space returned during checking above */
+ ep = esp += 1;
+ make_int(ep, depth);
+ /* Store the 'stage' of processing (initially 0) */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ ep = esp += 1;
+ *ep = *op;
+ /* Finally, the actual continuation routine */
+ push_op_estack(setcolorspace_cont);
+ return o_push_estack;
+}
+
+/*
+ * A sepcial version of the setcolorspace operation above. This sets the
+ * CIE substitution flag to true before starting, which prevents any further
+ * CIE substitution taking place.
+ */
+static int
+setcolorspace_nosubst(i_ctx_t * i_ctx_p)
+{
+ os_ptr op = osp;
+ es_ptr ep = esp;
+ int code, depth;
+
+ /* Make sure we have an operand... */
+ check_op(1);
+ /* Check its either a name (base space) or an array */
+ if (!r_has_type(op, t_name))
+ if (!r_is_array(op))
+ return_error(e_typecheck);
+
+ code = validate_spaces(i_ctx_p, op, &depth);
+ if (code < 0)
+ return code;
+
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ /* Store the initial value of CIE substitution (substituting) */
+ ep = esp += 1;
+ make_int(ep, 1);
+ /* Store the 'depth' of the space returned during checking above */
+ ep = esp += 1;
+ make_int(ep, depth);
+ /* Store the 'stage' of processing (initially 0) */
+ ep = esp += 1;
+ make_int(ep, 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ ep = esp += 1;
+ *ep = *op;
+ /* Finally, the actual continuation routine */
+ push_op_estack(setcolorspace_cont);
+ return o_push_estack;
}
/*
@@ -279,54 +531,6 @@ zincludecolorspace(i_ctx_t * i_ctx_p)
return code;
}
-
-/*
- * <int> .setdevcspace -
- *
- * Set a parameterless color space. This is now used to set the
- * DeviceGray, DeviceRGB, and DeviceCMYK color spaces, rather than
- * the setgray/setrgbcolor/setcmykcolor operators. All PostScript-based
- * color space substitution will have been accomplished before this
- * operator is called.
- *
- * The use of an integer to indicate the specific color space is
- * historical and on the whole not particularly desirable, as it ties
- * the PostScript code to a specific enumeration. This may be modified
- * in the future.
- *
- * As with setcolorspace, this operator is called only under controlled
- * circumstances, hence it does no operand error checking.
- */
-static int
-zsetdevcspace(i_ctx_t * i_ctx_p)
-{
-
- gs_color_space *pcs;
- int code;
-
- switch((gs_color_space_index)osp->value.intval) {
- default: /* can't happen */
- case gs_color_space_index_DeviceGray:
- pcs = gs_cspace_new_DeviceGray(imemory);
- break;
-
- case gs_color_space_index_DeviceRGB:
- pcs = gs_cspace_new_DeviceRGB(imemory);
- break;
-
- case gs_color_space_index_DeviceCMYK:
- pcs = gs_cspace_new_DeviceCMYK(imemory);
- break;
- }
- if (pcs == NULL)
- return_error(e_VMerror);
- if ((code = gs_setcolorspace(igs, pcs)) >= 0)
- pop(1);
- rc_decrement_only(pcs, "zsetdevcspace");
- return code;
-}
-
-
/* - currenttransfer <proc> */
static int
zcurrenttransfer(i_ctx_t *i_ctx_p)
@@ -667,9 +871,5093 @@ zcolor_test_all(i_ctx_t *i_ctx_p)
return 0;
}
+/* Convert between RGB and HSB colors, using the hexcone approach (see
+ * Rogers, David, "Procedureal Elements For Computer Graphics",
+ * (McGraw-Hill, 1985), pp. 402 - 3).
+ *
+ * The rgb ==> hsb calculation is:
+ *
+ * br = max(r, g, b)
+ *
+ * if (br == 0)
+ * h = 0, s = 0;
+ * else {
+ * v = min(r, g, b)
+ * diff = br - v;
+ * sat = diff / br;
+ * if (r == br)
+ * h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
+ * else if (g == br)
+ * h = 1/3 + (b - r) / (6 * diff);
+ * else
+ * h = 2/3 + (r - g) / (6 * diff);
+ * }
+ */
+static int rgb2hsb(float *RGB)
+{
+ float HSB[3], v, diff;
+ int i, j=0;
+
+ v = 1.0;
+ for (i=0;i<3;i++)
+ HSB[i] = 0.0;
+ for (i=0;i<3;i++) {
+ if (RGB[i] > HSB[2]) {
+ HSB[2] = RGB[i];
+ j = i;
+ }
+ if (RGB[i] < v)
+ v = RGB[i];
+ }
+ if (HSB[2] != 0) {
+ diff = HSB[2] - v;
+ HSB[1] = diff / HSB[2];
+ switch (j) {
+ case 0 : /* R == Brightness */
+ if (diff)
+ HSB[0] = ((RGB[1] - RGB[2]) / (6.0 * (HSB[2] - v))) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
+ else
+ HSB[0] = (RGB[1] - RGB[2]) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
+ break;
+ case 1 : /* G == Brightness */
+ if (diff)
+ HSB[0] = (1.0 / 3.0) + (RGB[2] - RGB[0]) / (6.0 * (HSB[2] - v));
+ else
+ HSB[0] = (1.0 / 3.0) + (RGB[2] - RGB[0]);
+ break;
+ case 2 : /* B == Brightness */
+ if (diff)
+ HSB[0] = (2.0 / 3.0) + (RGB[0] - RGB[1]) / (6.0 * (HSB[2] - v));
+ else
+ HSB[0] = (2.0 / 3.0) + (RGB[0] - RGB[1]);
+ break;
+ }
+ }
+ for (i=0;i<3;i++) {
+ if (HSB[i] < 0)
+ HSB[i] = 0;
+ if (RGB[i] > 1)
+ HSB[i] = 1;
+ RGB[i] = HSB[i];
+ }
+ return 0;
+}
+/* The hsb ==> rgb conversion is:
+ *
+ * mn = (1 - s) * br, md = 6 * s * br;
+ *
+ * switch ((int)floor(6 * h)) {
+ * case 0: %% r >= g >= b
+ * r = br;
+ * g = mn + h * md;
+ * b = mn;
+ * break;
+ *
+ * case 1: %% g >= r >= b
+ * r = mn + md * (1/3 - h);
+ * g = br;
+ * b = mn;
+ * break;
+ *
+ * case 2: %% g >= b >= r
+ * r = mn;
+ * g = br;
+ * b = mn + (h - 1/3) * md;
+ * break;
+ *
+ * case 3: %% b >= g >= r
+ * r = mn;
+ * g = mn + (2/3 - h) * md;
+ * b = br;
+ * break;
+ *
+ * case 4: %% b >= r >= g
+ * r = mn + (h - 2/3) * md;
+ * g = mn;
+ * b = br;
+ * break;
+ *
+ * case 5: %% r >= b >= g
+ * r = br;
+ * g = mn;
+ * b = mn + (1 - h) * md;
+ * break;
+ *
+ * case 6: %% We have wrapped around the hexcone. Thus this case is
+ * the same as case 0 with h = 0
+ * h = 0;
+ * r = br;
+ * g = mn + h * md = mn;
+ * b = mn;
+ * break;
+ * }
+ */
+static int hsb2rgb(float *HSB)
+{
+ float RGB[3], mn, md;
+ int i;
+
+ mn = (1.0 - HSB[1]) * HSB[2];
+ md = 6.0 * HSB[1] * HSB[2];
+
+ switch ((int)floor(6.0 * HSB[0])) {
+ case 6:
+ HSB[0] = (float)0;
+ case 0:
+ RGB[0] = HSB[2];
+ RGB[1] = mn + (HSB[0] * md);
+ RGB[2] = mn;
+ break;
+ case 1:
+ RGB[0] = mn + (md * ((1.0 / 3.0) - HSB[0]));
+ RGB[1] = HSB[2];
+ RGB[2] = mn;
+ break;
+ case 2:
+ RGB[0] = mn;
+ RGB[1] = HSB[2];
+ RGB[2] = mn + ((HSB[0] - (1.0 / 3.0)) * md);
+ break;
+ case 3:
+ RGB[0] = mn;
+ RGB[1] = mn + (((2.0 / 3.0f) - HSB[0]) * md);
+ RGB[2] = HSB[2];
+ break;
+ case 4:
+ RGB[0] = mn + ((HSB[0] - (2.0 / 3.0)) * md);
+ RGB[1] = mn;
+ RGB[2] = HSB[2];
+ break;
+ case 5:
+ RGB[0] = HSB[2];
+ RGB[1] = mn;
+ RGB[2] = mn + ((1.0 - HSB[0]) * md);
+ break;
+ }
+ for (i=0;i<3;i++) {
+ if (RGB[i] < 0)
+ RGB[i] = 0;
+ if (RGB[i] > 1)
+ RGB[i] = 1;
+ HSB[i] = RGB[i];
+ }
+ return 0;
+}
+
+/* The routiens for handling colors and color spaces, moved from
+ * PostScript to C, start here.
+ */
+
+/* DeviceGray */
+static int setgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp;
+ gs_color_space *pcs;
+ int code=0;
+ ref stref;
+
+ do {
+ switch (*stage) {
+ case 0:
+ if (istate->use_cie_color.value.boolval && !CIESubst) {
+ byte *body;
+ ref *nosubst;
+
+ code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nosubst, t_boolean))
+ return_error(e_typecheck);
+ if (nosubst->value.boolval) {
+ *stage = 4;
+ *cont = 1;
+ body = ialloc_string(32, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "/DefaultGray ..nosubstdevicetest",32);
+ make_string(&stref, a_all | icurrent_space, 32, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ } else {
+ *stage = 2;
+ *cont = 1;
+ body = ialloc_string(47, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "{/DefaultGray /ColorSpace findresource} stopped",47);
+ make_string(&stref, a_all | icurrent_space, 47, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ }
+ break;
+ }
+ /* fall through */
+ case 1:
+ pcs = gs_cspace_new_DeviceGray(imemory);
+ if (pcs == NULL)
+ return_error(e_VMerror);
+ code = gs_setcolorspace(igs, pcs);
+ if (code >= 0) {
+ gs_client_color * pcc = igs->ccolor;
+
+ cs_adjust_color_count(igs, -1); /* not strictly necessary */
+ pcc->paint.values[0] = (0);
+ pcc->pattern = 0; /* for GC */
+ gx_unset_dev_color(igs);
+ }
+ rc_decrement_only(pcs, "zsetdevcspace");
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 2:
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ if (op->value.boolval) {
+ /* Failed to find the /DefaultGray CSA, so give up and
+ * just use DeviceGray
+ */
+ pop(1);
+ *stage = 1;
+ break;
+ }
+ pop(1);
+ *cont = 1;
+ *stage = 3;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ case 3:
+ /* We end up here after setting the DefaultGray space
+ * We've finished setting the gray color space, so we
+ * just exit now
+ */
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 4:
+ /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
+ * is also true. We will have a boolean on the stack, if its true
+ * then we need to set the space (also on the stack), invoke
+ * .includecolorspace, and set /DeviceGray, otherwise we just need
+ * to set DeviceGray. See gs_cspace.ps.
+ */
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ pop(1);
+ *stage = 1;
+ *cont = 1;
+ if (op->value.boolval) {
+ *stage = 5;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ }
+ break;
+ case 5:
+ /* After stage 4 above, if we had to set a color space, we come
+ * here. Now we need to use .includecolorspace to register the space
+ * with any high-level devices which want it.
+ */
+ *stage = 1;
+ *cont = 1;
+ code = zincludecolorspace(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ }
+ } while (*stage);
+ return code;
+}
+static int graydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ptr[0] = 0;
+ ptr[1] = 1;
+ return 0;
+}
+static int grayrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ptr[0] = 0;
+ ptr[1] = 1;
+ return 0;
+}
+/* This routine converts a Gray value into its equivalent in a different
+ * device space, required by currentgray, currentrgb, currenthsb and
+ * currentcmyk. The actual color value will have been processed through
+ * the tint transform(s) of the parent space(s) until it reaches a device
+ * space. This converts that final value into the requested space.
+ */
+static int graybasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp;
+ double Gray, RGB[3];
+
+ *cont = 0;
+ *stage = 0;
+ check_op(1);
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ Gray = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ Gray = (double)op->value.intval;
+
+ if (Gray < 0 || Gray > 1)
+ return_error(e_rangecheck);
+
+ switch (base) {
+ case 0:
+ /* Requested space is DeviceGray, just use the value */
+ make_real(op, Gray);
+ break;
+ case 1:
+ /* Requested space is HSB */
+ case 2:
+ /* Requested space is RGB, set all the components
+ * to the gray value
+ */
+ push(2);
+ RGB[0] = RGB[1] = RGB[2] = Gray;
+ if (base == 1)
+ /* If the requested space is HSB, convert the RGB to HSB */
+ rgb2hsb((float *)&RGB);
+ make_real(&op[-2], RGB[0]);
+ make_real(&op[-1], RGB[1]);
+ make_real(op, RGB[2]);
+ break;
+ case 3:
+ /* Requested space is CMYK, use the gray value to set the
+ * black channel.
+ */
+ push(3);
+ make_real(&op[-3], (float)0);
+ make_real(&op[-2], (float)0);
+ make_real(&op[-1], (float)0);
+ make_real(op, (float)1.0 - Gray);
+ break;
+ default:
+ return_error(e_undefined);
+ }
+ return 0;
+}
+static int grayvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+
+ if (num_comps < 1)
+ return_error(e_stackunderflow);
+
+ if (*values > 1.0)
+ *values = 1.0;
+
+ if ( *values < 0.0)
+ *values = 0.0;
+
+ return 0;
+}
+static int grayinitialproc(i_ctx_t *i_ctx_p, ref *space)
+{
+ gs_client_color cc;
+
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 0;
+ return gs_setcolor(igs, &cc);
+}
+
+/* DeviceRGB */
+static int setrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp;
+ gs_color_space *pcs;
+ int code=0;
+ ref stref;
+
+ do {
+ switch (*stage) {
+ case 0:
+ if (istate->use_cie_color.value.boolval && !CIESubst) {
+ byte *body;
+ ref *nosubst;
+
+ code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nosubst, t_boolean))
+ return_error(e_typecheck);
+ if (nosubst->value.boolval) {
+ *stage = 4;
+ *cont = 1;
+ body = ialloc_string(31, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "/DefaultRGB ..nosubstdevicetest",31);
+ make_string(&stref, a_all | icurrent_space, 31, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ } else {
+ *stage = 2;
+ *cont = 1;
+ body = ialloc_string(46, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "{/DefaultRGB /ColorSpace findresource} stopped", 46);
+ make_string(&stref, a_all | icurrent_space, 46, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ }
+ }
+ /* fall through */
+ case 1:
+ pcs = gs_cspace_new_DeviceRGB(imemory);
+ if (pcs == NULL)
+ return_error(e_VMerror);
+ code = gs_setcolorspace(igs, pcs);
+ if (code >= 0) {
+ gs_client_color * pcc = igs->ccolor;
+
+ cs_adjust_color_count(igs, -1); /* not strictly necessary */
+ pcc->paint.values[0] = 0;
+ pcc->paint.values[1] = 0;
+ pcc->paint.values[2] = 0;
+ pcc->pattern = 0; /* for GC */
+ gx_unset_dev_color(igs);
+ }
+ rc_decrement_only(pcs, "zsetdevcspace");
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 2:
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ if (op->value.boolval) {
+ /* Failed to find the /DefaultRGB CSA, so give up and
+ * just use DeviceRGB
+ */
+ pop(1);
+ *stage = 1;
+ break;
+ }
+ pop(1);
+ *stage = 3;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ case 3:
+ /* We end up here after setting the DefaultGray CIE space
+ * We've finished setting the gray color space, so we
+ * just exit now
+ */
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 4:
+ /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
+ * is also true. We will have a boolean on the stack, if its true
+ * then we need to set the space (also on the stack), invoke
+ * .includecolorspace, and set /DeviceGray, otherwise we just need
+ * to set DeviceGray. See gs-cspace.ps.
+ */
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ pop(1);
+ *stage = 1;
+ *cont = 1;
+ if (op->value.boolval) {
+ *stage = 5;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ }
+ break;
+ case 5:
+ /* After stage 4 above, if we had to set a color space, we come
+ * here. Now we need to use .includecolorspace to register the space
+ * with any high-level devices which want it.
+ */
+ *stage = 1;
+ *cont = 1;
+ code = zincludecolorspace(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ }
+ } while (*stage);
+ return code;
+}
+static int rgbdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i;
+
+ for (i = 0;i < 6;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+static int rgbrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i;
+
+ for (i = 0;i < 6;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+/* This routine converts an RGB value into its equivalent in a different
+ * device space, required by currentgray, currentrgb, currenthsb and
+ * currentcmyk. The actual color value will have been processed through
+ * the tint transform(s) of the parent space(s) until it reaches a device
+ * space. This converts that final value into the requested space.
+ */
+static int rgbbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp;
+ float RGB[3], CMYK[4], Gray, UCR, BG;
+ int i;
+
+ switch (*stage) {
+ case 0:
+ *cont = 0;
+ check_op(3);
+ op -= 2;
+ for (i=0;i<3;i++) {
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ RGB[i] = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ RGB[i] = (float)op->value.intval;
+ if (RGB[i] < 0 || RGB[i] > 1)
+ return_error(e_rangecheck);
+ op++;
+ }
+ op = osp;
+
+ switch (base) {
+ case 0:
+ pop(2);
+ op = osp;
+ /* If R == G == B, then this is gray, so just use it. Avoids
+ * rounding errors.
+ */
+ if (RGB[0] == RGB[1] && RGB[1] == RGB[2])
+ Gray = RGB[0];
+ else
+ Gray = (0.3 * RGB[0]) + (0.59 * RGB[1]) + (0.11 * RGB[2]);
+ make_real(op, Gray);
+ return 0;
+ break;
+ case 1:
+ rgb2hsb((float *)&RGB);
+ make_real(&op[-2], RGB[0]);
+ make_real(&op[-1], RGB[1]);
+ make_real(op, RGB[2]);
+ return 0;
+ break;
+ case 2:
+ make_real(&op[-2], RGB[0]);
+ make_real(&op[-1], RGB[1]);
+ make_real(op, RGB[2]);
+ return 0;
+ break;
+ case 3:
+ *stage = 1;
+ *cont = 1;
+ for (i=0;i<3;i++)
+ CMYK[i] = 1 - RGB[i];
+ if (CMYK[0] < CMYK[1]) {
+ if (CMYK[0] < CMYK[2])
+ CMYK[3] = CMYK[0];
+ else
+ CMYK[3] = CMYK[2];
+ } else {
+ if (CMYK[1] < CMYK[2])
+ CMYK[3] = CMYK[1];
+ else
+ CMYK[3] = CMYK[2];
+ }
+ check_estack(1);
+ push(2);
+ op = osp - 4;
+ for (i=0;i<4;i++) {
+ make_real(op, CMYK[i]);
+ op++;
+ }
+ make_real(op, CMYK[3]);
+ esp++;
+ *esp = istate->undercolor_removal;
+ return o_push_estack;
+ break;
+ default:
+ return_error(e_undefined);
+ break;
+ }
+ break;
+ case 1:
+ (*stage)++;
+ *cont = 1;
+ check_estack(1);
+ check_op(5);
+ op -= 4;
+ for (i=0;i<4;i++) {
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ CMYK[i] = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ CMYK[i] = (float)op->value.intval;
+ op++;
+ }
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ UCR = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ UCR = (float)op->value.intval;
+ for (i=0;i<3;i++) {
+ CMYK[i] = CMYK[i] - UCR;
+ if (CMYK[i] < 0)
+ CMYK[i] = 0;
+ if (CMYK[i] > 1)
+ CMYK[i] = 1.0;
+ }
+ op -= 4;
+ for (i=0;i<4;i++) {
+ make_real(op, CMYK[i]);
+ op++;
+ }
+ make_real(op, CMYK[3]);
+ esp++;
+ *esp = istate->black_generation;
+ return o_push_estack;
+ break;
+ case 2:
+ *stage = 0;
+ *cont = 0;
+ check_op(5);
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ BG = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ BG = (float)op->value.intval;
+ pop(1);
+ op = osp;
+ if (BG < 0)
+ BG = 0;
+ if (BG > 1)
+ BG = 1;
+ make_real(op, BG);
+ break;
+ }
+ return 0;
+}
+static int rgbvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+ int i;
+
+ if (num_comps < 3)
+ return_error(e_stackunderflow);
+
+ op -= 2;
+ for (i=0;i<3;i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+ op++;
+ }
+
+ for (i=0;i < 3; i++) {
+ if (values[i] > 1.0)
+ values[i] = 1.0;
+
+ if (values[i] < 0.0)
+ values[i] = 0.0;
+ }
+
+ return 0;
+}
+static int rgbinitialproc(i_ctx_t *i_ctx_p, ref *space)
+{
+ gs_client_color cc;
+
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 0;
+ cc.paint.values[1] = 0;
+ cc.paint.values[2] = 0;
+ return gs_setcolor(igs, &cc);
+}
+
+/* DeviceCMYK */
+static int setcmykspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp;
+ gs_color_space *pcs;
+ int code=0;
+ ref stref;
+
+ do {
+ switch (*stage) {
+ case 0:
+ if (istate->use_cie_color.value.boolval && !CIESubst) {
+ byte *body;
+ ref *nosubst;
+
+ code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nosubst, t_boolean))
+ return_error(e_typecheck);
+ if (nosubst->value.boolval) {
+ *stage = 4;
+ *cont = 1;
+ body = ialloc_string(32, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "/DefaultCMYK ..nosubstdevicetest",32);
+ make_string(&stref, a_all | icurrent_space, 32, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ } else {
+ *stage = 2;
+ *cont = 1;
+ body = ialloc_string(47, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "{/DefaultCMYK /ColorSpace findresource} stopped", 47);
+ make_string(&stref, a_all | icurrent_space, 47, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ }
+ }
+ /* fall through */
+ case 1:
+ pcs = gs_cspace_new_DeviceCMYK(imemory);
+ if (pcs == NULL)
+ return_error(e_VMerror);
+ code = gs_setcolorspace(igs, pcs);
+ if (code >= 0) {
+ gs_client_color * pcc = igs->ccolor;
+
+ cs_adjust_color_count(igs, -1); /* not strictly necessary */
+ pcc->paint.values[0] = 0;
+ pcc->paint.values[1] = 0;
+ pcc->paint.values[2] = 0;
+ pcc->paint.values[3] = 1;
+ pcc->pattern = 0; /* for GC */
+ gx_unset_dev_color(igs);
+ }
+ rc_decrement_only(pcs, "zsetdevcspace");
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 2:
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ if (op->value.boolval) {
+ /* Failed to find the /DefaultCMYK CSA, so give up and
+ * just use DeviceCMYK
+ */
+ pop(1);
+ *stage = 1;
+ break;
+ }
+ pop(1);
+ *stage = 3;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ case 3:
+ /* We end up here after setting the DefaultGray CIE space
+ * We've finished setting the gray color space, so we
+ * just exit now
+ */
+ *cont = 0;
+ *stage = 0;
+ break;
+ case 4:
+ /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
+ * is also true. We will have a boolean on the stack, if its true
+ * then we need to set the space (also on the stack), invoke
+ * .includecolorspace, and set /DeviceGray, otherwise we just need
+ * to set DeviceGray. See gs-cspace.ps.
+ */
+ if (!r_has_type(op, t_boolean))
+ return_error(e_typecheck);
+ pop(1);
+ *stage = 1;
+ *cont = 1;
+ if (op->value.boolval) {
+ *stage = 5;
+ code = setcolorspace_nosubst(i_ctx_p);
+ if (code != 0)
+ return code;
+ }
+ break;
+ case 5:
+ /* After stage 4 above, if we had to set a color space, we come
+ * here. Now we need to use .includecolorspace to register the space
+ * with any high-level devices which want it.
+ */
+ *stage = 1;
+ *cont = 1;
+ code = zincludecolorspace(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ }
+ } while (*stage);
+ return code;
+}
+static int cmykdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i;
+
+ for (i = 0;i < 8;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+static int cmykrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i;
+
+ for (i = 0;i < 8;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+/* This routine converts a CMYK value into its equivalent in a different
+ * device space, required by currentgray, currentrgb, currenthsb and
+ * currentcmyk. The actual color value will have been processed through
+ * the tint transform(s) of the parent space(s) until it reaches a device
+ * space. This converts that final value into the requested space.
+ */
+static int cmykbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp;
+ float CMYK[4], Gray, RGB[3];
+ int i;
+
+ *cont = 0;
+ *stage = 0;
+ check_op(4);
+ op -= 3;
+ for (i=0;i<4;i++) {
+ if (!r_has_type(op, t_integer)) {
+ if (r_has_type(op, t_real)) {
+ CMYK[i] = op->value.realval;
+ } else
+ return_error(e_typecheck);
+ } else
+ CMYK[i] = (float)op->value.intval;
+ if (CMYK[i] < 0 || CMYK[i] > 1)
+ return_error(e_rangecheck);
+ op++;
+ }
+
+ switch (base) {
+ case 0:
+ pop(3);
+ op = osp;
+ Gray = (0.3 * CMYK[0]) + (0.59 * CMYK[1]) + (0.11 * CMYK[2]) + CMYK[3];
+ if (Gray > 1.0)
+ Gray = 0;
+ else
+ Gray = 1.0 - Gray;
+ make_real(op, Gray);
+ break;
+ case 1:
+ case 2:
+ pop(1);
+ op = osp;
+ RGB[0] = 1.0 - (CMYK[0] + CMYK[3]);
+ if (RGB[0] < 0)
+ RGB[0] = 0;
+ RGB[1] = 1.0 - (CMYK[1] + CMYK[3]);
+ if (RGB[1] < 0)
+ RGB[1] = 0;
+ RGB[2] = 1.0 - (CMYK[2] + CMYK[3]);
+ if (RGB[2] < 0)
+ RGB[2] = 0;
+ if (base == 1)
+ rgb2hsb((float *)&RGB);
+ make_real(&op[-2], RGB[0]);
+ make_real(&op[-1], RGB[1]);
+ make_real(op, RGB[2]);
+ break;
+ case 3:
+ op = osp;
+ make_real(&op[-3], CMYK[0]);
+ make_real(&op[-2], CMYK[1]);
+ make_real(&op[-1], CMYK[2]);
+ make_real(op, CMYK[3]);
+ break;
+ default:
+ return_error(e_undefined);
+ }
+ return 0;
+}
+static int cmykvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+ int i;
+
+ if (num_comps < 4)
+ return_error(e_stackunderflow);
+
+ op -= 3;
+ for (i=0;i < 4;i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+ op++;
+ }
+
+ for (i=0;i < 4; i++) {
+ if (values[i] > 1.0)
+ values[i] = 1.0;
+
+ if (values[i] < 0.0)
+ values[i] = 0.0;
+ }
+
+ return 0;
+}
+static int cmykinitialproc(i_ctx_t *i_ctx_p, ref *space)
+{
+ gs_client_color cc;
+
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 0;
+ cc.paint.values[1] = 0;
+ cc.paint.values[2] = 0;
+ cc.paint.values[3] = 1;
+ return gs_setcolor(igs, &cc);
+}
+
+/* CIEBased */
+/* A utility routine to check whether two arrays contain the same
+ * contents. Used to check whether two color spaces are the same
+ * Note that this can be recursive if the array contains arrays.
+ */
+static int comparearrays(i_ctx_t * i_ctx_p, ref *m1, ref *m2)
+{
+ int i, code;
+ ref ref1, ref2;
+
+ if (r_size(m1) != r_size(m2))
+ return 0;
+
+ for (i=0;i < r_size(m1);i++) {
+ code = array_get(imemory, m1, i, &ref1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, m2, i, &ref2);
+ if (code < 0)
+ return 0;
+
+ if (r_type(&ref1) != r_type(&ref2))
+ return 0;
+
+ code = r_type(&ref1);
+ switch(r_type(&ref1)) {
+ case t_null:
+ break;
+ case t_boolean:
+ if (ref1.value.boolval != ref2.value.boolval)
+ return 0;
+ break;
+ case t_integer:
+ if (ref1.value.intval != ref2.value.intval)
+ return 0;
+ break;
+ case t_real:
+ if (ref1.value.realval != ref2.value.realval)
+ return 0;
+ break;
+ case t_name:
+ if (!name_eq(&ref1, &ref2))
+ return 0;
+ break;
+ case t_string:
+ if (r_size(&ref1) != r_size(&ref2))
+ return 0;
+ if (strncmp((const char *)ref1.value.const_bytes, (const char *)ref2.value.const_bytes, r_size(&ref1)) != 0)
+ return 0;
+ break;
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ if (!comparearrays(i_ctx_p, &ref1, &ref2))
+ return 0;
+ break;
+ case t_oparray:
+ break;
+ case t_operator:
+ if (ref1.value.opproc != ref2.value.opproc)
+ return 0;
+ break;
+ case t__invalid:
+ case t_dictionary:
+ case t_file:
+ case t_unused_array_:
+ case t_struct:
+ case t_astruct:
+ case t_fontID:
+ case t_save:
+ case t_mark:
+ case t_device:
+ return 0;
+ default:
+ /* Some high frequency operators are defined starting at t_next_index
+ * I think as long as the 'type' of each is the same, we are OK
+ */
+ break;
+ }
+ }
+ return 1;
+}
+/* A utility routine to check whether two dictionaries contain the same
+ * arrays. This is a simple routine, unlike comparearrays above it is only
+ * used by the CIE comparison code and expects only to check that the
+ * dictionary contains an array, and checks the arrays.
+ */
+static int comparedictkey(i_ctx_t * i_ctx_p, ref *CIEdict1, ref *CIEdict2, char *key)
+{
+ int code, code1;
+ ref *tempref1, *tempref2;
+
+ code = dict_find_string(CIEdict1, key, &tempref1);
+ code1 = dict_find_string(CIEdict2, key, &tempref2);
+ if (code != code1)
+ return 0;
+
+ if (code < 0)
+ return 1;
+
+ if (r_type(tempref1) != r_type(tempref2))
+ return 0;
+
+ if (r_type(tempref1) == t_null)
+ return 1;
+
+ return comparearrays(i_ctx_p, tempref1, tempref2);
+}
+
+/* Check that the WhitePoint of a CIE space is valid */
+static int checkWhitePoint(i_ctx_t * i_ctx_p, ref *CIEdict)
+{
+ int code = 0, i;
+ float value[3];
+ ref *tempref, valref;
+
+ code = dict_find_string(CIEdict, "WhitePoint", &tempref);
+ if (code < 0 || r_has_type(tempref, t_null))
+ return code;
+
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ /* Xw and Zw must be positive and Yw must be 1 (3rd edition PLRM p230) */
+ if (value[0] < 0 || value[1] != 1 || value[2] < 0 )
+ return_error(e_rangecheck);
+
+ return 0;
+}
+/* Check that the BlackPoint of a CIE space is valid */
+static int checkBlackPoint(i_ctx_t * i_ctx_p, ref *CIEdict)
+{
+ int code = 0, i;
+ float value[3];
+ ref *tempref, valref;
+
+ code = dict_find_string(CIEdict, "BlackPoint", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ }
+ return 0;
+}
+/* Check that the RangeLMN of a CIE space is valid */
+static int checkRangeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
+{
+ int code = 0, i;
+ float value[6];
+ ref *tempref, valref;
+
+ code = dict_find_string(CIEdict, "RangeLMN", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 6)
+ return_error(e_rangecheck);
+
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
+ return_error(e_rangecheck);
+ }
+ return 0;
+}
+/* Check that the DecodeLMN of a CIE space is valid */
+static int checkDecodeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
+{
+ int code = 0, i;
+ ref *tempref, valref;
+
+ code = dict_find_string(CIEdict, "DecodeLMN", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ check_proc(valref);
+ }
+ }
+ return 0;
+}
+/* Check that the MatrixLMN of a CIE space is valid */
+static int checkMatrixLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
+{
+ int code = 0, i;
+ float value[9];
+ ref *tempref, valref;
+
+ code = dict_find_string(CIEdict, "MatrixLMN", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 9)
+ return_error(e_rangecheck);
+
+ for (i=0;i<9;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ }
+ return 0;
+}
+
+/* CIEBasedA */
+static int setcieaspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ int code = 0;
+ ref CIEDict, *nocie;
+
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ code = dict_find_string(systemdict, "NOCIE", &nocie);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nocie, t_boolean))
+ return_error(e_typecheck);
+ if (nocie->value.boolval)
+ return setgrayspace(i_ctx_p, r, stage, cont, 1);
+
+ *cont = 0;
+ code = array_get(imemory, r, 1, &CIEDict);
+ if (code < 0)
+ return code;
+ if ((*stage) > 0) {
+ gs_client_color cc;
+
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 0;
+ code = gs_setcolor(igs, &cc);
+ *stage = 0;
+ return code;
+ }
+ code = cieaspace(i_ctx_p, &CIEDict);
+ (*stage)++;
+ *cont = 1;
+ return code;
+}
+static int validatecieaspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code = 0, i;
+ float value[9];
+ ref CIEdict, *CIEspace = *r, *tempref, valref;
+
+ if (!r_is_array(CIEspace))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(CIEspace) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, CIEspace, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ check_read_type(CIEdict, t_dictionary);
+
+ /* Check white point exists, and is an array of three numbers */
+ code = checkWhitePoint(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ /* Remaining parameters are optional, but we must validate
+ * them if they are present
+ */
+ code = dict_find_string(&CIEdict, "RangeA", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ /* Array of two numbers A0 < A1 */
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 2)
+ return_error(e_rangecheck);
+
+ for (i=0;i<2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0])
+ return_error(e_rangecheck);
+ }
+
+ code = dict_find_string(&CIEdict, "DecodeA", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ check_proc(*tempref);
+ }
+
+ code = dict_find_string(&CIEdict, "MatrixA", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ }
+
+ code = checkRangeLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkDecodeLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkMatrixLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkBlackPoint(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ *r = 0;
+ return 0;
+}
+static int cieadomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeA entry in the dictionary, get the
+ * values from that
+ */
+ code = dict_find_string(&CIEdict, "RangeA", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for CIEBasedA */
+ ptr[0] = 0;
+ ptr[1] = 1;
+ }
+ return 0;
+}
+static int ciearange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeA entry in the dictionary, get the
+ * values from that
+ */
+ code = dict_find_string(&CIEdict, "RangeA", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for CIEBasedA */
+ ptr[0] = 0;
+ ptr[1] = 1;
+ }
+ return 0;
+}
+static int cieavalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+
+ if (num_comps < 1)
+ return_error(e_stackunderflow);
+
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+
+ return 0;
+}
+static int cieacompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ int code = 0;
+ ref CIEdict1, CIEdict2;
+
+ code = array_get(imemory, space, 1, &CIEdict1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 1, &CIEdict2);
+ if (code < 0)
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeA"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeA"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixA"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
+ return 0;
+ return 1;
+}
+
+/* CIEBasedABC */
+static int setcieabcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ int code = 0;
+ ref CIEDict, *nocie;
+
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ code = dict_find_string(systemdict, "NOCIE", &nocie);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nocie, t_boolean))
+ return_error(e_typecheck);
+ if (nocie->value.boolval)
+ return setrgbspace(i_ctx_p, r, stage, cont, 1);
+
+ *cont = 0;
+ code = array_get(imemory, r, 1, &CIEDict);
+ if (code < 0)
+ return code;
+
+ if ((*stage) > 0) {
+ gs_client_color cc;
+ int i;
+
+ cc.pattern = 0x00;
+ for (i=0;i<3;i++)
+ cc.paint.values[i] = 0;
+ code = gs_setcolor(igs, &cc);
+ *stage = 0;
+ return code;
+ }
+ code = cieabcspace(i_ctx_p, &CIEDict);
+ *cont = 1;
+ (*stage)++;
+ return code;
+}
+static int validatecieabcspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code = 0, i;
+ float value[9];
+ ref CIEdict, *CIEspace = *r, *tempref, valref;
+
+ if (!r_is_array(CIEspace))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(CIEspace) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, CIEspace, 1, &CIEdict);
+ if (code < 0)
+ return code;
+ check_read_type(CIEdict, t_dictionary);
+
+ /* Check white point exists, and is an array of three numbers */
+ code = checkWhitePoint(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ /* Remaining parameters are optional, but we must validate
+ * them if they are present
+ */
+ code = dict_find_string(&CIEdict, "RangeABC", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 6)
+ return_error(e_rangecheck);
+
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
+ return_error(e_rangecheck);
+ }
+
+ code = dict_find_string(&CIEdict, "DecodeABC", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ check_proc(valref);
+ }
+ }
+
+ code = dict_find_string(&CIEdict, "MatrixABC", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) != 9)
+ return_error(e_rangecheck);
+
+ for (i=0;i<9;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ }
+
+
+ code = checkRangeLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkDecodeLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkMatrixLMN(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ code = checkBlackPoint(i_ctx_p, &CIEdict);
+ if (code != 0)
+ return code;
+
+ *r = 0;
+ return 0;
+}
+static int cieabcdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeABC, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeABC", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for CIEBasedABC */
+ for (i=0;i<3;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int cieabcrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeABC, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeABC", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for CIEBasedABC */
+ for (i=0;i<3;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int cieabcvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+ int i;
+
+ if (num_comps < 3)
+ return_error(e_stackunderflow);
+
+ op -= 2;
+ for (i=0;i<3;i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+ op++;
+ }
+
+ return 0;
+}
+static int cieabccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ int code = 0;
+ ref CIEdict1, CIEdict2;
+
+ code = array_get(imemory, space, 1, &CIEdict1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 1, &CIEdict2);
+ if (code < 0)
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
+ return 0;
+ return 1;
+}
+
+/* CIEBasedDEF */
+static int setciedefspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ int code = 0;
+ ref CIEDict, *nocie;
+
+ if (i_ctx_p->language_level < 3)
+ return_error(e_undefined);
+
+ code = dict_find_string(systemdict, "NOCIE", &nocie);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nocie, t_boolean))
+ return_error(e_typecheck);
+ if (nocie->value.boolval)
+ return setrgbspace(i_ctx_p, r, stage, cont, 1);
+
+ *cont = 0;
+ code = array_get(imemory, r, 1, &CIEDict);
+ if (code < 0)
+ return code;
+ if ((*stage) > 0) {
+ gs_client_color cc;
+ int i;
+
+ cc.pattern = 0x00;
+ for (i=0;i<3;i++)
+ cc.paint.values[i] = 0;
+ code = gs_setcolor(igs, &cc);
+ *stage = 0;
+ return code;
+ }
+ code = ciedefspace(i_ctx_p, &CIEDict);
+ *cont = 1;
+ (*stage)++;
+ return code;
+}
+static int validateciedefspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code = 0, i;
+ float value[6];
+ ref CIEdict, *pref, *CIEspace = *r, tempref, valref;
+
+ if (!r_is_array(CIEspace))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(CIEspace) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, CIEspace, 1, &CIEdict);
+ if (code < 0)
+ return code;
+ check_read_type(CIEdict, t_dictionary);
+
+ code = validatecieabcspace(i_ctx_p, r);
+ if (code != 0)
+ return code;
+
+ pref = &tempref;
+ code = dict_find_string(&CIEdict, "Table", &pref);
+ if (code >= 0) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 4)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, pref, 3, &valref);
+ if (code < 0)
+ return code;
+ if (!r_is_array(&valref))
+ return_error(e_typecheck);
+ if (r_size(&valref) != value[0])
+ return_error(e_rangecheck);
+
+ for (i=0;i<value[0];i++) {
+ code = array_get(imemory, &valref, i, &tempref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&tempref, t_string))
+ return_error(e_typecheck);
+
+ if (r_size(&tempref) != (3 * value[1] * value[2]))
+ return_error(e_rangecheck);
+ }
+ }
+
+ /* Remaining parameters are optional, but we must validate
+ * them if they are present
+ */
+ code = dict_find_string(&CIEdict, "RangeDEF", &pref);
+ if (code >= 0 && !r_has_type(&tempref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 6)
+ return_error(e_rangecheck);
+
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
+ return_error(e_rangecheck);
+ }
+
+ code = dict_find_string(&CIEdict, "DecodeDEF", &pref);
+ if (code >= 0 && !r_has_type(pref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 3)
+ return_error(e_rangecheck);
+
+ for (i=0;i<3;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ check_proc(valref);
+ }
+ }
+
+ code = dict_find_string(&CIEdict, "RangeHIJ", &pref);
+ if (code >= 0 && !r_has_type(pref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 6)
+ return_error(e_rangecheck);
+
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
+ return_error(e_rangecheck);
+ }
+
+ *r = 0;
+ return 0;
+}
+static int ciedefdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeDEF, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for a CIEBasedDEF */
+ for (i=0;i<3;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int ciedefrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeDEF, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<6;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for a CIEBasedDEF */
+ for (i=0;i<3;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int ciedefvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+ int i;
+
+ if (num_comps < 3)
+ return_error(e_stackunderflow);
+
+ op -= 2;
+ for (i=0;i<3;i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+ op++;
+ }
+
+ return 0;
+}
+static int ciedefcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ int code = 0;
+ ref CIEdict1, CIEdict2;
+
+ code = array_get(imemory, space, 1, &CIEdict1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 1, &CIEdict2);
+ if (code < 0)
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEF"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEF"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJ"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
+ return 0;
+ return 1;
+}
+
+/* CIEBasedDEFG */
+static int setciedefgspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ int code = 0;
+ ref CIEDict, *nocie;
+
+ if (i_ctx_p->language_level < 3)
+ return_error(e_undefined);
+
+ code = dict_find_string(systemdict, "NOCIE", &nocie);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nocie, t_boolean))
+ return_error(e_typecheck);
+ if (nocie->value.boolval)
+ return setcmykspace(i_ctx_p, r, stage, cont, 1);
+
+ *cont = 0;
+ code = array_get(imemory, r, 1, &CIEDict);
+ if (code < 0)
+ return code;
+ if ((*stage) > 0) {
+ gs_client_color cc;
+ int i;
+
+ cc.pattern = 0x00;
+ for (i=0;i<4;i++)
+ cc.paint.values[i] = 0;
+ code = gs_setcolor(igs, &cc);
+ *stage = 0;
+ return code;
+ }
+ code = ciedefgspace(i_ctx_p, &CIEDict);
+ *cont = 1;
+ (*stage)++;
+ return code;
+}
+static int validateciedefgspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code = 0, i, j;
+ float value[8];
+ ref CIEdict, *CIEspace = *r, tempref, arrayref, valref, *pref = &tempref;
+
+ if (!r_is_array(CIEspace))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(CIEspace) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, CIEspace, 1, &CIEdict);
+ if (code < 0)
+ return code;
+ check_read_type(CIEdict, t_dictionary);
+
+ code = validatecieabcspace(i_ctx_p, r);
+ if (code != 0)
+ return code;
+
+ code = dict_find_string(&CIEdict, "Table", &pref);
+ if (code >= 0) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 5)
+ return_error(e_rangecheck);
+
+ for (i=0;i<4;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1 || value[3] <= 1)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, pref, 4, &arrayref);
+ if (code < 0)
+ return code;
+ if (!r_is_array(&arrayref))
+ return_error(e_typecheck);
+ if (r_size(&arrayref) != value[0])
+ return_error(e_rangecheck);
+
+ for (i=0;i<value[0];i++) {
+ code = array_get(imemory, &arrayref, i, &tempref);
+ if (code < 0)
+ return code;
+ for (j=0;j<value[1];j++) {
+ code = array_get(imemory, &tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&valref, t_string))
+ return_error(e_typecheck);
+
+ if (r_size(&valref) != (3 * value[2] * value[3]))
+ return_error(e_rangecheck);
+ }
+ }
+ }
+
+ /* Remaining parameters are optional, but we must validate
+ * them if they are present
+ */
+ code = dict_find_string(&CIEdict, "RangeDEFG", &pref);
+ if (code >= 0 && !r_has_type(pref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 8)
+ return_error(e_rangecheck);
+
+ for (i=0;i<8;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
+ return_error(e_rangecheck);
+ }
+
+ code = dict_find_string(&CIEdict, "DecodeDEFG", &pref);
+ if (code >= 0 && !r_has_type(pref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 4)
+ return_error(e_rangecheck);
+
+ for (i=0;i<4;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ check_proc(valref);
+ }
+ }
+
+ code = dict_find_string(&CIEdict, "RangeHIJK", &pref);
+ if (code >= 0 && !r_has_type(pref, t_null)) {
+ if (!r_is_array(pref))
+ return_error(e_typecheck);
+ if (r_size(pref) != 8)
+ return_error(e_rangecheck);
+
+ for (i=0;i<8;i++) {
+ code = array_get(imemory, pref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ value[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ value[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
+ return_error(e_rangecheck);
+ }
+
+ *r = 0;
+ return 0;
+}
+static int ciedefgdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeDEFG, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<8;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for a CIEBasedDEFG */
+ for (i=0;i<4;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int ciedefgrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, code;
+ ref CIEdict, *tempref, valref;
+
+ code = array_get(imemory, space, 1, &CIEdict);
+ if (code < 0)
+ return code;
+
+ /* If we have a RangeDEFG, get the values from that */
+ code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<8;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i] = (float)valref.value.intval;
+ else if (r_has_type(&valref, t_real))
+ ptr[i] = (float)valref.value.realval;
+ else
+ return_error(e_typecheck);
+ }
+ } else {
+ /* Default values for a CIEBasedDEFG */
+ for (i=0;i<4;i++) {
+ ptr[2 * i] = 0;
+ ptr[(2 * i) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int ciedefgvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+ int i;
+
+ if (num_comps < 4)
+ return_error(e_stackunderflow);
+
+ op -= 3;
+ for (i=0;i < 4;i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+ op++;
+ }
+ return 0;
+}
+static int ciedefgcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ /* If the problems mentioned above are resolved, then this code could
+ * be re-instated.
+ */
+ int code = 0;
+ ref CIEdict1, CIEdict2;
+
+ code = array_get(imemory, space, 1, &CIEdict1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 1, &CIEdict2);
+ if (code < 0)
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEFG"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEFG"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJK"))
+ return 0;
+ if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
+ return 0;
+ return 1;
+}
+
+static char *CIESpaces[] = {
+ (char *)"CIEBasedA",
+ (char *)"CIEBasedABC",
+ (char *)"CIEBasedDEF",
+ (char *)"CIEBasedDEFG"
+};
+/* This routine returns the Device space equivalents for a CIEBased space.
+ * Used by currentgray, currentrgb and currentcmyk, the PLRM says that CIE
+ * spaces return 0 for all components.
+ */
+static int ciebasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op;
+ ref *spacename, nref;
+ int i, components=1;
+
+ /* If the spaece is an array, the first element is always the name */
+ if (r_is_array(space))
+ spacename = space->value.refs;
+ else
+ spacename = space;
+ /* Check that it really is a name */
+ if (!r_has_type(spacename, t_name))
+ return_error(e_typecheck);
+
+ /* Find the relevant color space object */
+ for (i=0;i<4;i++) {
+ names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)CIESpaces[i], strlen(CIESpaces[i]), &nref, 0);
+ if (name_eq(spacename, &nref)) {
+ break;
+ }
+ }
+ /* Find out how many values are on the stack, which depends
+ * on what kind of CIEBased space this is.
+ */
+ switch(i){
+ case 0:
+ components = 1;
+ break;
+ case 1:
+ case 2:
+ components = 3;
+ break;
+ case 3:
+ components = 4;
+ break;
+ }
+ /* Remove teh requisite number of values */
+ pop(components);
+ op = osp;
+ /* Find out how many values we need to return, which
+ * depends on the requested space.
+ */
+ switch(base) {
+ case 0:
+ components = 1;
+ break;
+ case 1:
+ case 2:
+ components = 3;
+ break;
+ case 3:
+ components = 4;
+ break;
+ }
+ push(components);
+ /* The PLRM says that all the components should be returned as 0.0 */
+ op -= components-1;
+ for (i=0;i<components;i++) {
+ make_real(op, (float)0);
+ op++;
+ }
+ /* However, Adobe implementations actually return 1.0 for the black
+ * channel of CMYK...
+ */
+ if (components == 4) {
+ op--;
+ make_real(op, (float)1);
+ }
+ *stage = 0;
+ *cont = 0;
+ return 0;
+}
+
+/* This routine used by both Separatin and DeviceN spaces to convert
+ * a PostScript tint transform into a Function, either a type 4
+ * 'PostScript calculator (see PDF reference) or a type 0 'sampled'
+ * function.
+ */
+static int convert_transform(i_ctx_t * i_ctx_p, ref *arr, ref *pproc)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code;
+
+ /* buildfunction returns an operand on the stack. In fact
+ * it replaces the lowest operand, so make sure there is an
+ * empty sacrificial one present.
+ */
+ push(1);
+ /* Start by trying a type 4 function */
+ code = buildfunction(i_ctx_p, arr, pproc, 4);
+
+ if (code < 0)
+ /* If that fails, try a type 0. We prefer a type 4
+ * because a type 0 will require us to sample the
+ * space, which is expensive
+ */
+ code = buildfunction(i_ctx_p, arr, pproc, 0);
+
+ return code;
+}
+
+/* Separation */
+static int setseparationspace(i_ctx_t * i_ctx_p, ref *sepspace, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code = 0;
+ ref sname, proc;
+ ref name_none, name_all;
+ separation_type sep_type;
+ ref_colorspace cspace_old;
+ gs_color_space *pcs;
+ gs_color_space * pacs;
+ gs_function_t *pfn = NULL;
+ gs_client_color cc;
+
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ *cont = 0;
+ if ((*stage) == 0) {
+ code = array_get(imemory, sepspace, 3, &proc);
+ if (code < 0)
+ return code;
+ /* Check to see if we already have a function (eg from a PDF file) */
+ pfn = ref_function(&proc);
+ if (pfn == NULL) {
+ /* Convert tint transform to a PostScript function */
+ code = convert_transform(i_ctx_p, sepspace, &proc);
+ if (code < 0)
+ return code;
+ if (code > 0) {
+ *cont = 1;
+ (*stage)++;
+ return code;
+ }
+ /* We can only get here if the transform converted to a function
+ * without requiring a continuation. Most likely this means its a
+ * type 4 function. If so then it is still on the stack.
+ */
+ op = osp;
+ pfn = ref_function(op);
+ pop (1);
+ }
+ } else {
+ /* The function is returned on the operand stack */
+ op = osp;
+ pfn = ref_function(op);
+ pop (1);
+ }
+
+ *stage = 0;
+ if ((code = name_ref(imemory, (const byte *)"All", 3, &name_all, 0)) < 0)
+ return code;
+ if ((code = name_ref(imemory, (const byte *)"None", 4, &name_none, 0)) < 0)
+ return code;
+ /* Check separation name is a string or name object */
+ code = array_get(imemory, sepspace, 1, &sname);
+ if (code < 0)
+ return code;
+
+ if (r_has_type(&sname, t_string)) {
+ code = name_from_string(imemory, &sname, &sname);
+ if (code < 0)
+ return code;
+ }
+ sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
+ name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
+
+ /* The alternate color space has been selected as the current color space */
+ pacs = gs_currentcolorspace(igs);
+
+ cspace_old = istate->colorspace;
+ /* Now set the current color space as Separation */
+ code = gs_cspace_new_Separation(&pcs, pacs, imemory);
+ if (code < 0)
+ return code;
+ pcs->params.separation.sep_type = sep_type;
+ pcs->params.separation.sep_name = name_index(imemory, &sname);
+ pcs->params.separation.get_colorname_string = gs_get_colorname_string;
+ code = array_get(imemory, sepspace, 1, &proc);
+ if (code < 0)
+ return code;
+ istate->colorspace.procs.special.separation.layer_name = proc;
+ code = array_get(imemory, sepspace, 3, &proc);
+ if (code < 0)
+ return code;
+ istate->colorspace.procs.special.separation.tint_transform = proc;
+ if (code >= 0)
+ code = gs_cspace_set_sepr_function(pcs, pfn);
+ if (code >= 0)
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ rc_decrement_only(pcs, "setseparationspace");
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ return code;
+ }
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 1.0;
+ code = gs_setcolor(igs, &cc);
+ return code;
+}
+static int validateseparationspace(i_ctx_t * i_ctx_p, ref **space)
+{
+ int code = 0;
+ ref *sepspace = *space;
+ ref nameref, sref, sname, altspace, tref;
+
+ if (!r_is_array(sepspace))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(sepspace) != 4)
+ return_error(e_rangecheck);
+
+ /* Check separation name is a string or name object */
+ code = array_get(imemory, sepspace, 1, &sname);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&sname, t_name)) {
+ if (!r_has_type(&sname, t_string))
+ return_error(e_typecheck);
+ else {
+ code = name_from_string(imemory, &sname, &sname);
+ if (code < 0)
+ return code;
+ }
+ }
+
+ /* Check the tint transform is a procedure */
+ code = array_get(imemory, sepspace, 3, &tref);
+ if (code < 0)
+ return code;
+ check_proc(tref);
+
+ /* Get the name of the alternate space */
+ code = array_get(imemory, sepspace, 2, &altspace);
+ if (code < 0)
+ return code;
+ if (r_has_type(&altspace, t_name))
+ ref_assign(&nameref, &altspace);
+ else {
+ /* Make sure the alternate space is an array */
+ if (!r_is_array(&altspace))
+ return_error(e_typecheck);
+ /* And has a name for its type */
+ code = array_get(imemory, &altspace, 0, &tref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&tref, t_name))
+ return_error(e_typecheck);
+ ref_assign(&nameref, &tref);
+ }
+
+ /* Convert alternate space name to string */
+ name_string_ref(imemory, &nameref, &sref);
+ /* Check its not /Indexed or /Pattern or /DeviceN */
+ if (r_size(&sref) == 7) {
+ if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
+ return_error(e_typecheck);
+ if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
+ return_error(e_typecheck);
+ if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
+ return_error(e_typecheck);
+ }
+ /* and also not /Separation */
+ if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
+ return_error(e_typecheck);
+
+ ref_assign(*space, &altspace);
+ return 0;
+}
+static int separationalternatespace(i_ctx_t * i_ctx_p, ref *sepspace, ref **r)
+{
+ ref tref;
+ int code;
+
+ code = array_get(imemory, sepspace, 2, &tref);
+ if (code < 0)
+ return code;
+ ref_assign(*r, &tref);
+ return 0;
+}
+static int sepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ptr[0] = 0;
+ ptr[1] = 1;
+ return 0;
+}
+static int seprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ptr[0] = 0;
+ ptr[1] = 1;
+ return 0;
+}
+static int septransform(i_ctx_t *i_ctx_p, ref *sepspace, int *usealternate, int *stage, int *stack_depth)
+{
+ gx_device * dev = igs->device;
+ ref sname, proc;
+ int code, colorant_number;
+
+ code = array_get(imemory, sepspace, 1, &sname);
+ if (code < 0)
+ return code;
+ if (r_has_type(&sname, t_name)) {
+ name_string_ref(imemory, &sname, &sname);
+ }
+
+ /* Check for /All and /None, never need the alternate for these */
+ if (r_size(&sname) == 3 &&
+ strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 0;
+ return 0;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 0;
+ return 0;
+ }
+ /*
+ * Compare the colorant name to the device's. If the device's
+ * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
+ * colorant is in the SeparationNames list but not in the
+ * SeparationOrder list.
+ */
+ colorant_number = (*dev_proc(dev, get_color_comp_index))
+ (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
+ if (colorant_number >= 0) { /* If valid colorant name */
+ *usealternate = 0;
+ } else
+ *usealternate = 1;
+
+ if (r_size(&sname) == 4 &&
+ strncmp("Gray", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("Cyan", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 7 &&
+ strncmp("Magenta", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 6 &&
+ strncmp("Yellow", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 5 &&
+ strncmp("Black", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 3 &&
+ strncmp("Red", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 5 &&
+ strncmp("Green", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("Blue", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ }
+ if (*usealternate && *stage == 0) {
+ (*stage)++;
+ esp++;
+ code = array_get(imemory, sepspace, 3, &proc);
+ if (code < 0)
+ return code;
+ *esp = proc;
+ return o_push_estack;
+ }
+ *stage = 0;
+ return 0;
+}
+static int sepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int use, code;
+
+ code = septransform(i_ctx_p, space, &use, stage, stack_depth);
+ if (code != 0)
+ return code;
+ if (!use) {
+ *stage = 0;
+ *cont = 0;
+ pop(1);
+ op = osp;
+ switch(base) {
+ case 0:
+ push(1);
+ make_real(op, 0.0);
+ break;
+ case 1:
+ case 2:
+ push(3);
+ make_real(&op[-2], 0.0);
+ make_real(&op[-1], 0.0);
+ make_real(op, 0.0);
+ break;
+ case 3:
+ push(4);
+ make_real(&op[-3], 0.0);
+ make_real(&op[-2], 0.0);
+ make_real(&op[-1], 0.0);
+ make_real(op, 0.0);
+ break;
+ }
+ } else {
+ *stage = 0;
+ *cont = 1;
+ }
+ return 0;
+}
+static int sepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+
+ if (num_comps < 1)
+ return_error(e_stackunderflow);
+
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+
+ if (*values > 1.0)
+ *values = 1.0;
+
+ if (*values < 0.0)
+ *values = 0.0;
+
+ return 0;
+}
+static int sepcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ ref sname1, sname2;
+ int code;
+
+ code = array_get(imemory, space, 1, &sname1);
+ if (code < 0)
+ return 0;
+
+ code = array_get(imemory, testspace, 1, &sname2);
+ if (code < 0)
+ return 0;
+
+ if (r_type(&sname1) != r_type(&sname2))
+ return 0;
+
+ switch(r_type(&sname1)) {
+ case t_name:
+ if (!name_eq(&sname1, &sname2))
+ return 0;
+ break;
+ case t_string:
+ if (r_size(&sname1) != r_size(&sname2))
+ return 0;
+ if (strncmp((const char *)sname1.value.const_bytes, (const char *)sname2.value.const_bytes, r_size(&sname1)) != 0)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ code = array_get(imemory, testspace, 2, &sname1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 2, &sname2);
+ if (code < 0)
+ return 0;
+ if (r_type(&sname1) != r_type(&sname2))
+ return 0;
+
+ if (r_is_array(&sname1)) {
+ if (!comparearrays(i_ctx_p, &sname1, &sname2))
+ return 0;
+ } else {
+ if (!r_has_type(&sname1, t_name))
+ return 0;
+ if (!name_eq(&sname1, &sname2))
+ return 0;
+ }
+ code = array_get(imemory, space, 3, &sname1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 3, &sname2);
+ if (code < 0)
+ return 0;
+ return(comparearrays(i_ctx_p, &sname1, &sname2));
+}
+static int sepinitialproc(i_ctx_t *i_ctx_p, ref *space)
+{
+ gs_client_color cc;
+
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 1.0;
+ return gs_setcolor(igs, &cc);
+}
+
+/* DeviceN */
+static int devicencolorants_cont(i_ctx_t *i_ctx_p)
+{
+ ref dict, *pdict = &dict, space[2], sname;
+ int index, code, depth, stage;
+ es_ptr ep = esp, pindex, pstage;
+ os_ptr op = osp;
+ gs_separation_name sep_name;
+
+ pindex = &ep[-2];
+ pstage = &ep[-1];
+ index = (int)pindex->value.intval;
+ stage = (int)pstage->value.intval;
+ ref_assign(&dict, ep);
+
+ do {
+ if (index >= dict_length(pdict)) {
+ esp -= 4;
+ return o_pop_estack;
+ }
+
+ if (stage == 0) {
+ code = gs_gsave(igs);
+ if (code < 0)
+ return code;
+
+ /* If we get a continuation from a sub-procedure, we will want to come back
+ * here afterward, to do any remaining stages. We need to set up for that now.
+ * so that our continuation is ahead of the sub-proc's continuation.
+ */
+ check_estack(1);
+ /* The push_op_estack macro increments esp before use, so we don't need to */
+ push_op_estack(devicencolorants_cont);
+
+ code = dict_index_entry(pdict, index, (ref *)&space);
+ if (code < 0)
+ return code;
+
+ code = validate_spaces(i_ctx_p, &space[1], &depth);
+ if (code < 0) {
+ make_int(pindex, ++index);
+ code = gs_grestore(igs);
+ if (code < 0)
+ return code;
+ return o_push_estack;
+ }
+
+ make_int(pstage, 1);
+ push(1);
+ *op = space[1];
+ code = zsetcolorspace(i_ctx_p);
+ if (code != 0)
+ return code;
+ } else {
+ stage = 0;
+ code = dict_index_entry(pdict, index, (ref *)&space);
+ if (code == 0) {
+ switch (r_type(&space[0])) {
+ case t_string:
+ code = name_from_string(imemory, &space[0], &sname);
+ if (code == 0)
+ sep_name = name_index(imemory, &sname);
+ break;
+ case t_name:
+ sep_name = name_index(imemory, &space[0]);
+ break;
+ default:
+ code = e_typecheck;
+ }
+ }
+ make_int(pindex, ++index);
+ make_int(pstage, stage);
+ if (code == 0)
+ gs_attachattributecolorspace(sep_name, igs);
+ code = gs_grestore(igs);
+ if (code < 0)
+ return code;
+ }
+ }
+ while(1);
+}
+
+static int setdevicenspace(i_ctx_t * i_ctx_p, ref *devicenspace, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code = 0, num_components, i;
+ ref namesarray, proc, sname, sref, tempref[2];
+ ref_colorspace cspace_old;
+ gs_color_space *pcs;
+ gs_color_space * pacs;
+ gs_function_t *pfn = NULL;
+ gs_separation_name *names;
+ gs_device_n_map *pmap;
+ gs_client_color cc;
+
+ if (i_ctx_p->language_level < 3)
+ return_error(e_undefined);
+
+ *cont = 0;
+ if ((*stage) == 2) {
+ if (r_size(devicenspace) == 5) {
+ /* We have a Colorants dictionary from a PDF file. We need to handle this by
+ * temporarily setting each of the spaces in the dict, and attaching the
+ * resulting space to the DeviceN array. This is complicated, because
+ * each space must be fully set up, and may result in running tint transform
+ * procedures and caching results. We need to handle this in yet another
+ * layering of continuation procedures.
+ */
+ code = array_get(imemory, devicenspace, 4, &sref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&sref, t_dictionary)) {
+ *stage = 0;
+ return 0;
+ }
+ if (r_size(&sref) == 0)
+ return 0;
+
+ code = dict_index_entry(&sref, 0, (ref *)&tempref);
+ if (code < 0)
+ return code;
+ name_string_ref(imemory, &tempref[0], &sname);
+ if (r_size(&sname) != 9 || strncmp((const char *)sname.value.const_bytes, "Colorants", r_size(&sname)) != 0) {
+ *stage = 0;
+ return 0;
+ }
+
+ *stage = 3;
+ *cont = 1;
+ check_estack(5);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold index of the space we are dealing with */
+ make_int(esp, 0);
+ esp++;
+ /* variable to hold processing step */
+ make_int(esp, 0);
+ esp++;
+ /* Store a pointer to the Colorants dictionary
+ */
+ ref_assign(esp, &tempref[1]);
+ push_op_estack(devicencolorants_cont);
+ return o_push_estack;
+ } else {
+ *stage = 0;
+ return 0;
+ }
+ }
+ if ((*stage) == 3) {
+ *stage = 0;
+ return 0;
+ }
+ if ((*stage) == 0) {
+ code = array_get(imemory, devicenspace, 3, &proc);
+ if (code < 0)
+ return code;
+ pfn = ref_function(&proc);
+ if (pfn == NULL) {
+ /* Convert tint transform to a PostScript function */
+ code = convert_transform(i_ctx_p, devicenspace, &proc);
+ if (code < 0)
+ return code;
+ if (code > 0) {
+ *cont = 1;
+ *stage = 1;
+ return code;
+ }
+ /* We can only get here if the transform converted to a function
+ * without requiring a continuation. Most likely this means its a
+ * type 4 function. If so then it is still on the stack.
+ */
+ op = osp;
+ pfn = ref_function(op);
+ pop (1);
+ }
+ } else {
+ /* The function is returned on the operand stack */
+ op = osp;
+ pfn = ref_function(op);
+ pop (1);
+ }
+
+ *stage = 2;
+
+ code = array_get(imemory, devicenspace, 1, &namesarray);
+ if (code < 0)
+ return code;
+ num_components = r_size(&namesarray);
+ /* The alternate color space has been selected as the current color space */
+ pacs = gs_currentcolorspace(igs);
+
+ if (num_components == 1) {
+ array_get(imemory, &namesarray, (long)0, &sname);
+ switch (r_type(&sname)) {
+ case t_string:
+ break;
+ case t_name:
+ name_string_ref(imemory, &sname, &sname);
+ break;
+ default:
+ return_error(e_typecheck);
+ break;
+ }
+ if (strncmp((const char *)sname.value.const_bytes, "All", 3) == 0 && r_size(&sname) == 3) {
+ separation_type sep_type;
+
+ /* Sigh, Acrobat allows this, even though its contra the spec. Convert to
+ * a /Separation space and go on
+ */
+ sep_type = SEP_ALL;
+
+ /* The alternate color space has been selected as the current color space */
+ pacs = gs_currentcolorspace(igs);
+
+ cspace_old = istate->colorspace;
+ /* Now set the current color space as Separation */
+ code = gs_cspace_new_Separation(&pcs, pacs, imemory);
+ if (code < 0)
+ return code;
+ pcs->params.separation.sep_type = sep_type;
+ pcs->params.separation.sep_name = name_index(imemory, &sname);
+ pcs->params.separation.get_colorname_string = gs_get_colorname_string;
+ array_get(imemory, &namesarray, (long)0, &sname);
+ if (code < 0)
+ return code;
+ istate->colorspace.procs.special.separation.layer_name = sname;
+ code = array_get(imemory, devicenspace, 3, &proc);
+ if (code < 0)
+ return code;
+ istate->colorspace.procs.special.separation.tint_transform = proc;
+ if (code >= 0)
+ code = gs_cspace_set_sepr_function(pcs, pfn);
+ if (code >= 0)
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ rc_decrement_only(pcs, "setseparationspace");
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ return code;
+ }
+ cc.pattern = 0x00;
+ cc.paint.values[0] = 1.0;
+ code = gs_setcolor(igs, &cc);
+ return code;
+ }
+ }
+ code = gs_cspace_new_DeviceN(&pcs, num_components, pacs, imemory);
+ if (code < 0)
+ return code;
+ names = pcs->params.device_n.names;
+ pmap = pcs->params.device_n.map;
+ pcs->params.device_n.get_colorname_string = gs_get_colorname_string;
+
+ /* Pick up the names of the components */
+ {
+ uint i;
+ ref sname;
+
+ for (i = 0; i < num_components; ++i) {
+ array_get(imemory, &namesarray, (long)i, &sname);
+ switch (r_type(&sname)) {
+ case t_string:
+ code = name_from_string(imemory, &sname, &sname);
+ if (code < 0) {
+ rc_decrement(pcs, "setdevicenspace");
+ return code;
+ }
+ /* falls through */
+ case t_name:
+ names[i] = name_index(imemory, &sname);
+ break;
+ default:
+ rc_decrement(pcs, "setdevicenspace");
+ return_error(e_typecheck);
+ }
+ }
+ }
+
+ /* Now set the current color space as DeviceN */
+
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.special.device_n.layer_names = namesarray;
+ code = array_get(imemory, devicenspace, 3, &proc);
+ if (code < 0)
+ return code;
+ istate->colorspace.procs.special.device_n.tint_transform = proc;
+ gs_cspace_set_devn_function(pcs, pfn);
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ rc_decrement_only(pcs, "setdevicenspace");
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ return code;
+ }
+
+ cc.pattern = 0x00;
+ for (i=0;i<num_components;i++)
+ cc.paint.values[i] = 1.0;
+ code = gs_setcolor(igs, &cc);
+ *cont = 1;
+ return code;
+}
+static int validatedevicenspace(i_ctx_t * i_ctx_p, ref **space)
+{
+ int i, code = 0;
+ ref *devicenspace = *space, proc;
+ ref nameref, sref, altspace, namesarray, sname;
+
+ /* Check enough arguments in the space */
+ if (r_size(devicenspace) < 4)
+ return_error(e_rangecheck);
+ /* Check the names parameter is an array */
+ code = array_get(imemory, devicenspace, 1, &namesarray);
+ if (code < 0)
+ return code;
+ if (!r_is_array(&namesarray))
+ return_error(e_typecheck);
+ /* Ensure we have at least one ink */
+ if (r_size(&namesarray) < 1)
+ return_error(e_typecheck);
+ /* Make sure no more inks than we can cope with */
+ if (r_size(&namesarray) > GS_CLIENT_COLOR_MAX_COMPONENTS)
+ return_error(e_limitcheck);
+ /* Check the tint transform is a procedure */
+ code = array_get(imemory, devicenspace, 3, &proc);
+ if (code < 0)
+ return code;
+ check_proc(proc);
+
+ /* Check the array of ink names only contains names or strings */
+ for (i = 0; i < r_size(&namesarray); ++i) {
+ array_get(imemory, &namesarray, (long)i, &sname);
+ switch (r_type(&sname)) {
+ case t_string:
+ case t_name:
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+
+ /* Get the name of the alternate space */
+ code = array_get(imemory, devicenspace, 2, &altspace);
+ if (code < 0)
+ return code;
+ if (r_has_type(&altspace, t_name))
+ ref_assign(&nameref, &altspace);
+ else {
+ /* Make sure the alternate space is an array */
+ if (!r_is_array(&altspace))
+ return_error(e_typecheck);
+ /* And has a name for its type */
+ code = array_get(imemory, &altspace, 0, &nameref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&nameref, t_name))
+ return_error(e_typecheck);
+ }
+ /* Convert alternate space name to string */
+ name_string_ref(imemory, &nameref, &sref);
+ /* Check its not /Indexed, /Pattern, /DeviceN */
+ if (r_size(&sref) == 7) {
+ if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
+ return_error(e_typecheck);
+ if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
+ return_error(e_typecheck);
+ if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
+ return_error(e_typecheck);
+ }
+ /* and also not /Separation */
+ if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
+ return_error(e_typecheck);
+
+ ref_assign(*space, &altspace);
+ return 0;
+}
+static int devicenalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r)
+{
+ ref altspace;
+ int code;
+
+ code = array_get(imemory, space, 2, &altspace);
+ if (code < 0)
+ return code;
+ ref_assign(*r, &altspace);
+ return 0;
+}
+static int devicencomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ ref namesarray;
+ int code;
+
+ code = array_get(imemory, space, 1, &namesarray);
+ if (code < 0)
+ return code;
+ *n = r_size(&namesarray);
+ return 0;
+}
+static int devicendomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, limit, code;
+ ref namesarray;
+
+ code = array_get(imemory, space, 1, &namesarray);
+ if (code < 0)
+ return code;
+
+ limit = r_size(&namesarray) * 2;
+ for (i = 0;i < limit;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+static int devicenrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int i, limit, code;
+ PS_colour_space_t *cspace;
+
+ ref altspace;
+
+ code = array_get(imemory, space, 1, &altspace);
+ if (code < 0)
+ return code;
+
+ code = get_space_object(i_ctx_p, &altspace, &cspace);
+ if (code < 0)
+ return code;
+
+ code = cspace->numcomponents(i_ctx_p, &altspace, &limit);
+ if (code < 0)
+ return code;
+
+ for (i = 0;i < limit * 2;i+=2) {
+ ptr[i] = 0;
+ ptr[i+1] = 1;
+ }
+ return 0;
+}
+static int devicentransform(i_ctx_t *i_ctx_p, ref *devicenspace, int *usealternate, int *stage, int *stack_depth)
+{
+ gx_device * dev = igs->device;
+ ref narray, sname, proc;
+ int i, code, colorant_number;
+
+ *usealternate = 0;
+ code = array_get(imemory, devicenspace, 1, &narray);
+ if (code < 0)
+ return code;
+ if (!r_is_array(&narray))
+ return_error(e_typecheck);
+
+ for (i=0;i<r_size(&narray);i++) {
+ code = array_get(imemory, &narray, i, &sname);
+ if (code < 0)
+ return code;
+ if (r_has_type(&sname, t_name)) {
+ name_string_ref(imemory, &sname, &sname);
+ }
+
+ /* Check for /All and /None, never need the alternate for these */
+ if (r_size(&sname) == 3 &&
+ strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0)
+ continue;
+ if (r_size(&sname) == 4 &&
+ strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0)
+ continue;
+ /*
+ * Compare the colorant name to the device's. If the device's
+ * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
+ * colorant is in the SeparationNames list but not in the
+ * SeparationOrder list.
+ */
+ colorant_number = (*dev_proc(dev, get_color_comp_index))
+ (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
+ if (colorant_number < 0) { /* If not valid colorant name */
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("Gray", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("Cyan", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 7 &&
+ strncmp("Magenta", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 6 &&
+ strncmp("Yellow", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 5 &&
+ strncmp("Black", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 3 &&
+ strncmp("Red", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 5 &&
+ strncmp("Green", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ if (r_size(&sname) == 4 &&
+ strncmp("Blue", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
+ *usealternate = 1;
+ break;
+ }
+ }
+ if (*usealternate && *stage == 0) {
+ (*stage)++;
+ esp++;
+ code = array_get(imemory, devicenspace, 3, &proc);
+ if (code < 0)
+ return code;
+ *esp = proc;
+ return o_push_estack;
+ }
+
+ if (*stage == 1){
+ *stack_depth = 0;
+ *stage = 0;
+ }
+ return 0;
+}
+static int devicenbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code, use, n_comp;
+ ref narray;
+
+ code = devicentransform(i_ctx_p, space, &use, stage, stack_depth);
+ if (code != 0)
+ return code;
+ if (!use) {
+ *stage = 0;
+ *cont = 0;
+ code = array_get(imemory, space, 1, &narray);
+ if (code < 0)
+ return code;
+ n_comp = r_size(&narray);
+ pop(n_comp);
+ op = osp;
+ switch(base) {
+ case 0:
+ push(1);
+ make_real(op, 0.0);
+ break;
+ case 1:
+ case 2:
+ push(3);
+ make_real(&op[-2], 0.0);
+ make_real(&op[-1], 0.0);
+ make_real(op, 0.0);
+ break;
+ case 3:
+ push(4);
+ make_real(&op[-3], 0.0);
+ make_real(&op[-2], 0.0);
+ make_real(&op[-1], 0.0);
+ make_real(op, 0.0);
+ break;
+ }
+ } else {
+ *stage = 0;
+ *cont = 1;
+ }
+ return 0;
+}
+static int devicenvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ int i, code;
+ ref narray;
+ os_ptr op = osp;
+
+ code = array_get(imemory, space, 1, &narray);
+ if (code < 0)
+ return code;
+ if (!r_is_array(&narray))
+ return_error(e_typecheck);
+
+ if (num_comps < r_size(&narray))
+ return_error(e_stackunderflow);
+
+ op -= r_size(&narray) - 1;
+
+ for (i=0;i < r_size(&narray); i++) {
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+
+ if (values[i] > 1.0)
+ values[i] = 1.0;
+
+ if (values[i] < 0.0)
+ values[i] = 0.0;
+ op++;
+ }
+
+ return 0;
+}
+static int devicencompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ ref sname1, sname2;
+ int code;
+
+ code = array_get(imemory, space, 1, &sname1);
+ if (code < 0)
+ return 0;
+
+ code = array_get(imemory, testspace, 1, &sname2);
+ if (code < 0)
+ return 0;
+
+ if (!r_is_array(&sname1))
+ return 0;
+ if (!r_is_array(&sname2))
+ return 0;
+
+ if (!comparearrays(i_ctx_p, &sname1, &sname2))
+ return 0;
+
+ code = array_get(imemory, testspace, 2, &sname1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 2, &sname2);
+ if (code < 0)
+ return 0;
+ if (r_type(&sname1) != r_type(&sname2))
+ return 0;
+
+ if (r_is_array(&sname1)) {
+ if (!comparearrays(i_ctx_p, &sname1, &sname2))
+ return 0;
+ } else {
+ if (!r_has_type(&sname1, t_name))
+ return 0;
+ if (!name_eq(&sname1, &sname2))
+ return 0;
+ }
+ code = array_get(imemory, space, 3, &sname1);
+ if (code < 0)
+ return 0;
+ code = array_get(imemory, testspace, 3, &sname2);
+ if (code < 0)
+ return 0;
+ return(comparearrays(i_ctx_p, &sname1, &sname2));
+}
+static int deviceninitialproc(i_ctx_t *i_ctx_p, ref *space)
+{
+ gs_client_color cc;
+ int i, num_components, code;
+ ref namesarray;
+
+ code = array_get(imemory, space, 1, &namesarray);
+ if (code < 0)
+ return code;
+ num_components = r_size(&namesarray);
+ cc.pattern = 0x00;
+ for (i=0;i<num_components;i++)
+ cc.paint.values[i] = 1.0;
+ return gs_setcolor(igs, &cc);
+}
+
+/* Indexed */
+/*
+ * This routine samples the indexed space, it pushes values from -1
+ * to 'hival', then executes the tint transform procedure. Returns here
+ * to store the resulting value(s) in the indexed map.
+ */
+static int
+indexed_cont(i_ctx_t *i_ctx_p)
+{
+ os_ptr op = osp;
+ es_ptr ep = esp;
+ int i = (int)ep[csme_index].value.intval;
+
+ if (i >= 0) { /* i.e., not first time */
+ int m = (int)ep[csme_num_components].value.intval;
+ int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
+
+ if (code < 0)
+ return code;
+ pop(m);
+ op -= m;
+ if (i == (int)ep[csme_hival].value.intval) { /* All done. */
+ esp -= num_csme;
+ return o_pop_estack;
+ }
+ }
+ push(1);
+ ep[csme_index].value.intval = ++i;
+ make_int(op, i);
+ make_op_estack(ep + 1, indexed_cont);
+ ep[2] = ep[csme_proc]; /* lookup proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+static int setindexedspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ ref *pproc = &istate->colorspace.procs.special.index_proc;
+ int code = 0;
+ uint edepth = ref_stack_count(&e_stack);
+ ref_colorspace cspace_old;
+ ref hival, lookup;
+ gs_color_space *pcs;
+ gs_color_space *pcs_base;
+
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ *cont = 0;
+ if (*stage == 1) {
+ *stage = 0;
+ return 0;
+ }
+
+ cspace_old = istate->colorspace;
+
+ pcs_base = gs_currentcolorspace(igs);
+
+ code = array_get(imemory, r, 3, &lookup);
+ if (code < 0)
+ return code;
+ code = array_get(imemory, r, 2, &hival);
+ if (code < 0)
+ return code;
+ if (r_has_type(&lookup, t_string)) {
+ int num_values = (hival.value.intval + 1) * cs_num_components(pcs_base);
+
+ check_read(lookup);
+ /*
+ * The PDF and PS specifications state that the lookup table must have
+ * the exact number of of data bytes needed. However we have found
+ * PDF files from Amyuni with extra data bytes. Acrobat 6.0 accepts
+ * these files without complaint, so we ignore the extra data.
+ */
+ if (r_size(&lookup) < num_values)
+ return_error(e_rangecheck);
+ pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
+ pcs->base_space = pcs_base;
+ rc_increment(pcs_base);
+ pcs->params.indexed.lookup.table.data = lookup.value.const_bytes;
+ pcs->params.indexed.lookup.table.size = num_values;
+ pcs->params.indexed.use_proc = 0;
+ make_null(pproc);
+ code = 0;
+ } else {
+ gs_indexed_map *map;
+
+ /*
+ * We have to call zcs_begin_map before moving the parameters,
+ * since if the color space is a DeviceN or Separation space,
+ * the memmove will overwrite its parameters.
+ */
+ code = zcs_begin_map(i_ctx_p, &map, &lookup, (hival.value.intval + 1),
+ pcs_base, indexed_cont);
+ if (code < 0)
+ return code;
+ pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
+ pcs->base_space = pcs_base;
+ rc_increment(pcs_base);
+ pcs->params.indexed.use_proc = 1;
+ *pproc = lookup;
+ map->proc.lookup_index = lookup_indexed_map;
+ pcs->params.indexed.lookup.map = map;
+ }
+ pcs->params.indexed.hival = hival.value.intval;
+ pcs->params.indexed.n_comps = cs_num_components(pcs_base);
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ rc_decrement_only(pcs, "setindexedspace");
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ *stage = 0;
+ if (ref_stack_count(&e_stack) == edepth) {
+ return 0;
+ } else {
+ *cont = 1;
+ *stage = 1;
+ return o_push_estack; /* installation will load the caches */
+ }
+}
+static int validateindexedspace(i_ctx_t * i_ctx_p, ref **space)
+{
+ int code = 0;
+ ref *r = *space;
+ ref nameref, sref, hival, lookup, altspace;
+
+ if (!r_is_array(r))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(r) != 4)
+ return_error(e_rangecheck);
+ /* Check operand type(s) */
+ /* Make sure 'hival' is an integer */
+ code = array_get(imemory, r, 2, &hival);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&hival, t_integer))
+ return_error(e_typecheck);
+ /* Make sure 'hival' lies between 0 and 4096 */
+ if (hival.value.intval < 0 || hival.value.intval > 4096)
+ return_error(e_rangecheck);
+ /* Ensure the 'lookup' is either a string or a procedure */
+ code = array_get(imemory, r, 3, &lookup);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&lookup, t_string))
+ check_proc(lookup);
+
+ /* Get the name of the alternate space */
+ code = array_get(imemory, r, 1, &altspace);
+ if (code < 0)
+ return code;
+ if (r_has_type(&altspace, t_name))
+ ref_assign(&nameref, &altspace);
+ else {
+ if (!r_is_array(&altspace))
+ return_error(e_typecheck);
+ code = array_get(imemory, &altspace, 0, &nameref);
+ if (code < 0)
+ return code;
+ }
+ /* Convert alternate space name to string */
+ name_string_ref(imemory, &nameref, &sref);
+ /* Check its not /Indexed or /Pattern */
+ if (r_size(&sref) == 7) {
+ if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
+ return_error(e_typecheck);
+ if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
+ return_error(e_typecheck);
+ }
+ ref_assign(*space, &altspace);
+ return 0;
+}
+static int indexedalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r)
+{
+ ref alt;
+ int code;
+
+ code = array_get(imemory, *r, 1, &alt);
+ if (code < 0)
+ return code;
+ ref_assign(*r, &alt);
+ return 0;
+}
+static int indexeddomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ref hival;
+ int code;
+
+ code = array_get(imemory, space, 2, &hival);
+ if (code < 0)
+ return code;
+ ptr[0] = 0;
+ ptr[1] = (float)hival.value.intval;
+ return 0;
+}
+static int indexedrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ ref hival;
+ int code;
+
+ code = array_get(imemory, space, 2, &hival);
+ if (code < 0)
+ return code;
+ ptr[0] = 0;
+ ptr[1] = (float)hival.value.intval;
+ return 0;
+}
+static int indexedbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ es_ptr ep = ++esp;
+ ref proc;
+ int code;
+
+ if (*stage == 0) {
+ *stage = 1;
+ *cont = 1;
+ check_estack(1);
+ code = array_get(imemory, space, 3, &proc);
+ if (code < 0)
+ return code;
+ *ep = proc; /* lookup proc */
+ return o_push_estack;
+ } else {
+ *stage = 0;
+ *cont = 1;
+ return 0;
+ }
+}
+static int indexedvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ int code;
+ ref hival;
+ os_ptr op = osp;
+
+ if (num_comps < 1)
+ return_error(e_stackunderflow);
+
+ if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
+ return_error(e_typecheck);
+
+ code = array_get(imemory, space, 2, &hival);
+ if (code < 0)
+ return code;
+
+ if (*values > hival.value.intval)
+ *values = (float)hival.value.intval;
+
+ if (*values < 0)
+ *values = 0;
+
+ /* The PLRM says 'If it is a real number, it is rounded to the nearest integer
+ * but in fact Acrobat simply floors the value.
+ */
+ *values = floor(*values);
+
+ return 0;
+}
+
+/* Pattern */
+static int setpatternspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ gs_color_space *pcs;
+ gs_color_space *pcs_base;
+ uint edepth = ref_stack_count(&e_stack);
+ int code = 0;
+
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ *cont = 0;
+ pcs_base = NULL;
+ if (r_is_array(r)) {
+ check_read(*r);
+
+ switch (r_size(r)) {
+ case 1: /* no base space */
+ pcs_base = NULL;
+ break;
+ default:
+ return_error(e_rangecheck);
+ case 2:
+ pcs_base = gs_currentcolorspace(igs);
+ if (cs_num_components(pcs_base) < 0) /* i.e., Pattern space */
+ return_error(e_rangecheck);
+ }
+ }
+ pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Pattern);
+ pcs->base_space = pcs_base;
+ pcs->params.pattern.has_base_space = (pcs_base != NULL);
+ rc_increment(pcs_base);
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ rc_decrement_only(pcs, "zsetpatternspace");
+ if (code < 0) {
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ make_null(&istate->pattern); /* PLRM: initial color value is a null object */
+ *stage = 0;
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+static int validatepatternspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code;
+ ref tref;
+
+ /* since makepattern has already been run, we don't need to do much validation */
+ if (!r_has_type(*r, t_name)) {
+ if (r_is_array(*r)) {
+ if (r_size(*r) > 1) {
+ code = array_get(imemory, *r, 1, &tref);
+ if (code < 0)
+ return code;
+ ref_assign(*r, &tref);
+ } else
+ *r = 0;
+ } else
+ return_error(e_typecheck);
+ } else
+ *r = 0;
+ return 0;
+}
+static int patternalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r)
+{
+ ref tref;
+ int code;
+
+ if (!r_has_type(*r, t_name)) {
+ if (r_is_array(*r)) {
+ if (r_size(*r) > 1) {
+ code = array_get(imemory, space, 1, &tref);
+ if (code < 0)
+ return code;
+ ref_assign(*r, &tref);
+ } else
+ *r = 0;
+ } else
+ return_error(e_typecheck);
+ } else
+ *r = 0;
+ return 0;
+}
+static int patterncomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ os_ptr op = osp;
+ int n_comps, code;
+ const gs_color_space * pcs = gs_currentcolorspace(igs);
+ gs_client_color cc;
+
+ /* check for a pattern color space */
+ if ((n_comps = cs_num_components(pcs)) < 0) {
+ n_comps = -n_comps;
+ if (r_has_type(op, t_dictionary)) {
+ ref *pImpl, pPatInst;
+
+ code = dict_find_string(op, "Implementation", &pImpl);
+ if (code < 0)
+ return code;
+ code = array_get(imemory, pImpl, 0, &pPatInst);
+ if (code < 0)
+ return code;
+ cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
+ if (pattern_instance_uses_base_space(cc.pattern))
+ *n = n_comps;
+ else
+ *n = 1;
+ } else
+ *n = 1;
+ } else
+ return_error(e_typecheck);
+
+ return 0;
+}
+static int patternbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op;
+ int i, components=0;
+
+ if (r_size(space) > 1) {
+ const gs_color_space * pcs = gs_currentcolorspace(igs);
+ const gs_client_color * pcc = gs_currentcolor(igs);
+ int n = cs_num_components(pcs);
+ bool push_pattern = n < 0;
+ gs_pattern_instance_t * pinst = pcc->pattern;
+
+ if (pinst != 0 && pattern_instance_uses_base_space(pinst)) {
+ /* check for pattern */
+ if (push_pattern)
+ pop(1); /* The pattern instance */
+ *stage = 0;
+ *cont = 1;
+ return 0;
+ }
+ /* If the pattern isn't yet initialised, or doesn't use the
+ * base space, treat as uncolored and return defaults below
+ * Fall Through.
+ */
+ }
+
+ pop(1);
+ op = osp;
+ switch(base) {
+ case 0:
+ components = 1;
+ break;
+ case 1:
+ case 2:
+ components = 3;
+ break;
+ case 3:
+ components = 4;
+ break;
+ }
+ push(components);
+ op -= components-1;
+ for (i=0;i<components;i++) {
+ make_real(op, (float)0);
+ op++;
+ }
+ if (components == 4) {
+ op--;
+ make_real(op, (float)1);
+ }
+ *stage = 0;
+ *cont = 0;
+ return 0;
+}
+static int patternvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ os_ptr op = osp;
+
+ check_op(1);
+
+ if (!r_has_type(op, t_dictionary) && !r_has_type(op, t_null))
+ return_error(e_typecheck);
+
+ return 0;
+}
+
+/* DevicePixel */
+static int setdevicepspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ int code = 0;
+ gs_color_space *pcs;
+ ref bpp;
+
+ /* The comment in the original PostScript (gs_lev2.ps) said
+ * "DevicePixel is actually a LanguageLevel 3 feature; it is here for
+ * historical reasons." Actually DevicePixel is a Display PostScript
+ * space, as far as I can tell. It certainly isn't a level 3 space.
+ * Preserve the old behaviour anyway.
+ */
+ if (i_ctx_p->language_level < 2)
+ return_error(e_undefined);
+
+ *cont = 0;
+ code = array_get(imemory, r, 1, &bpp);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&bpp, t_integer))
+ return_error(e_typecheck);
+ code = gs_cspace_new_DevicePixel(imemory, &pcs, (int)bpp.value.intval);
+ if (code < 0)
+ return code;
+ code = gs_setcolorspace(igs, pcs);
+ /* release reference from construction */
+ *stage = 0;
+ rc_decrement_only(pcs, "setseparationspace");
+ return code;
+}
+static int validatedevicepspace(i_ctx_t * i_ctx_p, ref **space)
+{
+ int code = 0;
+ ref *r = *space, bpp;
+
+ if (!r_is_array(r))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(r) != 2)
+ return_error(e_rangecheck);
+ /* Make sure 'bits per pixel' is an integer */
+ code = array_get(imemory, r, 1, &bpp);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&bpp, t_integer))
+ return_error(e_typecheck);
+
+ /* Make sure 'bits per pixel' lies between 0 and 31 */
+ if (bpp.value.intval < 0 || bpp.value.intval > 31)
+ return_error(e_rangecheck);
+
+ *space = 0;
+ return code;
+}
+static int devicepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int code;
+ ref tref;
+
+ code = array_get(imemory, space, 1, &tref);
+ if (code < 0)
+ return code;
+ ptr[0] = 0;
+ ptr[1] = (float)(1 << tref.value.intval);
+ return 0;
+}
+static int deviceprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int code;
+ ref tref;
+
+ code = array_get(imemory, space, 1, &tref);
+ if (code < 0)
+ return code;
+ ptr[0] = 0;
+ ptr[1] = (float)(1 << tref.value.intval);
+ return 0;
+}
+static int devicepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ os_ptr op = osp;
+
+ *stage = 0;
+ *cont = 0;
+ make_int(op, 0);
+ return 0;
+}
+static int devicepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ return 0;
+}
+
+/* ICCBased */
+static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr);
+static int seticcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
+{
+ os_ptr op = osp;
+ ref ICCdict, *tempref, *altref, *icc, *nocie;
+ int components, code;
+ float range[8];
+
+ code = dict_find_string(systemdict, ".seticcspace", &icc);
+ if (code < 0)
+ return_error(e_undefined);
+
+ code = dict_find_string(systemdict, "NOCIE", &nocie);
+ if (code < 0)
+ return code;
+ if (!r_has_type(nocie, t_boolean))
+ return_error(e_typecheck);
+
+ *cont = 0;
+ do {
+ switch(*stage) {
+ case 0:
+ (*stage)++;
+ code = array_get(imemory, r, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "Alternate", &altref);
+ if (code < 0)
+ return code;
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ if (code < 0)
+ return code;
+ components = tempref->value.intval;
+
+ /* Don't allow ICCBased spaces if NOCIE is true */
+ if (nocie->value.boolval) {
+ if (r_type(altref) != t_null) {
+ /* The PDF interpreter sets a null Alternate. If we have an
+ * Alternate, and its not null, and NOCIE is true, then use the
+ * Alternate instead of the ICC
+ */
+ push(1);
+ ref_assign(op, altref);
+ /* If CIESubst, we are already substituting for CIE, so use nosubst
+ * to prevent further substitution!
+ */
+ return setcolorspace_nosubst(i_ctx_p);
+ } else {
+ /* There's no /Alternate (or it is null), set a default space
+ * based on the number of components in the ICCBased space
+ */
+ int stage1 = 1, cont1 = 0;
+ switch(components) {
+ case 1:
+ code = setgrayspace(i_ctx_p, (ref *)0x00, &stage1, &cont1, 1);
+ if (code != 0)
+ return code;
+ *stage = 0;
+ break;
+ case 3:
+ code = setrgbspace(i_ctx_p, (ref *)0x00, &stage1, &cont1, 1);
+ if (code != 0)
+ return code;
+ *stage = 0;
+ break;
+ case 4:
+ code = setcmykspace(i_ctx_p, (ref *)0x00, &stage1, &cont1, 1);
+ if (code != 0)
+ return code;
+ *stage = 0;
+ break;
+ default:
+ return_error(e_rangecheck);
+ break;
+ }
+ }
+ } else {
+ code = iccrange(i_ctx_p, r, (float *)&range);
+ if (code < 0)
+ return code;
+ code = dict_find_string(&ICCdict, "DataSource", &tempref);
+ if (code < 0)
+ return code;
+ /* Check for string based ICC and convert to a file (stage = 2) */
+ if (!r_has_type(tempref, t_file)){
+ ref stref;
+ byte *body;
+
+ (*stage)++;
+ body = ialloc_string(48, "string");
+ if (body == 0)
+ return_error(e_VMerror);
+ memcpy(body, "{systemdict /.convertICCSource get exec} stopped",48);
+ make_string(&stref, a_all | icurrent_space, 48, body);
+ r_set_attrs(&stref, a_executable);
+ esp++;
+ ref_assign(esp, &stref);
+ return o_push_estack;
+ }
+ code = seticc(i_ctx_p, components, &ICCdict, (float *)&range);
+ if (code < 0) {
+ push(1);
+ ref_assign(op, altref);
+ /* If CIESubst, we are already substituting for CIE, so use nosubst
+ * to prevent further substitution!
+ */
+ if (CIESubst)
+ return setcolorspace_nosubst(i_ctx_p);
+ else
+ return zsetcolorspace(i_ctx_p);
+ }
+ if (code != 0)
+ return code;
+ }
+ break;
+ case 1:
+ /* All done, exit */
+ *stage = 0;
+ code = 0;
+ break;
+ case 2:
+ /* Converted a string DataSource ICC profile into a file
+ * using ReusableStreamDecode. See gs_cspace.ps.
+ */
+ *stage = 1;
+ code = array_get(imemory, r, 1, &ICCdict);
+ if (code < 0)
+ return code;
+ code = iccrange(i_ctx_p, r, (float *)&range);
+ if (code < 0)
+ return code;
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ if (code < 0)
+ return code;
+ components = tempref->value.intval;
+
+ code = seticc(i_ctx_p, components, &ICCdict, (float *)&range);
+ if (code < 0) {
+ push(1);
+ ref_assign(op, altref);
+ /* If CIESubst, we are already substituting for CIE, so use nosubst
+ * to prevent further substitution!
+ */
+ if (CIESubst)
+ return setcolorspace_nosubst(i_ctx_p);
+ else
+ return zsetcolorspace(i_ctx_p);
+ }
+ break;
+ default:
+ return_error (e_rangecheck);
+ break;
+ }
+ }while(*stage);
+ return code;
+}
+static int validateiccspace(i_ctx_t * i_ctx_p, ref **r)
+{
+ int code=0, i, components = 0;
+ ref *space, *tempref, valref, ICCdict, sref;
+
+ space = *r;
+ if (!r_is_array(space))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(space) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, space, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ if (code <= 0)
+ return code;
+ if (!r_has_type(tempref, t_null)) {
+ if (!r_has_type(tempref, t_integer))
+ return_error(e_typecheck);
+ components = tempref->value.intval;
+ } else
+ return_error(e_typecheck);
+ code = dict_find_string(&ICCdict, "DataSource", &tempref);
+ if (code <= 0)
+ return_error(e_typecheck);
+ if (!r_has_type(tempref, t_null)) {
+ if (!r_has_type(tempref, t_string) && !r_has_type(tempref, t_file))
+ return_error(e_typecheck);
+ } else
+ return_error(e_typecheck);
+
+ /* Following are optional entries */
+ code = dict_find_string(&ICCdict, "Range", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ if (!r_is_array(tempref))
+ return_error(e_typecheck);
+ if (r_size(tempref) < (components * 2))
+ return_error(e_rangecheck);
+ for (i=0;i<components * 2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&valref, t_integer) && !r_has_type(&valref, t_real))
+ return_error(e_typecheck);
+ }
+ }
+ code = dict_find_string(&ICCdict, "Alternate", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ *r = tempref;
+ if (r_has_type(tempref, t_name)) {
+ name_string_ref(imemory, tempref, &sref);
+ if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
+ return_error(e_typecheck);
+ } else {
+ if (r_is_array(tempref)) {
+ code = array_get(imemory, tempref, 0, &valref);
+ if (code < 0)
+ return code;
+ if (!r_has_type(&valref, t_name) && !r_has_type(&valref, t_string))
+ return_error(e_typecheck);
+ if (r_has_type(&valref, t_name))
+ name_string_ref(imemory, &valref, &sref);
+ else
+ sref.value.bytes = valref.value.bytes;
+ if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
+ return_error(e_typecheck);
+ } else
+ return_error(e_typecheck);
+ }
+ } else {
+ switch (components) {
+ case 1:
+ code = name_enter_string(imemory, "DeviceGray", *r);
+ break;
+ case 3:
+ code = name_enter_string(imemory, "DeviceRGB", *r);
+ break;
+ case 4:
+ code = name_enter_string(imemory, "DeviceCMYK", *r);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ }
+ return code;
+}
+static int iccalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r)
+{
+ int components, code = 0;
+ ref *tempref, ICCdict;
+
+ if (!r_is_array(space))
+ return_error(e_typecheck);
+ /* Validate parameters, check we have enough operands */
+ if (r_size(space) != 2)
+ return_error(e_rangecheck);
+
+ code = array_get(imemory, space, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ if (code <= 0)
+ return code;
+
+ components = tempref->value.intval;
+
+ code = dict_find_string(&ICCdict, "Alternate", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ *r = tempref;
+ } else {
+ switch (components) {
+ case 1:
+ code = name_enter_string(imemory, "DeviceGray", *r);
+ break;
+ case 3:
+ code = name_enter_string(imemory, "DeviceRGB", *r);
+ break;
+ case 4:
+ code = name_enter_string(imemory, "DeviceCMYK", *r);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ }
+ return code;
+}
+static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ int code = 0;
+ ref *tempref, ICCdict;
+
+ code = array_get(imemory, space, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ *n = tempref->value.intval;
+ return 0;
+}
+static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int components, i, code = 0;
+ ref *tempref, ICCdict, valref;
+
+ code = array_get(imemory, space, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ components = tempref->value.intval;
+
+ code = dict_find_string(&ICCdict, "Range", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<components * 2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i * 2] = (float)valref.value.intval;
+ else
+ ptr[i * 2] = valref.value.realval;
+ }
+ } else {
+ for (i=0;i<components;i++) {
+ ptr[i * 2] = 0;
+ ptr[(i * 2) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ int components, i, code = 0;
+ ref *tempref, ICCdict, valref;
+
+ code = array_get(imemory, space, 1, &ICCdict);
+ if (code < 0)
+ return code;
+
+ code = dict_find_string(&ICCdict, "N", &tempref);
+ components = tempref->value.intval;
+
+ code = dict_find_string(&ICCdict, "Range", &tempref);
+ if (code >= 0 && !r_has_type(tempref, t_null)) {
+ for (i=0;i<components * 2;i++) {
+ code = array_get(imemory, tempref, i, &valref);
+ if (code < 0)
+ return code;
+ if (r_has_type(&valref, t_integer))
+ ptr[i * 2] = (float)valref.value.intval;
+ else
+ ptr[i * 2] = (float)valref.value.realval;
+ }
+ } else {
+ for (i=0;i<components;i++) {
+ ptr[i * 2] = 0;
+ ptr[(i * 2) + 1] = 1;
+ }
+ }
+ return 0;
+}
+static int iccbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
+{
+ *stage = 0;
+ *cont = 1;
+ return 0;
+}
+static int iccvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
+{
+ return 0;
+}
+
+static int dummydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ return 0;
+}
+static int dummyrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
+{
+ return 0;
+}
+static int onecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ *n = 1;
+ return 0;
+}
+static int threecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ *n = 3;
+ return 0;
+}
+static int fourcomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
+{
+ *n = 4;
+ return 0;
+}
+static int truecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ return 1;
+}
+static int falsecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
+{
+ return 0;
+}
+
+PS_colour_space_t colorProcs[] = {
+ {(char *)"DeviceGray", setgrayspace, 0, 0, onecomponent, grayrange, graydomain,
+ graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
+ {(char *)"DeviceRGB", setrgbspace, 0, 0, threecomponent, rgbrange, rgbdomain,
+ rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc},
+ {(char *)"DeviceCMYK", setcmykspace, 0, 0, fourcomponent, cmykrange, cmykdomain,
+ cmykbasecolor, 0, cmykvalidate, truecompareproc, cmykinitialproc},
+ {(char *)"CIEBasedA", setcieaspace, validatecieaspace, 0, onecomponent, ciearange, cieadomain,
+ ciebasecolor, 0, cieavalidate, cieacompareproc, 0},
+ {(char *)"CIEBasedABC", setcieabcspace, validatecieabcspace, 0, threecomponent, cieabcrange, cieabcdomain,
+ ciebasecolor, 0, cieabcvalidate, cieabccompareproc, 0},
+ {(char *)"CIEBasedDEF", setciedefspace, validateciedefspace, 0, threecomponent, ciedefrange, ciedefdomain,
+ ciebasecolor, 0, ciedefvalidate, ciedefcompareproc, 0},
+ {(char *)"CIEBasedDEFG", setciedefgspace, validateciedefgspace, 0, fourcomponent, ciedefgrange, ciedefgdomain,
+ ciebasecolor, 0, ciedefgvalidate, ciedefgcompareproc, 0},
+ {(char *)"Separation", setseparationspace, validateseparationspace, separationalternatespace, onecomponent, seprange, sepdomain,
+ sepbasecolor, septransform, sepvalidate, sepcompareproc, sepinitialproc},
+ {(char *)"DeviceN", setdevicenspace, validatedevicenspace, devicenalternatespace, devicencomponents, devicenrange, devicendomain,
+ devicenbasecolor, devicentransform, devicenvalidate, devicencompareproc, deviceninitialproc},
+ {(char *)"Indexed", setindexedspace, validateindexedspace, indexedalternatespace, onecomponent, indexedrange, indexeddomain,
+ indexedbasecolor, 0, indexedvalidate, falsecompareproc, 0},
+ {(char *)"Pattern", setpatternspace, validatepatternspace, patternalternatespace, patterncomponent, dummyrange, dummydomain,
+ patternbasecolor, 0, patternvalidate, falsecompareproc, 0},
+ {(char *)"DevicePixel", setdevicepspace, validatedevicepspace, 0, onecomponent, deviceprange, devicepdomain,
+ devicepbasecolor, 0, devicepvalidate, falsecompareproc, 0},
+ {(char *)"ICCBased", seticcspace, validateiccspace, iccalternatespace, icccomponents, iccrange, iccdomain,
+ iccbasecolor, 0, iccvalidate, falsecompareproc, 0},
+};
+
+/*
+ * Given a color space, this finds the appropriate object from the list above
+ */
+int get_space_object(i_ctx_t *i_ctx_p, ref *arr, PS_colour_space_t **obj)
+{
+ ref spacename, nref;
+ int i, nprocs = sizeof(colorProcs) / sizeof(PS_colour_space_t), code;
+
+ /* If the spaece is an array, the first element is always the name */
+ if (r_is_array(arr))
+ code = array_get(imemory, arr, 0, &spacename);
+ else
+ ref_assign(&spacename, arr);
+
+ /* Check that it really is a name */
+ if (!r_has_type(&spacename, t_name))
+ return_error(e_typecheck);
+
+ /* Find the relevant color space object */
+ for (i=0;i<nprocs;i++) {
+ names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)colorProcs[i].name, strlen(colorProcs[i].name), &nref, 0);
+ if (name_eq(&spacename, &nref)) {
+ *obj = &colorProcs[i];
+ return 0;
+ }
+ }
+ return_error(e_undefined);
+}
+/*
+ * This routine checks all the color spaces in an operand by
+ * calling the specific 'validate' method for each in turn. It also
+ * returns the 'depth' which is the number of nested spaces.
+ */
+static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth)
+{
+ ref space, *sp = &space;
+ int code = 0;
+ PS_colour_space_t *obj;
+
+ ref_assign(&space, arr);
+ *depth = 0;
+ do {
+ code = get_space_object(i_ctx_p, sp, &obj);
+ if (code < 0)
+ return code;
+
+ (*depth)++;
+ if (!obj->validateproc)
+ break;
+
+ code = obj->validateproc(i_ctx_p, &sp);
+ if (code < 0)
+ return code;
+ }while(sp);
+ return 0;
+}
+/*
+ * The routine which does all the setcolor dispatching. This is initially set up by
+ * zsetcolor above. Because setcolorspace samples the space and converts the tint
+ * transform to a function, we don't need to run the PS tint transform in order to
+ * set the color. However, some applications, notably Photoshop 5 and above, rely
+ * on the tint transform being executed, so we must do so if the normal PostScript
+ * processing would result in the tintr transform being executed.
+ *
+ * We check each space in turn to see whether we would normally run the tint
+ * transform, eg Indexed is always executed, Separation and DeviceN only if the
+ * required ink(s) aren't present in the device. If we discover that any space
+ * doesn't require a tint transform, then we can short-circuit the processing.
+ * Otherwise we set up to execute the tint transform.
+ */
+static int
+setcolor_cont(i_ctx_t *i_ctx_p)
+{
+ ref arr, *parr = &arr;
+ es_ptr ep = esp;
+ int i=0, code = 0,depth, usealternate, stage, stack_depth;
+ PS_colour_space_t *obj;
+
+ stack_depth = (int)ep[-3].value.intval;
+ depth = (int)ep[-2].value.intval;
+ stage = (int)ep[-1].value.intval;
+ /* If we get a continuation from a sub-procedure, we will want to come back
+ * here afterward, to do any remaining spaces. We need to set up for that now.
+ * so that our continuation is ahead of the sub-proc's continuation.
+ */
+ check_estack(1);
+ push_op_estack(setcolor_cont);
+
+ while (code == 0) {
+ ref_assign(&arr, ep);
+ /* Run along the nested color spaces until we get to the first one
+ * that we haven't yet processed (given by 'depth')
+ */
+ for (i=0;i<=depth;i++) {
+ code = get_space_object(i_ctx_p, parr, &obj);
+ if (code < 0)
+ return code;
+
+ if (i < (depth)) {
+ if (!obj->alternateproc) {
+ return_error(e_typecheck);
+ }
+ code = obj->alternateproc(i_ctx_p, parr, &parr);
+ if (code < 0)
+ return code;
+ }
+ }
+ if (obj->runtransformproc) {
+ code = obj->runtransformproc(i_ctx_p, &istate->colorspace.array, &usealternate, &stage, &stack_depth);
+ make_int(&ep[-3], stack_depth);
+ make_int(&ep[-1], stage);
+ if (code != 0) {
+ return code;
+ }
+ make_int(&ep[-2], ++depth);
+ if (!usealternate)
+ break;
+ } else
+ break;
+ }
+ /* Remove our next continuation and our data */
+ obj->numcomponents(i_ctx_p, parr, &i);
+ pop(i);
+ esp -= 5;
+ return o_pop_estack;
+}
+/*
+ * The routine which does all the setcolorspace dispatching. This is initially set up by
+ * zsetcolorspace above. It starts by descending to the bottom-most space
+ * and setting that as the current space. It then descends the array again
+ * to the next-to-bottom- space and sets that as the current, and so on.
+ *
+ * The 'stage' parameter is passed in to each 'set' method. If a method needs
+ * to do a continuation itself (eg sample a space) then it should set the stage
+ * to a non-zero value. When the continuation is complete we return here, and
+ * attempt to 'set' the same space again. This time stage will be whatever was
+ * set the first time, which is a signal to the 'set' routine that a continuation
+ * took place, and is complete. Stage must always be set to 0 when a 'set'
+ * of a color space is complete.
+ */
+static int
+setcolorspace_cont(i_ctx_t *i_ctx_p)
+{
+ ref arr, *parr = &arr;
+ os_ptr op = osp;
+ es_ptr ep = esp, pdepth, pstage, pCIESubst;
+ int i, code = 0,depth, stage, cont, CIESubst = 0;
+ PS_colour_space_t *obj;
+
+ pCIESubst = &ep[-3];
+ pdepth = &ep[-2];
+ pstage = &ep[-1];
+
+ CIESubst = (int)pCIESubst->value.intval;
+ depth = (int)pdepth->value.intval;
+ stage = (int)pstage->value.intval;
+ /* If we get a continuation from a sub-procedure, we will want to come back
+ * here afterward, to do any remaining stages. We need to set up for that now.
+ * so that our continuation is ahead of the sub-proc's continuation.
+ */
+ check_estack(1);
+ push_op_estack(setcolorspace_cont);
+
+ while (code == 0 && depth) {
+ ref_assign(&arr, ep);
+ /* Run along the nested color spaces until we get to the lowest one
+ * that we haven't yet processed (given by 'depth')
+ */
+ for (i = 0;i < depth;i++) {
+ code = get_space_object(i_ctx_p, parr, &obj);
+ if (code < 0)
+ return code;
+
+ if (i < (depth - 1)) {
+ if (!obj->alternateproc) {
+ return_error(e_typecheck);
+ }
+ code = obj->alternateproc(i_ctx_p, parr, &parr);
+ if (code < 0)
+ return code;
+ }
+ }
+
+ code = obj->setproc(i_ctx_p, parr, &stage, &cont, CIESubst);
+ make_int(pstage, stage);
+ if (code != 0)
+ return code;
+ if (!cont) {
+ /* Completed that space, decrement the 'depth' */
+ make_int(pdepth, --depth);
+ parr = &arr;
+ }
+ }
+ if (code == 0) {
+ /* Remove our next continuation and our data */
+ esp -= 5;
+ op = osp;
+ istate->colorspace.array = *op;
+ /* Remove the colorspace array form the operand stack */
+ pop(1);
+ code = o_pop_estack;
+ }
+ return code;
+}
+/*
+ * The routine which does all the dispatching for the device-space specific
+ * operators below (eg setgray). This is initially set up by the routines below.
+ *
+ * It would seem unnecessary to have a continuation procedure, because at first
+ * sight these can only be a single space with no alternate and can't require
+ * sampling, because they are device space. However if UseCIEColor is true, then
+ * we will actually use a Default Color Space Array in place of the requested color
+ * space. These are often CIEBased spaces, and these do need to be sampled. So
+ * actually we do need a continuation procedure, unfortunately.
+ *
+ * Also, we need to set the initial color value after we have set the color space.
+ */
+static int
+setdevicecolor_cont(i_ctx_t *i_ctx_p)
+{
+ os_ptr op = osp;
+ es_ptr ep = esp, pstage;
+ int code = 0, stage, base;
+
+ pstage = ep;
+ base = (int)ep[-1].value.intval;
+ stage = (int)pstage->value.intval;
+ /* If we get a continuation from a sub-procedure, we will want to come back
+ * here afterward, to do any remaining stages. We need to set up for that now.
+ * so that our continuation is ahead of the sub-proc's continuation.
+ */
+ check_estack(1);
+ /* The push_op_estack macro increments esp before use, so we don't need to */
+ push_op_estack(setdevicecolor_cont);
+
+ do {
+ switch(stage) {
+ case 0:
+ make_int(pstage, ++stage);
+ push(1);
+ switch(base) {
+ case 0: /* DeviceGray */
+ code = name_enter_string(imemory, "DeviceGray", op);
+ break;
+ case 1: /* DeviceRGB */
+ code = name_enter_string(imemory, "DeviceRGB", op);
+ break;
+ case 2: /* DeviceCMYK */
+ code = name_enter_string(imemory, "DeviceCMYK", op);
+ break;
+ }
+ if (code < 0)
+ return code;
+ code = zsetcolorspace(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ case 1:
+ make_int(pstage, ++stage);
+ code = zsetcolor(i_ctx_p);
+ if (code != 0)
+ return code;
+ break;
+ case 2:
+ esp -= 3;
+ return o_pop_estack;
+ break;
+ }
+ }while(1);
+ return 0;
+}
+
+/* These routines implement the device-space set color routines
+ * These set both the space and the color in a single operation.
+ * Previously these were implemented in PostScript.
+ */
+static int
+zsetgray(i_ctx_t * i_ctx_p)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ float value;
+ int code;
+
+ /* Gather numeric operand value(s) */
+ code = float_params(op, 1, &value);
+ if (code < 0)
+ return code;
+ /* Clamp numeric operand range(s) */
+ if (value < 0)
+ value = 0;
+ else if (value > 1)
+ value = 1;
+ code = make_floats(op, &value, 1);
+ if (code < 0)
+ return code;
+
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold base type (0 = gray) */
+ make_int(esp, 0);
+ esp++;
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(esp, 0);
+ /* Finally, the actual continuation routine */
+ push_op_estack(setdevicecolor_cont);
+ return o_push_estack;
+}
+static int
+zsethsbcolor(i_ctx_t * i_ctx_p)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code, i;
+ float values[3];
+
+ /* Gather numeric operand value(s) (also checks type) */
+ code = float_params(op, 3, (float *)&values);
+ if (code < 0)
+ return code;
+ /* Clamp numeric operand range(s) */
+ for (i = 0;i < 3; i++) {
+ if (values[i] < 0)
+ values[i] = 0;
+ else if (values[i] > 1)
+ values[i] = 1;
+ }
+
+ hsb2rgb((float *)&values);
+
+ code = make_floats(&op[-2], (const float *)&values, 3);
+ if (code < 0)
+ return code;
+
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold base type (1 = RGB) */
+ make_int(esp, 1);
+ esp++;
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(esp, 0);
+ /* Finally, the actual continuation routine */
+ push_op_estack(setdevicecolor_cont);
+ return o_push_estack;
+}
+static int
+zsetrgbcolor(i_ctx_t * i_ctx_p)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code, i;
+ float values[3];
+
+ /* Gather numeric operand value(s) (also checks type) */
+ code = float_params(op, 3, (float *)&values);
+ if (code < 0)
+ return code;
+ /* Clamp numeric operand range(s) */
+ for (i = 0;i < 3; i++) {
+ if (values[i] < 0)
+ values[i] = 0;
+ else if (values[i] > 1)
+ values[i] = 1;
+ }
+
+ code = make_floats(&op[-2], (const float *)&values, 3);
+ if (code < 0)
+ return code;
+
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold base type (1 = RGB) */
+ make_int(esp, 1);
+ esp++;
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(esp, 0);
+ /* Finally, the actual continuation routine */
+ push_op_estack(setdevicecolor_cont);
+ return o_push_estack;
+}
+static int
+zsetcmykcolor(i_ctx_t * i_ctx_p)
+{
+ os_ptr op = osp; /* required by "push" macro */
+ int code, i;
+ float values[4];
+
+ /* Gather numeric operand value(s) (also checks type) */
+ code = float_params(op, 4, (float *)&values);
+ if (code < 0)
+ return code;
+ /* Clamp numeric operand range(s) */
+ for (i = 0;i < 4; i++) {
+ if (values[i] < 0)
+ values[i] = 0;
+ else if (values[i] > 1)
+ values[i] = 1;
+ }
+
+ code = make_floats(&op[-3], (const float *)&values, 4);
+ if (code < 0)
+ return code;
+
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(5);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold base type (2 = CMYK) */
+ make_int(esp, 2);
+ esp++;
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(esp, 0);
+ /* Finally, the actual continuation routine */
+ push_op_estack(setdevicecolor_cont);
+ return o_push_estack;
+}
+/*
+ * The routine which does all the dispatching for the device-space specific
+ * 'current color' routines currentgray, currentrgbcolo and currentcmykcolor.
+ *
+ * Starting with the top-level color space we need to take the current color
+ * value(s) and pass it through the tint transform procedure (actually we use the
+ * converted function) to get equivalent components for the next space. We then
+ * repeat with each alternate space in turn until we reach a 'terminal' space.
+ * That can be a device space (eg DeviceGray), a CIEBased or ICCBased space, or
+ * a Separation or DeviceN space which is not using its alternate space.
+ *
+ * Depending on which kind of terminal space we reach we will either return
+ * fixed values (all 0.0) or we will convert the terminal device space components
+ * into the requested device space.
+ *
+ * Because we might need to run a tint transform procedure, this requires a
+ * continuation procedure.
+ */
+static int
+currentbasecolor_cont(i_ctx_t *i_ctx_p)
+{
+ ref arr, *parr = &arr;
+ es_ptr ep = esp;
+ int i, code = 0,depth, stage, base, cont=1, stack_depth = 0;
+ PS_colour_space_t *obj;
+
+ stack_depth = (int)ep[-4].value.intval;
+ base = (int)ep[-3].value.intval;
+ depth = (int)ep[-2].value.intval;
+ stage = (int)ep[-1].value.intval;
+ /* If we get a continuation from a sub-procedure, we will want to come back
+ * here afterward, to do any remaining stages. We need to set up for that now.
+ * so that our continuation is ahead of the sub-proc's continuation.
+ */
+ check_estack(1);
+ /* The push_op_estack macro increments esp before use, so we don't need to */
+ push_op_estack(currentbasecolor_cont);
+
+ while (code == 0 && cont) {
+ ref_assign(&arr, ep);
+ /* Run along the nested color spaces until we get to the lowest one
+ * that we haven't yet processed (given by 'depth')
+ */
+ for (i = 0;i < depth;i++) {
+ code = get_space_object(i_ctx_p, parr, &obj);
+ if (code < 0)
+ return code;
+
+ if (i < (depth - 1)) {
+ if (!obj->alternateproc) {
+ return_error(e_typecheck);
+ }
+ code = obj->alternateproc(i_ctx_p, parr, &parr);
+ if (code < 0)
+ return code;
+ }
+ }
+
+ code = obj->basecolorproc(i_ctx_p, parr, base, &stage, &cont, &stack_depth);
+ make_int(&ep[-4], stack_depth);
+ make_int(&ep[-1], stage);
+ if (code != 0)
+ return code;
+ /* Completed that space, increment the 'depth' */
+ make_int(&ep[-2], ++depth);
+ }
+ if (code == 0) {
+ /* Remove our next continuation and our data */
+ esp -= 7;
+ code = o_pop_estack;
+ }
+ return code;
+}
+
+/* These routines implement the device-space 'current' color routines.
+ * Previously these were implemented in PostScript.
+ */
+static int
+zcurrentgray(i_ctx_t * i_ctx_p)
+{
+ int code, depth;
+
+ code = validate_spaces(i_ctx_p, &istate->colorspace.array, &depth);
+ if (code < 0)
+ return code;
+
+ code = zcurrentcolor(i_ctx_p);
+ if (code < 0)
+ return code;
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(7);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold stack depth for tint transform */
+ make_int(&esp[0], 0);
+ esp++;
+ /* Store the 'base' type color wanted, in this case Gray */
+ make_int(&esp[0], 0);
+ make_int(&esp[1], 1);
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(&esp[2], 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ esp[3] = istate->colorspace.array;
+ esp += 3; /* The push_op_estack macro increments esp before using it */
+ /* Finally, the actual continuation routine */
+ push_op_estack(currentbasecolor_cont);
+ return o_push_estack;
+}
+static int
+zcurrenthsbcolor(i_ctx_t * i_ctx_p)
+{
+ int code, depth;
+
+ code = validate_spaces(i_ctx_p, &istate->colorspace.array, &depth);
+ if (code < 0)
+ return code;
+
+ code = zcurrentcolor(i_ctx_p);
+ if (code < 0)
+ return code;
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(7);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold stack depth for tint transform */
+ make_int(&esp[0], 0);
+ esp++;
+ /* Store the 'base' type color wanted, in this case HSB */
+ make_int(&esp[0], 1);
+ make_int(&esp[1], 1);
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(&esp[2], 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ esp[3] = istate->colorspace.array;
+ esp += 3; /* The push_op_estack macro increments esp before using it */
+ /* Finally, the actual continuation routine */
+ push_op_estack(currentbasecolor_cont);
+ return o_push_estack;
+}
+static int
+zcurrentrgbcolor(i_ctx_t * i_ctx_p)
+{
+ int code;
+
+ code = zcurrentcolor(i_ctx_p);
+ if (code < 0)
+ return code;
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(7);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold stack depth for tint transform */
+ make_int(&esp[0], 0);
+ esp++;
+ /* Store the 'base' type color wanted, in this case RGB */
+ make_int(&esp[0], 2);
+ make_int(&esp[1], 1);
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(&esp[2], 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ esp[3] = istate->colorspace.array;
+ esp += 3; /* The push_op_estack macro increments esp before using it */
+ /* Finally, the actual continuation routine */
+ push_op_estack(currentbasecolor_cont);
+ return o_push_estack;
+}
+static int
+zcurrentcmykcolor(i_ctx_t * i_ctx_p)
+{
+ int code;
+
+ code = zcurrentcolor(i_ctx_p);
+ if (code < 0)
+ return code;
+ /* Set up for the continuation procedure which will do the work */
+ /* Make sure the exec stack has enough space */
+ check_estack(7);
+ push_mark_estack(es_other, 0);
+ esp++;
+ /* variable to hold stack depth for tint transform */
+ make_int(&esp[0], 0);
+ esp++;
+ /* Store the 'base' type color wanted, in this case CMYK */
+ make_int(&esp[0], 3);
+ make_int(&esp[1], 1);
+ /* Store the 'stage' of processing (initially 0) */
+ make_int(&esp[2], 0);
+ /* Store a pointer to the color space stored on the operand stack
+ * as the stack may grow unpredictably making further access
+ * to the space difficult
+ */
+ esp[3] = istate->colorspace.array;
+ esp += 3; /* The push_op_estack macro increments esp before using it */
+ /* Finally, the actual continuation routine */
+ push_op_estack(currentbasecolor_cont);
+ return o_push_estack;
+}
/* ------ Initialization procedure ------ */
+/* We need to split the table because of the 16-element limit. */
const op_def zcolor_op_defs[] =
{
{ "0currentcolor", zcurrentcolor },
@@ -677,7 +5965,6 @@ const op_def zcolor_op_defs[] =
{ "0.getuseciecolor", zgetuseciecolor },
{ "1setcolor", zsetcolor },
{ "1setcolorspace", zsetcolorspace },
- { "1.setdevcspace", zsetdevcspace },
/* basic transfer operators */
{ "0currenttransfer", zcurrenttransfer },
@@ -692,8 +5979,21 @@ const op_def zcolor_op_defs[] =
{ "0.color_test", zcolor_test },
{ "1.color_test_all", zcolor_test_all },
-
/* high level device support */
{ "0.includecolorspace", zincludecolorspace },
op_def_end(0)
};
+
+const op_def zcolor_ext_op_defs[] =
+{
+ {"0currentgray", zcurrentgray },
+ {"1setgray", zsetgray },
+ {"0currenthsbcolor", zcurrenthsbcolor },
+ {"3sethsbcolor", zsethsbcolor },
+ {"0currentrgbcolor", zcurrentrgbcolor },
+ {"3setrgbcolor", zsetrgbcolor },
+ {"0currentcmykcolor", zcurrentcmykcolor },
+ {"4setcmykcolor", zsetcmykcolor },
+ op_def_end(0)
+};
+
diff --git a/gs/src/zcolor.h b/gs/src/zcolor.h
new file mode 100644
index 000000000..52069bd7f
--- /dev/null
+++ b/gs/src/zcolor.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2001-2006 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/
+ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* $Id: zcolor.h $ */
+/* Definitions for setcolorspace */
+
+#ifndef zcolor_INCLUDED
+# define zcolor_INCLUDED
+
+/*
+ * The code to set color space and color values has been moved from PostScript
+ * into C (mostly). The new C code broadly follows the old PostScript method, each
+ * possible color space is defined by an instance of the PS_colour_space_s object below. These
+ * are stored in an array (in zcolor.c) called colorProcs. When color spaces or
+ * color values are set, or values retrieved, we examine the array or name which
+ * represents the space, and extract a C string representation of the color space
+ * name. We compare the name with each of the names in the colorProcs array to
+ * retrieve the instance which handles that color space.
+ *
+ * When setting a new color space, we must follow the existing Ghostscript policy
+ * which requires us to set the spaces 'backwards'. That is, before we set a space
+ * which has an alternate color space (eg Separation) we must first set the
+ * alternate space as the current.
+ *
+ * Now, when setting a color space, we convert any tint transform procedure from
+ * a PostScript procedure into a PostScript Function, either a type 4 PostScript
+ * calculator or a type 0 sampled function. This has performance benefits, especially
+ * wehn dealing with images. Now, if we are converting into a type 4 function this is
+ * easy, however a type 0 function requires us to sample the color space and in order
+ * to do this, we must actually execute the tint transform procedure. This means we
+ * must exit the C world and hand control back to the PostScript interpreter
+ * temporarily.
+ *
+ * We do this with a 'continuation function', we store our procdure on the PostScript
+ * execution stack, and when we need to run a tint transform, we push the procedure
+ * onto the execution stack after our function, and exit back to the interpreter.
+ * When the interpreter has finished executing the transform, it executes the next
+ * entry on the execution stack, which is our C procedure, and returns control back
+ * to our code. Of course, we need to know what stage of processing we were up to
+ * and so we also store some variables on the execution stack. Continuation
+ * procedures are basically state machines.
+ *
+ * In fact, we need quite a few of these, for setting the color space, the current
+ * color (we may need to execute tint transforms), converting the current color into
+ * a device space (for currentcmykcolor and so on). These are all defined in zcolor.c.
+ */
+typedef struct PS_colour_space_s PS_colour_space_t;
+struct PS_colour_space_s {
+ char *name; /* C string representing the name of the space */
+ int (*setproc)(i_ctx_t * i_ctx_p, ref *r, /* Routine to set the color space, if CIESubst */
+ int *stage, int *cont, int CIESubst); /* is true then we are already doing CIE substitution */
+ int (*validateproc)(i_ctx_t * i_ctx_p, /* Validates the color space operands */
+ ref **r);
+ int (*alternateproc)(i_ctx_t * i_ctx_p, /* Retrieve the alternate color space (if any) */
+ ref *space, ref **r);
+ int (*numcomponents)(i_ctx_t * i_ctx_p, /* Returns the number of components in the space */
+ ref *space, int *n);
+ int (*range)(i_ctx_t * i_ctx_p, ref *space, /* Returns 'components' pairs of values which represent */
+ float *ptr); /* the valid ranges of values for this space */
+ int (*domain)(i_ctx_t * i_ctx_p, /* Returns 'components' pairs of values which represent */
+ ref *space, float *ptr); /* the domain over which values are valid */
+ int (*basecolorproc)(i_ctx_t * i_ctx_p, /* convert the current color values into device space */
+ ref *space, int base, int *stage, /* values. 'base' is the requested base space, 0=gray */
+ int *cont, int *stack_depth); /* 1 = HSB, 2 = RGB, 3 = CMYK. Separation and DeviceN */
+ /* spaces will return default values if they are not using */
+ /* the alternate space, and will convert the components */
+ /* into values in the alternate otherwise, by executing */
+ /* the tint transform procedure */
+ int (*runtransformproc)(i_ctx_t *i_ctx_p, /* executes the tint transform for this space */
+ ref *space, int *usealternate,
+ int *stage, int *stack_depth);
+ int (*validatecomponents)(i_ctx_t *i_ctx_p, /* Check the components supplied as an argument to setcolor */
+ ref *space, float *values, /* are valid */
+ int num_comps);
+ int (*compareproc)(i_ctx_t *i_ctx_p, /* Compare two color spaces of this type, to see if they */
+ ref *space, ref *testspace); /* are the same */
+ int (*initialcolorproc)(i_ctx_t *i_ctx_p, /* Set the appropriate initial color for this space */
+ ref *space);
+};
+
+
+/* Given a pointer to a color space (name or array), returns
+ * the appropriate instance of PS_colour_space_s from the colorProcs array
+ */
+int get_space_object(i_ctx_t *i_ctx_p, ref *arr, PS_colour_space_t **obj);
+
+#endif /* zcolor_INCLUDED */
diff --git a/gs/src/zcsdevn.c b/gs/src/zcsdevn.c
index 00e25a663..d13d4cc5b 100644
--- a/gs/src/zcsdevn.c
+++ b/gs/src/zcsdevn.c
@@ -31,6 +31,7 @@
/* Imported from gscdevn.c */
extern const gs_color_space_type gs_color_space_type_DeviceN;
+#if 0
/* <array> .setdevicenspace - */
/* The current color space is the alternate space for the DeviceN space. */
static int
@@ -167,14 +168,16 @@ zattachdevicenattributespace(i_ctx_t *i_ctx_p)
pop(1);
return code;
}
-
+#endif
/* ------ Initialization procedure ------ */
const op_def zcsdevn_op_defs[] =
{
op_def_begin_ll3(),
+#if 0
{"1.setdevicenspace", zsetdevicenspace},
{"1.attachdevicenattributespace", zattachdevicenattributespace},
+#endif
op_def_end(0)
};
diff --git a/gs/src/zcsindex.c b/gs/src/zcsindex.c
index e3cdea33a..2b8f6d9b7 100644
--- a/gs/src/zcsindex.c
+++ b/gs/src/zcsindex.c
@@ -29,135 +29,6 @@
#include "ivmspace.h"
#include "store.h"
-/* Imported from gscolor2.c */
-extern const gs_color_space_type gs_color_space_type_Indexed;
-
-/* Forward references. */
-static int indexed_map1(i_ctx_t *);
-
-/* <array> .setindexedspace - */
-/* The current color space is the base space for the indexed space. */
-static int
-zsetindexedspace(i_ctx_t *i_ctx_p)
-{
- os_ptr op = osp;
- ref *pproc = &istate->colorspace.procs.special.index_proc;
- const ref *pcsa;
- gs_color_space *pcs;
- gs_color_space *pcs_base;
- ref_colorspace cspace_old;
- uint edepth = ref_stack_count(&e_stack);
- int num_entries;
- int code;
-
- check_read_type(*op, t_array);
- if (r_size(op) != 4)
- return_error(e_rangecheck);
- pcsa = op->value.const_refs + 1;
- check_type_only(pcsa[1], t_integer);
- if (pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095)
- return_error(e_rangecheck);
- num_entries = (int)pcsa[1].value.intval + 1;
- pcs_base = gs_currentcolorspace(igs);
- if (!pcs_base->type->can_be_base_space)
- return_error(e_rangecheck);
- cspace_old = istate->colorspace;
-
- if (r_has_type(&pcsa[2], t_string)) {
- int num_values = num_entries * cs_num_components(pcs_base);
-
- check_read(pcsa[2]);
- /*
- * The PDF and PS specifications state that the lookup table must have
- * the exact number of of data bytes needed. However we have found
- * PDF files from Amyuni with extra data bytes. Acrobat 6.0 accepts
- * these files without complaint, so we ignore the extra data.
- */
- if (r_size(&pcsa[2]) < num_values)
- return_error(e_rangecheck);
- pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
- pcs->base_space = pcs_base;
- rc_increment(pcs_base);
- pcs->params.indexed.lookup.table.data = pcsa[2].value.const_bytes;
- pcs->params.indexed.lookup.table.size = num_values;
- pcs->params.indexed.use_proc = 0;
- make_null(pproc);
- code = 0;
- } else {
- gs_indexed_map *map;
-
- check_proc(pcsa[2]);
- /*
- * We have to call zcs_begin_map before moving the parameters,
- * since if the color space is a DeviceN or Separation space,
- * the memmove will overwrite its parameters.
- */
- code = zcs_begin_map(i_ctx_p, &map, &pcsa[2], num_entries,
- pcs_base, indexed_map1);
- if (code < 0)
- return code;
- pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
- pcs->base_space = pcs_base;
- rc_increment(pcs_base);
- pcs->params.indexed.use_proc = 1;
- *pproc = pcsa[2];
- map->proc.lookup_index = lookup_indexed_map;
- pcs->params.indexed.lookup.map = map;
- }
- pcs->params.indexed.hival = num_entries - 1;
- pcs->params.indexed.n_comps = cs_num_components(pcs_base);
- code = gs_setcolorspace(igs, pcs);
- /* release reference from construction */
- rc_decrement_only(pcs, "zsetindexedspace");
- if (code < 0) {
- istate->colorspace = cspace_old;
- ref_stack_pop_to(&e_stack, edepth);
- return code;
- }
- pop(1);
- return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
-}
-
-/* Continuation procedure for saving mapped Indexed color values. */
-static int
-indexed_map1(i_ctx_t *i_ctx_p)
-{
- os_ptr op = osp;
- es_ptr ep = esp;
- int i = (int)ep[csme_index].value.intval;
-
- if (i >= 0) { /* i.e., not first time */
- int m = (int)ep[csme_num_components].value.intval;
- int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
-
- if (code < 0)
- return code;
- pop(m);
- op -= m;
- if (i == (int)ep[csme_hival].value.intval) { /* All done. */
- esp -= num_csme;
- return o_pop_estack;
- }
- }
- push(1);
- ep[csme_index].value.intval = ++i;
- make_int(op, i);
- make_op_estack(ep + 1, indexed_map1);
- ep[2] = ep[csme_proc]; /* lookup proc */
- esp = ep + 2;
- return o_push_estack;
-}
-
-/* ------ Initialization procedure ------ */
-
-const op_def zcsindex_l2_op_defs[] =
-{
- op_def_begin_level2(),
- {"1.setindexedspace", zsetindexedspace},
- /* Internal operators */
- {"1%indexed_map1", indexed_map1},
- op_def_end(0)
-};
/* ------ Internal routines ------ */
diff --git a/gs/src/zcspixel.c b/gs/src/zcspixel.c
index 720c92d38..ef4584306 100644
--- a/gs/src/zcspixel.c
+++ b/gs/src/zcspixel.c
@@ -22,35 +22,3 @@
#include "gscpixel.h"
#include "ialloc.h"
-/* <array> .setdevicepixelspace - */
-static int
-zsetdevicepixelspace(i_ctx_t *i_ctx_p)
-{
- os_ptr op = osp;
- ref depth;
- gs_color_space *pcs;
- int code;
-
- check_read_type(*op, t_array);
- if (r_size(op) != 2)
- return_error(e_rangecheck);
- array_get(imemory, op, 1L, &depth);
- check_type_only(depth, t_integer);
- code = gs_cspace_new_DevicePixel(imemory, &pcs, (int)depth.value.intval);
- if (code < 0)
- return code;
- code = gs_setcolorspace(igs, pcs);
- /* release reference from construction */
- rc_decrement_only(pcs, "zsetseparationspace");
- if (code >= 0)
- pop(1);
- return code;
-}
-
-/* ------ Initialization procedure ------ */
-
-const op_def zcspixel_op_defs[] =
-{
- {"1.setdevicepixelspace", zsetdevicepixelspace},
- op_def_end(0)
-};
diff --git a/gs/src/zcssepr.c b/gs/src/zcssepr.c
index fb486f3f6..de0454dc1 100644
--- a/gs/src/zcssepr.c
+++ b/gs/src/zcssepr.c
@@ -48,89 +48,6 @@ extern const gs_color_space_type gs_color_space_type_DeviceN;
* colorspace except for the /All case.
*/
-/* <array> .setseparationspace - */
-/* The current color space is the alternate space for the separation space. */
-static int
-zsetseparationspace(i_ctx_t *i_ctx_p)
-{
- os_ptr op = osp;
- const ref *pcsa;
- gs_color_space *pcs;
- gs_color_space * pacs;
- ref_colorspace cspace_old;
- ref sname, name_none, name_all;
- gs_function_t *pfn = NULL;
- separation_type sep_type;
- int code;
- const gs_memory_t * mem = imemory;
-
- /* Verify that we have an array as our input parameter */
- check_read_type(*op, t_array);
- if (r_size(op) != 4)
- return_error(e_rangecheck);
-
- /* The alternate color space has been selected as the current color space */
- pacs = gs_currentcolorspace(igs);
- if (!pacs->type->can_be_alt_space)
- return_error(e_rangecheck);
-
- /*
- * pcsa is a pointer to element 1 (2nd element) in the Separation colorspace
- * description array. Thus pcsa[2] is element #3 (4th element) which is the
- * tint transform.
- */
- pcsa = op->value.const_refs + 1;
- sname = *pcsa;
- switch (r_type(&sname)) {
- default:
- return_error(e_typecheck);
- case t_string:
- code = name_from_string(mem, &sname, &sname);
- if (code < 0)
- return code;
- /* falls through */
- case t_name:
- break;
- }
-
- if ((code = name_ref(mem, (const byte *)"All", 3, &name_all, 0)) < 0)
- return code;
- if ((code = name_ref(mem, (const byte *)"None", 4, &name_none, 0)) < 0)
- return code;
- sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
- name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
-
- /* Check tint transform procedure. */
- /* See comment above about psca */
- check_proc(pcsa[2]);
- pfn = ref_function(pcsa + 2);
- if (pfn == NULL)
- return_error(e_rangecheck);
-
- cspace_old = istate->colorspace;
- /* Now set the current color space as Separation */
- code = gs_cspace_new_Separation(&pcs, pacs, imemory);
- if (code < 0)
- return code;
- pcs->params.separation.sep_type = sep_type;
- pcs->params.separation.sep_name = name_index(mem, &sname);
- pcs->params.separation.get_colorname_string = gs_get_colorname_string;
- istate->colorspace.procs.special.separation.layer_name = pcsa[0];
- istate->colorspace.procs.special.separation.tint_transform = pcsa[2];
- if (code >= 0)
- code = gs_cspace_set_sepr_function(pcs, pfn);
- if (code >= 0)
- code = gs_setcolorspace(igs, pcs);
- /* release reference from construction */
- rc_decrement_only(pcs, "zsetseparationspace");
- if (code < 0) {
- istate->colorspace = cspace_old;
- return code;
- }
- pop(1);
- return 0;
-}
-
/* - currentoverprint <bool> */
static int
zcurrentoverprint(i_ctx_t *i_ctx_p)
@@ -188,6 +105,5 @@ const op_def zcssepr_l2_op_defs[] =
{"0.currentoverprintmode", zcurrentoverprintmode},
{"1setoverprint", zsetoverprint},
{"1.setoverprintmode", zsetoverprintmode},
- {"1.setseparationspace", zsetseparationspace},
op_def_end(0)
};
diff --git a/gs/src/zfsample.c b/gs/src/zfsample.c
index 9a9447a3b..dcf730a60 100644
--- a/gs/src/zfsample.c
+++ b/gs/src/zfsample.c
@@ -27,6 +27,8 @@
#include "gsfunc0.h"
#include "gscdevn.h"
+#include "zcolor.h"
+
/*
* We store the data in a string. Since the max size for a string is 64k,
* we use that as our max data size.
@@ -128,7 +130,7 @@ zbuildsampledfunction(i_ctx_t *i_ctx_p)
*/
return sampled_data_setup(i_ctx_p, pfn, pfunc, sampled_data_finish, imemory);
}
-
+
/* ------- Internal procedures ------- */
@@ -480,18 +482,16 @@ sampled_data_continue(i_ctx_t *i_ctx_p)
int code = 0;
byte * data_ptr;
double sampled_data_value_max = (double)((1 << params->BitsPerSample) - 1);
- int bps = bits2bytes(params->BitsPerSample);
+ int bps = bits2bytes(params->BitsPerSample), stack_depth_adjust = 0;
/*
* Check to make sure that the procedure produced the correct number of
* values. If not, move the stack back to where it belongs and abort
*/
if (num_out + O_STACK_PAD + penum->o_stack_depth != ref_stack_count(&o_stack)) {
- int stack_depth_adjust = ref_stack_count(&o_stack) - penum->o_stack_depth;
+ stack_depth_adjust = ref_stack_count(&o_stack) - penum->o_stack_depth;
- if (stack_depth_adjust >= 0)
- pop(stack_depth_adjust);
- else {
+ if (stack_depth_adjust < 0) {
/*
* If we get to here then there were major problems. The function
* removed too many items off of the stack. We had placed extra
@@ -502,10 +502,10 @@ sampled_data_continue(i_ctx_t *i_ctx_p)
* problem.)
*/
push(-stack_depth_adjust);
+ ifree_object(penum->pfn, "sampled_data_continue(pfn)");
+ ifree_object(penum, "sampled_data_continue((enum)");
+ return_error(e_undefinedresult);
}
- ifree_object(penum->pfn, "sampled_data_continue(pfn)");
- ifree_object(penum, "sampled_data_continue((enum)");
- return_error(e_undefinedresult);
}
/* Save data from the given function */
@@ -533,13 +533,23 @@ sampled_data_continue(i_ctx_t *i_ctx_p)
/* Check if we are done collecting data. */
if (increment_cube_indexes(params, penum->indexes)) {
- pop(O_STACK_PAD); /* Remove spare stack space */
+ if (stack_depth_adjust == 0)
+ pop(O_STACK_PAD); /* Remove spare stack space */
+ else
+ pop(stack_depth_adjust - num_out);
/* Execute the closing procedure, if given */
code = 0;
if (esp_finish_proc != 0)
code = esp_finish_proc(i_ctx_p);
return code;
+ } else {
+ if (stack_depth_adjust) {
+ stack_depth_adjust -= num_out;
+ push(O_STACK_PAD - stack_depth_adjust);
+ for (i=0;i<O_STACK_PAD - stack_depth_adjust;i++)
+ make_null(op - i);
+ }
}
/* Now get the data for the next location */
@@ -580,6 +590,121 @@ sampled_data_finish(i_ctx_t *i_ctx_p)
return o_pop_estack;
}
+int make_sampled_function(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, gs_function_t **func)
+{
+ int code = 0, *ptr, i, total_size, num_components;
+ byte * bytes = 0;
+ float *fptr;
+ gs_function_t *pfn = *func;
+ gs_function_Sd_params_t params = {0};
+ ref alternatespace, *palternatespace = &alternatespace;
+ PS_colour_space_t *space, *altspace;
+
+ code = get_space_object(i_ctx_p, arr, &space);
+ if (code < 0)
+ return code;
+ if (!space->alternateproc)
+ return e_typecheck;
+ code = space->alternateproc(i_ctx_p, arr, &palternatespace);
+ if (code < 0)
+ return code;
+ code = get_space_object(i_ctx_p, palternatespace, &altspace);
+ if (code < 0)
+ return code;
+ /*
+ * Set up the hyper cube function data structure.
+ */
+ params.Order = 3;
+ params.BitsPerSample = 16;
+
+ code = space->numcomponents(i_ctx_p, arr, &num_components);
+ if (code < 0)
+ return code;
+ fptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_sampled_function(Domain)");
+ if (!fptr)
+ return e_VMerror;
+ code = space->domain(i_ctx_p, arr, fptr);
+ if (code < 0) {
+ gs_free_const_object(imemory, fptr, "make_sampled_function(Domain)");
+ return code;
+ }
+ params.Domain = fptr;
+ params.m = num_components;
+
+ code = altspace->numcomponents(i_ctx_p, palternatespace, &num_components);
+ if (code < 0) {
+ gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
+ return code;
+ }
+ fptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_sampled_function(Range)");
+ if (!fptr) {
+ gs_free_const_object(imemory, params.Domain, "make_sampled_function(Domain)");
+ return e_VMerror;
+ }
+ code = altspace->range(i_ctx_p, palternatespace, fptr);
+ if (code < 0) {
+ gs_free_const_object(imemory, params.Domain, "make_sampled_function(Domain)");
+ gs_free_const_object(imemory, fptr, "make_sampled_function(Range)");
+ return code;
+ }
+ params.Range = fptr;
+ params.n = num_components;
+
+ /*
+ * The Size array may or not be specified. If it is not specified then
+ * we need to determine a set of default values for the Size array.
+ */
+ ptr = (int *)gs_alloc_byte_array(imemory, params.m, sizeof(int), "Size");
+ if (ptr == NULL) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ params.Size = ptr;
+ /*
+ * Determine a default
+ * set of values.
+ */
+ code = determine_sampled_data_size(params.m, params.n,
+ params.BitsPerSample, (int *)params.Size);
+ if (code < 0)
+ goto fail;
+ /*
+ * Determine space required for the sample data storage.
+ */
+ total_size = params.n * bits2bytes(params.BitsPerSample);
+ for (i = 0; i < params.m; i++)
+ total_size *= params.Size[i];
+ /*
+ * Allocate space for the data cube itself.
+ */
+ bytes = gs_alloc_byte_array(imemory, total_size, 1, "cube_build_func0(bytes)");
+ if (!bytes) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ data_source_init_bytes(&params.DataSource,
+ (const unsigned char *)bytes, total_size);
+
+ /*
+ * This is temporary. We will call gs_function_Sd_init again after
+ * we have collected the cube data. We are doing it now because we need
+ * a function structure created (along with its GC enumeration stuff)
+ * that we can use while collecting the cube data. We will call
+ * the routine again after the cube data is collected to correctly
+ * initialize the function.
+ */
+ code = gs_function_Sd_init(&pfn, &params, imemory);
+ if (code < 0)
+ return code;
+ /*
+ * Now setup to collect the sample data.
+ */
+ return sampled_data_setup(i_ctx_p, pfn, pproc, sampled_data_finish, imemory);
+
+fail:
+ gs_function_Sd_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
/* ------ Initialization procedure ------ */
diff --git a/gs/src/zfunc.c b/gs/src/zfunc.c
index ebd6097a1..75eeaf44a 100644
--- a/gs/src/zfunc.c
+++ b/gs/src/zfunc.c
@@ -50,7 +50,7 @@ make_function_proc(i_ctx_t *i_ctx_p, ref *op, gs_function_t *pfn)
}
/* <dict> .buildfunction <function_proc> */
-static int
+int
zbuildfunction(i_ctx_t *i_ctx_p)
{
os_ptr op = osp;
@@ -65,6 +65,30 @@ zbuildfunction(i_ctx_t *i_ctx_p)
return 0;
}
+int buildfunction(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, int type)
+{
+ os_ptr op = osp;
+ ref cref; /* closure */
+ gs_function_t *pfn;
+ int code, code1;
+
+ switch(type) {
+ case 0:
+ code = make_sampled_function(i_ctx_p, arr, pproc, &pfn);
+ break;
+ case 4:
+ code = make_type4_function(i_ctx_p, arr, pproc, &pfn);
+ if (code == 0) {
+ code = make_function_proc(i_ctx_p, op, pfn);
+ if (code < 0) {
+ gs_function_free(pfn, true, imemory);
+ }
+ }
+ break;
+ }
+ return code;
+}
+
#ifdef TEST
/* <function_proc> <array> .scalefunction <function_proc> */
diff --git a/gs/src/zfunc4.c b/gs/src/zfunc4.c
index bb66631d2..6e77d661c 100644
--- a/gs/src/zfunc4.c
+++ b/gs/src/zfunc4.c
@@ -28,6 +28,9 @@
#include "gzstate.h" /* these are needed to check if device is pdfwrite */
#include "gxdevcli.h" /* these are needed to check if device is pdfwrite */
#include "string_.h" /* these are needed to check if device is pdfwrite */
+
+#include "zcolor.h"
+
/*
* FunctionType 4 functions are not defined in the PostScript language. We
* provide support for them because they are needed for PDF 1.3. In
@@ -335,3 +338,78 @@ fail:
gs_function_PtCr_free_params(&params, mem);
return (code < 0 ? code : gs_note_error(e_rangecheck));
}
+
+int make_type4_function(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, gs_function_t **func)
+{
+ int i, code, size, num_components;
+ byte *ops;
+ gs_function_PtCr_params_t params;
+ float *ptr;
+ ref alternatespace, *palternatespace = &alternatespace;
+ PS_colour_space_t *space, *altspace;
+
+ code = get_space_object(i_ctx_p, arr, &space);
+ if (code < 0)
+ return code;
+ if (!space->alternateproc)
+ return e_typecheck;
+ code = space->alternateproc(i_ctx_p, arr, &palternatespace);
+ if (code < 0)
+ return code;
+ code = get_space_object(i_ctx_p, palternatespace, &altspace);
+ if (code < 0)
+ return code;
+
+ code = space->numcomponents(i_ctx_p, arr, &num_components);
+ if (code < 0)
+ return code;
+ ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Domain)");
+ if (!ptr)
+ return e_VMerror;
+ code = space->domain(i_ctx_p, arr, ptr);
+ if (code < 0) {
+ gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
+ return code;
+ }
+ params.Domain = ptr;
+ params.m = num_components;
+
+ code = altspace->numcomponents(i_ctx_p, &alternatespace, &num_components);
+ if (code < 0) {
+ gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
+ return code;
+ }
+ ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Range)");
+ if (!ptr) {
+ gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
+ return e_VMerror;
+ }
+ code = altspace->range(i_ctx_p, &alternatespace, ptr);
+ if (code < 0) {
+ gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
+ gs_free_const_object(imemory, params.Domain, "make_type4_function(Range)");
+ return code;
+ }
+ params.Range = ptr;
+ params.n = num_components;
+
+ params.ops.data = 0; /* in case of failure, see gs_function_PtCr_free_params */
+ params.ops.size = 0; /* ditto */
+ size = 0;
+ code = check_psc_function(i_ctx_p, (const ref *)pproc, 0, NULL, &size);
+ if (code < 0) {
+ gs_function_PtCr_free_params(&params, imemory);
+ return code;
+ }
+ ops = gs_alloc_string(imemory, size + 1, "make_type4_function(ops)");
+ size = 0;
+ check_psc_function(i_ctx_p, (const ref *)pproc, 0, ops, &size); /* can't fail */
+ ops[size] = PtCr_return;
+ params.ops.data = ops;
+ params.ops.size = size + 1;
+ code = gs_function_PtCr_init(func, &params, imemory);
+ if (code < 0)
+ gs_function_PtCr_free_params(&params, imemory);
+
+ return code;
+} \ No newline at end of file
diff --git a/gs/src/zicc.c b/gs/src/zicc.c
index 1d93d34e1..e3d1e93db 100644
--- a/gs/src/zicc.c
+++ b/gs/src/zicc.c
@@ -31,7 +31,87 @@
#include "igstate.h"
#include "icie.h"
#include "ialloc.h"
+#include "zicc.h"
+int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff)
+{
+ os_ptr op = osp;
+ int edepth = ref_stack_count(&e_stack);
+ int code;
+ gs_color_space * pcs;
+ gs_color_space * palt_cs;
+ int i;
+ gs_cie_icc * picc_info;
+ ref * pstrmval;
+ stream * s = 0L;
+
+ palt_cs = gs_currentcolorspace(igs);
+ /* verify the DataSource entry */
+ if (dict_find_string(ICCdict, "DataSource", &pstrmval) <= 0)
+ return_error(e_undefined);
+ check_read_file(s, pstrmval);
+
+ /* build the color space object */
+ code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
+ if (code < 0)
+ return code;
+ picc_info = pcs->params.icc.picc_info;
+ picc_info->num_components = ncomps;
+ picc_info->instrp = s;
+ picc_info->file_id = (s->read_id | s->write_id);
+ for (i = 0; i < ncomps; i++) {
+ picc_info->Range.ranges[i].rmin = range_buff[2 * i];
+ picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];
+
+ }
+
+ /* record the current space as the alternative color space */
+ pcs->base_space = palt_cs;
+ rc_increment(palt_cs);
+
+ code = gx_load_icc_profile(picc_info);
+ if (code < 0)
+ return code;
+
+ /* If the input space to this profile is CIELAB, then we need to adjust the limits */
+ /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4 */
+ if(picc_info->plu->e_inSpace == icSigLabData)
+ {
+ picc_info->Range.ranges[0].rmin = 0.0;
+ picc_info->Range.ranges[0].rmax = 100.0;
+
+ picc_info->Range.ranges[1].rmin = -128.0;
+ picc_info->Range.ranges[1].rmax = 127.0;
+
+ picc_info->Range.ranges[2].rmin = -128.0;
+ picc_info->Range.ranges[2].rmax = 127.0;
+
+ }
+ /* If the input space is icSigXYZData, then we should do the limits based upon the white point of the profile. */
+ if(picc_info->plu->e_inSpace == icSigXYZData)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ picc_info->Range.ranges[i].rmin = 0;
+ }
+
+ picc_info->Range.ranges[0].rmax = picc_info->common.points.WhitePoint.u;
+ picc_info->Range.ranges[1].rmax = picc_info->common.points.WhitePoint.v;
+ picc_info->Range.ranges[2].rmax = picc_info->common.points.WhitePoint.w;
+ }
+
+ code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
+ (gs_cie_common *)picc_info, igs);
+ if (code < 0)
+ return code;
+
+ push(1);
+ return cie_set_finish( i_ctx_p,
+ pcs,
+ &istate->colorspace.procs.cie,
+ edepth,
+ code );
+}
/*
* <dict> .seticcspace -
@@ -64,15 +144,12 @@ static int
zseticcspace(i_ctx_t * i_ctx_p)
{
os_ptr op = osp;
- int edepth = ref_stack_count(&e_stack);
int code;
- gs_color_space * pcs;
gs_color_space * palt_cs;
ref * pnval;
ref * pstrmval;
stream * s;
int i, ncomps;
- gs_cie_icc * picc_info;
float range_buff[8];
static const float dflt_range[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
@@ -124,70 +201,7 @@ zseticcspace(i_ctx_t * i_ctx_p)
if (i != 2 * ncomps)
return_error(e_rangecheck);
- /* build the color space object */
- code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
- if (code < 0)
- return code;
- picc_info = pcs->params.icc.picc_info;
- picc_info->num_components = ncomps;
- picc_info->instrp = s;
- picc_info->file_id = (s->read_id | s->write_id);
- for (i = 0; i < ncomps; i++) {
- picc_info->Range.ranges[i].rmin = range_buff[2 * i];
- picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];
-
- }
-
- /* record the current space as the alternative color space */
- pcs->base_space = palt_cs;
- rc_increment(palt_cs);
-
- code = gx_load_icc_profile(picc_info);
- if (code < 0)
- return code;
-
- /* If the input space to this profile is CIELAB, then we need to adjust the limits */
- /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4 */
- if(picc_info->plu->e_inSpace == icSigLabData)
- {
- picc_info->Range.ranges[0].rmin = 0.0;
- picc_info->Range.ranges[0].rmax = 100.0;
-
- picc_info->Range.ranges[1].rmin = -128.0;
- picc_info->Range.ranges[1].rmax = 127.0;
-
- picc_info->Range.ranges[2].rmin = -128.0;
- picc_info->Range.ranges[2].rmax = 127.0;
-
- }
-
- /* If the input space is icSigXYZData, then we should do the limits based upon the white point of the profile. */
-
- if(picc_info->plu->e_inSpace == icSigXYZData)
- {
- for (i = 0; i < 3; i++)
- {
-
- picc_info->Range.ranges[i].rmin = 0;
-
- }
-
- picc_info->Range.ranges[0].rmax = picc_info->common.points.WhitePoint.u;
- picc_info->Range.ranges[1].rmax = picc_info->common.points.WhitePoint.v;
- picc_info->Range.ranges[2].rmax = picc_info->common.points.WhitePoint.w;
-
- }
-
- code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
- (gs_cie_common *)picc_info, igs);
- if (code < 0)
- return code;
-
- return cie_set_finish( i_ctx_p,
- pcs,
- &istate->colorspace.procs.cie,
- edepth,
- code );
+ return seticc(i_ctx_p, ncomps, op, range_buff);
}
diff --git a/gs/src/zicc.h b/gs/src/zicc.h
new file mode 100644
index 000000000..5625a838d
--- /dev/null
+++ b/gs/src/zicc.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2001-2006 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/
+ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* $Id: zcolor.h $ */
+/* Definitions for setcolorspace */
+
+#ifndef zicc_INCLUDED
+# define zicc_INCLUDED
+
+int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff);
+
+#endif /* zicc_INCLUDED */
diff --git a/gs/src/zpcolor.c b/gs/src/zpcolor.c
index f37fa23c1..e139df812 100644
--- a/gs/src/zpcolor.c
+++ b/gs/src/zpcolor.c
@@ -159,56 +159,12 @@ zbuildpattern1(i_ctx_t *i_ctx_p)
return code;
}
-/* <array> .setpatternspace - */
-/* In the case of uncolored patterns, the current color space is */
-/* the base space for the pattern space. */
-static int
-zsetpatternspace(i_ctx_t *i_ctx_p)
-{
- os_ptr op = osp;
- gs_color_space *pcs;
- gs_color_space *pcs_base;
- uint edepth = ref_stack_count(&e_stack);
- int code = 0;
-
- if (!r_is_array(op))
- return_error(e_typecheck);
- check_read(*op);
- switch (r_size(op)) {
- case 1: /* no base space */
- pcs_base = NULL;
- break;
- default:
- return_error(e_rangecheck);
- case 2:
- pcs_base = gs_currentcolorspace(igs);
- if (cs_num_components(pcs_base) < 0) /* i.e., Pattern space */
- return_error(e_rangecheck);
- }
- pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Pattern);
- pcs->base_space = pcs_base;
- pcs->params.pattern.has_base_space = (pcs_base != NULL);
- rc_increment(pcs_base);
- code = gs_setcolorspace(igs, pcs);
- /* release reference from construction */
- rc_decrement_only(pcs, "zsetpatternspace");
- if (code < 0) {
- ref_stack_pop_to(&e_stack, edepth);
- return code;
- }
- make_null(&istate->pattern); /* PLRM: initial color value is a null object */
- pop(1);
- return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
-}
-
/* ------ Initialization procedure ------ */
const op_def zpcolor_l2_op_defs[] =
{
op_def_begin_level2(),
{"2.buildpattern1", zbuildpattern1},
- {"1.setpatternspace", zsetpatternspace},
- /* Internal operators */
{"0%pattern_paint_prepare", pattern_paint_prepare},
{"0%pattern_paint_finish", pattern_paint_finish},
op_def_end(zpcolor_init)