1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gsicc.c 8780 2008-05-27 20:12:08Z mvrhel $ */
15
/* Implementation of the ICCBased color space family */
23
#include "gxcspace.h" /* for gxcie.c */
27
#include "icc.h" /* must precede icc.h */
30
#define SAVEICCPROFILE 0
32
typedef struct _icmFileGs icmFileGs;
41
/* Garbage collection code */
44
* Discard a gs_cie_icc_s structure. This requires that we call the
45
* destructor for ICC profile, lookup, and file objects (which are
46
* stored in "foreign" memory).
48
* No special action is taken with respect to the stream pointer; that is
49
* the responsibility of the client. */
51
cie_icc_finalize(void * pvicc_info)
53
gs_cie_icc * picc_info = (gs_cie_icc *)pvicc_info;
55
if (picc_info->plu != NULL) {
56
picc_info->plu->del(picc_info->plu);
57
picc_info->plu = NULL;
59
if (picc_info->picc != NULL) {
60
picc_info->picc->del(picc_info->picc);
61
picc_info->picc = NULL;
63
if (picc_info->pfile != NULL) {
64
picc_info->pfile->del(picc_info->pfile);
65
picc_info->pfile = NULL;
72
* Because the color space structure stores alternative color space in-line,
73
* we must enumerate and relocate pointers in these space explicity.
75
gs_private_st_composite( st_color_space_CIEICC,
77
"gs_color_space_CIEICC",
79
cs_CIEICC_reloc_ptrs );
81
/* pointer enumeration routine */
83
ENUM_PTRS_BEGIN(cs_CIEICC_enum_ptrs) return 0;
84
ENUM_PTR(0, gs_color_space, params.icc.picc_info);
87
/* pointer relocation routine */
89
RELOC_PTRS_BEGIN(cs_CIEICC_reloc_ptrs)
90
RELOC_PTR(gs_color_space, params.icc.picc_info);
95
* Color space methods for ICCBased color spaces.
97
* As documented, ICCBased color spaces may be used as both base and
98
* alternative color spaces. Futhermore,, they can themselves contain paint
99
* color spaces as alternative color space. In this implementation we allow
100
* them to be used as base and alternative color spaces, but only to contain
101
* "small" base color spaces (CIEBased or smaller). This arrangement avoids
102
* breaking the color space heirarchy. Providing a more correct arrangement
103
* requires a major change in the color space mechanism.
105
* Several of the methods used by ICCBased color space apply as well to
106
* DeviceN color spaces, in that they are generic to color spaces having
107
* a variable number of components. We have elected not to attempt to
108
* extract and combine these operations, because this would save only a
109
* small amount of code, and much more could be saved by intorducing certain
110
* common elements (ranges, number of components, etc.) into the color space
113
static cs_proc_num_components(gx_num_components_CIEICC);
114
static cs_proc_init_color(gx_init_CIEICC);
115
static cs_proc_restrict_color(gx_restrict_CIEICC);
116
static cs_proc_concrete_space(gx_concrete_space_CIEICC);
117
static cs_proc_concretize_color(gx_concretize_CIEICC);
118
#if ENABLE_CUSTOM_COLOR_CALLBACK
119
static cs_proc_remap_color(gx_remap_ICCBased);
121
static cs_proc_final(gx_final_CIEICC);
122
static cs_proc_serialize(gx_serialize_CIEICC);
124
static const gs_color_space_type gs_color_space_type_CIEICC = {
125
gs_color_space_index_CIEICC, /* index */
126
true, /* can_be_base_space */
127
true, /* can_be_alt_space */
128
&st_color_space_CIEICC, /* stype - structure descriptor */
129
gx_num_components_CIEICC, /* num_components */
130
gx_init_CIEICC, /* init_color */
131
gx_restrict_CIEICC, /* restrict_color */
132
gx_concrete_space_CIEICC, /* concrete_space */
133
gx_concretize_CIEICC, /* concreteize_color */
134
NULL, /* remap_concrete_color */
135
#if ENABLE_CUSTOM_COLOR_CALLBACK
136
gx_remap_ICCBased, /* remap_color */
138
gx_default_remap_color, /* remap_color */
140
gx_install_CIE, /* install_cpsace */
141
gx_spot_colors_set_overprint, /* set_overprint */
142
gx_final_CIEICC, /* final */
143
gx_no_adjust_color_count, /* adjust_color_count */
144
gx_serialize_CIEICC, /* serialize */
145
gx_cspace_is_linear_default
150
* Return the number of components used by a ICCBased color space - 1, 3, or 4
153
gx_num_components_CIEICC(const gs_color_space * pcs)
155
return pcs->params.icc.picc_info->num_components;
159
* Set the initial client color for an ICCBased color space. The convention
160
* suggested by the ICC specification is to set all components to 0.
163
gx_init_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
165
int i, ncomps = pcs->params.icc.picc_info->num_components;
167
for (i = 0; i < ncomps; ++i)
168
pcc->paint.values[i] = 0.0;
170
/* make sure that [ 0, ... 0] is in range */
171
gx_restrict_CIEICC(pcc, pcs);
175
* Restrict an color to the range specified for an ICCBased color space.
178
gx_restrict_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
180
int i, ncomps = pcs->params.icc.picc_info->num_components;
181
const gs_range * ranges = pcs->params.icc.picc_info->Range.ranges;
183
for (i = 0; i < ncomps; ++i) {
184
floatp v = pcc->paint.values[i];
185
floatp rmin = ranges[i].rmin, rmax = ranges[i].rmax;
188
pcc->paint.values[i] = rmin;
190
pcc->paint.values[i] = rmax;
195
* Return the conrecte space to which this color space will map. If the
196
* ICCBased color space is being used in native mode, the concrete space
197
* will be dependent on the current color rendering dictionary, as it is
198
* for all CIE bases. If the alternate color space is being used, then
199
* this question is passed on the the appropriate method of that space.
201
static const gs_color_space *
202
gx_concrete_space_CIEICC(const gs_color_space * pcs, const gs_imager_state * pis)
204
if (pcs->params.icc.picc_info->picc == NULL) {
205
const gs_color_space * pacs = pcs->base_space;
207
return cs_concrete_space(pacs, pis);
209
return gx_concrete_space_CIE(NULL, pis);
213
* Convert an ICCBased color space to a concrete color space.
216
gx_concretize_CIEICC(
217
const gs_client_color * pcc,
218
const gs_color_space * pcs,
220
const gs_imager_state * pis )
222
const gs_icc_params * picc_params = &pcs->params.icc;
223
const gs_cie_icc * picc_info = picc_params->picc_info;
224
stream * instrp = picc_info->instrp;
225
icc * picc = picc_info->picc;
226
double inv[4], outv[3];
227
cie_cached_vector3 vlmn;
228
gs_client_color lcc = *pcc;
229
int i, ncomps = picc_info->num_components;
232
/* use the altenate space concretize if appropriate */
234
return pcs->base_space->type->concretize_color(
240
/* set up joint cache as required */
241
code = gx_cie_check_rendering(pcs, pconc, pis);
247
/* verify and update the stream pointer */
248
if (picc_info->file_id != (instrp->read_id | instrp->write_id))
249
return_error(gs_error_ioerror);
250
((icmFileGs *)picc->fp)->strp = instrp;
252
/* translate the input components */
253
gx_restrict_CIEICC(&lcc, pcs);
254
for (i = 0; i < ncomps; i++)
255
inv[i] = lcc.paint.values[i];
257
/* Since the original limits were wrong for this case, We need to adjust things a bit different */
259
/* For input Lab color space massage the values into Lab range */
261
/* if (picc_info->plu->e_inSpace == icSigLabData) {
264
inv[1] = inv[1]*255 - 128;
265
inv[2] = inv[2]*255 - 128;
270
* Perform the lookup operation. A return value of 1 indicates that
271
* clipping occurred somewhere in the operation, but the result is
272
* legitimate. Other non-zero return values indicate an error, which
273
* should not occur in practice.
276
if (picc_info->plu->lookup(picc_info->plu, outv, inv) > 1)
277
return_error(gs_error_unregistered);
279
/* if the output is in the CIE L*a*b* space, convert to XYZ */
280
if (picc_info->pcs_is_cielab) {
282
const gs_vector3 * pwhtpt = &picc_info->common.points.WhitePoint;
285
f[1] = (outv[0] + 16.0) / 116.0;
286
f[0] = f[1] + outv[1] / 500.0;
287
f[2] = f[1] - outv[2] / 200;
289
for (i = 0; i < 3; i++) {
290
if (f[i] >= 6.0 / 29.0)
291
outv[i] = f[i] * f[i] * f[i];
293
outv[i] = 108.0 * (f[i] - 4.0 / 29.0) / 841.0;
297
* The connection space white-point is known to be D50, but we
298
* use the more general form in case of future revisions.
300
outv[0] *= pwhtpt->u;
301
outv[1] *= pwhtpt->v;
302
outv[2] *= pwhtpt->w;
305
/* translate the output */
306
vlmn.u = float2cie_cached(outv[0]);
307
vlmn.v = float2cie_cached(outv[1]);
308
vlmn.w = float2cie_cached(outv[2]);
310
gx_cie_remap_finish(vlmn, pconc, pis, pcs);
314
#if ENABLE_CUSTOM_COLOR_CALLBACK
316
* This routine is only used if ENABLE_CUSTOM_COLOR_CALLBACK is true.
317
* Otherwise we use gx_default_remap_color directly for CIEBasedDEFG color
320
* Render a CIEBasedDEFG color.
323
gx_remap_ICCBased(const gs_client_color * pc, const gs_color_space * pcs,
324
gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
325
gs_color_select_t select)
327
client_custom_color_params_t * pcb =
328
(client_custom_color_params_t *) (pis->memory->gs_lib_ctx->custom_color_callback);
331
if (pcb->client_procs->remap_ICCBased(pcb, pc, pcs,
332
pdc, pis, dev, select) == 0)
335
/* Use default routine for non custom color processing. */
336
return gx_default_remap_color(pc, pcs, pdc, pis, dev, select);
341
* Finalize the contents of an ICC color space. Now that color space
342
* objects have straightforward reference counting discipline, there's
343
* nothing special about it. In the previous state of affairs, the
344
* argument in favor of correct reference counting spoke of "an
345
* unintuitive but otherwise legitimate state of affairs".
348
gx_final_CIEICC(const gs_color_space * pcs)
350
rc_decrement_only(pcs->params.icc.picc_info, "gx_final_CIEICC");
354
icmFileGs_seek(icmFile *pp, long int offset)
356
icmFileGs *p = (icmFileGs *)pp;
358
return spseek(p->strp, offset);
362
icmFileGs_read(icmFile *pp, void *buffer, size_t size, size_t count)
364
icmFileGs *p = (icmFileGs *)pp;
366
int status = sgets(p->strp, buffer, size * count, &tot);
368
return (status < 0) ? status : tot;
372
icmFileGs_write(icmFile *pp, void *buffer, size_t size, size_t count)
374
icmFileGs *p = (icmFileGs *)pp;
376
int status = sputs(p->strp, buffer, size * count, &tot);
378
return (status < 0) ? status : tot;
382
icmFileGs_flush(icmFile *pp)
384
icmFileGs *p = (icmFileGs *)pp;
386
return s_std_write_flush(p->strp);
390
icmFileGs_delete(icmFile *pp)
397
* gx_wrap_icc_stream: Wrap a Ghostscript stream as an icclib file.
398
* @strp: The Ghostscript stream.
400
* Creates an icmFile object that wraps @stream.
402
* Note: the memory for this object is allocated using malloc, and the
403
* relocation of the stream pointer is done lazily, before an icclu
404
* operation. It would probably be cleaner to allocate the icmFile in
405
* garbage collected memory, and have the relocation happen there, but
406
* I wanted to minimally modify Jan's working code.
408
* Return value: the stream wrapped as an icmFile object, or NULL on
412
gx_wrap_icc_stream(stream *strp)
416
if ((p = (icmFileGs *) calloc(1,sizeof(icmFileGs))) == NULL)
418
p->seek = icmFileGs_seek;
419
p->read = icmFileGs_read;
420
p->write = icmFileGs_write;
421
p->flush = icmFileGs_flush;
422
p->del = icmFileGs_delete;
430
gx_load_icc_profile(gs_cie_icc *picc_info)
432
stream * instrp = picc_info->instrp;
434
icmLuBase * plu = NULL;
435
icmFile *pfile = NULL;
439
unsigned int num_bytes;
440
unsigned char *iccbuffer;
445
/* verify that the file is legitimate */
446
if (picc_info->file_id != (instrp->read_id | instrp->write_id))
447
return_error(gs_error_ioerror);
449
* Load the top-level ICC profile.
451
* If an ICC profile fails to load, generate an error.
453
* Testing demonstrates, however, Acrobat Reader silently
454
* ignores the error and uses the alternate color space.
455
* This behaviour is implemented by catching the error using
456
* a stopped context from within the interpreter (gs_icc.ps).
458
* Failure to allocate the top-level profile object is considered
459
* a limitcheck rather than a VMerror, as profile data structures
460
* are stored in "foreign" memory.
462
if ((picc = new_icc()) == NULL)
463
return_error(gs_error_limitcheck);
465
icProfileClassSignature profile_class;
466
icColorSpaceSignature cspace_type;
469
pfile = gx_wrap_icc_stream (instrp);
471
if ((picc->read(picc, pfile, 0)) != 0)
472
goto return_rangecheck;
476
num_bytes = picc->header->size;
477
iccbuffer = (unsigned char *) malloc(num_bytes);
478
pfile->seek(pfile,0);
479
pfile->read(pfile,iccbuffer,1,num_bytes);
480
fid = fopen("DumpedICC.icm","wb");
481
fwrite(iccbuffer,sizeof(unsigned char),num_bytes,fid);
488
/* verify the profile type */
489
profile_class = picc->header->deviceClass;
490
if ( profile_class != icSigInputClass &&
491
profile_class != icSigDisplayClass &&
492
profile_class != icSigOutputClass &&
493
profile_class != icSigColorSpaceClass )
494
goto return_rangecheck;
496
/* verify the profile connection space */
497
cspace_type = picc->header->pcs;
498
if (cspace_type == icSigLabData)
499
picc_info->pcs_is_cielab = true;
500
else if (cspace_type == icSigXYZData)
501
picc_info->pcs_is_cielab = false;
503
goto return_rangecheck;
505
/* verify the source color space */
506
cspace_type = picc->header->colorSpace;
507
if (cspace_type == icSigCmykData) {
508
if (picc_info->num_components != 4)
509
goto return_rangecheck;
510
} else if ( cspace_type == icSigRgbData ||
511
cspace_type == icSigLabData ) {
512
if (picc_info->num_components != 3)
513
goto return_rangecheck;
514
} else if (cspace_type == icSigGrayData) {
515
if (picc_info->num_components != 1)
516
goto return_rangecheck;
520
* Fetch the lookup object.
522
* PostScript and PDF deal with rendering intent as strictly a
523
* rendering dictionary facility. ICC profiles allow a rendering
524
* intent to be specified for both the input (device ==> pcs) and
525
* output (pcs ==> device) operations. Hence, when using ICCBased
526
* color spaces with PDF, no clue is provided as to which source
529
* In the absence of other information, there are two possible
530
* selections. If our understanding is correct, when relative
531
* colorimetry is specified, the icclib code will map source
532
* color values to XYZ or L*a*b* values such that the relationship
533
* of the source color, relative to the source white and black
534
* points, will be the same as the output colors and the
535
* profile connection space illuminant (currently always D50)
536
* and pure black ([0, 0, 0]). In this case, the white and black
537
* points that should be listed in the color space are the
538
* profile connection space illuminant (D50) and pure black.
540
* If absolute colorimetry is employed, the XYZ or L*a*b* values
541
* generated will be absolute in the chromatic sense (they are
542
* not literally "absolute", as we still must have overall
543
* intensity information inorder to determine weighted spectral
544
* power levels). To achieve relative colorimetry for the output,
545
* these colors must be evaluated relative to the source white
546
* and black points. Hence, in this case, the appropriate white
547
* and black points to list in the color space are the source
548
* white and black points provided in the profile tag array.
550
* In this implementation, we will always request relative
551
* colorimetry from the icclib, and so will use the profile
552
* connection space illuminant and pure black as the white and
553
* black points of the color space. This approach is somewhat
554
* simpler, as it allows the color space white point to also
555
* be used for L*a*b* to XYZ conversion (otherwise we would
556
* need to store the profile connection space illuminant
557
* separately for that purpose). The approach does reduce to
558
* to some extent the range of mappings that can be achieved
559
* via the color rendering dictionary, but for now we believe
560
* this loss is not significant.
562
* For reasons that are not clear to us, the icclib code does
563
* not support relative colorimetry for all color profiles. For
564
* this reason, we specify icmDefaultIntent rather than
565
* icRelativeColormetric.
567
* NB: We are not color experts; our understanding of this area
568
* may well be incorrect.
570
plu = picc->get_luobj( picc,
573
0, /* PCS override */
576
goto return_rangecheck;
579
* Get the appropriate white and black points. See the note on
580
* rendering intent above for a discussion of why we are using
581
* the profile space illuminant and pure black. (Pure black need
582
* not be set explicitly, as it is the default.)
584
ppt = &picc_info->common.points.WhitePoint;
585
ppt->u = picc->header->illuminant.X;
586
ppt->v = picc->header->illuminant.Y;
587
ppt->w = picc->header->illuminant.Z;
589
picc_info->picc = picc;
590
picc_info->plu = plu;
591
picc_info->pfile = pfile;
603
return_error(gs_error_rangecheck);
607
* Install an ICCBased color space.
609
* Note that an ICCBased color space must be installed before it is known if
610
* the ICC profile or the alternate color space is to be used.
613
gx_install_CIEICC(gs_color_space * pcs, gs_state * pgs)
615
const gs_icc_params * picc_params = (const gs_icc_params *)&pcs->params.icc;
616
gs_cie_icc * picc_info = picc_params->picc_info;
618
#if ENABLE_CUSTOM_COLOR_CALLBACK
621
* Check if we want to use the callback color processing for this
624
client_custom_color_params_t * pcb =
625
(client_custom_color_params_t *) pgs->memory->gs_lib_ctx->custom_color_callback;
628
if (pcb->client_procs->install_ICCBased(pcb, pcs, pgs))
629
/* Exit if the client will handle the colorspace completely */
634
/* update the stub information used by the joint caches */
635
gx_cie_load_common_cache(&picc_info->common, pgs);
636
gx_cie_common_complete(&picc_info->common);
637
return gs_cie_cs_complete(pgs, true);
642
* Constructor for ICCBased color space. As with the other color space
643
* constructors, this provides only minimal initialization.
646
gs_cspace_build_CIEICC(
647
gs_color_space ** ppcspace,
651
gs_cie_icc * picc_info;
652
gs_color_space * pcs;
655
* The gs_cie_icc_s structure is the only CIE-based color space structure
656
* which accesses additional memory for which it is responsible. We make
657
* use of the finalization procedure to handle this task, so we can use
658
* the generic CIE space build routine (otherwise we would need a
659
* separate build routine that provided its own reference count freeing
662
picc_info = gx_build_cie_space( ppcspace,
663
&gs_color_space_type_CIEICC,
667
if (picc_info == NULL)
668
return_error(gs_error_VMerror);
670
gx_set_common_cie_defaults(&picc_info->common, client_data);
672
* Now set the D50 WhitePoint. The above function does not set any
673
* valid WhitepPoint since PostScript always requires this, but ICC
674
* assumes a D50 WhitePoint as a default
676
picc_info->common.points.WhitePoint.u = (float)0.9642; /* Profile illuminant - D50 */
677
picc_info->common.points.WhitePoint.v = 1.0000;
678
picc_info->common.points.WhitePoint.w = (float)0.8249;
679
picc_info->common.install_cspace = gx_install_CIEICC;
680
picc_info->num_components = 0;
681
picc_info->Range = Range4_default;
682
picc_info->instrp = NULL;
683
picc_info->pcs_is_cielab = false;
684
picc_info->picc = NULL;
685
picc_info->plu = NULL;
686
picc_info->pfile = NULL;
689
pcs->params.icc.picc_info = picc_info;
693
/* ---------------- Serialization. -------------------------------- */
696
gx_serialize_CIEICC(const gs_color_space * pcs, stream * s)
698
const gs_icc_params * p = &pcs->params.icc;
699
gs_cie_icc *picc = p->picc_info;
701
int code = gx_serialize_cspace_type(pcs, s);
702
long avail, pos, count;
707
code = gx_serialize_cie_common_elements(pcs, s);
710
code = sputs(s, (byte *)&picc->num_components, sizeof(picc->num_components), &n);
713
code = sputs(s, (byte *)&picc->Range, sizeof(picc->Range), &n);
716
if (sseek(picc->instrp, 0) < 0)
717
return_error(gs_error_unregistered); /* Unimplemented. */
718
if (savailable(picc->instrp, &avail) != 0)
719
return_error(gs_error_unregistered); /* Unimplemented. */
720
code = sputs(s, (byte *)&avail, sizeof(avail), &n);
723
for (pos = 0; pos < avail; pos += count) {
724
count = min(sizeof(buf), avail - pos);
725
code = sgets(picc->instrp, buf, count, &n);
728
code = sputs(s, buf, count, &n);
732
return sputs(s, (byte *)&picc->pcs_is_cielab, sizeof(picc->pcs_is_cielab), &n);