2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
160 |
gs_settransfer(gs_state * pgs, gs_mapping_proc tproc)
|
|
|
161 |
{
|
|
|
162 |
return gs_settransfer_remap(pgs, tproc, true);
|
|
|
163 |
}
|
|
|
164 |
int
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|