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