1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* CIE color rendering dictionary creation */
18 #include "math_.h"
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gscdefs.h" /* for gs_lib_device_list */
23 #include "gsdevice.h"
24 #include "gserrors.h"
25 #include "gsmatrix.h" /* for gscolor2.h */
26 #include "gsparam.h"
27 #include "gsstruct.h"
28 #include "gsutil.h"
29 #include "gxcspace.h"
30 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
31 #include "gscrd.h"
32
33 /* Import gs_lib_device_list() */
34 extern_gs_lib_device_list();
35
36 /* Allocator structure type */
37 public_st_cie_render1();
38 static
39 ENUM_PTRS_WITH(cie_render1_enum_ptrs, gs_cie_render *pcrd) return 0;
40 case 0: return ENUM_OBJ(pcrd->client_data);
41 case 1: return ENUM_OBJ(pcrd->RenderTable.lookup.table);
42 case 2: return (pcrd->RenderTable.lookup.table ?
43 ENUM_CONST_STRING(&pcrd->TransformPQR.proc_data) :
44 0);
45 ENUM_PTRS_END
46 static RELOC_PTRS_WITH(cie_render1_reloc_ptrs, gs_cie_render *pcrd);
47 RELOC_OBJ_VAR(pcrd->client_data);
48 if (pcrd->RenderTable.lookup.table)
49 {
50 RELOC_OBJ_VAR(pcrd->RenderTable.lookup.table);
51 RELOC_CONST_STRING_VAR(pcrd->TransformPQR.proc_data);
52 }
53 RELOC_PTRS_END
54
55 /* Default CRD procedures. */
56
57 static int
tpqr_identity(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)58 tpqr_identity(int index, floatp in, const gs_cie_wbsd * pwbsd,
59 gs_cie_render * pcrd, float *out)
60 {
61 *out = in;
62 return 0;
63 }
64
65 static int
tpqr_from_cache(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)66 tpqr_from_cache(int index, floatp in, const gs_cie_wbsd * pwbsd,
67 gs_cie_render * pcrd, float *out)
68 {
69 /*
70 * Since the TransformPQR cache is in the joint caches, not in the
71 * CRD cache, we can't actually implement this procedure.
72 * Instead, the place that calls it checks for it specially.
73 */
74 *out = in;
75 return 0;
76 }
77
78 static float
render_identity(floatp in,const gs_cie_render * pcrd)79 render_identity(floatp in, const gs_cie_render * pcrd)
80 {
81 return in;
82 }
83 static frac
render_table_identity(byte in,const gs_cie_render * pcrd)84 render_table_identity(byte in, const gs_cie_render * pcrd)
85 {
86 return byte2frac(in);
87 }
88
89 /* Transformation procedures that just consult the cache. */
90
91 static float
EncodeABC_cached_A(floatp in,const gs_cie_render * pcrd)92 EncodeABC_cached_A(floatp in, const gs_cie_render * pcrd)
93 {
94 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[0].floats);
95 }
96 static float
EncodeABC_cached_B(floatp in,const gs_cie_render * pcrd)97 EncodeABC_cached_B(floatp in, const gs_cie_render * pcrd)
98 {
99 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[1].floats);
100 }
101 static float
EncodeABC_cached_C(floatp in,const gs_cie_render * pcrd)102 EncodeABC_cached_C(floatp in, const gs_cie_render * pcrd)
103 {
104 return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[2].floats);
105 }
106 static float
EncodeLMN_cached_L(floatp in,const gs_cie_render * pcrd)107 EncodeLMN_cached_L(floatp in, const gs_cie_render * pcrd)
108 {
109 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[0].floats);
110 }
111 static float
EncodeLMN_cached_M(floatp in,const gs_cie_render * pcrd)112 EncodeLMN_cached_M(floatp in, const gs_cie_render * pcrd)
113 {
114 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[1].floats);
115 }
116 static float
EncodeLMN_cached_N(floatp in,const gs_cie_render * pcrd)117 EncodeLMN_cached_N(floatp in, const gs_cie_render * pcrd)
118 {
119 return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[2].floats);
120 }
121
122 static frac
RTT_cached(byte in,const gs_cie_render * pcrd,int i)123 RTT_cached(byte in, const gs_cie_render * pcrd, int i)
124 {
125 return pcrd->caches.RenderTableT[i].fracs.values[
126 in * (gx_cie_cache_size - 1) / 255
127 ];
128 }
129 static frac
RTT_cached_0(byte in,const gs_cie_render * pcrd)130 RTT_cached_0(byte in, const gs_cie_render * pcrd)
131 {
132 return RTT_cached(in, pcrd, 0);
133 }
134 static frac
RTT_cached_1(byte in,const gs_cie_render * pcrd)135 RTT_cached_1(byte in, const gs_cie_render * pcrd)
136 {
137 return RTT_cached(in, pcrd, 1);
138 }
139 static frac
RTT_cached_2(byte in,const gs_cie_render * pcrd)140 RTT_cached_2(byte in, const gs_cie_render * pcrd)
141 {
142 return RTT_cached(in, pcrd, 2);
143 }
144 static frac
RTT_cached_3(byte in,const gs_cie_render * pcrd)145 RTT_cached_3(byte in, const gs_cie_render * pcrd)
146 {
147 return RTT_cached(in, pcrd, 3);
148 }
149
150 /* Define the TransformPQR trampoline procedure that looks up proc_name. */
151
152 static int
tpqr_do_lookup(gs_cie_render * pcrd,const gx_device * dev_proto)153 tpqr_do_lookup(gs_cie_render *pcrd, const gx_device *dev_proto)
154 {
155 gx_device *dev;
156 gs_memory_t *mem = pcrd->rc.memory;
157 gs_c_param_list list;
158 gs_param_string proc_addr;
159 int code;
160
161 /* Device prototypes are const, so we must create a copy. */
162 code = gs_copydevice(&dev, dev_proto, mem);
163 if (code < 0)
164 return code;
165 gs_c_param_list_write(&list, mem);
166 code = param_request((gs_param_list *)&list,
167 pcrd->TransformPQR.proc_name);
168 if (code >= 0) {
169 code = gs_getdeviceparams(dev, (gs_param_list *)&list);
170 if (code >= 0) {
171 gs_c_param_list_read(&list);
172 code = param_read_string((gs_param_list *)&list,
173 pcrd->TransformPQR.proc_name,
174 &proc_addr);
175 if (code == 0 && proc_addr.size == sizeof(gs_cie_transform_proc)) {
176 memcpy(&pcrd->TransformPQR.proc, proc_addr.data,
177 sizeof(gs_cie_transform_proc));
178 } else
179 code = gs_note_error(gs_error_rangecheck);
180 }
181 }
182 gs_c_param_list_release(&list);
183 gs_free_object(mem, dev, "tpqr_do_lookup(device)");
184 return code;
185 }
186 static int
tpqr_lookup(int index,floatp in,const gs_cie_wbsd * pwbsd,gs_cie_render * pcrd,float * out)187 tpqr_lookup(int index, floatp in, const gs_cie_wbsd * pwbsd,
188 gs_cie_render * pcrd, float *out)
189 {
190 const gx_device *const *dev_list;
191 int count = gs_lib_device_list(&dev_list, NULL);
192 int i;
193 int code;
194
195 for (i = 0; i < count; ++i)
196 if (!strcmp(gs_devicename(dev_list[i]),
197 pcrd->TransformPQR.driver_name))
198 break;
199 if (i < count)
200 code = tpqr_do_lookup(pcrd, dev_list[i]);
201 else
202 code = gs_note_error(gs_error_undefined);
203 if (code < 0)
204 return code;
205 return pcrd->TransformPQR.proc(index, in, pwbsd, pcrd, out);
206 }
207
208 /* Default vectors. */
209 const gs_cie_transform_proc3 TransformPQR_default = {
210 tpqr_identity,
211 0, /* proc_name */
212 {0, 0}, /* proc_data */
213 0 /* driver_name */
214 };
215 const gs_cie_transform_proc3 TransformPQR_from_cache = {
216 tpqr_from_cache,
217 0, /* proc_name */
218 {0, 0}, /* proc_data */
219 0 /* driver_name */
220 };
221 const gs_cie_transform_proc TransformPQR_lookup_proc_name = tpqr_lookup;
222 const gs_cie_render_proc3 Encode_default = {
223 {render_identity, render_identity, render_identity}
224 };
225 const gs_cie_render_proc3 EncodeLMN_from_cache = {
226 {EncodeLMN_cached_L, EncodeLMN_cached_M, EncodeLMN_cached_N}
227 };
228 const gs_cie_render_proc3 EncodeABC_from_cache = {
229 {EncodeABC_cached_A, EncodeABC_cached_B, EncodeABC_cached_C}
230 };
231 const gs_cie_render_table_procs RenderTableT_default = {
232 {render_table_identity, render_table_identity, render_table_identity,
233 render_table_identity
234 }
235 };
236 const gs_cie_render_table_procs RenderTableT_from_cache = {
237 {RTT_cached_0, RTT_cached_1, RTT_cached_2, RTT_cached_3}
238 };
239
240 /*
241 * Allocate and minimally initialize a CRD. Note that this procedure sets
242 * the reference count of the structure to 1, not 0. gs_setcolorrendering
243 * will increment the reference count again, so unless you want the
244 * structure to stay allocated permanently (or until a garbage collection),
245 * you should call rc_decrement(pcrd, "client name") *after* calling
246 * gs_setcolorrendering.
247 */
248 int
gs_cie_render1_build(gs_cie_render ** ppcrd,gs_memory_t * mem,client_name_t cname)249 gs_cie_render1_build(gs_cie_render ** ppcrd, gs_memory_t * mem,
250 client_name_t cname)
251 {
252 gs_cie_render *pcrd;
253
254 rc_alloc_struct_1(pcrd, gs_cie_render, &st_cie_render1, mem,
255 return_error(gs_error_VMerror), cname);
256 pcrd->id = gs_next_ids(mem, 1);
257 /* Initialize pointers for the GC. */
258 pcrd->client_data = 0;
259 pcrd->RenderTable.lookup.table = 0;
260 pcrd->status = CIE_RENDER_STATUS_BUILT;
261 *ppcrd = pcrd;
262 return 0;
263 }
264
265 /*
266 * Initialize a CRD given all of the relevant parameters.
267 * Any of the pointers except WhitePoint may be zero, meaning
268 * use the default values.
269 *
270 * The actual point, matrix, range, and procedure values are copied into the
271 * CRD, but only the pointer to the color lookup table is copied.
272 *
273 * If pfrom_crd is not NULL, then if the EncodeLMN, EncodeABC, or
274 * RenderTable.T procedures indicate that the values exist only in the
275 * cache, the corresponding values will be copied from pfrom_crd.
276 * Note that NULL values for the individual pointers still represent
277 * default values.
278 */
279 int
gs_cie_render1_init_from(const gs_memory_t * mem,gs_cie_render * pcrd,void * client_data,const gs_cie_render * pfrom_crd,const gs_vector3 * WhitePoint,const gs_vector3 * BlackPoint,const gs_matrix3 * MatrixPQR,const gs_range3 * RangePQR,const gs_cie_transform_proc3 * TransformPQR,const gs_matrix3 * MatrixLMN,const gs_cie_render_proc3 * EncodeLMN,const gs_range3 * RangeLMN,const gs_matrix3 * MatrixABC,const gs_cie_render_proc3 * EncodeABC,const gs_range3 * RangeABC,const gs_cie_render_table_t * RenderTable)280 gs_cie_render1_init_from(const gs_memory_t *mem,
281 gs_cie_render * pcrd,
282 void *client_data,
283 const gs_cie_render * pfrom_crd,
284 const gs_vector3 * WhitePoint,
285 const gs_vector3 * BlackPoint,
286 const gs_matrix3 * MatrixPQR,
287 const gs_range3 * RangePQR,
288 const gs_cie_transform_proc3 * TransformPQR,
289 const gs_matrix3 * MatrixLMN,
290 const gs_cie_render_proc3 * EncodeLMN,
291 const gs_range3 * RangeLMN,
292 const gs_matrix3 * MatrixABC,
293 const gs_cie_render_proc3 * EncodeABC,
294 const gs_range3 * RangeABC,
295 const gs_cie_render_table_t * RenderTable)
296 {
297 pcrd->id = gs_next_ids(mem, 1);
298 pcrd->client_data = client_data;
299 pcrd->points.WhitePoint = *WhitePoint;
300 pcrd->points.BlackPoint =
301 *(BlackPoint ? BlackPoint : &BlackPoint_default);
302 pcrd->MatrixPQR = *(MatrixPQR ? MatrixPQR : &Matrix3_default);
303 pcrd->RangePQR = *(RangePQR ? RangePQR : &Range3_default);
304 pcrd->TransformPQR =
305 *(TransformPQR ? TransformPQR : &TransformPQR_default);
306 pcrd->MatrixLMN = *(MatrixLMN ? MatrixLMN : &Matrix3_default);
307 pcrd->EncodeLMN = *(EncodeLMN ? EncodeLMN : &Encode_default);
308 if (pfrom_crd &&
309 !memcmp(&pcrd->EncodeLMN, &EncodeLMN_from_cache,
310 sizeof(EncodeLMN_from_cache))
311 )
312 memcpy(&pcrd->caches.EncodeLMN, &pfrom_crd->caches.EncodeLMN,
313 sizeof(pcrd->caches.EncodeLMN));
314 pcrd->RangeLMN = *(RangeLMN ? RangeLMN : &Range3_default);
315 pcrd->MatrixABC = *(MatrixABC ? MatrixABC : &Matrix3_default);
316 pcrd->EncodeABC = *(EncodeABC ? EncodeABC : &Encode_default);
317 if (pfrom_crd &&
318 !memcmp(&pcrd->EncodeABC, &EncodeABC_from_cache,
319 sizeof(EncodeABC_from_cache))
320 )
321 memcpy(pcrd->caches.EncodeABC, pfrom_crd->caches.EncodeABC,
322 sizeof(pcrd->caches.EncodeABC));
323 pcrd->RangeABC = *(RangeABC ? RangeABC : &Range3_default);
324 if (RenderTable) {
325 pcrd->RenderTable = *RenderTable;
326 if (pfrom_crd &&
327 !memcmp(&pcrd->RenderTable.T, &RenderTableT_from_cache,
328 sizeof(RenderTableT_from_cache))
329 ) {
330 memcpy(pcrd->caches.RenderTableT, pfrom_crd->caches.RenderTableT,
331 sizeof(pcrd->caches.RenderTableT));
332 pcrd->caches.RenderTableT_is_identity =
333 pfrom_crd->caches.RenderTableT_is_identity;
334 }
335 } else {
336 pcrd->RenderTable.lookup.table = 0;
337 pcrd->RenderTable.T = RenderTableT_default;
338 }
339 pcrd->status = CIE_RENDER_STATUS_BUILT;
340 return 0;
341 }
342 /*
343 * Initialize a CRD without the option of copying cached values.
344 */
345 int
gs_cie_render1_initialize(const gs_memory_t * mem,gs_cie_render * pcrd,void * client_data,const gs_vector3 * WhitePoint,const gs_vector3 * BlackPoint,const gs_matrix3 * MatrixPQR,const gs_range3 * RangePQR,const gs_cie_transform_proc3 * TransformPQR,const gs_matrix3 * MatrixLMN,const gs_cie_render_proc3 * EncodeLMN,const gs_range3 * RangeLMN,const gs_matrix3 * MatrixABC,const gs_cie_render_proc3 * EncodeABC,const gs_range3 * RangeABC,const gs_cie_render_table_t * RenderTable)346 gs_cie_render1_initialize(const gs_memory_t *mem,
347 gs_cie_render * pcrd, void *client_data,
348 const gs_vector3 * WhitePoint,
349 const gs_vector3 * BlackPoint,
350 const gs_matrix3 * MatrixPQR,
351 const gs_range3 * RangePQR,
352 const gs_cie_transform_proc3 * TransformPQR,
353 const gs_matrix3 * MatrixLMN,
354 const gs_cie_render_proc3 * EncodeLMN,
355 const gs_range3 * RangeLMN,
356 const gs_matrix3 * MatrixABC,
357 const gs_cie_render_proc3 * EncodeABC,
358 const gs_range3 * RangeABC,
359 const gs_cie_render_table_t * RenderTable)
360 {
361 return gs_cie_render1_init_from(mem, pcrd, client_data, NULL,
362 WhitePoint, BlackPoint,
363 MatrixPQR, RangePQR, TransformPQR,
364 MatrixLMN, EncodeLMN, RangeLMN,
365 MatrixABC, EncodeABC, RangeABC,
366 RenderTable);
367 }
368