985 lines
29 KiB
PostScript
985 lines
29 KiB
PostScript
% 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: gs_cspace.ps,v 1.6 2003/06/26 22:42:33 dan Exp $
|
|
% 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.
|
|
%
|
|
% The color space mechanism is built around two dictionaries:
|
|
%
|
|
% .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
|
|
|
|
%
|
|
% 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
|
|
|
|
%
|
|
% <name|array> <proc_name> .get_method <name|array> <proc | bool>
|
|
%
|
|
% Get the named method for the operand color space.
|
|
%
|
|
/.get_method
|
|
{ exch //.get_method_dict exec exch get }
|
|
bind def
|
|
|
|
|
|
%
|
|
% <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.
|
|
%
|
|
/.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
|
|
|
|
/.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 ] 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.
|
|
%
|
|
/_setcolorspace
|
|
{
|
|
{
|
|
% see if the operand space is the same as the current space
|
|
currentcolorspace dup length 1 eq
|
|
{
|
|
0 get
|
|
2 index dup type dup /arraytype eq exch /packedarraytype eq or
|
|
{
|
|
dup length 1 eq
|
|
{ 0 get }
|
|
if
|
|
}
|
|
if
|
|
}
|
|
{ 2 index }
|
|
ifelse
|
|
eq 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
|
|
{ //.cs_get_default_color exec setcolor }
|
|
{
|
|
//.cs_validate exec
|
|
//.cs_substitute exec
|
|
//.cs_prepare exec
|
|
//.cs_install exec
|
|
//make_array1 exec //setcolorspace
|
|
}
|
|
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
|
|
|
|
%
|
|
% - initgraphics -
|
|
%
|
|
% The initgraphics operator must be redefined create a real color space.
|
|
% Previously this was unnecessary, as .currentcolorspace could return
|
|
% an integer.
|
|
%
|
|
%
|
|
/initgraphics
|
|
{ initgraphics { /DeviceGray } cvlit 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 } cvlit //setcolorspace //setcolor }
|
|
stopped
|
|
{ /setgray load $error /errorname get signalerror }
|
|
if
|
|
}
|
|
bind systemdict begin odef end
|
|
|
|
/setrgbcolor
|
|
{
|
|
{ { /DeviceRGB } cvlit //setcolorspace //setcolor }
|
|
stopped
|
|
{ /setrgbcolor load $error /errorname get signalerror }
|
|
if
|
|
}
|
|
bind systemdict begin odef end
|
|
|
|
/setcolorscreen where
|
|
{
|
|
pop
|
|
/setcmykcolor
|
|
{
|
|
{ { /DeviceCMYK } cvlit //setcolorspace //setcolor }
|
|
stopped
|
|
{ /setcmykcolor load $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
|
|
{
|
|
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 }
|
|
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
|
|
{
|
|
dup 2 add copy exch pop
|
|
{
|
|
type dup /integertype ne exch /realtype ne and
|
|
//setcolor_typecheck
|
|
if
|
|
}
|
|
repeat
|
|
pop % remove the extra op_count
|
|
}
|
|
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.0 } bind def
|
|
|
|
|
|
%
|
|
% <num> bound_0_1 <num>
|
|
%
|
|
% Bound a number to the range [0, 1]
|
|
%
|
|
/bound_0_1
|
|
{
|
|
dup 0 lt
|
|
{ pop 0 }
|
|
{
|
|
dup 1 gt
|
|
{ pop 1 }
|
|
if
|
|
}
|
|
ifelse
|
|
}
|
|
bind def
|
|
|
|
|
|
%
|
|
% 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.
|
|
%
|
|
|
|
%
|
|
% <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
|
|
|
|
/min_n
|
|
{
|
|
1 sub
|
|
{ 2 copy gt { exch } if pop }
|
|
repeat
|
|
}
|
|
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;
|
|
%
|
|
% 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;
|
|
% }
|
|
%
|
|
/.rgb_2_hsb
|
|
{
|
|
% find the largest and smallest components
|
|
3 copy 3 //max_n exec dup 5 1 roll
|
|
dup 0 eq
|
|
{ pop pop pop pop 0 0 }
|
|
{
|
|
4 copy pop 3 //min_n exec 1 index exch sub
|
|
dup 2 index div 7 1 roll
|
|
dup 0 eq
|
|
{ 5 { pop } repeat 0 3 1 roll }
|
|
{
|
|
6 mul 5 1 roll
|
|
2 copy eq % blue == brightness
|
|
{ pop pop sub exch div .666667 add }
|
|
{
|
|
2 index eq % green == brightness
|
|
{ exch pop exch sub exch div .3333333 add }
|
|
{
|
|
% red == brightness
|
|
sub exch pop exch div
|
|
dup 0 lt
|
|
{ 1 add }
|
|
if
|
|
}
|
|
ifelse
|
|
}
|
|
ifelse
|
|
3 1 roll
|
|
}
|
|
ifelse
|
|
}
|
|
ifelse
|
|
}
|
|
bind def
|
|
|
|
|
|
/.hsb_2_rgb
|
|
{
|
|
3 { 0 max 1 min 3 1 roll } repeat
|
|
1 2 index sub 1 index mul % (1 - s) * br
|
|
3 -1 roll 2 index mul 6 mul % 6 * s * br
|
|
4 -1 roll % stack: <br> <(1 - s) * br> <6 * s * br> <h>
|
|
|
|
% array of procedures for the 7 hue cases
|
|
{
|
|
% 0 ==> r >= g >= b
|
|
{ mul 1 index add exch }
|
|
|
|
% 1 ==> g >= r >= b
|
|
{ 0.333333 exch sub mul 1 index add 3 1 roll }
|
|
|
|
% 2 ==> g >= b >= r
|
|
{ 0.333333 sub mul 1 index add 3 1 roll exch 3 -1 roll }
|
|
|
|
% 3 ==> b >= g >= r
|
|
{ 0.666667 exch sub mul 1 index add 3 -1 roll }
|
|
|
|
% 4 ==> b >= r >= g
|
|
{ 0.666667 sub mul 1 index add 3 1 roll exch }
|
|
|
|
% 5 ==> r >= b >= g
|
|
{ 1 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 mul cvi % (int)(6 * h)
|
|
get exec
|
|
}
|
|
bind def
|
|
|
|
|
|
%
|
|
% <hue> <saturation> <brightness sethsbcolor -
|
|
%
|
|
% - currenthsbcolor <hue> <saturation> <brightness>
|
|
%
|
|
/sethsbcolor
|
|
{
|
|
{ //.hsb_2_rgb exec setrgbcolor }
|
|
stopped
|
|
{ /sethsbcolor load $error /errorname get signalerror }
|
|
if
|
|
}
|
|
bind systemdict begin odef end
|
|
|
|
/currenthsbcolor
|
|
{
|
|
{ currentrgbcolor //.rgb_2_hsb exec }
|
|
stopped
|
|
{ /currenthsbcolor load $error /errorname get signalerror }
|
|
if
|
|
}
|
|
bind systemdict begin odef end
|
|
|
|
end % .cspace_util
|
|
.setglobal
|