diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2008-08-11 14:16:18 +0000 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2008-08-11 14:16:18 +0000 |
commit | cecbdfcd156a190dfe3bc7ed07e2179cf45dbbb4 (patch) | |
tree | a1e8539ea070d84fcd924b0c27b069c5bbe67d0f | |
parent | 91d8f890b4429c3d73f7c28bb1b1ac7a6c3a9751 (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
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(¶ms.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, ¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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, ¶ms, imemory); + if (code < 0) + gs_function_PtCr_free_params(¶ms, 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) |