1 /* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
3 This file is part of GNU Ghostscript.
5 GNU Ghostscript is distributed in the hope that it will be useful, but
6 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
7 to anyone for the consequences of using it or for whether it serves any
8 particular purpose or works at all, unless he says so in writing. Refer
9 to the GNU General Public License for full details.
11 Everyone is granted permission to copy, modify and redistribute GNU
12 Ghostscript, but only under the conditions described in the GNU General
13 Public License. A copy of this license is supposed to have been given
14 to you along with GNU Ghostscript so you can know your rights and
15 responsibilities. It should be in a file named COPYING. Among other
16 things, the copyright notice and this notice must be preserved on all
19 Aladdin Enterprises supports the work of the GNU Project, but is not
20 affiliated with the Free Software Foundation or the GNU Project. GNU
21 Ghostscript, as distributed by Aladdin Enterprises, does not require any
22 GNU software to build or run it.
25 /*$Id: gscrdp.c,v 1.2 2000/10/13 01:04:41 mike Exp $ */
26 /* CIE color rendering dictionary creation */
32 #include "gsmatrix.h" /* for gscolor2.h */
34 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
38 /* Define the CRD type that we use here. */
41 /* ---------------- Writing ---------------- */
43 /* Internal procedures for writing parameter values. */
45 store_vector3(float *p
, const gs_vector3
* pvec
)
47 p
[0] = pvec
->u
, p
[1] = pvec
->v
, p
[2] = pvec
->w
;
50 write_floats(gs_param_list
* plist
, gs_param_name key
,
51 const float *values
, int size
, gs_memory_t
* mem
)
54 gs_alloc_byte_array(mem
, size
, sizeof(float), "write_floats");
55 gs_param_float_array fa
;
58 return_error(gs_error_VMerror
);
59 memcpy(p
, values
, size
* sizeof(float));
64 return param_write_float_array(plist
, key
, &fa
);
67 write_vector3(gs_param_list
* plist
, gs_param_name key
,
68 const gs_vector3
* pvec
, gs_memory_t
* mem
)
72 store_vector3(values
, pvec
);
73 return write_floats(plist
, key
, values
, 3, mem
);
76 write_matrix3(gs_param_list
* plist
, gs_param_name key
,
77 const gs_matrix3
* pmat
, gs_memory_t
* mem
)
81 if (!memcmp(pmat
, &Matrix3_default
, sizeof(*pmat
)))
83 store_vector3(values
, &pmat
->cu
);
84 store_vector3(values
+ 3, &pmat
->cv
);
85 store_vector3(values
+ 6, &pmat
->cw
);
86 return write_floats(plist
, key
, values
, 9, mem
);
89 write_range3(gs_param_list
* plist
, gs_param_name key
,
90 const gs_range3
* prange
, gs_memory_t
* mem
)
94 if (!memcmp(prange
, &Range3_default
, sizeof(*prange
)))
96 values
[0] = prange
->ranges
[0].rmin
, values
[1] = prange
->ranges
[0].rmax
;
97 values
[2] = prange
->ranges
[1].rmin
, values
[3] = prange
->ranges
[1].rmax
;
98 values
[4] = prange
->ranges
[2].rmin
, values
[5] = prange
->ranges
[2].rmax
;
99 return write_floats(plist
, key
, values
, 6, mem
);
102 write_proc3(gs_param_list
* plist
, gs_param_name key
,
103 const gs_cie_render
* pcrd
, const gs_cie_render_proc3
* procs
,
104 const gs_range3
* domain
, gs_memory_t
* mem
)
107 uint size
= gx_cie_cache_size
;
108 gs_param_float_array fa
;
111 if (!memcmp(procs
, &Encode_default
, sizeof(*procs
)))
113 values
= (float *)gs_alloc_byte_array(mem
, size
* 3, sizeof(float),
117 return_error(gs_error_VMerror
);
118 for (i
= 0; i
< 3; ++i
) {
119 double base
= domain
->ranges
[i
].rmin
;
120 double scale
= (domain
->ranges
[i
].rmax
- base
) / (size
- 1);
123 for (j
= 0; j
< size
; ++j
)
124 values
[i
* size
+ j
] =
125 (*procs
->procs
[i
]) (j
* scale
+ base
, pcrd
);
129 fa
.persistent
= true;
130 return param_write_float_array(plist
, key
, &fa
);
133 /* Write a CRD as a device parameter. */
135 param_write_cie_render1(gs_param_list
* plist
, gs_param_name key
,
136 const gs_cie_render
* pcrd
, gs_memory_t
* mem
)
142 if ((code
= param_begin_write_dict(plist
, key
, &dict
, false)) < 0)
144 code
= param_put_cie_render1(dict
.list
, pcrd
, mem
);
145 dcode
= param_end_write_dict(plist
, key
, &dict
);
146 return (code
< 0 ? code
: dcode
);
149 /* Write a CRD directly to a parameter list. */
151 param_put_cie_render1(gs_param_list
* plist
, const gs_cie_render
* pcrd
,
154 int crd_type
= CRD_TYPE
;
157 if (pcrd
->TransformPQR
.proc_name
) {
158 gs_param_string pn
, pd
;
160 param_string_from_string(pn
, pcrd
->TransformPQR
.proc_name
);
161 pn
.size
++; /* include terminating null */
162 pd
.data
= pcrd
->TransformPQR
.proc_data
.data
;
163 pd
.size
= pcrd
->TransformPQR
.proc_data
.size
;
164 pd
.persistent
= true; /****** WRONG ******/
165 if ((code
= param_write_name(plist
, "TransformPQRName", &pn
)) < 0 ||
166 (code
= param_write_string(plist
, "TransformPQRData", &pd
)) < 0
170 else if (pcrd
->TransformPQR
.proc
!= TransformPQR_default
.proc
) {
171 /* We have no way to represent the procedure, so return an error. */
172 return_error(gs_error_rangecheck
);
174 if ((code
= param_write_int(plist
, "ColorRenderingType", &crd_type
)) < 0 ||
175 (code
= write_vector3(plist
, "WhitePoint", &pcrd
->points
.WhitePoint
, mem
)) < 0
178 if (memcmp(&pcrd
->points
.BlackPoint
, &BlackPoint_default
,
179 sizeof(pcrd
->points
.BlackPoint
))) {
180 if ((code
= write_vector3(plist
, "BlackPoint", &pcrd
->points
.BlackPoint
, mem
)) < 0)
183 if ((code
= write_matrix3(plist
, "MatrixPQR", &pcrd
->MatrixPQR
, mem
)) < 0 ||
184 (code
= write_range3(plist
, "RangePQR", &pcrd
->RangePQR
, mem
)) < 0 ||
185 /* TransformPQR is handled separately */
186 (code
= write_matrix3(plist
, "MatrixLMN", &pcrd
->MatrixLMN
, mem
)) < 0 ||
187 (code
= write_proc3(plist
, "EncodeLMNValues", pcrd
,
188 &pcrd
->EncodeLMN
, &pcrd
->DomainLMN
, mem
)) < 0 ||
189 (code
= write_range3(plist
, "RangeLMN", &pcrd
->RangeLMN
, mem
)) < 0 ||
190 (code
= write_matrix3(plist
, "MatrixABC", &pcrd
->MatrixABC
, mem
)) < 0 ||
191 (code
= write_proc3(plist
, "EncodeABCValues", pcrd
,
192 &pcrd
->EncodeABC
, &pcrd
->DomainABC
, mem
)) < 0 ||
193 (code
= write_range3(plist
, "RangeABC", &pcrd
->RangeABC
, mem
)) < 0
196 if (pcrd
->RenderTable
.lookup
.table
) {
197 int n
= pcrd
->RenderTable
.lookup
.n
;
198 int m
= pcrd
->RenderTable
.lookup
.m
;
199 int na
= pcrd
->RenderTable
.lookup
.dims
[0];
201 gs_alloc_byte_array(mem
, n
+ 1, sizeof(int), "RenderTableSize");
204 * In principle, we should use gs_alloc_struct_array with a
205 * type descriptor for gs_param_string. However, it is widely
206 * assumed that parameter lists are transient, and don't require
207 * accurate GC information; so we can get away with allocating
208 * the string table as bytes.
210 gs_param_string
*table
=
212 gs_alloc_byte_array(mem
, na
, sizeof(gs_param_string
),
214 gs_param_int_array ia
;
216 if (size
== 0 || table
== 0)
217 code
= gs_note_error(gs_error_VMerror
);
219 memcpy(size
, pcrd
->RenderTable
.lookup
.dims
, sizeof(int) * n
);
224 ia
.persistent
= true;
225 code
= param_write_int_array(plist
, "RenderTableSize", &ia
);
228 gs_param_string_array sa
;
231 for (a
= 0; a
< na
; ++a
)
232 table
[a
].data
= pcrd
->RenderTable
.lookup
.table
[a
].data
,
233 table
[a
].size
= pcrd
->RenderTable
.lookup
.table
[a
].size
,
234 table
[a
].persistent
= true;
237 sa
.persistent
= true;
238 code
= param_write_string_array(plist
, "RenderTableTable", &sa
);
239 if (code
>= 0 && !pcrd
->caches
.RenderTableT_is_identity
) {
240 /****** WRITE RenderTableTValues LIKE write_proc3 ******/
241 uint size
= gx_cie_cache_size
;
243 (float *)gs_alloc_byte_array(mem
, size
* m
,
246 gs_param_float_array fa
;
250 return_error(gs_error_VMerror
);
251 for (i
= 0; i
< m
; ++i
) {
252 double scale
= 255.0 / (size
- 1);
255 for (j
= 0; j
< size
; ++j
)
256 values
[i
* size
+ j
] =
257 frac2float((*pcrd
->RenderTable
.T
.procs
[i
])
262 fa
.persistent
= true;
263 code
= param_write_float_array(plist
, "RenderTableTValues",
268 gs_free_object(mem
, table
, "RenderTableTable");
269 gs_free_object(mem
, size
, "RenderTableSize");
276 /* ---------------- Reading ---------------- */
278 /* Internal procedures for reading parameter values. */
280 load_vector3(gs_vector3
* pvec
, const float *p
)
282 pvec
->u
= p
[0], pvec
->v
= p
[1], pvec
->w
= p
[2];
285 read_floats(gs_param_list
* plist
, gs_param_name key
, float *values
, int count
)
287 gs_param_float_array fa
;
288 int code
= param_read_float_array(plist
, key
, &fa
);
292 if (fa
.size
!= count
)
293 return_error(gs_error_rangecheck
);
294 memcpy(values
, fa
.data
, sizeof(float) * count
);
299 read_vector3(gs_param_list
* plist
, gs_param_name key
,
300 gs_vector3
* pvec
, const gs_vector3
* dflt
)
303 int code
= read_floats(plist
, key
, values
, 3);
306 case 1: /* not defined */
311 load_vector3(pvec
, values
);
318 read_matrix3(gs_param_list
* plist
, gs_param_name key
, gs_matrix3
* pmat
)
321 int code
= read_floats(plist
, key
, values
, 9);
324 case 1: /* not defined */
325 *pmat
= Matrix3_default
;
328 load_vector3(&pmat
->cu
, values
);
329 load_vector3(&pmat
->cv
, values
+ 3);
330 load_vector3(&pmat
->cw
, values
+ 6);
337 read_range3(gs_param_list
* plist
, gs_param_name key
, gs_range3
* prange
)
340 int code
= read_floats(plist
, key
, values
, 6);
343 case 1: /* not defined */
344 *prange
= Range3_default
;
347 prange
->ranges
[0].rmin
= values
[0];
348 prange
->ranges
[0].rmax
= values
[1];
349 prange
->ranges
[1].rmin
= values
[2];
350 prange
->ranges
[1].rmax
= values
[3];
351 prange
->ranges
[2].rmin
= values
[4];
352 prange
->ranges
[2].rmax
= values
[5];
359 read_proc3(gs_param_list
* plist
, gs_param_name key
,
360 float values
[gx_cie_cache_size
* 3])
362 return read_floats(plist
, key
, values
, gx_cie_cache_size
* 3);
365 /* Read a CRD from a device parameter. */
367 gs_cie_render1_param_initialize(gs_cie_render
* pcrd
, gs_param_list
* plist
,
368 gs_param_name key
, gx_device
* dev
)
371 int code
= param_begin_read_dict(plist
, key
, &dict
, false);
376 code
= param_get_cie_render1(pcrd
, dict
.list
, dev
);
377 dcode
= param_end_read_dict(plist
, key
, &dict
);
382 gs_cie_render_init(pcrd
);
383 gs_cie_render_sample(pcrd
);
384 return gs_cie_render_complete(pcrd
);
387 /* Define the structure for passing Encode values as "client data". */
388 typedef struct encode_data_s
{
389 float lmn
[gx_cie_cache_size
* 3]; /* EncodeLMN */
390 float abc
[gx_cie_cache_size
* 3]; /* EncodeABC */
391 float t
[gx_cie_cache_size
* 4]; /* RenderTable.T */
394 /* Define procedures that retrieve the Encode values read from the list. */
396 encode_from_data(floatp v
, const float values
[gx_cie_cache_size
],
397 const gs_range
* range
)
399 return (v
<= range
->rmin
? values
[0] :
400 v
>= range
->rmax
? values
[gx_cie_cache_size
- 1] :
401 values
[(int)((v
- range
->rmin
) / (range
->rmax
- range
->rmin
) *
402 (gx_cie_cache_size
- 1) + 0.5)]);
405 * The repetitive boilerplate in the next 10 procedures really sticks in
406 * my craw, but I've got a mandate not to use macros....
409 encode_lmn_0_from_data(floatp v
, const gs_cie_render
* pcrd
)
411 const encode_data_t
*data
= pcrd
->client_data
;
413 return encode_from_data(v
, &data
->lmn
[0],
414 &pcrd
->DomainLMN
.ranges
[0]);
417 encode_lmn_1_from_data(floatp v
, const gs_cie_render
* pcrd
)
419 const encode_data_t
*data
= pcrd
->client_data
;
421 return encode_from_data(v
, &data
->lmn
[gx_cie_cache_size
],
422 &pcrd
->DomainLMN
.ranges
[1]);
425 encode_lmn_2_from_data(floatp v
, const gs_cie_render
* pcrd
)
427 const encode_data_t
*data
= pcrd
->client_data
;
429 return encode_from_data(v
, &data
->lmn
[gx_cie_cache_size
* 2],
430 &pcrd
->DomainLMN
.ranges
[2]);
433 encode_abc_0_from_data(floatp v
, const gs_cie_render
* pcrd
)
435 const encode_data_t
*data
= pcrd
->client_data
;
437 return encode_from_data(v
, &data
->abc
[0],
438 &pcrd
->DomainABC
.ranges
[0]);
441 encode_abc_1_from_data(floatp v
, const gs_cie_render
* pcrd
)
443 const encode_data_t
*data
= pcrd
->client_data
;
445 return encode_from_data(v
, &data
->abc
[gx_cie_cache_size
],
446 &pcrd
->DomainABC
.ranges
[1]);
449 encode_abc_2_from_data(floatp v
, const gs_cie_render
* pcrd
)
451 const encode_data_t
*data
= pcrd
->client_data
;
453 return encode_from_data(v
, &data
->abc
[gx_cie_cache_size
* 2],
454 &pcrd
->DomainABC
.ranges
[2]);
457 render_table_t_0_from_data(byte v
, const gs_cie_render
* pcrd
)
459 const encode_data_t
*data
= pcrd
->client_data
;
461 return float2frac(encode_from_data(v
/ 255.0,
463 &Range3_default
.ranges
[0]));
466 render_table_t_1_from_data(byte v
, const gs_cie_render
* pcrd
)
468 const encode_data_t
*data
= pcrd
->client_data
;
470 return float2frac(encode_from_data(v
/ 255.0,
471 &data
->t
[gx_cie_cache_size
],
472 &Range3_default
.ranges
[0]));
475 render_table_t_2_from_data(byte v
, const gs_cie_render
* pcrd
)
477 const encode_data_t
*data
= pcrd
->client_data
;
479 return float2frac(encode_from_data(v
/ 255.0,
480 &data
->t
[gx_cie_cache_size
* 2],
481 &Range3_default
.ranges
[0]));
484 render_table_t_3_from_data(byte v
, const gs_cie_render
* pcrd
)
486 const encode_data_t
*data
= pcrd
->client_data
;
488 return float2frac(encode_from_data(v
/ 255.0,
489 &data
->t
[gx_cie_cache_size
* 3],
490 &Range3_default
.ranges
[0]));
492 private const gs_cie_render_proc3 EncodeLMN_from_data
= {
493 {encode_lmn_0_from_data
, encode_lmn_1_from_data
, encode_lmn_2_from_data
}
495 private const gs_cie_render_proc3 EncodeABC_from_data
= {
496 {encode_abc_0_from_data
, encode_abc_1_from_data
, encode_abc_2_from_data
}
498 private const gs_cie_render_table_procs RenderTableT_from_data
= {
499 {render_table_t_0_from_data
, render_table_t_1_from_data
,
500 render_table_t_2_from_data
, render_table_t_3_from_data
504 /* Read a CRD directly from a parameter list. */
506 param_get_cie_render1(gs_cie_render
* pcrd
, gs_param_list
* plist
,
510 gs_param_int_array rt_size
;
512 int code
, code_lmn
, code_abc
, code_rt
, code_t
;
513 gs_param_string pname
, pdata
;
515 if ((code
= param_read_int(plist
, "ColorRenderingType", &crd_type
)) < 0 ||
516 crd_type
!= CRD_TYPE
||
517 (code
= read_vector3(plist
, "WhitePoint", &pcrd
->points
.WhitePoint
,
519 (code
= read_vector3(plist
, "BlackPoint", &pcrd
->points
.BlackPoint
,
520 &BlackPoint_default
)) < 0 ||
521 (code
= read_matrix3(plist
, "MatrixPQR", &pcrd
->MatrixPQR
)) < 0 ||
522 (code
= read_range3(plist
, "RangePQR", &pcrd
->RangePQR
)) < 0 ||
523 /* TransformPQR is handled specially below. */
524 (code
= read_matrix3(plist
, "MatrixLMN", &pcrd
->MatrixLMN
)) < 0 ||
526 read_proc3(plist
, "EncodeLMNValues", data
.lmn
)) < 0 ||
527 (code
= read_range3(plist
, "RangeLMN", &pcrd
->RangeLMN
)) < 0 ||
528 (code
= read_matrix3(plist
, "MatrixABC", &pcrd
->MatrixABC
)) < 0 ||
530 read_proc3(plist
, "EncodeABCValues", data
.abc
)) < 0 ||
531 (code
= read_range3(plist
, "RangeABC", &pcrd
->RangeABC
)) < 0
534 /* Handle the sampled functions. */
535 switch (code
= param_read_string(plist
, "TransformPQRName", &pname
)) {
538 case 1: /* missing */
539 pcrd
->TransformPQR
= TransformPQR_default
;
541 case 0: /* specified */
542 /* The procedure name must be null-terminated: */
543 /* see param_put_cie_render1 above. */
544 if (pname
.size
< 1 || pname
.data
[pname
.size
- 1] != 0)
545 return_error(gs_error_rangecheck
);
546 pcrd
->TransformPQR
.proc
= TransformPQR_lookup_proc_name
;
547 pcrd
->TransformPQR
.proc_name
= (char *)pname
.data
;
548 switch (code
= param_read_string(plist
, "TransformPQRData", &pdata
)) {
551 case 1: /* missing */
552 pcrd
->TransformPQR
.proc_data
.data
= 0;
553 pcrd
->TransformPQR
.proc_data
.size
= 0;
556 pcrd
->TransformPQR
.proc_data
.data
= pdata
.data
;
557 pcrd
->TransformPQR
.proc_data
.size
= pdata
.size
;
559 pcrd
->TransformPQR
.driver_name
= gs_devicename(dev
);
562 pcrd
->client_data
= &data
;
564 pcrd
->EncodeLMN
= Encode_default
;
566 pcrd
->EncodeLMN
= EncodeLMN_from_data
;
568 pcrd
->EncodeABC
= Encode_default
;
570 pcrd
->EncodeABC
= EncodeABC_from_data
;
571 code_rt
= code
= param_read_int_array(plist
, "RenderTableSize", &rt_size
);
573 if (pcrd
->RenderTable
.lookup
.table
) {
574 gs_free_object(pcrd
->rc
.memory
,
575 (void *)pcrd
->RenderTable
.lookup
.table
, /* break const */
576 "param_get_cie_render1(RenderTable)");
577 pcrd
->RenderTable
.lookup
.table
= 0;
579 pcrd
->RenderTable
.T
= RenderTableT_default
;
583 else if (rt_size
.size
!= 4)
584 return_error(gs_error_rangecheck
);
586 gs_param_string_array rt_values
;
587 gs_const_string
*table
;
590 code
= param_read_string_array(plist
, "RenderTableTable", &rt_values
);
594 rt_values
.size
!= rt_size
.data
[3] *
595 rt_size
.data
[1] * rt_size
.data
[2])
596 return_error(gs_error_rangecheck
);
597 pcrd
->RenderTable
.lookup
.n
= n
= rt_size
.size
- 1;
598 pcrd
->RenderTable
.lookup
.m
= m
= rt_size
.data
[n
];
600 return_error(gs_error_rangecheck
);
601 memcpy(pcrd
->RenderTable
.lookup
.dims
, rt_size
.data
, n
* sizeof(int));
602 table
= (gs_const_string
*)gs_malloc(pcrd
->RenderTable
.lookup
.dims
[0],
603 sizeof(gs_const_string
*),
604 "param_get_cie_render1");
605 for (j
= 0; j
< pcrd
->RenderTable
.lookup
.dims
[0]; ++j
) {
606 table
[j
].data
= rt_values
.data
[j
].data
;
607 table
[j
].size
= rt_values
.data
[j
].size
;
609 pcrd
->RenderTable
.lookup
.table
= table
;
610 pcrd
->RenderTable
.T
= RenderTableT_from_data
;
611 code_t
= code
= read_floats(plist
, "RenderTableTValues", data
.t
,
612 gx_cie_cache_size
* m
);
614 pcrd
->RenderTable
.T
= RenderTableT_default
;
616 pcrd
->RenderTable
.T
= RenderTableT_from_data
;
618 if ((code
= gs_cie_render_init(pcrd
)) >= 0 &&
619 (code
= gs_cie_render_sample(pcrd
)) >= 0
621 code
= gs_cie_render_complete(pcrd
);
622 /* Clean up before exiting. */
623 pcrd
->client_data
= 0;
625 pcrd
->EncodeLMN
= EncodeLMN_from_cache
;
627 pcrd
->EncodeABC
= EncodeABC_from_cache
;
629 pcrd
->RenderTable
.T
= RenderTableT_from_cache
;