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