xref: /plan9/sys/src/cmd/gs/src/zicc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 2001 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: zicc.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
183ff48bf5SDavid du Colombier /* ICCBased color operators */
19*593dc095SDavid du Colombier 
203ff48bf5SDavid du Colombier #include "math_.h"
213ff48bf5SDavid du Colombier #include "memory_.h"
223ff48bf5SDavid du Colombier #include "ghost.h"
233ff48bf5SDavid du Colombier #include "oper.h"
243ff48bf5SDavid du Colombier #include "gsstruct.h"
253ff48bf5SDavid du Colombier #include "gxcspace.h"		/* gscolor2.h requires gscspace.h */
263ff48bf5SDavid du Colombier #include "stream.h"
273ff48bf5SDavid du Colombier #include "files.h"
283ff48bf5SDavid du Colombier #include "gscolor2.h"
293ff48bf5SDavid du Colombier #include "gsicc.h"
303ff48bf5SDavid du Colombier #include "estack.h"
313ff48bf5SDavid du Colombier #include "idict.h"
323ff48bf5SDavid du Colombier #include "idparam.h"
333ff48bf5SDavid du Colombier #include "igstate.h"
343ff48bf5SDavid du Colombier #include "icie.h"
35*593dc095SDavid du Colombier #include "ialloc.h"
363ff48bf5SDavid du Colombier 
373ff48bf5SDavid du Colombier /*
383ff48bf5SDavid du Colombier  *   <dict>  .seticcspace  -
393ff48bf5SDavid du Colombier  *
403ff48bf5SDavid du Colombier  * Create an ICCBased color space and set it to be the current color space.
413ff48bf5SDavid du Colombier  *
423ff48bf5SDavid du Colombier  * The PostScript structure of an ICCBased color space is that same as that
433ff48bf5SDavid du Colombier  * for a CIEBased* color space:
443ff48bf5SDavid du Colombier  *
453ff48bf5SDavid du Colombier  *     [ /ICCBased <dictionary> ]
463ff48bf5SDavid du Colombier  *
473ff48bf5SDavid du Colombier  * As is the for other .setcie*space operators, the operand dictionary rather
483ff48bf5SDavid du Colombier  * than the complete color space array is on the stack when this operator
493ff48bf5SDavid du Colombier  * is inovked.
503ff48bf5SDavid du Colombier  *
513ff48bf5SDavid du Colombier  * At the time this procedure is called, the alternative color space for
523ff48bf5SDavid du Colombier  * the ICCBased color space is expected to be the current color space,
533ff48bf5SDavid du Colombier  * whether that space was explicitly specified or implied by the number
543ff48bf5SDavid du Colombier  * of components in the ICCBased color space dictionary. This is consistent
553ff48bf5SDavid du Colombier  * with the handling of alternative spaces in Separation, DeviceN, and
563ff48bf5SDavid du Colombier  * Indexed color spaces. Unlike the "zset*space" routines for those spaces,
573ff48bf5SDavid du Colombier  * however, the current code does not attempt to build the color space
583ff48bf5SDavid du Colombier  * "in place" in the graphic state.
593ff48bf5SDavid du Colombier  *
603ff48bf5SDavid du Colombier  * The procedure that invokes this operator will already have checked that
613ff48bf5SDavid du Colombier  * the operand is a dictionary, is readable, and defines the key /N
623ff48bf5SDavid du Colombier  * (number of components).
633ff48bf5SDavid du Colombier  */
643ff48bf5SDavid du Colombier private int
zseticcspace(i_ctx_t * i_ctx_p)653ff48bf5SDavid du Colombier zseticcspace(i_ctx_t * i_ctx_p)
663ff48bf5SDavid du Colombier {
673ff48bf5SDavid du Colombier     os_ptr                  op = osp;
683ff48bf5SDavid du Colombier     int edepth = ref_stack_count(&e_stack);
693ff48bf5SDavid du Colombier     int                     code;
703ff48bf5SDavid du Colombier     gs_color_space *        pcs;
713ff48bf5SDavid du Colombier     const gs_color_space *  palt_cs;
723ff48bf5SDavid du Colombier     ref *                   pnval;
733ff48bf5SDavid du Colombier     ref *                   pstrmval;
743ff48bf5SDavid du Colombier     stream *                s;
753ff48bf5SDavid du Colombier     int                     i, ncomps;
763ff48bf5SDavid du Colombier     gs_cie_icc *            picc_info;
773ff48bf5SDavid du Colombier     float                   range_buff[8];
783ff48bf5SDavid du Colombier     static const float      dflt_range[8] = { 0, 1,   0, 1,   0, 1,   0, 1 };
793ff48bf5SDavid du Colombier 
803ff48bf5SDavid du Colombier     dict_find_string(op, "N", &pnval);
813ff48bf5SDavid du Colombier     ncomps = pnval->value.intval;
823ff48bf5SDavid du Colombier 
833ff48bf5SDavid du Colombier     /* verify the DataSource entry */
843ff48bf5SDavid du Colombier     if (dict_find_string(op, "DataSource", &pstrmval) <= 0)
853ff48bf5SDavid du Colombier         return_error(e_undefined);
863ff48bf5SDavid du Colombier     check_read_file(s, pstrmval);
873ff48bf5SDavid du Colombier 
883ff48bf5SDavid du Colombier     /*
893ff48bf5SDavid du Colombier      * Verify that the current color space can be a alternative color space.
903ff48bf5SDavid du Colombier      * The check for ICCBased color space is a hack to avoid introducing yet
913ff48bf5SDavid du Colombier      * another category indicator into the gs_color_space_type structur.
923ff48bf5SDavid du Colombier      */
933ff48bf5SDavid du Colombier     palt_cs = gs_currentcolorspace(igs);
943ff48bf5SDavid du Colombier     if ( !palt_cs->type->can_be_alt_space                                ||
953ff48bf5SDavid du Colombier          gs_color_space_get_index(palt_cs) == gs_color_space_index_CIEICC  )
963ff48bf5SDavid du Colombier         return_error(e_rangecheck);
973ff48bf5SDavid du Colombier 
983ff48bf5SDavid du Colombier     /*
993ff48bf5SDavid du Colombier      * Fetch and verify the Range array.
1003ff48bf5SDavid du Colombier      *
1013ff48bf5SDavid du Colombier      * The PDF documentation is unclear as to the purpose of this array.
1023ff48bf5SDavid du Colombier      * Essentially all that is stated is that "These values must match the
1033ff48bf5SDavid du Colombier      * information in the ICC profile" (PDF Reference, 2nd ed., p. 174).
1043ff48bf5SDavid du Colombier      * If that is the case, why not use the information in the profile?
1053ff48bf5SDavid du Colombier      * The only reason we can think of is range specification is intended
1063ff48bf5SDavid du Colombier      * to be used to limit the range of values passed to the alternate
1073ff48bf5SDavid du Colombier      * color space (the range may be smaller than the native range of values
1083ff48bf5SDavid du Colombier      * provided by that color space).
1093ff48bf5SDavid du Colombier      *
1103ff48bf5SDavid du Colombier      * Because the icclib code will perform normalization based on color
1113ff48bf5SDavid du Colombier      * space, we use the range values only to restrict the set of input
1123ff48bf5SDavid du Colombier      * values; they are not used for normalization.
1133ff48bf5SDavid du Colombier      */
114*593dc095SDavid du Colombier     code = dict_floats_param( imemory,
115*593dc095SDavid du Colombier 			      op,
1163ff48bf5SDavid du Colombier                               "Range",
1173ff48bf5SDavid du Colombier                               2 * ncomps,
1183ff48bf5SDavid du Colombier                               range_buff,
1193ff48bf5SDavid du Colombier                               dflt_range );
1203ff48bf5SDavid du Colombier     for (i = 0; i < 2 * ncomps && range_buff[i + 1] >= range_buff[i]; i += 2)
1213ff48bf5SDavid du Colombier         ;
1223ff48bf5SDavid du Colombier     if (i != 2 * ncomps)
1233ff48bf5SDavid du Colombier         return_error(e_rangecheck);
1243ff48bf5SDavid du Colombier 
1253ff48bf5SDavid du Colombier     /* build the color space object */
1263ff48bf5SDavid du Colombier     code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
1273ff48bf5SDavid du Colombier     if (code < 0)
1283ff48bf5SDavid du Colombier         return code;
1293ff48bf5SDavid du Colombier     picc_info = pcs->params.icc.picc_info;
1303ff48bf5SDavid du Colombier     picc_info->num_components = ncomps;
1313ff48bf5SDavid du Colombier     picc_info->instrp = s;
1323ff48bf5SDavid du Colombier     picc_info->file_id = (s->read_id | s->write_id);
1333ff48bf5SDavid du Colombier     for (i = 0; i < ncomps; i++) {
1343ff48bf5SDavid du Colombier         picc_info->Range.ranges[i].rmin = range_buff[2 * i];
1353ff48bf5SDavid du Colombier         picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];
1363ff48bf5SDavid du Colombier 
1373ff48bf5SDavid du Colombier     }
1383ff48bf5SDavid du Colombier 
1393ff48bf5SDavid du Colombier     /* record the current space as the alternative color space */
1403ff48bf5SDavid du Colombier     memmove( &pcs->params.icc.alt_space,
1413ff48bf5SDavid du Colombier              palt_cs,
1423ff48bf5SDavid du Colombier              sizeof(pcs->params.icc.alt_space) );
143*593dc095SDavid du Colombier     /*
144*593dc095SDavid du Colombier      * Increment reference counts for current cspace since it is the
145*593dc095SDavid du Colombier      * alternate color space for the ICC space.
146*593dc095SDavid du Colombier      */
147*593dc095SDavid du Colombier     gx_increment_cspace_count(palt_cs);
1483ff48bf5SDavid du Colombier 
1493ff48bf5SDavid du Colombier     code = gx_load_icc_profile(picc_info);
1503ff48bf5SDavid du Colombier     if (code < 0)
1513ff48bf5SDavid du Colombier 	return code;
1523ff48bf5SDavid du Colombier 
1533ff48bf5SDavid du Colombier     code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
1543ff48bf5SDavid du Colombier 			   (gs_cie_common *)picc_info, igs);
1553ff48bf5SDavid du Colombier     if (code < 0)
1563ff48bf5SDavid du Colombier 	return code;
1573ff48bf5SDavid du Colombier 
1583ff48bf5SDavid du Colombier     return cie_set_finish( i_ctx_p,
1593ff48bf5SDavid du Colombier                            pcs,
1603ff48bf5SDavid du Colombier                            &istate->colorspace.procs.cie,
1613ff48bf5SDavid du Colombier                            edepth,
1623ff48bf5SDavid du Colombier                            code );
1633ff48bf5SDavid du Colombier }
1643ff48bf5SDavid du Colombier 
1653ff48bf5SDavid du Colombier 
1663ff48bf5SDavid du Colombier const op_def    zicc_ll3_op_defs[] = {
1673ff48bf5SDavid du Colombier     op_def_begin_ll3(),
1683ff48bf5SDavid du Colombier     { "1.seticcspace", zseticcspace },
1693ff48bf5SDavid du Colombier     op_def_end(0)
1703ff48bf5SDavid du Colombier };
171