1 /* Copyright (C) 1992, 1995, 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: gscie.c,v 1.16 2004/03/16 02:16:20 dan Exp $ */
18 /* CIE color rendering cache management */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "gsmatrix.h" /* for gscolor2.h */
25 #include "gxcspace.h" /* for gxcie.c */
26 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
27 #include "gxarith.h"
28 #include "gxcie.h"
29 #include "gxdevice.h" /* for gxcmap.h */
30 #include "gxcmap.h"
31 #include "gzstate.h"
32 #include "gsicc.h"
33
34 /*
35 * Define whether to optimize the CIE mapping process by combining steps.
36 * This should only be disabled (commented out) for debugging.
37 */
38 #define OPTIMIZE_CIE_MAPPING
39
40 /* Forward references */
41 private int cie_joint_caches_init(gx_cie_joint_caches *,
42 const gs_cie_common *,
43 gs_cie_render *);
44 private void cie_joint_caches_complete(gx_cie_joint_caches *,
45 const gs_cie_common *,
46 const gs_cie_abc *,
47 const gs_cie_render *);
48 private void cie_cache_restrict(cie_cache_floats *, const gs_range *);
49 private void cie_mult3(const gs_vector3 *, const gs_matrix3 *,
50 gs_vector3 *);
51 private void cie_matrix_mult3(const gs_matrix3 *, const gs_matrix3 *,
52 gs_matrix3 *);
53 private void cie_invert3(const gs_matrix3 *, gs_matrix3 *);
54 private void cie_matrix_init(gs_matrix3 *);
55
56 /* Allocator structure types */
57 private_st_joint_caches();
58 extern_st(st_imager_state);
59
60 #define RESTRICTED_INDEX(v, n, itemp)\
61 ((uint)(itemp = (int)(v)) >= (n) ?\
62 (itemp < 0 ? 0 : (n) - 1) : itemp)
63
64 /* Define the template for loading a cache. */
65 /* If we had parameterized types, or a more flexible type system, */
66 /* this could be done with a single procedure. */
67 #define CIE_LOAD_CACHE_BODY(pcache, domains, rprocs, dprocs, pcie, cname)\
68 BEGIN\
69 int j;\
70 \
71 for (j = 0; j < countof(pcache); j++) {\
72 cie_cache_floats *pcf = &(pcache)[j].floats;\
73 int i;\
74 gs_sample_loop_params_t lp;\
75 \
76 gs_cie_cache_init(&pcf->params, &lp, &(domains)[j], cname);\
77 for (i = 0; i <= lp.N; ++i) {\
78 float v = SAMPLE_LOOP_VALUE(i, lp);\
79 pcf->values[i] = (*(rprocs)->procs[j])(v, pcie);\
80 if_debug5('C', "[C]%s[%d,%d] = %g => %g\n",\
81 cname, j, i, v, pcf->values[i]);\
82 }\
83 pcf->params.is_identity =\
84 (rprocs)->procs[j] == (dprocs).procs[j];\
85 }\
86 END
87
88 /* Define cache interpolation threshold values. */
89 #ifdef CIE_CACHE_INTERPOLATE
90 # ifdef CIE_INTERPOLATE_THRESHOLD
91 # define CACHE_THRESHOLD CIE_INTERPOLATE_THRESHOLD
92 # else
93 # define CACHE_THRESHOLD 0 /* always interpolate */
94 # endif
95 #else
96 # define CACHE_THRESHOLD 1.0e6 /* never interpolate */
97 #endif
98 #ifdef CIE_RENDER_TABLE_INTERPOLATE
99 # define RENDER_TABLE_THRESHOLD 0
100 #else
101 # define RENDER_TABLE_THRESHOLD 1.0e6
102 #endif
103
104 /*
105 * Determine whether a function is a linear transformation of the form
106 * f(x) = scale * x + origin.
107 */
108 private bool
cache_is_linear(cie_linear_params_t * params,const cie_cache_floats * pcf)109 cache_is_linear(cie_linear_params_t *params, const cie_cache_floats *pcf)
110 {
111 double origin = pcf->values[0];
112 double diff = pcf->values[countof(pcf->values) - 1] - origin;
113 double scale = diff / (countof(pcf->values) - 1);
114 int i;
115 double test = origin + scale;
116
117 for (i = 1; i < countof(pcf->values) - 1; ++i, test += scale)
118 if (fabs(pcf->values[i] - test) >= 0.5 / countof(pcf->values))
119 return (params->is_linear = false);
120 params->origin = origin - pcf->params.base;
121 params->scale =
122 diff * pcf->params.factor / (countof(pcf->values) - 1);
123 return (params->is_linear = true);
124 }
125
126 private void
cache_set_linear(cie_cache_floats * pcf)127 cache_set_linear(cie_cache_floats *pcf)
128 {
129 if (pcf->params.is_identity) {
130 if_debug1('c', "[c]is_linear(0x%lx) = true (is_identity)\n",
131 (ulong)pcf);
132 pcf->params.linear.is_linear = true;
133 pcf->params.linear.origin = 0;
134 pcf->params.linear.scale = 1;
135 } else if (cache_is_linear(&pcf->params.linear, pcf)) {
136 if (pcf->params.linear.origin == 0 &&
137 fabs(pcf->params.linear.scale - 1) < 0.00001)
138 pcf->params.is_identity = true;
139 if_debug4('c',
140 "[c]is_linear(0x%lx) = true, origin = %g, scale = %g%s\n",
141 (ulong)pcf, pcf->params.linear.origin,
142 pcf->params.linear.scale,
143 (pcf->params.is_identity ? " (=> is_identity)" : ""));
144 }
145 #ifdef DEBUG
146 else
147 if_debug1('c', "[c]linear(0x%lx) = false\n", (ulong)pcf);
148 #endif
149 }
150 private void
cache3_set_linear(gx_cie_vector_cache3_t * pvc)151 cache3_set_linear(gx_cie_vector_cache3_t *pvc)
152 {
153 cache_set_linear(&pvc->caches[0].floats);
154 cache_set_linear(&pvc->caches[1].floats);
155 cache_set_linear(&pvc->caches[2].floats);
156 }
157
158 #ifdef DEBUG
159 private void
if_debug_vector3(const char * str,const gs_vector3 * vec)160 if_debug_vector3(const char *str, const gs_vector3 *vec)
161 {
162 if_debug4('c', "%s[%g %g %g]\n", str, vec->u, vec->v, vec->w);
163 }
164 private void
if_debug_matrix3(const char * str,const gs_matrix3 * mat)165 if_debug_matrix3(const char *str, const gs_matrix3 *mat)
166 {
167 if_debug10('c', "%s [%g %g %g] [%g %g %g] [%g %g %g]\n", str,
168 mat->cu.u, mat->cu.v, mat->cu.w,
169 mat->cv.u, mat->cv.v, mat->cv.w,
170 mat->cw.u, mat->cw.v, mat->cw.w);
171 }
172 #else
173 # define if_debug_vector3(str, vec) DO_NOTHING
174 # define if_debug_matrix3(str, mat) DO_NOTHING
175 #endif
176
177 /* ------ Default values for CIE dictionary elements ------ */
178
179 /* Default transformation procedures. */
180
181 private float
a_identity(floatp in,const gs_cie_a * pcie)182 a_identity(floatp in, const gs_cie_a * pcie)
183 {
184 return in;
185 }
186 private float
a_from_cache(floatp in,const gs_cie_a * pcie)187 a_from_cache(floatp in, const gs_cie_a * pcie)
188 {
189 return gs_cie_cached_value(in, &pcie->caches.DecodeA.floats);
190 }
191
192 private float
abc_identity(floatp in,const gs_cie_abc * pcie)193 abc_identity(floatp in, const gs_cie_abc * pcie)
194 {
195 return in;
196 }
197 private float
abc_from_cache_0(floatp in,const gs_cie_abc * pcie)198 abc_from_cache_0(floatp in, const gs_cie_abc * pcie)
199 {
200 return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[0].floats);
201 }
202 private float
abc_from_cache_1(floatp in,const gs_cie_abc * pcie)203 abc_from_cache_1(floatp in, const gs_cie_abc * pcie)
204 {
205 return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[1].floats);
206 }
207 private float
abc_from_cache_2(floatp in,const gs_cie_abc * pcie)208 abc_from_cache_2(floatp in, const gs_cie_abc * pcie)
209 {
210 return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[2].floats);
211 }
212
213 private float
def_identity(floatp in,const gs_cie_def * pcie)214 def_identity(floatp in, const gs_cie_def * pcie)
215 {
216 return in;
217 }
218 private float
def_from_cache_0(floatp in,const gs_cie_def * pcie)219 def_from_cache_0(floatp in, const gs_cie_def * pcie)
220 {
221 return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[0].floats);
222 }
223 private float
def_from_cache_1(floatp in,const gs_cie_def * pcie)224 def_from_cache_1(floatp in, const gs_cie_def * pcie)
225 {
226 return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[1].floats);
227 }
228 private float
def_from_cache_2(floatp in,const gs_cie_def * pcie)229 def_from_cache_2(floatp in, const gs_cie_def * pcie)
230 {
231 return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[2].floats);
232 }
233
234 private float
defg_identity(floatp in,const gs_cie_defg * pcie)235 defg_identity(floatp in, const gs_cie_defg * pcie)
236 {
237 return in;
238 }
239 private float
defg_from_cache_0(floatp in,const gs_cie_defg * pcie)240 defg_from_cache_0(floatp in, const gs_cie_defg * pcie)
241 {
242 return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[0].floats);
243 }
244 private float
defg_from_cache_1(floatp in,const gs_cie_defg * pcie)245 defg_from_cache_1(floatp in, const gs_cie_defg * pcie)
246 {
247 return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[1].floats);
248 }
249 private float
defg_from_cache_2(floatp in,const gs_cie_defg * pcie)250 defg_from_cache_2(floatp in, const gs_cie_defg * pcie)
251 {
252 return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[2].floats);
253 }
254 private float
defg_from_cache_3(floatp in,const gs_cie_defg * pcie)255 defg_from_cache_3(floatp in, const gs_cie_defg * pcie)
256 {
257 return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[3].floats);
258 }
259
260 private float
common_identity(floatp in,const gs_cie_common * pcie)261 common_identity(floatp in, const gs_cie_common * pcie)
262 {
263 return in;
264 }
265 private float
lmn_from_cache_0(floatp in,const gs_cie_common * pcie)266 lmn_from_cache_0(floatp in, const gs_cie_common * pcie)
267 {
268 return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[0].floats);
269 }
270 private float
lmn_from_cache_1(floatp in,const gs_cie_common * pcie)271 lmn_from_cache_1(floatp in, const gs_cie_common * pcie)
272 {
273 return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[1].floats);
274 }
275 private float
lmn_from_cache_2(floatp in,const gs_cie_common * pcie)276 lmn_from_cache_2(floatp in, const gs_cie_common * pcie)
277 {
278 return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[2].floats);
279 }
280
281 /* Transformation procedures for accessing an already-loaded cache. */
282
283 float
gs_cie_cached_value(floatp in,const cie_cache_floats * pcache)284 gs_cie_cached_value(floatp in, const cie_cache_floats *pcache)
285 {
286 /*
287 * We need to get the same results when we sample an already-loaded
288 * cache, so we need to round the index just a tiny bit.
289 */
290 int index =
291 (int)((in - pcache->params.base) * pcache->params.factor + 0.0001);
292
293 CIE_CLAMP_INDEX(index);
294 return pcache->values[index];
295 }
296
297 /* Default vectors and matrices. */
298
299 const gs_range3 Range3_default = {
300 { {0, 1}, {0, 1}, {0, 1} }
301 };
302 const gs_range4 Range4_default = {
303 { {0, 1}, {0, 1}, {0, 1}, {0, 1} }
304 };
305 const gs_cie_defg_proc4 DecodeDEFG_default = {
306 {defg_identity, defg_identity, defg_identity, defg_identity}
307 };
308 const gs_cie_defg_proc4 DecodeDEFG_from_cache = {
309 {defg_from_cache_0, defg_from_cache_1, defg_from_cache_2, defg_from_cache_3}
310 };
311 const gs_cie_def_proc3 DecodeDEF_default = {
312 {def_identity, def_identity, def_identity}
313 };
314 const gs_cie_def_proc3 DecodeDEF_from_cache = {
315 {def_from_cache_0, def_from_cache_1, def_from_cache_2}
316 };
317 const gs_cie_abc_proc3 DecodeABC_default = {
318 {abc_identity, abc_identity, abc_identity}
319 };
320 const gs_cie_abc_proc3 DecodeABC_from_cache = {
321 {abc_from_cache_0, abc_from_cache_1, abc_from_cache_2}
322 };
323 const gs_cie_common_proc3 DecodeLMN_default = {
324 {common_identity, common_identity, common_identity}
325 };
326 const gs_cie_common_proc3 DecodeLMN_from_cache = {
327 {lmn_from_cache_0, lmn_from_cache_1, lmn_from_cache_2}
328 };
329 const gs_matrix3 Matrix3_default = {
330 {1, 0, 0},
331 {0, 1, 0},
332 {0, 0, 1},
333 1 /*true */
334 };
335 const gs_range RangeA_default = {0, 1};
336 const gs_cie_a_proc DecodeA_default = a_identity;
337 const gs_cie_a_proc DecodeA_from_cache = a_from_cache;
338 const gs_vector3 MatrixA_default = {1, 1, 1};
339 const gs_vector3 BlackPoint_default = {0, 0, 0};
340
341 /* Initialize a CIE color. */
342 /* This only happens on setcolorspace. */
343 void
gx_init_CIE(gs_client_color * pcc,const gs_color_space * pcs)344 gx_init_CIE(gs_client_color * pcc, const gs_color_space * pcs)
345 {
346 gx_init_paint_4(pcc, pcs);
347 /* (0...) may not be within the range of allowable values. */
348 (*pcs->type->restrict_color)(pcc, pcs);
349 }
350
351 /* Restrict CIE colors. */
352
353 inline private void
cie_restrict(float * pv,const gs_range * range)354 cie_restrict(float *pv, const gs_range *range)
355 {
356 if (*pv <= range->rmin)
357 *pv = range->rmin;
358 else if (*pv >= range->rmax)
359 *pv = range->rmax;
360 }
361
362 void
gx_restrict_CIEDEFG(gs_client_color * pcc,const gs_color_space * pcs)363 gx_restrict_CIEDEFG(gs_client_color * pcc, const gs_color_space * pcs)
364 {
365 const gs_cie_defg *pcie = pcs->params.defg;
366
367 cie_restrict(&pcc->paint.values[0], &pcie->RangeDEFG.ranges[0]);
368 cie_restrict(&pcc->paint.values[1], &pcie->RangeDEFG.ranges[1]);
369 cie_restrict(&pcc->paint.values[2], &pcie->RangeDEFG.ranges[2]);
370 cie_restrict(&pcc->paint.values[3], &pcie->RangeDEFG.ranges[3]);
371 }
372 void
gx_restrict_CIEDEF(gs_client_color * pcc,const gs_color_space * pcs)373 gx_restrict_CIEDEF(gs_client_color * pcc, const gs_color_space * pcs)
374 {
375 const gs_cie_def *pcie = pcs->params.def;
376
377 cie_restrict(&pcc->paint.values[0], &pcie->RangeDEF.ranges[0]);
378 cie_restrict(&pcc->paint.values[1], &pcie->RangeDEF.ranges[1]);
379 cie_restrict(&pcc->paint.values[2], &pcie->RangeDEF.ranges[2]);
380 }
381 void
gx_restrict_CIEABC(gs_client_color * pcc,const gs_color_space * pcs)382 gx_restrict_CIEABC(gs_client_color * pcc, const gs_color_space * pcs)
383 {
384 const gs_cie_abc *pcie = pcs->params.abc;
385
386 cie_restrict(&pcc->paint.values[0], &pcie->RangeABC.ranges[0]);
387 cie_restrict(&pcc->paint.values[1], &pcie->RangeABC.ranges[1]);
388 cie_restrict(&pcc->paint.values[2], &pcie->RangeABC.ranges[2]);
389 }
390 void
gx_restrict_CIEA(gs_client_color * pcc,const gs_color_space * pcs)391 gx_restrict_CIEA(gs_client_color * pcc, const gs_color_space * pcs)
392 {
393 const gs_cie_a *pcie = pcs->params.a;
394
395 cie_restrict(&pcc->paint.values[0], &pcie->RangeA);
396 }
397
398 /* ================ Table setup ================ */
399
400 /* ------ Install a CIE color space ------ */
401
402 private void cie_cache_mult(gx_cie_vector_cache *, const gs_vector3 *,
403 const cie_cache_floats *, floatp);
404 private bool cie_cache_mult3(gx_cie_vector_cache3_t *,
405 const gs_matrix3 *, floatp);
406
407 private int
gx_install_cie_abc(gs_cie_abc * pcie,gs_state * pgs)408 gx_install_cie_abc(gs_cie_abc *pcie, gs_state * pgs)
409 {
410 if_debug_matrix3("[c]CIE MatrixABC =", &pcie->MatrixABC);
411 cie_matrix_init(&pcie->MatrixABC);
412 CIE_LOAD_CACHE_BODY(pcie->caches.DecodeABC.caches, pcie->RangeABC.ranges,
413 &pcie->DecodeABC, DecodeABC_default, pcie,
414 "DecodeABC");
415 gx_cie_load_common_cache(&pcie->common, pgs);
416 gs_cie_abc_complete(pcie);
417 return gs_cie_cs_complete(pgs, true);
418 }
419
420 int
gx_install_CIEDEFG(const gs_color_space * pcs,gs_state * pgs)421 gx_install_CIEDEFG(const gs_color_space * pcs, gs_state * pgs)
422 {
423 gs_cie_defg *pcie = pcs->params.defg;
424
425 CIE_LOAD_CACHE_BODY(pcie->caches_defg.DecodeDEFG, pcie->RangeDEFG.ranges,
426 &pcie->DecodeDEFG, DecodeDEFG_default, pcie,
427 "DecodeDEFG");
428 return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
429 }
430
431 int
gx_install_CIEDEF(const gs_color_space * pcs,gs_state * pgs)432 gx_install_CIEDEF(const gs_color_space * pcs, gs_state * pgs)
433 {
434 gs_cie_def *pcie = pcs->params.def;
435
436 CIE_LOAD_CACHE_BODY(pcie->caches_def.DecodeDEF, pcie->RangeDEF.ranges,
437 &pcie->DecodeDEF, DecodeDEF_default, pcie,
438 "DecodeDEF");
439 return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
440 }
441
442 int
gx_install_CIEABC(const gs_color_space * pcs,gs_state * pgs)443 gx_install_CIEABC(const gs_color_space * pcs, gs_state * pgs)
444 {
445 return gx_install_cie_abc(pcs->params.abc, pgs);
446 }
447
448 int
gx_install_CIEA(const gs_color_space * pcs,gs_state * pgs)449 gx_install_CIEA(const gs_color_space * pcs, gs_state * pgs)
450 {
451 gs_cie_a *pcie = pcs->params.a;
452 gs_sample_loop_params_t lp;
453 int i;
454
455 gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp,
456 &pcie->RangeA, "DecodeA");
457 for (i = 0; i <= lp.N; ++i) {
458 float in = SAMPLE_LOOP_VALUE(i, lp);
459
460 pcie->caches.DecodeA.floats.values[i] = (*pcie->DecodeA)(in, pcie);
461 if_debug3('C', "[C]DecodeA[%d] = %g => %g\n",
462 i, in, pcie->caches.DecodeA.floats.values[i]);
463 }
464 gx_cie_load_common_cache(&pcie->common, pgs);
465 gs_cie_a_complete(pcie);
466 return gs_cie_cs_complete(pgs, true);
467 }
468
469 /* Load the common caches when installing the color space. */
470 /* This routine is exported for the benefit of gsicc.c */
471 void
gx_cie_load_common_cache(gs_cie_common * pcie,gs_state * pgs)472 gx_cie_load_common_cache(gs_cie_common * pcie, gs_state * pgs)
473 {
474 if_debug_matrix3("[c]CIE MatrixLMN =", &pcie->MatrixLMN);
475 cie_matrix_init(&pcie->MatrixLMN);
476 CIE_LOAD_CACHE_BODY(pcie->caches.DecodeLMN, pcie->RangeLMN.ranges,
477 &pcie->DecodeLMN, DecodeLMN_default, pcie,
478 "DecodeLMN");
479 }
480
481 /* Complete loading the common caches. */
482 /* This routine is exported for the benefit of gsicc.c */
483 void
gx_cie_common_complete(gs_cie_common * pcie)484 gx_cie_common_complete(gs_cie_common *pcie)
485 {
486 int i;
487
488 for (i = 0; i < 3; ++i)
489 cache_set_linear(&pcie->caches.DecodeLMN[i].floats);
490 }
491
492 /*
493 * Restrict the DecodeDEF[G] cache according to RangeHIJ[K], and scale to
494 * the dimensions of Table.
495 */
496 private void
gs_cie_defx_scale(float * values,const gs_range * range,int dim)497 gs_cie_defx_scale(float *values, const gs_range *range, int dim)
498 {
499 double scale = (dim - 1.0) / (range->rmax - range->rmin);
500 int i;
501
502 for (i = 0; i < gx_cie_cache_size; ++i) {
503 float value = values[i];
504
505 values[i] =
506 (value <= range->rmin ? 0 :
507 value >= range->rmax ? dim - 1 :
508 (value - range->rmin) * scale);
509 }
510 }
511
512 /* Complete loading a CIEBasedDEFG color space. */
513 /* This routine is NOT idempotent. */
514 void
gs_cie_defg_complete(gs_cie_defg * pcie)515 gs_cie_defg_complete(gs_cie_defg * pcie)
516 {
517 int j;
518
519 for (j = 0; j < 4; ++j)
520 gs_cie_defx_scale(pcie->caches_defg.DecodeDEFG[j].floats.values,
521 &pcie->RangeHIJK.ranges[j], pcie->Table.dims[j]);
522 gs_cie_abc_complete((gs_cie_abc *)pcie);
523 }
524
525 /* Complete loading a CIEBasedDEF color space. */
526 /* This routine is NOT idempotent. */
527 void
gs_cie_def_complete(gs_cie_def * pcie)528 gs_cie_def_complete(gs_cie_def * pcie)
529 {
530 int j;
531
532 for (j = 0; j < 3; ++j)
533 gs_cie_defx_scale(pcie->caches_def.DecodeDEF[j].floats.values,
534 &pcie->RangeHIJ.ranges[j], pcie->Table.dims[j]);
535 gs_cie_abc_complete((gs_cie_abc *)pcie);
536 }
537
538 /* Complete loading a CIEBasedABC color space. */
539 /* This routine is idempotent. */
540 void
gs_cie_abc_complete(gs_cie_abc * pcie)541 gs_cie_abc_complete(gs_cie_abc * pcie)
542 {
543 cache3_set_linear(&pcie->caches.DecodeABC);
544 pcie->caches.skipABC =
545 cie_cache_mult3(&pcie->caches.DecodeABC, &pcie->MatrixABC,
546 CACHE_THRESHOLD);
547 gx_cie_common_complete((gs_cie_common *)pcie);
548 }
549
550 /* Complete loading a CIEBasedA color space. */
551 /* This routine is idempotent. */
552 void
gs_cie_a_complete(gs_cie_a * pcie)553 gs_cie_a_complete(gs_cie_a * pcie)
554 {
555 cie_cache_mult(&pcie->caches.DecodeA, &pcie->MatrixA,
556 &pcie->caches.DecodeA.floats,
557 CACHE_THRESHOLD);
558 cache_set_linear(&pcie->caches.DecodeA.floats);
559 gx_cie_common_complete((gs_cie_common *)pcie);
560 }
561
562 /*
563 * Set the ranges where interpolation is required in a vector cache.
564 * This procedure is idempotent.
565 */
566 typedef struct cie_cache_range_temp_s {
567 cie_cached_value prev;
568 int imin, imax;
569 } cie_cache_range_temp_t;
570 private void
check_interpolation_required(cie_cache_range_temp_t * pccr,cie_cached_value cur,int i,floatp threshold)571 check_interpolation_required(cie_cache_range_temp_t *pccr,
572 cie_cached_value cur, int i, floatp threshold)
573 {
574 cie_cached_value prev = pccr->prev;
575
576 if (any_abs(cur - prev) > threshold * min(any_abs(prev), any_abs(cur))) {
577 if (i - 1 < pccr->imin)
578 pccr->imin = i - 1;
579 if (i > pccr->imax)
580 pccr->imax = i;
581 }
582 pccr->prev = cur;
583 }
584 private void
cie_cache_set_interpolation(gx_cie_vector_cache * pcache,floatp threshold)585 cie_cache_set_interpolation(gx_cie_vector_cache *pcache, floatp threshold)
586 {
587 cie_cached_value base = pcache->vecs.params.base;
588 cie_cached_value factor = pcache->vecs.params.factor;
589 cie_cache_range_temp_t temp[3];
590 int i, j;
591
592 for (j = 0; j < 3; ++j)
593 temp[j].imin = gx_cie_cache_size, temp[j].imax = -1;
594 temp[0].prev = pcache->vecs.values[0].u;
595 temp[1].prev = pcache->vecs.values[0].v;
596 temp[2].prev = pcache->vecs.values[0].w;
597
598 for (i = 0; i < gx_cie_cache_size; ++i) {
599 check_interpolation_required(&temp[0], pcache->vecs.values[i].u, i,
600 threshold);
601 check_interpolation_required(&temp[1], pcache->vecs.values[i].v, i,
602 threshold);
603 check_interpolation_required(&temp[2], pcache->vecs.values[i].w, i,
604 threshold);
605 }
606
607 for (j = 0; j < 3; ++j) {
608 pcache->vecs.params.interpolation_ranges[j].rmin =
609 base + (cie_cached_value)((double)temp[j].imin / factor);
610 pcache->vecs.params.interpolation_ranges[j].rmax =
611 base + (cie_cached_value)((double)temp[j].imax / factor);
612 if_debug3('c', "[c]interpolation_ranges[%d] = %g, %g\n", j,
613 cie_cached2float(pcache->vecs.params.interpolation_ranges[j].rmin),
614 cie_cached2float(pcache->vecs.params.interpolation_ranges[j].rmax));
615 }
616
617 }
618
619 /*
620 * Convert a scalar cache to a vector cache by multiplying the scalar
621 * values by a vector. Also set the range where interpolation is needed.
622 * This procedure is idempotent.
623 */
624 private void
cie_cache_mult(gx_cie_vector_cache * pcache,const gs_vector3 * pvec,const cie_cache_floats * pcf,floatp threshold)625 cie_cache_mult(gx_cie_vector_cache * pcache, const gs_vector3 * pvec,
626 const cie_cache_floats * pcf, floatp threshold)
627 {
628 float u = pvec->u, v = pvec->v, w = pvec->w;
629 int i;
630
631 pcache->vecs.params.base = float2cie_cached(pcf->params.base);
632 pcache->vecs.params.factor = float2cie_cached(pcf->params.factor);
633 pcache->vecs.params.limit =
634 float2cie_cached((gx_cie_cache_size - 1) / pcf->params.factor +
635 pcf->params.base);
636 for (i = 0; i < gx_cie_cache_size; ++i) {
637 float f = pcf->values[i];
638
639 pcache->vecs.values[i].u = float2cie_cached(f * u);
640 pcache->vecs.values[i].v = float2cie_cached(f * v);
641 pcache->vecs.values[i].w = float2cie_cached(f * w);
642 }
643 cie_cache_set_interpolation(pcache, threshold);
644 }
645
646 /*
647 * Set the interpolation ranges in a 3-vector cache, based on the ranges in
648 * the individual vector caches. This procedure is idempotent.
649 */
650 private void
cie_cache3_set_interpolation(gx_cie_vector_cache3_t * pvc)651 cie_cache3_set_interpolation(gx_cie_vector_cache3_t * pvc)
652 {
653 int j, k;
654
655 /* Iterate over output components. */
656 for (j = 0; j < 3; ++j) {
657 /* Iterate over sub-caches. */
658 cie_interpolation_range_t *p =
659 &pvc->caches[0].vecs.params.interpolation_ranges[j];
660 cie_cached_value rmin = p->rmin, rmax = p->rmax;
661
662 for (k = 1; k < 3; ++k) {
663 p = &pvc->caches[k].vecs.params.interpolation_ranges[j];
664 rmin = min(rmin, p->rmin), rmax = max(rmax, p->rmax);
665 }
666 pvc->interpolation_ranges[j].rmin = rmin;
667 pvc->interpolation_ranges[j].rmax = rmax;
668 if_debug3('c', "[c]Merged interpolation_ranges[%d] = %g, %g\n",
669 j, rmin, rmax);
670 }
671 }
672
673 /*
674 * Convert 3 scalar caches to vector caches by multiplying by a matrix.
675 * Return true iff the resulting cache is an identity transformation.
676 * This procedure is idempotent.
677 */
678 private bool
cie_cache_mult3(gx_cie_vector_cache3_t * pvc,const gs_matrix3 * pmat,floatp threshold)679 cie_cache_mult3(gx_cie_vector_cache3_t * pvc, const gs_matrix3 * pmat,
680 floatp threshold)
681 {
682 cie_cache_mult(&pvc->caches[0], &pmat->cu, &pvc->caches[0].floats, threshold);
683 cie_cache_mult(&pvc->caches[1], &pmat->cv, &pvc->caches[1].floats, threshold);
684 cie_cache_mult(&pvc->caches[2], &pmat->cw, &pvc->caches[2].floats, threshold);
685 cie_cache3_set_interpolation(pvc);
686 return pmat->is_identity & pvc->caches[0].floats.params.is_identity &
687 pvc->caches[1].floats.params.is_identity &
688 pvc->caches[2].floats.params.is_identity;
689 }
690
691 /* ------ Install a rendering dictionary ------ */
692
693 /* setcolorrendering */
694 int
gs_setcolorrendering(gs_state * pgs,gs_cie_render * pcrd)695 gs_setcolorrendering(gs_state * pgs, gs_cie_render * pcrd)
696 {
697 int code = gs_cie_render_complete(pcrd);
698 const gs_cie_render *pcrd_old = pgs->cie_render;
699 bool joint_ok;
700
701 if (code < 0)
702 return code;
703 if (pcrd_old != 0 && pcrd->id == pcrd_old->id)
704 return 0; /* detect needless reselecting */
705 joint_ok =
706 pcrd_old != 0 &&
707 #define CRD_SAME(elt) !memcmp(&pcrd->elt, &pcrd_old->elt, sizeof(pcrd->elt))
708 CRD_SAME(points.WhitePoint) && CRD_SAME(points.BlackPoint) &&
709 CRD_SAME(MatrixPQR) && CRD_SAME(RangePQR) &&
710 CRD_SAME(TransformPQR);
711 #undef CRD_SAME
712 rc_assign(pgs->cie_render, pcrd, "gs_setcolorrendering");
713 /* Initialize the joint caches if needed. */
714 if (!joint_ok)
715 code = gs_cie_cs_complete(pgs, true);
716 gx_unset_dev_color(pgs);
717 return code;
718 }
719
720 /* currentcolorrendering */
721 const gs_cie_render *
gs_currentcolorrendering(const gs_state * pgs)722 gs_currentcolorrendering(const gs_state * pgs)
723 {
724 return pgs->cie_render;
725 }
726
727 /* Unshare (allocating if necessary) the joint caches. */
728 gx_cie_joint_caches *
gx_currentciecaches(gs_state * pgs)729 gx_currentciecaches(gs_state * pgs)
730 {
731 gx_cie_joint_caches *pjc = pgs->cie_joint_caches;
732
733 rc_unshare_struct(pgs->cie_joint_caches, gx_cie_joint_caches,
734 &st_joint_caches, pgs->memory,
735 return 0, "gx_currentciecaches");
736 if (pgs->cie_joint_caches != pjc) {
737 pjc = pgs->cie_joint_caches;
738 pjc->cspace_id = pjc->render_id = gs_no_id;
739 pjc->id_status = pjc->status = CIE_JC_STATUS_BUILT;
740 }
741 return pjc;
742 }
743
744 /* Compute the parameters for loading a cache, setting base and factor. */
745 /* This procedure is idempotent. */
746 void
gs_cie_cache_init(cie_cache_params * pcache,gs_sample_loop_params_t * pslp,const gs_range * domain,client_name_t cname)747 gs_cie_cache_init(cie_cache_params * pcache, gs_sample_loop_params_t * pslp,
748 const gs_range * domain, client_name_t cname)
749 {
750 /*
751 We need to map the values in the range [domain->rmin..domain->rmax].
752 However, if rmin < 0 < rmax and the function is non-linear, this can
753 lead to anomalies at zero, which is the default value for CIE colors.
754 The "correct" way to approach this is to run the mapping functions on
755 demand, but we don't want to deal with the complexities of the
756 callbacks this would involve (especially in the middle of rendering
757 images); instead, we adjust the range so that zero maps precisely to a
758 cache slot. Define:
759
760 A = domain->rmin;
761 B = domain->rmax;
762 N = gx_cie_cache_size - 1;
763
764 R = B - A;
765 h(v) = N * (v - A) / R; // the index of v in the cache
766 X = h(0).
767
768 If X is not an integer, we can decrease A and/increase B to make it
769 one. Let A' and B' be the adjusted values of A and B respectively,
770 and let K be the integer derived from X (either floor(X) or ceil(X)).
771 Define
772
773 f(K) = (K * B' + (N - K) * A') / N).
774
775 We want f(K) = 0. This occurs precisely when, for any real number
776 C != 0,
777
778 A' = -K * C;
779 B' = (N - K) * C.
780
781 In order to ensure A' <= A and B' >= B, we require
782
783 C >= -A / K;
784 C >= B / (N - K).
785
786 Since A' and B' must be exactly representable as floats, we round C
787 upward to ensure that it has no more than M mantissa bits, where
788
789 M = ARCH_FLOAT_MANTISSA_BITS - ceil(log2(N)).
790 */
791 float A = domain->rmin, B = domain->rmax;
792 double R = B - A, delta;
793 #define NN (gx_cie_cache_size - 1) /* 'N' is a member name, see end of proc */
794 #define N NN
795 #define CEIL_LOG2_N CIE_LOG2_CACHE_SIZE
796
797 /* Adjust the range if necessary. */
798 if (A < 0 && B >= 0) {
799 const double X = -N * A / R; /* know X > 0 */
800 /* Choose K to minimize range expansion. */
801 const int K = (int)(A + B < 0 ? floor(X) : ceil(X)); /* know 0 < K < N */
802 const double Ca = -A / K, Cb = B / (N - K); /* know Ca, Cb > 0 */
803 double C = max(Ca, Cb); /* know C > 0 */
804 const int M = ARCH_FLOAT_MANTISSA_BITS - CEIL_LOG2_N;
805 int cexp;
806 const double cfrac = frexp(C, &cexp);
807
808 if_debug4('c', "[c]adjusting cache_init(%8g, %8g), X = %8g, K = %d:\n",
809 A, B, X, K);
810 /* Round C to no more than M significant bits. See above. */
811 C = ldexp(ceil(ldexp(cfrac, M)), cexp - M);
812 /* Finally, compute A' and B'. */
813 A = -K * C;
814 B = (N - K) * C;
815 if_debug2('c', "[c] => %8g, %8g\n", A, B);
816 R = B - A;
817 }
818 delta = R / N;
819 #ifdef CIE_CACHE_INTERPOLATE
820 pcache->base = A; /* no rounding */
821 #else
822 pcache->base = A - delta / 2; /* so lookup will round */
823 #endif
824 /*
825 * If size of the domain is zero, then use 1.0 as the scaling
826 * factor. This prevents divide by zero errors in later calculations.
827 * This should only occurs with zero matrices. It does occur with
828 * Genoa test file 050-01.ps.
829 */
830 pcache->factor = (any_abs(delta) < 1e-30 ? 1.0 : N / R);
831 if_debug4('c', "[c]cache %s 0x%lx base=%g, factor=%g\n",
832 (const char *)cname, (ulong) pcache,
833 pcache->base, pcache->factor);
834 pslp->A = A;
835 pslp->B = B;
836 #undef N
837 pslp->N = NN;
838 #undef NN
839 }
840
841 /* ------ Complete a rendering structure ------ */
842
843 /*
844 * Compute the derived values in a CRD that don't involve the cached
845 * procedure values. This procedure is idempotent.
846 */
847 private void cie_transform_range3(const gs_range3 *, const gs_matrix3 *,
848 gs_range3 *);
849 int
gs_cie_render_init(gs_cie_render * pcrd)850 gs_cie_render_init(gs_cie_render * pcrd)
851 {
852 gs_matrix3 PQR_inverse;
853
854 if (pcrd->status >= CIE_RENDER_STATUS_INITED)
855 return 0; /* init already done */
856 if_debug_matrix3("[c]CRD MatrixLMN =", &pcrd->MatrixLMN);
857 cie_matrix_init(&pcrd->MatrixLMN);
858 if_debug_matrix3("[c]CRD MatrixABC =", &pcrd->MatrixABC);
859 cie_matrix_init(&pcrd->MatrixABC);
860 if_debug_matrix3("[c]CRD MatrixPQR =", &pcrd->MatrixPQR);
861 cie_matrix_init(&pcrd->MatrixPQR);
862 cie_invert3(&pcrd->MatrixPQR, &PQR_inverse);
863 cie_matrix_mult3(&pcrd->MatrixLMN, &PQR_inverse,
864 &pcrd->MatrixPQR_inverse_LMN);
865 cie_transform_range3(&pcrd->RangePQR, &pcrd->MatrixPQR_inverse_LMN,
866 &pcrd->DomainLMN);
867 cie_transform_range3(&pcrd->RangeLMN, &pcrd->MatrixABC,
868 &pcrd->DomainABC);
869 cie_mult3(&pcrd->points.WhitePoint, &pcrd->MatrixPQR, &pcrd->wdpqr);
870 cie_mult3(&pcrd->points.BlackPoint, &pcrd->MatrixPQR, &pcrd->bdpqr);
871 pcrd->status = CIE_RENDER_STATUS_INITED;
872 return 0;
873 }
874
875 /*
876 * Sample the EncodeLMN, EncodeABC, and RenderTableT CRD procedures, and
877 * load the caches. This procedure is idempotent.
878 */
879 int
gs_cie_render_sample(gs_cie_render * pcrd)880 gs_cie_render_sample(gs_cie_render * pcrd)
881 {
882 int code;
883
884 if (pcrd->status >= CIE_RENDER_STATUS_SAMPLED)
885 return 0; /* sampling already done */
886 code = gs_cie_render_init(pcrd);
887 if (code < 0)
888 return code;
889 CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeLMN.caches, pcrd->DomainLMN.ranges,
890 &pcrd->EncodeLMN, Encode_default, pcrd, "EncodeLMN");
891 cache3_set_linear(&pcrd->caches.EncodeLMN);
892 CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeABC, pcrd->DomainABC.ranges,
893 &pcrd->EncodeABC, Encode_default, pcrd, "EncodeABC");
894 if (pcrd->RenderTable.lookup.table != 0) {
895 int i, j, m = pcrd->RenderTable.lookup.m;
896 gs_sample_loop_params_t lp;
897 bool is_identity = true;
898
899 for (j = 0; j < m; j++) {
900 gs_cie_cache_init(&pcrd->caches.RenderTableT[j].fracs.params,
901 &lp, &Range3_default.ranges[0],
902 "RenderTableT");
903 is_identity &= pcrd->RenderTable.T.procs[j] ==
904 RenderTableT_default.procs[j];
905 }
906 pcrd->caches.RenderTableT_is_identity = is_identity;
907 /*
908 * Unfortunately, we defined the first argument of the RenderTable
909 * T procedures as being a byte, limiting the number of distinct
910 * cache entries to 256 rather than gx_cie_cache_size.
911 * We confine this decision to this loop, rather than propagating
912 * it to the procedures that use the cached data, so that we can
913 * change it more easily at some future time.
914 */
915 for (i = 0; i < gx_cie_cache_size; i++) {
916 #if gx_cie_log2_cache_size >= 8
917 byte value = i >> (gx_cie_log2_cache_size - 8);
918 #else
919 byte value = (i << (8 - gx_cie_log2_cache_size)) +
920 (i >> (gx_cie_log2_cache_size * 2 - 8));
921 #endif
922 for (j = 0; j < m; j++) {
923 pcrd->caches.RenderTableT[j].fracs.values[i] =
924 (*pcrd->RenderTable.T.procs[j])(value, pcrd);
925 if_debug3('C', "[C]RenderTableT[%d,%d] = %g\n",
926 i, j,
927 frac2float(pcrd->caches.RenderTableT[j].fracs.values[i]));
928 }
929 }
930 }
931 pcrd->status = CIE_RENDER_STATUS_SAMPLED;
932 return 0;
933 }
934
935 /* Transform a set of ranges. */
936 private void
cie_transform_range(const gs_range3 * in,floatp mu,floatp mv,floatp mw,gs_range * out)937 cie_transform_range(const gs_range3 * in, floatp mu, floatp mv, floatp mw,
938 gs_range * out)
939 {
940 float umin = mu * in->ranges[0].rmin, umax = mu * in->ranges[0].rmax;
941 float vmin = mv * in->ranges[1].rmin, vmax = mv * in->ranges[1].rmax;
942 float wmin = mw * in->ranges[2].rmin, wmax = mw * in->ranges[2].rmax;
943 float temp;
944
945 if (umin > umax)
946 temp = umin, umin = umax, umax = temp;
947 if (vmin > vmax)
948 temp = vmin, vmin = vmax, vmax = temp;
949 if (wmin > wmax)
950 temp = wmin, wmin = wmax, wmax = temp;
951 out->rmin = umin + vmin + wmin;
952 out->rmax = umax + vmax + wmax;
953 }
954 private void
cie_transform_range3(const gs_range3 * in,const gs_matrix3 * mat,gs_range3 * out)955 cie_transform_range3(const gs_range3 * in, const gs_matrix3 * mat,
956 gs_range3 * out)
957 {
958 cie_transform_range(in, mat->cu.u, mat->cv.u, mat->cw.u,
959 &out->ranges[0]);
960 cie_transform_range(in, mat->cu.v, mat->cv.v, mat->cw.v,
961 &out->ranges[1]);
962 cie_transform_range(in, mat->cu.w, mat->cv.w, mat->cw.w,
963 &out->ranges[2]);
964 }
965
966 /*
967 * Finish preparing a CRD for installation, by restricting and/or
968 * transforming the cached procedure values.
969 * This procedure is idempotent.
970 */
971 int
gs_cie_render_complete(gs_cie_render * pcrd)972 gs_cie_render_complete(gs_cie_render * pcrd)
973 {
974 int code;
975
976 if (pcrd->status >= CIE_RENDER_STATUS_COMPLETED)
977 return 0; /* completion already done */
978 code = gs_cie_render_sample(pcrd);
979 if (code < 0)
980 return code;
981 /*
982 * Since range restriction happens immediately after
983 * the cache lookup, we can save a step by restricting
984 * the values in the cache entries.
985 *
986 * If there is no lookup table, we want the final ABC values
987 * to be fracs; if there is a table, we want them to be
988 * appropriately scaled ints.
989 */
990 pcrd->MatrixABCEncode = pcrd->MatrixABC;
991 {
992 int c;
993 double f;
994
995 for (c = 0; c < 3; c++) {
996 gx_cie_float_fixed_cache *pcache = &pcrd->caches.EncodeABC[c];
997
998 cie_cache_restrict(&pcrd->caches.EncodeLMN.caches[c].floats,
999 &pcrd->RangeLMN.ranges[c]);
1000 cie_cache_restrict(&pcrd->caches.EncodeABC[c].floats,
1001 &pcrd->RangeABC.ranges[c]);
1002 if (pcrd->RenderTable.lookup.table == 0) {
1003 cie_cache_restrict(&pcache->floats,
1004 &Range3_default.ranges[0]);
1005 gs_cie_cache_to_fracs(&pcache->floats, &pcache->fixeds.fracs);
1006 pcache->fixeds.fracs.params.is_identity = false;
1007 } else {
1008 int i;
1009 int n = pcrd->RenderTable.lookup.dims[c];
1010
1011 #ifdef CIE_RENDER_TABLE_INTERPOLATE
1012 # define SCALED_INDEX(f, n, itemp)\
1013 RESTRICTED_INDEX(f * (1 << _cie_interpolate_bits),\
1014 (n) << _cie_interpolate_bits, itemp)
1015 #else
1016 int m = pcrd->RenderTable.lookup.m;
1017 int k =
1018 (c == 0 ? 1 : c == 1 ?
1019 m * pcrd->RenderTable.lookup.dims[2] : m);
1020 # define SCALED_INDEX(f, n, itemp)\
1021 (RESTRICTED_INDEX(f, n, itemp) * k)
1022 #endif
1023 const gs_range *prange = pcrd->RangeABC.ranges + c;
1024 double scale = (n - 1) / (prange->rmax - prange->rmin);
1025
1026 for (i = 0; i < gx_cie_cache_size; ++i) {
1027 float v =
1028 (pcache->floats.values[i] - prange->rmin) * scale
1029 #ifndef CIE_RENDER_TABLE_INTERPOLATE
1030 + 0.5
1031 #endif
1032 ;
1033 int itemp;
1034
1035 if_debug5('c',
1036 "[c]cache[%d][%d] = %g => %g => %d\n",
1037 c, i, pcache->floats.values[i], v,
1038 SCALED_INDEX(v, n, itemp));
1039 pcache->fixeds.ints.values[i] =
1040 SCALED_INDEX(v, n, itemp);
1041 }
1042 pcache->fixeds.ints.params = pcache->floats.params;
1043 pcache->fixeds.ints.params.is_identity = false;
1044 #undef SCALED_INDEX
1045 }
1046 }
1047 /* Fold the scaling of the EncodeABC cache index */
1048 /* into MatrixABC. */
1049 #define MABC(i, t)\
1050 f = pcrd->caches.EncodeABC[i].floats.params.factor;\
1051 pcrd->MatrixABCEncode.cu.t *= f;\
1052 pcrd->MatrixABCEncode.cv.t *= f;\
1053 pcrd->MatrixABCEncode.cw.t *= f;\
1054 pcrd->EncodeABC_base[i] =\
1055 float2cie_cached(pcrd->caches.EncodeABC[i].floats.params.base * f)
1056 MABC(0, u);
1057 MABC(1, v);
1058 MABC(2, w);
1059 #undef MABC
1060 pcrd->MatrixABCEncode.is_identity = 0;
1061 }
1062 cie_cache_mult3(&pcrd->caches.EncodeLMN, &pcrd->MatrixABCEncode,
1063 CACHE_THRESHOLD);
1064 pcrd->status = CIE_RENDER_STATUS_COMPLETED;
1065 return 0;
1066 }
1067
1068 /* Apply a range restriction to a cache. */
1069 private void
cie_cache_restrict(cie_cache_floats * pcache,const gs_range * prange)1070 cie_cache_restrict(cie_cache_floats * pcache, const gs_range * prange)
1071 {
1072 int i;
1073
1074 for (i = 0; i < gx_cie_cache_size; i++) {
1075 float v = pcache->values[i];
1076
1077 if (v < prange->rmin)
1078 pcache->values[i] = prange->rmin;
1079 else if (v > prange->rmax)
1080 pcache->values[i] = prange->rmax;
1081 }
1082 }
1083
1084 /* Convert a cache from floats to fracs. */
1085 /* Note that the two may be aliased. */
1086 void
gs_cie_cache_to_fracs(const cie_cache_floats * pfloats,cie_cache_fracs * pfracs)1087 gs_cie_cache_to_fracs(const cie_cache_floats *pfloats, cie_cache_fracs *pfracs)
1088 {
1089 int i;
1090
1091 /* Loop from bottom to top so that we don't */
1092 /* overwrite elements before they're used. */
1093 for (i = 0; i < gx_cie_cache_size; ++i)
1094 pfracs->values[i] = float2frac(pfloats->values[i]);
1095 pfracs->params = pfloats->params;
1096 }
1097
1098 /* ------ Fill in the joint cache ------ */
1099
1100 /* If the current color space is a CIE space, or has a CIE base space, */
1101 /* return a pointer to the common part of the space; otherwise return 0. */
1102 private const gs_cie_common *
cie_cs_common_abc(const gs_color_space * pcs_orig,const gs_cie_abc ** ppabc)1103 cie_cs_common_abc(const gs_color_space *pcs_orig, const gs_cie_abc **ppabc)
1104 {
1105 const gs_color_space *pcs = pcs_orig;
1106
1107 *ppabc = 0;
1108 do {
1109 switch (pcs->type->index) {
1110 case gs_color_space_index_CIEDEF:
1111 *ppabc = (const gs_cie_abc *)pcs->params.def;
1112 return &pcs->params.def->common;
1113 case gs_color_space_index_CIEDEFG:
1114 *ppabc = (const gs_cie_abc *)pcs->params.defg;
1115 return &pcs->params.defg->common;
1116 case gs_color_space_index_CIEABC:
1117 *ppabc = pcs->params.abc;
1118 return &pcs->params.abc->common;
1119 case gs_color_space_index_CIEA:
1120 return &pcs->params.a->common;
1121 case gs_color_space_index_CIEICC:
1122 return &pcs->params.icc.picc_info->common;
1123 default:
1124 pcs = gs_cspace_base_space(pcs);
1125 break;
1126 }
1127 } while (pcs != 0);
1128
1129 return 0;
1130 }
1131 const gs_cie_common *
gs_cie_cs_common(const gs_state * pgs)1132 gs_cie_cs_common(const gs_state * pgs)
1133 {
1134 const gs_cie_abc *ignore_pabc;
1135
1136 return cie_cs_common_abc(pgs->color_space, &ignore_pabc);
1137 }
1138
1139 /*
1140 * Mark the joint caches as needing completion. This is done lazily,
1141 * when a color is being mapped. However, make sure the joint caches
1142 * exist now.
1143 */
1144 int
gs_cie_cs_complete(gs_state * pgs,bool init)1145 gs_cie_cs_complete(gs_state * pgs, bool init)
1146 {
1147 gx_cie_joint_caches *pjc = gx_currentciecaches(pgs);
1148
1149 if (pjc == 0)
1150 return_error(gs_error_VMerror);
1151 pjc->status = (init ? CIE_JC_STATUS_BUILT : CIE_JC_STATUS_INITED);
1152 return 0;
1153 }
1154 /* Actually complete the joint caches. */
1155 int
gs_cie_jc_complete(const gs_imager_state * pis,const gs_color_space * pcs)1156 gs_cie_jc_complete(const gs_imager_state *pis, const gs_color_space *pcs)
1157 {
1158 const gs_cie_abc *pabc;
1159 const gs_cie_common *common = cie_cs_common_abc(pcs, &pabc);
1160 gs_cie_render *pcrd = pis->cie_render;
1161 gx_cie_joint_caches *pjc = pis->cie_joint_caches;
1162
1163 if (pjc->cspace_id == pcs->id &&
1164 pjc->render_id == pcrd->id)
1165 pjc->status = pjc->id_status;
1166 switch (pjc->status) {
1167 case CIE_JC_STATUS_BUILT: {
1168 int code = cie_joint_caches_init(pjc, common, pcrd);
1169
1170 if (code < 0)
1171 return code;
1172 }
1173 /* falls through */
1174 case CIE_JC_STATUS_INITED:
1175 cie_joint_caches_complete(pjc, common, pabc, pcrd);
1176 pjc->cspace_id = pcs->id;
1177 pjc->render_id = pcrd->id;
1178 pjc->id_status = pjc->status = CIE_JC_STATUS_COMPLETED;
1179 /* falls through */
1180 case CIE_JC_STATUS_COMPLETED:
1181 break;
1182 }
1183 return 0;
1184 }
1185
1186 /*
1187 * Compute the source and destination WhitePoint and BlackPoint for
1188 * the TransformPQR procedure.
1189 */
1190 int
gs_cie_compute_points_sd(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,const gs_cie_render * pcrd)1191 gs_cie_compute_points_sd(gx_cie_joint_caches *pjc,
1192 const gs_cie_common * pcie,
1193 const gs_cie_render * pcrd)
1194 {
1195 gs_cie_wbsd *pwbsd = &pjc->points_sd;
1196
1197 pwbsd->ws.xyz = pcie->points.WhitePoint;
1198 cie_mult3(&pwbsd->ws.xyz, &pcrd->MatrixPQR, &pwbsd->ws.pqr);
1199 pwbsd->bs.xyz = pcie->points.BlackPoint;
1200 cie_mult3(&pwbsd->bs.xyz, &pcrd->MatrixPQR, &pwbsd->bs.pqr);
1201 pwbsd->wd.xyz = pcrd->points.WhitePoint;
1202 pwbsd->wd.pqr = pcrd->wdpqr;
1203 pwbsd->bd.xyz = pcrd->points.BlackPoint;
1204 pwbsd->bd.pqr = pcrd->bdpqr;
1205 return 0;
1206 }
1207
1208 /*
1209 * Sample the TransformPQR procedure for the joint caches.
1210 * This routine is idempotent.
1211 */
1212 private int
cie_joint_caches_init(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,gs_cie_render * pcrd)1213 cie_joint_caches_init(gx_cie_joint_caches * pjc,
1214 const gs_cie_common * pcie,
1215 gs_cie_render * pcrd)
1216 {
1217 bool is_identity;
1218 int j;
1219
1220 gs_cie_compute_points_sd(pjc, pcie, pcrd);
1221 /*
1222 * If a client pre-loaded the cache, we can't adjust the range.
1223 * ****** WRONG ******
1224 */
1225 if (pcrd->TransformPQR.proc == TransformPQR_from_cache.proc)
1226 return 0;
1227 is_identity = pcrd->TransformPQR.proc == TransformPQR_default.proc;
1228 for (j = 0; j < 3; j++) {
1229 int i;
1230 gs_sample_loop_params_t lp;
1231
1232 gs_cie_cache_init(&pjc->TransformPQR.caches[j].floats.params, &lp,
1233 &pcrd->RangePQR.ranges[j], "TransformPQR");
1234 for (i = 0; i <= lp.N; ++i) {
1235 float in = SAMPLE_LOOP_VALUE(i, lp);
1236 float out;
1237 int code = (*pcrd->TransformPQR.proc)(j, in, &pjc->points_sd,
1238 pcrd, &out);
1239
1240 if (code < 0)
1241 return code;
1242 pjc->TransformPQR.caches[j].floats.values[i] = out;
1243 if_debug4('C', "[C]TransformPQR[%d,%d] = %g => %g\n",
1244 j, i, in, out);
1245 }
1246 pjc->TransformPQR.caches[j].floats.params.is_identity = is_identity;
1247 }
1248 return 0;
1249 }
1250
1251 /*
1252 * Complete the loading of the joint caches.
1253 * This routine is idempotent.
1254 */
1255 private void
cie_joint_caches_complete(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,const gs_cie_abc * pabc,const gs_cie_render * pcrd)1256 cie_joint_caches_complete(gx_cie_joint_caches * pjc,
1257 const gs_cie_common * pcie,
1258 const gs_cie_abc * pabc /* NULL if CIEA */,
1259 const gs_cie_render * pcrd)
1260 {
1261 gs_matrix3 mat3, mat2;
1262 gs_matrix3 MatrixLMN_PQR;
1263 int j;
1264
1265 pjc->remap_finish = gx_cie_real_remap_finish;
1266
1267 /*
1268 * We number the pipeline steps as follows:
1269 * 1 - DecodeABC/MatrixABC
1270 * 2 - DecodeLMN/MatrixLMN/MatrixPQR
1271 * 3 - TransformPQR/MatrixPQR'/MatrixLMN
1272 * 4 - EncodeLMN/MatrixABC
1273 * 5 - EncodeABC, RenderTable (we don't do anything with this here)
1274 * We work from back to front, combining steps where possible.
1275 * Currently we only combine steps if a procedure is the identity
1276 * transform, but we could do it whenever the procedure is linear.
1277 * A project for another day....
1278 */
1279
1280 /* Step 4 */
1281
1282 #ifdef OPTIMIZE_CIE_MAPPING
1283 if (pcrd->caches.EncodeLMN.caches[0].floats.params.is_identity &&
1284 pcrd->caches.EncodeLMN.caches[1].floats.params.is_identity &&
1285 pcrd->caches.EncodeLMN.caches[2].floats.params.is_identity
1286 ) {
1287 /* Fold step 4 into step 3. */
1288 if_debug0('c', "[c]EncodeLMN is identity, folding MatrixABC(Encode) into MatrixPQR'+LMN.\n");
1289 cie_matrix_mult3(&pcrd->MatrixABCEncode, &pcrd->MatrixPQR_inverse_LMN,
1290 &mat3);
1291 pjc->skipEncodeLMN = true;
1292 } else
1293 #endif /* OPTIMIZE_CIE_MAPPING */
1294 {
1295 if_debug0('c', "[c]EncodeLMN is not identity.\n");
1296 mat3 = pcrd->MatrixPQR_inverse_LMN;
1297 pjc->skipEncodeLMN = false;
1298 }
1299
1300 /* Step 3 */
1301
1302 cache3_set_linear(&pjc->TransformPQR);
1303 cie_matrix_mult3(&pcrd->MatrixPQR, &pcie->MatrixLMN,
1304 &MatrixLMN_PQR);
1305
1306 #ifdef OPTIMIZE_CIE_MAPPING
1307 if (pjc->TransformPQR.caches[0].floats.params.is_identity &
1308 pjc->TransformPQR.caches[1].floats.params.is_identity &
1309 pjc->TransformPQR.caches[2].floats.params.is_identity
1310 ) {
1311 /* Fold step 3 into step 2. */
1312 if_debug0('c', "[c]TransformPQR is identity, folding MatrixPQR'+LMN into MatrixLMN+PQR.\n");
1313 cie_matrix_mult3(&mat3, &MatrixLMN_PQR, &mat2);
1314 pjc->skipPQR = true;
1315 } else
1316 #endif /* OPTIMIZE_CIE_MAPPING */
1317 {
1318 if_debug0('c', "[c]TransformPQR is not identity.\n");
1319 mat2 = MatrixLMN_PQR;
1320 for (j = 0; j < 3; j++) {
1321 cie_cache_restrict(&pjc->TransformPQR.caches[j].floats,
1322 &pcrd->RangePQR.ranges[j]);
1323 }
1324 cie_cache_mult3(&pjc->TransformPQR, &mat3, CACHE_THRESHOLD);
1325 pjc->skipPQR = false;
1326 }
1327
1328 /* Steps 2 & 1 */
1329
1330 #ifdef OPTIMIZE_CIE_MAPPING
1331 if (pcie->caches.DecodeLMN[0].floats.params.is_identity &
1332 pcie->caches.DecodeLMN[1].floats.params.is_identity &
1333 pcie->caches.DecodeLMN[2].floats.params.is_identity
1334 ) {
1335 if_debug0('c', "[c]DecodeLMN is identity, folding MatrixLMN+PQR into MatrixABC.\n");
1336 if (!pabc) {
1337 pjc->skipDecodeLMN = mat2.is_identity;
1338 pjc->skipDecodeABC = false;
1339 if (!pjc->skipDecodeLMN) {
1340 for (j = 0; j < 3; j++) {
1341 cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat2.cu + j,
1342 &pcie->caches.DecodeLMN[j].floats,
1343 CACHE_THRESHOLD);
1344 }
1345 cie_cache3_set_interpolation(&pjc->DecodeLMN);
1346 }
1347 } else {
1348 /*
1349 * Fold step 2 into step 1. This is a little different because
1350 * the data for step 1 are in the color space structure.
1351 */
1352 gs_matrix3 mat1;
1353
1354 cie_matrix_mult3(&mat2, &pabc->MatrixABC, &mat1);
1355 for (j = 0; j < 3; j++) {
1356 cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat1.cu + j,
1357 &pabc->caches.DecodeABC.caches[j].floats,
1358 CACHE_THRESHOLD);
1359 }
1360 cie_cache3_set_interpolation(&pjc->DecodeLMN);
1361 pjc->skipDecodeLMN = false;
1362 pjc->skipDecodeABC = true;
1363 }
1364 } else
1365 #endif /* OPTIMIZE_CIE_MAPPING */
1366 {
1367 if_debug0('c', "[c]DecodeLMN is not identity.\n");
1368 for (j = 0; j < 3; j++) {
1369 cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat2.cu + j,
1370 &pcie->caches.DecodeLMN[j].floats,
1371 CACHE_THRESHOLD);
1372 }
1373 cie_cache3_set_interpolation(&pjc->DecodeLMN);
1374 pjc->skipDecodeLMN = false;
1375 pjc->skipDecodeABC = pabc != 0 && pabc->caches.skipABC;
1376 }
1377
1378 }
1379
1380 /*
1381 * Initialize (just enough of) an imager state so that "concretizing" colors
1382 * using this imager state will do only the CIE->XYZ mapping. This is a
1383 * semi-hack for the PDF writer.
1384 */
1385 int
gx_cie_to_xyz_alloc(gs_imager_state ** ppis,const gs_color_space * pcs,gs_memory_t * mem)1386 gx_cie_to_xyz_alloc(gs_imager_state **ppis, const gs_color_space *pcs,
1387 gs_memory_t *mem)
1388 {
1389 /*
1390 * In addition to the imager state itself, we need the joint caches.
1391 */
1392 gs_imager_state *pis =
1393 gs_alloc_struct(mem, gs_imager_state, &st_imager_state,
1394 "gx_cie_to_xyz_alloc(imager state)");
1395 gx_cie_joint_caches *pjc;
1396 const gs_cie_abc *pabc;
1397 const gs_cie_common *pcie = cie_cs_common_abc(pcs, &pabc);
1398 int j;
1399
1400 if (pis == 0)
1401 return_error(gs_error_VMerror);
1402 memset(pis, 0, sizeof(*pis)); /* mostly paranoia */
1403 pis->memory = mem;
1404
1405 pjc = gs_alloc_struct(mem, gx_cie_joint_caches, &st_joint_caches,
1406 "gx_cie_to_xyz_free(joint caches)");
1407 if (pjc == 0) {
1408 gs_free_object(mem, pis, "gx_cie_to_xyz_alloc(imager state)");
1409 return_error(gs_error_VMerror);
1410 }
1411
1412 /*
1413 * Perform an abbreviated version of cie_joint_caches_complete.
1414 * Don't bother with any optimizations.
1415 */
1416 for (j = 0; j < 3; j++) {
1417 cie_cache_mult(&pjc->DecodeLMN.caches[j], &pcie->MatrixLMN.cu + j,
1418 &pcie->caches.DecodeLMN[j].floats,
1419 CACHE_THRESHOLD);
1420 }
1421 cie_cache3_set_interpolation(&pjc->DecodeLMN);
1422 pjc->skipDecodeLMN = false;
1423 pjc->skipDecodeABC = pabc != 0 && pabc->caches.skipABC;
1424 /* Mark the joint caches as completed. */
1425 pjc->remap_finish = gx_cie_xyz_remap_finish;
1426 pjc->status = CIE_JC_STATUS_COMPLETED;
1427 pis->cie_joint_caches = pjc;
1428 /*
1429 * Set a non-zero CRD to pacify CIE_CHECK_RENDERING. (It will never
1430 * actually be referenced, aside from the zero test.)
1431 */
1432 pis->cie_render = (void *)~0;
1433 *ppis = pis;
1434 return 0;
1435 }
1436 void
gx_cie_to_xyz_free(gs_imager_state * pis)1437 gx_cie_to_xyz_free(gs_imager_state *pis)
1438 {
1439 gs_memory_t *mem = pis->memory;
1440
1441 gs_free_object(mem, pis->cie_joint_caches,
1442 "gx_cie_to_xyz_free(joint caches)");
1443 gs_free_object(mem, pis, "gx_cie_to_xyz_free(imager state)");
1444 }
1445
1446 /* ================ Utilities ================ */
1447
1448 /* Multiply a vector by a matrix. */
1449 /* Note that we are computing M * V where v is a column vector. */
1450 private void
cie_mult3(const gs_vector3 * in,register const gs_matrix3 * mat,gs_vector3 * out)1451 cie_mult3(const gs_vector3 * in, register const gs_matrix3 * mat,
1452 gs_vector3 * out)
1453 {
1454 if_debug_vector3("[c]mult", in);
1455 if_debug_matrix3(" *", mat);
1456 {
1457 float u = in->u, v = in->v, w = in->w;
1458
1459 out->u = (u * mat->cu.u) + (v * mat->cv.u) + (w * mat->cw.u);
1460 out->v = (u * mat->cu.v) + (v * mat->cv.v) + (w * mat->cw.v);
1461 out->w = (u * mat->cu.w) + (v * mat->cv.w) + (w * mat->cw.w);
1462 }
1463 if_debug_vector3(" =", out);
1464 }
1465
1466 /*
1467 * Multiply two matrices. Note that the composition of the transformations
1468 * M1 followed by M2 is M2 * M1, not M1 * M2. (See gscie.h for details.)
1469 */
1470 private void
cie_matrix_mult3(const gs_matrix3 * ma,const gs_matrix3 * mb,gs_matrix3 * mc)1471 cie_matrix_mult3(const gs_matrix3 *ma, const gs_matrix3 *mb, gs_matrix3 *mc)
1472 {
1473 gs_matrix3 mprod;
1474 gs_matrix3 *mp = (mc == ma || mc == mb ? &mprod : mc);
1475
1476 if_debug_matrix3("[c]matrix_mult", ma);
1477 if_debug_matrix3(" *", mb);
1478 cie_mult3(&mb->cu, ma, &mp->cu);
1479 cie_mult3(&mb->cv, ma, &mp->cv);
1480 cie_mult3(&mb->cw, ma, &mp->cw);
1481 cie_matrix_init(mp);
1482 if_debug_matrix3(" =", mp);
1483 if (mp != mc)
1484 *mc = *mp;
1485 }
1486
1487 /* Invert a matrix. */
1488 /* The output must not be an alias for the input. */
1489 private void
cie_invert3(const gs_matrix3 * in,gs_matrix3 * out)1490 cie_invert3(const gs_matrix3 *in, gs_matrix3 *out)
1491 { /* This is a brute force algorithm; maybe there are better. */
1492 /* We label the array elements */
1493 /* [ A B C ] */
1494 /* [ D E F ] */
1495 /* [ G H I ] */
1496 #define A cu.u
1497 #define B cv.u
1498 #define C cw.u
1499 #define D cu.v
1500 #define E cv.v
1501 #define F cw.v
1502 #define G cu.w
1503 #define H cv.w
1504 #define I cw.w
1505 double coA = in->E * in->I - in->F * in->H;
1506 double coB = in->F * in->G - in->D * in->I;
1507 double coC = in->D * in->H - in->E * in->G;
1508 double det = in->A * coA + in->B * coB + in->C * coC;
1509
1510 if_debug_matrix3("[c]invert", in);
1511 out->A = coA / det;
1512 out->D = coB / det;
1513 out->G = coC / det;
1514 out->B = (in->C * in->H - in->B * in->I) / det;
1515 out->E = (in->A * in->I - in->C * in->G) / det;
1516 out->H = (in->B * in->G - in->A * in->H) / det;
1517 out->C = (in->B * in->F - in->C * in->E) / det;
1518 out->F = (in->C * in->D - in->A * in->F) / det;
1519 out->I = (in->A * in->E - in->B * in->D) / det;
1520 if_debug_matrix3(" =", out);
1521 #undef A
1522 #undef B
1523 #undef C
1524 #undef D
1525 #undef E
1526 #undef F
1527 #undef G
1528 #undef H
1529 #undef I
1530 out->is_identity = in->is_identity;
1531 }
1532
1533 /* Set the is_identity flag that accelerates multiplication. */
1534 private void
cie_matrix_init(register gs_matrix3 * mat)1535 cie_matrix_init(register gs_matrix3 * mat)
1536 {
1537 mat->is_identity =
1538 mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
1539 mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
1540 mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
1541 }
1542