xref: /plan9/sys/src/cmd/gs/src/gscolor.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
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.
9 
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.
15 */
16 
17 /* $Id: gscolor.c,v 1.14 2004/08/04 19:36:12 stefan Exp $ */
18 /* Color and halftone operators for Ghostscript library */
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gsstruct.h"
22 #include "gsutil.h"		/* for gs_next_ids */
23 #include "gsccolor.h"
24 #include "gxcspace.h"
25 #include "gxdcconv.h"
26 #include "gxdevice.h"		/* for gx_color_index */
27 #include "gxcmap.h"
28 #include "gscolor2.h"
29 #include "gzstate.h"
30 
31 /* Imported from gsht.c */
32 void gx_set_effective_transfer(gs_state *);
33 
34 /* Structure descriptors */
35 public_st_client_color();
36 public_st_transfer_map();
37 
38 /* GC procedures */
39 private
40 ENUM_PTRS_WITH(transfer_map_enum_ptrs, gx_transfer_map *mptr) return 0;
41 case 0: ENUM_RETURN((mptr->proc == 0 ? mptr->closure.data : 0));
42 ENUM_PTRS_END
RELOC_PTRS_WITH(transfer_map_reloc_ptrs,gx_transfer_map * mptr)43 private RELOC_PTRS_WITH(transfer_map_reloc_ptrs, gx_transfer_map *mptr)
44 {
45     if (mptr->proc == 0)
46 	RELOC_PTR(gx_transfer_map, closure.data);
47 }
48 RELOC_PTRS_END
49 
50 /* Initialize colors with 1, or 3, or 4 paint components. */
51 /* (These are only used by setcolorspace.) */
52 void
gx_init_paint_1(gs_client_color * pcc,const gs_color_space * pcs)53 gx_init_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
54 {
55     pcc->paint.values[0] = 0.0;
56 }
57 void
gx_init_paint_3(gs_client_color * pcc,const gs_color_space * pcs)58 gx_init_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
59 {
60     pcc->paint.values[2] = 0.0;
61     pcc->paint.values[1] = 0.0;
62     pcc->paint.values[0] = 0.0;
63 }
64 void
gx_init_paint_4(gs_client_color * pcc,const gs_color_space * pcs)65 gx_init_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
66 {
67     /* DeviceCMYK and CIEBasedDEFG spaces initialize to 0,0,0,1. */
68     pcc->paint.values[3] = 1.0;
69     gx_init_paint_3(pcc, pcs);
70 }
71 
72 /* Force a value into the range [0.0..1.0]. */
73 #define FORCE_UNIT(p) (p <= 0.0 ? 0.0 : p >= 1.0 ? 1.0 : p)
74 
75 /* Restrict colors with 1, 3, or 4 components to the range (0,1). */
76 void
gx_restrict01_paint_1(gs_client_color * pcc,const gs_color_space * pcs)77 gx_restrict01_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
78 {
79     pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
80 }
81 void
gx_restrict01_paint_3(gs_client_color * pcc,const gs_color_space * pcs)82 gx_restrict01_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
83 {
84     pcc->paint.values[2] = FORCE_UNIT(pcc->paint.values[2]);
85     pcc->paint.values[1] = FORCE_UNIT(pcc->paint.values[1]);
86     pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
87 }
88 void
gx_restrict01_paint_4(gs_client_color * pcc,const gs_color_space * pcs)89 gx_restrict01_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
90 {
91     pcc->paint.values[3] = FORCE_UNIT(pcc->paint.values[3]);
92     gx_restrict01_paint_3(pcc, pcs);
93 }
94 
95 /* Null reference count adjustment procedure. */
96 void
gx_no_adjust_color_count(const gs_client_color * pcc,const gs_color_space * pcs,int delta)97 gx_no_adjust_color_count(const gs_client_color * pcc,
98 			 const gs_color_space * pcs, int delta)
99 {
100 }
101 
102 /* Forward declarations */
103 void load_transfer_map(gs_state *, gx_transfer_map *, floatp);
104 
105 /* setgray */
106 int
gs_setgray(gs_state * pgs,floatp gray)107 gs_setgray(gs_state * pgs, floatp gray)
108 {
109     gs_color_space      cs;
110     int                 code;
111 
112     gs_cspace_init_DeviceGray(pgs->memory, &cs);
113     if ((code = gs_setcolorspace(pgs, &cs)) >= 0) {
114         gs_client_color *   pcc = pgs->ccolor;
115 
116         cs_adjust_color_count(pgs, -1); /* not strictly necessary */
117         pcc->paint.values[0] = FORCE_UNIT(gray);
118         pcc->pattern = 0;		/* for GC */
119         gx_unset_dev_color(pgs);
120     }
121     return code;
122 }
123 
124 /* setrgbcolor */
125 int
gs_setrgbcolor(gs_state * pgs,floatp r,floatp g,floatp b)126 gs_setrgbcolor(gs_state * pgs, floatp r, floatp g, floatp b)
127 {
128     gs_color_space      cs;
129     int                 code;
130 
131     gs_cspace_init_DeviceRGB(pgs->memory, &cs);
132     if ((code = gs_setcolorspace(pgs, &cs)) >= 0) {
133        gs_client_color *    pcc = pgs->ccolor;
134 
135         cs_adjust_color_count(pgs, -1); /* not strictly necessary */
136         pcc->paint.values[0] = FORCE_UNIT(r);
137         pcc->paint.values[1] = FORCE_UNIT(g);
138         pcc->paint.values[2] = FORCE_UNIT(b);
139         pcc->pattern = 0;		/* for GC */
140         gx_unset_dev_color(pgs);
141     }
142     return code;
143 }
144 
145 
146 /* setnullcolor */
147 int
gs_setnullcolor(gs_state * pgs)148 gs_setnullcolor(gs_state * pgs)
149 {
150     if (pgs->in_cachedevice)
151 	return_error(gs_error_undefined);
152     gs_setgray(pgs, 0.0);	/* set color space to something harmless */
153     color_set_null(pgs->dev_color);
154     return 0;
155 }
156 
157 /* settransfer */
158 /* Remap=0 is used by the interpreter. */
159 int
gs_settransfer(gs_state * pgs,gs_mapping_proc tproc)160 gs_settransfer(gs_state * pgs, gs_mapping_proc tproc)
161 {
162     return gs_settransfer_remap(pgs, tproc, true);
163 }
164 int
gs_settransfer_remap(gs_state * pgs,gs_mapping_proc tproc,bool remap)165 gs_settransfer_remap(gs_state * pgs, gs_mapping_proc tproc, bool remap)
166 {
167     gx_transfer *ptran = &pgs->set_transfer;
168 
169     /*
170      * We can safely decrement the reference counts
171      * of the non-default transfer maps, because
172      * if any of them get freed, the rc_unshare can't fail.
173      */
174     rc_decrement(ptran->red, "gs_settransfer");
175     rc_decrement(ptran->green, "gs_settransfer");
176     rc_decrement(ptran->blue, "gs_settransfer");
177     rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
178 		      pgs->memory, goto fail, "gs_settransfer");
179     ptran->gray->proc = tproc;
180     ptran->gray->id = gs_next_ids(pgs->memory, 1);
181     ptran->red = 0;
182     ptran->green = 0;
183     ptran->blue = 0;
184     if (remap) {
185 	load_transfer_map(pgs, ptran->gray, 0.0);
186 	gx_set_effective_transfer(pgs);
187 	gx_unset_dev_color(pgs);
188     } else
189 	gx_set_effective_transfer(pgs);
190     return 0;
191   fail:
192     rc_increment(ptran->red);
193     rc_increment(ptran->green);
194     rc_increment(ptran->blue);
195     rc_increment(ptran->gray);
196     return_error(gs_error_VMerror);
197 }
198 
199 /* currenttransfer */
200 gs_mapping_proc
gs_currenttransfer(const gs_state * pgs)201 gs_currenttransfer(const gs_state * pgs)
202 {
203     return pgs->set_transfer.gray->proc;
204 }
205 
206 /* ------ Non-operator routines ------ */
207 
208 /* Set device color = 1 for writing into the character cache. */
209 void
gx_set_device_color_1(gs_state * pgs)210 gx_set_device_color_1(gs_state * pgs)
211 {
212     gs_color_space  cs;
213 
214     gs_setoverprint(pgs, false);
215     gs_setoverprintmode(pgs, 0);
216     gs_cspace_init_DeviceGray(pgs->memory, &cs);
217     gs_setcolorspace(pgs, &cs);
218     set_nonclient_dev_color(pgs->dev_color, 1);
219     pgs->log_op = lop_default;
220     /*
221      * In the unlikely event that  overprint mode is in effect,
222      * update the overprint information.
223      */
224     if (pgs->effective_overprint_mode == 1)
225 	(void)gs_do_set_overprint(pgs);
226 
227 }
228 
229 /* ------ Internal routines ------ */
230 
231 /*
232  * Load one cached transfer map.  We export this for gscolor1.c.
233  * Note that we must deal with both old (proc) and new (closure) maps.
234  */
235 private float
transfer_use_proc(floatp value,const gx_transfer_map * pmap,const void * ignore_proc_data)236 transfer_use_proc(floatp value, const gx_transfer_map * pmap,
237 		  const void *ignore_proc_data)
238 {
239     return (*pmap->proc) (value, pmap);
240 }
241 void
load_transfer_map(gs_state * pgs,gx_transfer_map * pmap,floatp min_value)242 load_transfer_map(gs_state * pgs, gx_transfer_map * pmap, floatp min_value)
243 {
244     gs_mapping_closure_proc_t proc;
245     const void *proc_data;
246     frac *values = pmap->values;
247     frac fmin = float2frac(min_value);
248     int i;
249 
250     if (pmap->proc == 0)	/* use closure */
251 	proc = pmap->closure.proc, proc_data = pmap->closure.data;
252     else			/* use proc */
253 	proc = transfer_use_proc, proc_data = 0 /* not used */;
254     for (i = 0; i < transfer_map_size; i++) {
255 	float fval =
256 	(*proc) ((float)i / (transfer_map_size - 1), pmap, proc_data);
257 
258 	values[i] =
259 	    (fval < min_value ? fmin :
260 	     fval >= 1.0 ? frac_1 :
261 	     float2frac(fval));
262     }
263 }
264