1 % Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
3 % This software is provided AS-IS with no warranty, either express or
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA 94903, U.S.A., +1(415)492-9861.
16 % $Id: gs_cspace.ps,v 1.6 2003/06/26 22:42:33 dan Exp $
17 % basic colorspace mechanism
20 % This new implementation of color spaces extends the color space
21 % formalism to all PostScript levels. Level specific features and
22 % operators continue to be accessible only in the appropriate level,
23 % but the colorspace concept and associated mechanisms are used
26 % The color space mechanism is built around two dictionaries:
29 % A dictionary in global VM that is accessible in userdict only
30 % during initialization. This dictionary is intended for various
31 % utility procedures that are used in implementing the individual
35 % A dictionary of methods for each color space type. The keys
36 % in this dictionary are color space type names (e.g.: /DeviceGray,
37 % /Separation, etc.), and the values are dictionaries of methods.
38 % The set of methods is the same for each color space type, and
39 % provides a complete implementation for the corresponding color
40 % space type. This dictionary is in global VM.
42 % The information specific to a color space type is created in a file
43 % for that type or group of types (e.g.: gs_csdev.ps, gs_csindx.ps,
44 % etc.). These files will generally adhere to the template:
46 % .currentglobal true .setglobal
47 % <level-specific dictionary> begin
51 % /<color space type name>
62 % end ... % level-specific dictionary
65 % The methods associated with a color space are listed below (along with
66 % their stack handling), followed by descriptions.
68 % - cs_potential_indexed_base <bool>
70 % - cs_potential_pattern_base <bool>
72 % - cs_potential_alternate <bool>
74 % - cs_potential_icc_alternate <bool>
77 % <name | array> cs_get_ncomps <int>
79 % <name | array> cs_get_range <range_array>
81 % <name | array> cs_get_default_color <c1> ... <cn>
84 % <c1> ... <cn> <name | array> cs_get_currentgray <gray>
86 % <c1> ... <cn> <name | array> cs_get_currentrgb <red> <green> <blue>
88 % <c1> ... <cn> <name | array> cs_get_currentcmyk
89 % <cyan> <magenta> <yellow> <black>
92 % <name | array> cs_validate <name | array>
94 % <name1 | array1> cs_substitute <name1 | array1> <array2>
96 % <name1 | array1> <array2> cs_prepare <name1 | array1> <array2>
98 % <name | array> cs_install -
101 % <c1> ... <cn> <array> cs_verify_color <c1> ... <cn>
103 % <array> cs_complete_color -
106 % cs_potential_indexed_base, cs_potential_pattern_base,
107 % cs_potential_alternate, cs_potential_icc_alternate
108 % These are booleans rather than procedures. They indicate if the color
109 % space can be a base space of an Indexed color space (anything except
110 % Indexed and Pattern), a Pattern color space (anything except Pattern),
111 % the alternative color space of a Separation or DeviceN color space, or
112 % the alternative color space of an ICCBased color space. The two
113 % parameters are distinct only because of a Ghostscript-specific
114 % implementation problem; in principle, there is nothing special about
115 % ICCBased color spaces in this regard.
118 % Return the number of color components for the color spaces. For Pattern
119 % color spaces, the value is -1 if there is no base space, or -(n + 1) if
120 % the base space has n components.
123 % Return the input Range array appropriate for this color space. This is
124 % defined for all color spaces, though it is of interest primarily for
125 % CIEBased and ICCBased color spaces. For Indexed color spaces this is
126 % [ 0 hival ], where hival is the maximum support index value. For all
127 % other non-CIEBased, non-ICCBased color spaces, the range is an array
128 % of ncomps elements, all of which are [ 0 1 ], where ncomps is the
129 % number of color space components.
131 % cs_get_default_color
132 % Generates the default color for the current color space. Under normal
133 % circumstances this is done internally. It is provided in PostScript
134 % only to support an optimization that doesn't change the current color
135 % space more often than necessary.
137 % cs_get_currentgray, cs_get_currentrgb, cs_get_currentcmyk
138 % These procedures are used to implement the currentgray, currentrgb,
139 % and currentcmyk operators (which are pseudo-operators in the current
143 % Validate the operand color space. Because color spaces are extensively
144 % manipulated in PostScript in this implementation, error handling can
145 % become burdensome. To make the code somewhat simpler, it is useful to
146 % be able to validate a color space prior to manipulation, so as to
147 % ensure that errors are not discovered in awkward places.
150 % Substitute a device-independent color space for device specific color
151 % space. This applies directly to the device-specific color spaces
152 % (DeviceGray, DeviceRGB, DeviceCMYK), and indirectly when these color
153 % spaces are used as base/alternative color spaces. The mechanism for
154 % color substitution is included in all language levels, though it may
155 % only be accessed for Language Level 3.
157 % The substituted color space is the topmost of the operands pushed.
158 % this may or may not be the same as the original color space, which
159 % is immediately below it on the operand stack. If the two differ,
160 % the substituted space will always be in local VM (and will be
163 % Substitution is applied recursively to the base/alternate color
164 % space of ICCBased, Indexed, Separation, DeviceN, or Pattern
165 % color spaces. Because Ghostscript currently requires that any
166 % base or alternative color space be the current color space when
167 % the enclosing color space is set, this substitution effectively
168 % occurs twice: once in the original color space, and once when the
169 % base/alternative color space is made the current color space.
170 % We retain the first substitution as we would eventually like to
171 % remove the restriction on making the base/alternative color space
172 % the current color space.
175 % Perform any operations required on the color space for installation.
176 % This method exists primarily to allow conversion of PostScript
177 % procedures to functions for CIEBased color spaces. Two operands are
178 % provided: the original and the substituted color space. If the two
179 % differ and the latter is writable, required modifications can
180 % be made "in place". Otherwise, a new instance of the second color
181 % space must be built.
183 % Currently, cs_prepare is not explicitly recursive. Because
184 % Ghostscript requires a base/alternate color space to be installed
185 % as the current color space prior to installing the enclosing color
186 % space, the cs_prepare method will implicitly be called recursively.
187 % The reason for not making this explicit is that color space
188 % preparation may involve a considerable amount of work, which could
189 % be avoided if, for example, an alternative color space will not
190 % be used because the enclosing Separation/DeviceN color space is
191 % supported in native mode by the process color model. We would
192 % eventually like to remove the need to prepare color spaces that
196 % This method actually installs the color space in the graphic state.
197 % Only the substituted/prepared space (which may be the same as the
198 % original space) is passed as an operand; the original space is handled
199 % directly by the .setcolorspace operator.
201 % The provision of a separate method for this tasks reflects the
202 % historical implementation of color spaces in the Ghostscript
203 % interpreter. This implementation provides a unique operator for each
207 % Modify a set of color operands as required by a color space. This
208 % is used primarily to verify the color operands, as this is most
209 % conveniently done in PostScript.
211 % cs_complete_setcolor
212 % This method is invoked immediately after a (successful) invocation
213 % of setcolor. Ii is provided as a separate method for compatibility
214 % with Adobe implementations. These implementations invoke the lookup
215 % (Indexed) or tint procedure each time setcolor is invoked (only if
216 % the alternative color space is used in the case of the tint
217 % transform). Because Ghostscript may convert these procedures to
218 % functions (or pre-sample them), the procedures may not always be
219 % called when expected. There are applications that depend on this
220 % behavior (e.g.: Adobe PhotoShop 5+), so this method provides a way
223 % In principle, a cs_complete_setcolor procedure for an Indexed color
224 % space whose base space should invoke cs_complete_setcolor on its
225 % base space. Currently we don't do this, because it has not been
226 % shown to be necessary. It would be simple to add if it is every
229 % All of these methods are procedures.
231 % For each of these methods, there is a procedure in .cspace_util with
232 % a dot ('.') prefix that will invoke the appropriate procedure for the
236 .currentglobal true .setglobal
237 userdict /.cspace_util 80 dict put
241 % Colorspacedict is initially in .cspace_util; it is copied to level2dict
242 % in the Level 2 initialization code to retain compatibility with
243 % earlier implementations.
245 /colorspacedict 20 dict def
249 % <obj> make_array1 <array>
251 % procedure for conditionally converting a named color space to a
252 % 1-element array. Since names are always global, the array will be
257 dup type /nametype eq
258 { currentglobal true setglobal exch 1 array astore exch setglobal }
264 % <name|array> .get_cspace_type name
266 % Provide generic routine for retrieving the color space type.
270 dup type dup /arraytype eq exch /packedarraytype eq or
277 % <name|array> .get_method_dict <dict>
279 % Get the method dictionary for a specific color space. Note that the
280 % color space is left on the stack.
283 { //colorspacedict exch //.get_cspace_type exec get }
287 % <name|array> <proc_name> .get_method <name|array> <proc | bool>
289 % Get the named method for the operand color space.
292 { exch //.get_method_dict exec exch get }
297 % <name_array> .cs_potential_indexed_base <bool>
298 % <name_array> .cs_potential_pattern_base <bool>
299 % <name_array> .cs_potential_alternate <bool>
300 % <name_array> .cs_potential_icc_alternate <bool>
301 % <name | array> .cs_get_ncomps <int>
302 % <name | array> .cs_get_range <range_array>
303 % <name | array> .cs_get_default_color <c1> ... <cn>
304 % <c1> ... <cn> <name | array> .cs_get_currentgray <gray>
305 % <c1> ... <cn> <name | array> .cs_get_currentrgb <r> <g> <b>
306 % <c1> ... <cn> <name | array> .cs_get_currentcmyk <c> <m> <y> <k>
307 % <name | array> .cs_validate <name | array>
308 % <name1 | array1> .cs_substitute <name1 | array1> <array2>
309 % <name1 | array1> <array2> .cs_prepare <name1 | array1> <array2>
310 % <name | array> .cs_install -
311 % <c1> ... <cn> <array> .cs_prepare_color <c1> ... <cn>
312 % <array> .cs_complete_setcolor -
314 % These procedures provide access to the corresponding methods of the
315 % operand color space.
317 /.cs_potential_indexed_base
318 { /cs_potential_indexed_base //.get_method exec }
321 /.cs_potential_pattern_base
322 { /cs_potential_pattern_base //.get_method exec }
325 /.cs_potential_alternate
326 { /cs_potential_alternate //.get_method exec }
329 /.cs_potential_icc_alternate
330 { /cs_potential_icc_alternate //.get_method exec }
334 { dup /cs_get_ncomps //.get_method exec exec }
338 { dup /cs_get_range //.get_method exec exec }
341 /.cs_get_default_color
342 { dup /cs_get_default_color //.get_method exec exec }
346 { dup /cs_get_currentgray //.get_method exec exec }
350 { dup /cs_get_currentrgb //.get_method exec exec }
354 { dup /cs_get_currentcmyk //.get_method exec exec }
358 { dup /cs_validate //.get_method exec exec }
362 { dup /cs_substitute //.get_method exec exec }
366 { dup /cs_prepare //.get_method exec exec }
370 { dup /cs_install //.get_method exec exec }
374 { dup /cs_prepare_color //.get_method exec exec }
377 /.cs_complete_setcolor
378 { dup /cs_complete_setcolor //.get_method exec exec }
383 % Make sure we have an interpreter color space before redefining
384 % setcolorspace. The interpreter internal code only sets the effective
385 % color space; the interpreters color spaces begins as a null object.
387 % NB: This should come prior to the redefinition of setcolorspace, and
388 % must use an array operand.
390 [ /DeviceGray ] setcolorspace
394 % <c1> ... <cn> setcolor -
396 % As with setcolorspace, setcolor is initially placed in .cspace_util,
397 % and is copied to level2dict by the Level 2 initialization code. The
398 % internal definition of setcolor is removed from systemdict as soon
399 % as this procedure is defined.
404 currentcolorspace //.cs_prepare_color exec //setcolor
405 currentcolorspace //.cs_complete_setcolor exec
408 { //.cspace_util /setcolor get $error /errorname get signalerror }
413 systemdict /setcolor .undef
417 % <name|array> <bool> _setcolorspace -
418 % <name|array> _setcolorspace_nosub -
420 % <name|array> setcolorspace -
421 % <name|array> forcesetcolorspace -
423 % setcolorspace is initially placed in .cspace_util. It is copied to
424 % level2dict by the Level 2 initialization code. The internal
425 % setcolorspace operator is removed from systemdict as soon as this
426 % procedure is defined.
428 % Because some jobs, in particular PDF jobs, repeatedly set the same
429 % color space, this procedure will check if the operand and current
430 % color spaces are the same. The check is absolute for parameterless
431 % color spaces, conservative for others. For PostScript, this
432 % optimization can only be employed if color space substitution is
433 % disabled, as otherwise there is no way to account for possible changes
434 % in the /Default* instances of the ColorSpace resource category. For PDF
435 % jobs, resource category instances can only be changed at very specific
436 % times (typically page boundaries), so the "operand color space is the
437 % same as current color space" optimization may be used even if color
438 % space substitution is in effect. The optimization is also highly
439 % desirable in such cases, as it greatly improves performance.
441 % In certain situations, it is critical that a color space be set,
442 % even if it is the same as the current color space. This is the case
443 % when a CIEBased color space is used as a base or alternative color
444 % space, due to some long-standing problems with the graphics libraries
445 % handling of sampled information from the procedures in CIE color
446 % spaces and the color rendering dictionary. The forcesetcolorspace
447 % operator is provided for those situations.
449 % Note also that, if the current color space is not reset, at least
450 % the current color must be reset to its default value.
452 % Another problem arises in the case of ICCBased color spaces. These
453 % color spaces may be used to substitute for a DeviceGray/DeviceRGB/
454 % DeviceCMYK color space, and may themselves require such a color
455 % space as an alternate. Obviously, when this is the case the normal
456 % setcolorspace mechanism would encounter and infinite loop if the
457 % alternate colro space needed to be used. For this particular case,
458 % the special _setcolorspace_nosub is provided, which suppresses
459 % color space substitution. This routine does not bother to check if
460 % the operand and current color space are the same.
465 % see if the operand space is the same as the current space
466 currentcolorspace dup length 1 eq
469 2 index dup type dup /arraytype eq exch /packedarraytype eq or
482 % If PDFfile is defined on the dictionary stack, this is a
483 % PDF job. No additional check is required in this case (see
488 { .getuseciecolor not and } % check that UseCIEColor is off
492 { //.cs_get_default_color exec setcolor }
495 //.cs_substitute exec
498 //make_array1 exec //setcolorspace
503 { //.cspace_util /setcolorspace get $error /errorname get signalerror }
508 /_setcolorspace_nosub
515 //make_array1 exec //setcolorspace
518 { //.cspace_util /setcolorspace get $error /errorname get signalerror }
523 /setcolorspace { //true //_setcolorspace exec } bind odef
524 /forcesetcolorspace { //false //_setcolorspace exec } bind odef
529 % The initgraphics operator must be redefined create a real color space.
530 % Previously this was unnecessary, as .currentcolorspace could return
535 { initgraphics { /DeviceGray } cvlit forcesetcolorspace }
536 .bind systemdict begin odef end
538 systemdict /setcolorspace .undef
544 % <r> <g> <b> setrgbcolor -
546 % <c> <m> <y> <b> setcmykcolor -
548 % The Level 1 color setting operators. setcmykcolor is created only if
549 % setcolorscreen is present. These operators are always defined in
554 { { /DeviceGray } cvlit //setcolorspace //setcolor }
556 { /setgray load $error /errorname get signalerror }
559 bind systemdict begin odef end
563 { { /DeviceRGB } cvlit //setcolorspace //setcolor }
565 { /setrgbcolor load $error /errorname get signalerror }
568 bind systemdict begin odef end
570 /setcolorscreen where
575 { { /DeviceCMYK } cvlit //setcolorspace //setcolor }
577 { /setcmykcolor load $error /errorname get signalerror }
580 bind systemdict begin odef end
586 % - currentgray <gray>
588 % - currentrgbcolor <r> <g> <b>
590 % - currentcmykcolor <c> <m> <y> <k>
592 % Return the current color, mapped to a DeviceGray, DeviceRGB, or
593 % DeviceCMYK color space. The latter is only created if setcolorscreen
596 { currentcolor currentcolorspace //.cs_get_currentgray exec }
597 bind systemdict begin odef end
600 { currentcolor currentcolorspace //.cs_get_currentrgb exec }
601 bind systemdict begin odef end
603 /setcolorscreen where
607 { currentcolor currentcolorspace //.cs_get_currentcmyk exec }
608 bind systemdict begin odef end
615 % Add some generically useful structures and procedures to .cspace_util.
619 % Some common errors. The command for these errors will normally be
620 % overwritten by the invoking operator. We cannot "load" the secolorspace
621 % or setcolor operators, as they are not present in Level 1 systems.
624 { /setcolorspace cvx /typecheck signalerror }
627 /setcspace_rangecheck
628 { /setcolorspace cvx /rangecheck signalerror }
631 /setcspace_invalidaccess
632 { /setcolorspace cvx /invalidaccess signalerror }
636 { /setcolorspace cvx /undefined signalerror }
640 { /setcolor cvx /typecheck signalerror }
643 /setcolor_invalidaccess
644 { /setcolor cvx /invalidaccess signalerror }
649 % <obj> check_array <obj>
651 % Check that an object is an array. Currently we don't check for
652 % readability, as a failing get or length operator should generate
653 % the appropriate invalidaccess error.
656 dup type dup /arraytype ne exch /packedarraytype ne and
657 { /setcolorspace cvx /typecheck signalerror }
663 % pre-defined procedures for cs_ncomps and cs_get_range
664 /ncomps_1 { pop 1 } bind def
665 /ncomps_3 { pop 3 } bind def
666 /ncomps_4 { pop 4 } bind def
668 /dflt_range_4 [ 0 1 0 1 0 1 0 1 ] readonly def
669 /dflt_range_3 dflt_range_4 0 6 getinterval def
670 /dflt_range_1 dflt_range_4 0 2 getinterval def
672 % <obj> get_range_[1|3|4] <range>
673 /get_range_1 { pop //dflt_range_1 } bind def
674 /get_range_3 { pop //dflt_range_3 } bind def
675 /get_range_4 { pop //dflt_range_4 } bind def
679 % <c1> ... <cn> <name | array> <n>
681 % <c1> ... <cn> <array | array>
683 % <c1> <array> validate_color_1 <c1>
684 % <c1> <c2> <c3> <arraY> validate_color_3 <c1> <c2> <c3>
685 % <c1> <c2> <c3> <c4> <arraY> validate_color_4 <c1> <c2> <c3> <c4>
687 % check_num_stack verifies that the stack consists of a color space array and
688 % n numbers. This is used by most of the cs_prepare_color procedures. The
689 % validate_color_[1|3|4] procedures can be used as the cs_prepare_color
690 % procedure for Device specific, CIEBased, and Indexed color spaces.
692 % Note that the pseudo-operator that (indirectly) invokes this routine will
693 % handle resetting the stacks.
697 dup 2 add copy exch pop
699 type dup /integertype ne exch /realtype ne and
704 pop % remove the extra op_count
708 % <c1> <array> validate_1 <c1>
709 /validate_1 { 1 //check_num_stack exec pop } bind def
711 % <c1> <c2> <c3> <array> validate_3 <c1> <c2> <c3>
712 /validate_3 { 3 //check_num_stack exec pop } bind def
714 % <c1> <c2> <c3> <c4> <array> validate_4 <c1> <c2> <c3> <c4>
715 /validate_4 { 4 //check_num_stack exec pop } bind def
721 % This is a procedure form of pop. It may be used where a procedure is
722 % expected, but the function of the procedure is the same as the pop
724 /pop_1 { pop } bind def
727 % <obj> dup_1 <obj> <obj>
729 % An analog to pop_1, this one for dup.
731 /dup_1 { dup } bind def
734 % <obj1> ... <objn> <n> clear_n_objs -
736 % Clear n objects from the operand stack.
738 /clear_n_objs { //pop_1 repeat } bind def
741 % <obj1> ... <objn> <array> clear_setcolor_operands -
743 % Clear the setcolor operands for a color space.
745 /clear_setcolor_operands
746 { //.cs_get_ncomps exec //clear_n_objs exec }
750 % Return 1, 3, or 4 zeros. These routines are used primarily for the
751 % CIEBased color spaces, for which currentgray and currentrgb
752 % should return 0 for all components, and currentcmyk should return
753 % 0 0 0 1.0 (this varies from Adobe's documentation but is consistent
754 % with their impelementations).
756 /no_currentgray { //.cs_get_ncomps exec //clear_n_objs exec 0 } bind def
757 /no_currentrgb { //.cs_get_ncomps exec //clear_n_objs exec 0 0 0 } bind def
758 /no_currentcmyk { //.cs_get_ncomps exec //clear_n_objs exec 0 0 0 1.0 } bind def
762 % <num> bound_0_1 <num>
764 % Bound a number to the range [0, 1]
781 % Provide pseudo-operators for sethsbcolor and currenthsbcolor. These are
782 % alternate versions of the setrgbcolor and currentrgbcolor operators, which
783 % make use of a hue/staturation/brightness color description.
787 % <num_1> ... <num_n> n max_n <num>
788 % <num_1> ... <num_n> n min_n <num>
790 % Find the maximum and minum of 3 color component intensities.
795 { 2 copy lt { exch } if pop }
803 { 2 copy gt { exch } if pop }
810 % <r> <g> <b> .rgb_2_hsb <h> <s> <br>
811 % <h> <s> <br> .hsb_2_rgb <r> <g> <b>
813 % Convert between RGB and HSB colors, using the hexcone approach (see
814 % Rogers, David, "Procedureal Elements For Computer Graphics",
815 % (McGraw-Hill, 1985), pp. 402 - 3).
817 % The rgb ==> hsb calculation is:
828 % h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
830 % h = 1/3 + (b - r) / (6 * diff);
832 % h = 2/3 + (r - g) / (6 * diff);
835 % The hsb ==> rgb conversion is:
837 % mn = (1 - s) * br, md = 6 * s * br;
839 % switch ((int)floor(6 * h)) {
840 % case 0: /* r >= g >= b */
846 % case 1: /* g >= r >= b */
847 % r = mn + md * (1/3 - h);
852 % case 2: /* g >= b >= r */
855 % b = mn + (h - 1/3) * md;
858 % case 3: /* b >= g >= r */
860 % g = mn + (2/3 - h) * md;
864 % case 4: /* b >= r >= g */
865 % r = mn + (h - 2/3) * md;
870 % case 5: /* r >= b >= g */
873 % b = mn + (1 - h) * md;
876 % case 6: /* We have wrapped around the hexcone. Thus this case is
877 % the same as case 0 with h = 0 */
880 % g = mn + h * md = mn;
887 % find the largest and smallest components
888 3 copy 3 //max_n exec dup 5 1 roll
890 { pop pop pop pop 0 0 }
892 4 copy pop 3 //min_n exec 1 index exch sub
893 dup 2 index div 7 1 roll
895 { 5 { pop } repeat 0 3 1 roll }
898 2 copy eq % blue == brightness
899 { pop pop sub exch div .666667 add }
901 2 index eq % green == brightness
902 { exch pop exch sub exch div .3333333 add }
905 sub exch pop exch div
924 3 { 0 max 1 min 3 1 roll } repeat
925 1 2 index sub 1 index mul % (1 - s) * br
926 3 -1 roll 2 index mul 6 mul % 6 * s * br
927 4 -1 roll % stack: <br> <(1 - s) * br> <6 * s * br> <h>
929 % array of procedures for the 7 hue cases
932 { mul 1 index add exch }
935 { 0.333333 exch sub mul 1 index add 3 1 roll }
938 { 0.333333 sub mul 1 index add 3 1 roll exch 3 -1 roll }
941 { 0.666667 exch sub mul 1 index add 3 -1 roll }
944 { 0.666667 sub mul 1 index add 3 1 roll exch }
947 { 1 exch sub mul 1 index add }
949 % 6 ==> r = br, g = b = mn
950 % Case 6 is the same as case 0 with h = 0. This also simplifies
954 1 index 6 mul cvi % (int)(6 * h)
961 % <hue> <saturation> <brightness sethsbcolor -
963 % - currenthsbcolor <hue> <saturation> <brightness>
967 { //.hsb_2_rgb exec setrgbcolor }
969 { /sethsbcolor load $error /errorname get signalerror }
972 bind systemdict begin odef end
976 { currentrgbcolor //.rgb_2_hsb exec }
978 { /currenthsbcolor load $error /errorname get signalerror }
981 bind systemdict begin odef end