Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1999, 2000, 2001 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: gdevpdfc.c,v 1.54 2005/10/18 09:05:58 leonardo Exp $ */
18
/* Color space management and writing for pdfwrite driver */
19
#include "math_.h"
20
#include "memory_.h"
21
#include "gx.h"
22
#include "gscspace.h"		/* for gscie.h */
23
#include "gscdevn.h"
24
#include "gscie.h"
25
#include "gscindex.h"
26
#include "gscsepr.h"
27
#include "stream.h"
28
#include "gsicc.h"
29
#include "gserrors.h"
30
#include "gdevpdfx.h"
31
#include "gdevpdfg.h"
32
#include "gdevpdfc.h"
33
#include "gdevpdfo.h"
34
#include "strimpl.h"
35
#include "sstring.h"
36
#include "gxcspace.h"
37
#include <assert.h>
38
 
39
/*
40
 * PDF doesn't have general CIEBased color spaces.  However, it provides
41
 * two methods for handling general CIE spaces:
42
 *
43
 *	- For PDF 1.2 and above, we note that the transformation from L*a*b*
44
 *	space to XYZ space is invertible, so we can handle any PostScript
45
 *	CIEBased space by transforming color values in that space to XYZ,
46
 *	then inverse-transforming them to L*a*b* and using a PDF Lab space
47
 *	with the same WhitePoint and BlackPoint and appropriate ranges for
48
 *	a and b.  This approach has the drawback that Y values outside the
49
 *	range [0..1] can't be represented: we just clamp them.
50
 *
51
 *	- For PDF 1.3 and above, we can create an ICCBased space.  This is
52
 *	actually necessary, not just an option, because for shadings (also
53
 *	introduced in PDF 1.3), we want color interpolation to occur in the
54
 *	original space.
55
 *
56
 * The Lab approach is not currently implemented, because it requires
57
 * transforming all the sample values of images.  The ICCBased approach is
58
 * implemented for color spaces whose ranges lie within [0..1], which are
59
 * the only ranges supported by the ICC standard: we think that removing
60
 * this limitation would also require transforming image sample values.
61
 */
62
 
63
/* GC descriptors */
64
public_st_pdf_color_space();
65
 
66
/* ------ CIE space testing ------ */
67
 
68
/* Test whether a cached CIE procedure is the identity function. */
69
#define CIE_CACHE_IS_IDENTITY(pc)\
70
  ((pc)->floats.params.is_identity)
71
#define CIE_CACHE3_IS_IDENTITY(pca)\
72
  (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
73
   CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
74
   CIE_CACHE_IS_IDENTITY(&(pca)[2]))
75
 
76
/*
77
 * Test whether a cached CIE procedure is an exponential.  A cached
78
 * procedure is exponential iff f(x) = k*(x^p).  We make a very cursory
79
 * check for this: we require that f(0) = 0, set k = f(1), set p =
80
 * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
81
 * two arbitrarily chosen values between 0 and 1.  Naturally all this is
82
 * done with some slop.
83
 */
84
#define CC_INDEX_A (gx_cie_cache_size / 3)
85
#define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
86
#define CC_INDEX_1 (gx_cie_cache_size - 1)
87
#define CC_KEY(i) ((i) / (double)CC_INDEX_1)
88
#define CC_KEY_A CC_KEY(CC_INDEX_A)
89
#define CC_KEY_B CC_KEY(CC_INDEX_B)
90
 
91
private bool
92
cie_values_are_exponential(floatp v0, floatp va, floatp vb, floatp k,
93
			   float *pexpt)
94
{
95
    double p;
96
 
97
    if (fabs(v0) >= 0.001 || fabs(k) < 0.001)
98
	return false;
99
    if (va == 0 || (va > 0) != (k > 0))
100
	return false;
101
    p = log(va / k) / log(CC_KEY_A);
102
    if (fabs(vb - k * pow(CC_KEY_B, p)) >= 0.001)
103
	return false;
104
    *pexpt = p;
105
    return true;
106
}
107
 
108
private bool
109
cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
110
{
111
    return cie_values_are_exponential(pc->floats.values[0],
112
				      pc->floats.values[CC_INDEX_A],
113
				      pc->floats.values[CC_INDEX_B],
114
				      pc->floats.values[CC_INDEX_1],
115
				      pexpt);
116
}
117
#define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
118
  (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
119
   cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
120
   cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
121
 
122
private bool
123
cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
124
{
125
    return cie_values_are_exponential(pc->vecs.values[0].u,
126
				      pc->vecs.values[CC_INDEX_A].u,
127
				      pc->vecs.values[CC_INDEX_B].u,
128
				      pc->vecs.values[CC_INDEX_1].u,
129
				      pexpt);
130
}
131
#define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
132
  (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
133
   cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
134
   cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
135
 
136
#undef CC_INDEX_A
137
#undef CC_INDEX_B
138
#undef CC_KEY_A
139
#undef CC_KEY_B
140
 
141
/*
142
 * Test whether a cached CIEBasedABC space consists only of a single
143
 * Decode step followed by a single Matrix step.
144
 */
145
private cie_cache_one_step_t
146
cie_cached_abc_is_one_step(const gs_cie_abc *pcie, const gs_matrix3 **ppmat)
147
{
148
    /* The order of steps is, DecodeABC, MatrixABC, DecodeLMN, MatrixLMN. */
149
 
150
    if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN)) {
151
	if (pcie->MatrixABC.is_identity) {
152
	    *ppmat = &pcie->common.MatrixLMN;
153
	    return ONE_STEP_ABC;
154
	}
155
	if (pcie->common.MatrixLMN.is_identity) {
156
	    *ppmat = &pcie->MatrixABC;
157
	    return ONE_STEP_ABC;
158
	}
159
    }
160
    if (CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC.caches)) {
161
	if (pcie->MatrixABC.is_identity) {
162
	    *ppmat = &pcie->common.MatrixLMN;
163
	    return ONE_STEP_LMN;
164
	}
165
    }
166
    return ONE_STEP_NOT;
167
}
168
 
169
/*
170
 * Test whether a cached CIEBasedABC space is a L*a*b* space.
171
 */
172
private bool
173
cie_scalar_cache_is_lab_lmn(const gs_cie_abc *pcie, int i)
174
{
175
    double k = CC_KEY(i);
176
    double g = (k >= 6.0 / 29 ? k * k * k :
177
		(k - 4.0 / 29) * (108.0 / 841));
178
 
179
#define CC_V(j,i) (pcie->common.caches.DecodeLMN[j].floats.values[i])
180
#define CC_WP(uvw) (pcie->common.points.WhitePoint.uvw)
181
 
182
    return (fabs(CC_V(0, i) - g * CC_WP(u)) < 0.001 &&
183
	    fabs(CC_V(1, i) - g * CC_WP(v)) < 0.001 &&
184
	    fabs(CC_V(2, i) - g * CC_WP(w)) < 0.001
185
	    );
186
 
187
#undef CC_V
188
#undef CC_WP
189
}
190
private bool
191
cie_vector_cache_is_lab_abc(const gx_cie_vector_cache3_t *pvc, int i)
192
{
193
    const gx_cie_vector_cache *const pc3 = pvc->caches;
194
    double k = CC_KEY(i);
195
    double l0 = pc3[0].vecs.params.base,
196
	l = l0 + k * (pc3[0].vecs.params.limit - l0);
197
    double a0 = pc3[1].vecs.params.base,
198
	a = a0 + k * (pc3[1].vecs.params.limit - a0);
199
    double b0 = pc3[2].vecs.params.base,
200
	b = b0 + k * (pc3[2].vecs.params.limit - b0);
201
 
202
    return (fabs(cie_cached2float(pc3[0].vecs.values[i].u) -
203
		 (l + 16) / 116) < 0.001 &&
204
	    fabs(cie_cached2float(pc3[1].vecs.values[i].u) -
205
		 a / 500) < 0.001 &&
206
	    fabs(cie_cached2float(pc3[2].vecs.values[i].w) -
207
		 b / -200) < 0.001
208
	    );
209
}
210
 
211
private bool
212
cie_is_lab(const gs_cie_abc *pcie)
213
{
214
    int i;
215
 
216
    /* Check MatrixABC and MatrixLMN. */
217
    if (!(pcie->MatrixABC.cu.u == 1 && pcie->MatrixABC.cu.v == 1 &&
218
	  pcie->MatrixABC.cu.w == 1 &&
219
	  pcie->MatrixABC.cv.u == 1 && pcie->MatrixABC.cv.v == 0 &&
220
	  pcie->MatrixABC.cv.w == 0 &&
221
	  pcie->MatrixABC.cw.u == 0 && pcie->MatrixABC.cw.v == 0 &&
222
	  pcie->MatrixABC.cw.w == -1 &&
223
	  pcie->common.MatrixLMN.is_identity
224
	  ))
225
	return false;
226
 
227
    /* Check DecodeABC and DecodeLMN. */
228
    for (i = 0; i <= CC_INDEX_1; ++i)
229
	if (!(cie_vector_cache_is_lab_abc(&pcie->caches.DecodeABC, i) &&
230
	      cie_scalar_cache_is_lab_lmn(pcie, i)
231
	      ))
232
	    return false;
233
 
234
    return true;
235
}
236
 
237
#undef CC_INDEX_1
238
#undef CC_KEY
239
 
240
/* Test whether one or more CIE-based ranges are [0..1]. */
241
private bool
242
cie_ranges_are_0_1(const gs_range *prange, int n)
243
{
244
    int i;
245
 
246
    for (i = 0; i < n; ++i)
247
	if (prange[i].rmin != 0 || prange[i].rmax != 1)
248
	    return false;
249
    return true;
250
}
251
 
252
/* ------ Utilities ------ */
253
 
254
/* Add a 3-element vector to a Cos array or dictionary. */
255
private int
256
cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
257
{
258
    int code = cos_array_add_real(pca, pvec->u);
259
 
260
    if (code >= 0)
261
	code = cos_array_add_real(pca, pvec->v);
262
    if (code >= 0)
263
	code = cos_array_add_real(pca, pvec->w);
264
    return code;
265
}
266
private int
267
cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
268
			   const gs_vector3 *pvec)
269
{
270
    cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
271
    int code;
272
 
273
    if (pca == 0)
274
	return_error(gs_error_VMerror);
275
    code = cos_array_add_vector3(pca, pvec);
276
    if (code < 0) {
277
	COS_FREE(pca, "cos_array_from_vector3");
278
	return code;
279
    }
280
    return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
281
}
282
 
283
/*
284
 * Finish creating a CIE-based color space (Calxxx or Lab.)
285
 * This procedure is exported for gdevpdfk.c.
286
 */
287
int
288
pdf_finish_cie_space(cos_array_t *pca, cos_dict_t *pcd,
289
		     const gs_cie_common *pciec)
290
{
291
    int code = cos_dict_put_c_key_vector3(pcd, "/WhitePoint",
292
					  &pciec->points.WhitePoint);
293
 
294
    if (code < 0)
295
	return code;
296
    if (pciec->points.BlackPoint.u != 0 ||
297
	pciec->points.BlackPoint.v != 0 ||
298
	pciec->points.BlackPoint.w != 0
299
	) {
300
	code = cos_dict_put_c_key_vector3(pcd, "/BlackPoint",
301
					  &pciec->points.BlackPoint);
302
	if (code < 0)
303
	    return code;
304
    }
305
    return cos_array_add_object(pca, COS_OBJECT(pcd));
306
}
307
 
308
/* ------ Color space writing ------ */
309
 
310
/* Define standard and short color space names. */
311
const pdf_color_space_names_t pdf_color_space_names = {
312
    PDF_COLOR_SPACE_NAMES
313
};
314
const pdf_color_space_names_t pdf_color_space_names_short = {
315
    PDF_COLOR_SPACE_NAMES_SHORT
316
};
317
 
318
/*
319
 * Create a local Device{Gray,RGB,CMYK} color space corresponding to the
320
 * given number of components.
321
 */
322
int
323
pdf_cspace_init_Device(const gs_memory_t *mem, gs_color_space *pcs, int num_components)
324
{
325
    switch (num_components) {
326
    case 1: gs_cspace_init_DeviceGray(mem, pcs); break;
327
    case 3: gs_cspace_init_DeviceRGB(mem, pcs); break;
328
    case 4: gs_cspace_init_DeviceCMYK(mem, pcs); break;
329
    default: return_error(gs_error_rangecheck);
330
    }
331
    return 0;
332
}
333
 
334
/* Create a Separation or DeviceN color space (internal). */
335
private int
336
pdf_separation_color_space(gx_device_pdf *pdev,
337
			   cos_array_t *pca, const char *csname,
338
			   const cos_value_t *snames,
339
			   const gs_color_space *alt_space,
340
			   const gs_function_t *pfn,
341
			   const pdf_color_space_names_t *pcsn)
342
{
343
    cos_value_t v;
344
    const gs_range_t *ranges;
345
    int code;
346
 
347
    if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
348
	(code = cos_array_add_no_copy(pca, snames)) < 0 ||
349
	(code = pdf_color_space(pdev, &v, &ranges, alt_space, pcsn, false)) < 0 ||
350
	(code = cos_array_add(pca, &v)) < 0 ||
351
	(code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
352
	(code = cos_array_add(pca, &v)) < 0
353
	)
354
	return code;
355
    return 0;
356
}
357
 
358
/*
359
 * Create an Indexed color space.  This is a single-use procedure,
360
 * broken out only for readability.
361
 */
362
private int
363
pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
364
			const gs_color_space *pcs, cos_array_t *pca)
365
{
366
    const gs_indexed_params *pip = &pcs->params.indexed;
367
    const gs_color_space *base_space =
368
	(const gs_color_space *)&pip->base_space;
369
    int num_entries = pip->hival + 1;
370
    int num_components = gs_color_space_num_components(base_space);
371
    uint table_size = num_entries * num_components;
372
    /* Guess at the extra space needed for PS string encoding. */
373
    uint string_size = 2 + table_size * 4;
374
    uint string_used;
375
    byte buf[100];		/* arbitrary */
376
    stream_AXE_state st;
377
    stream s, es;
378
    gs_memory_t *mem = pdev->pdf_memory;
379
    byte *table;
380
    byte *palette;
381
    gs_color_space cs_gray;
382
    cos_value_t v;
383
    int code;
384
 
385
    /* PDF doesn't support Indexed color spaces with more than 256 entries. */
386
    if (num_entries > 256)
387
	return_error(gs_error_rangecheck);
388
    if (pdev->CompatibilityLevel < 1.3) {
389
	switch (gs_color_space_get_index(pcs)) {
390
	    case gs_color_space_index_Pattern:
391
	    case gs_color_space_index_Separation:
392
	    case gs_color_space_index_Indexed:
393
	    case gs_color_space_index_DeviceN:
394
		return_error(gs_error_rangecheck);
395
	    default: DO_NOTHING; 
396
	}
397
 
398
    }
399
    table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
400
    palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
401
    if (table == 0 || palette == 0) {
402
	gs_free_string(mem, palette, table_size,
403
		       "pdf_color_space(palette)");
404
	gs_free_string(mem, table, string_size,
405
		       "pdf_color_space(table)");
406
	return_error(gs_error_VMerror);
407
    }
408
    swrite_string(&s, table, string_size);
409
    s_init(&es, mem);
410
    s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
411
    s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
412
    sputc(&s, '(');
413
    if (pcs->params.indexed.use_proc) {
414
	gs_client_color cmin, cmax;
415
	byte *pnext = palette;
416
	int i, j;
417
 
418
	/* Find the legal range for the color components. */
419
	for (j = 0; j < num_components; ++j)
420
	    cmin.paint.values[j] = (float)min_long,
421
		cmax.paint.values[j] = (float)max_long;
422
	gs_color_space_restrict_color(&cmin, base_space);
423
	gs_color_space_restrict_color(&cmax, base_space);
424
	/*
425
	 * Compute the palette values, with the legal range for each
426
	 * one mapped to [0 .. 255].
427
	 */
428
	for (i = 0; i < num_entries; ++i) {
429
	    gs_client_color cc;
430
 
431
	    gs_cspace_indexed_lookup(&pcs->params.indexed, i, &cc);
432
	    for (j = 0; j < num_components; ++j) {
433
		float v = (cc.paint.values[j] - cmin.paint.values[j])
434
		    * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
435
 
436
		*pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
437
	    }
438
	}
439
    } else
440
	memcpy(palette, pip->lookup.table.data, table_size);
441
    if (gs_color_space_get_index(base_space) ==
442
	gs_color_space_index_DeviceRGB
443
	) {
444
	/* Check for an all-gray palette3. */
445
	int i;
446
 
447
	for (i = table_size; (i -= 3) >= 0; )
448
	    if (palette[i] != palette[i + 1] ||
449
		palette[i] != palette[i + 2]
450
		)
451
		break;
452
	if (i < 0) {
453
	    /* Change the color space to DeviceGray. */
454
	    for (i = 0; i < num_entries; ++i)
455
		palette[i] = palette[i * 3];
456
	    table_size = num_entries;
457
	    gs_cspace_init_DeviceGray(mem, &cs_gray);
458
	    base_space = &cs_gray;
459
	}
460
    }
461
    stream_write(&es, palette, table_size);
462
    gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
463
    sclose(&es);
464
    sflush(&s);
465
    string_used = (uint)stell(&s);
466
    table = gs_resize_string(mem, table, string_size, string_used,
467
			     "pdf_color_space(table)");
468
    /*
469
     * Since the array is always referenced by name as a resource
470
     * rather than being written as a value, even for in-line images,
471
     * always use the full name for the color space.
472
     *
473
     * We don't have to worry about the range of the base space:
474
     * in PDF, unlike PostScript, the values from the lookup table are
475
     * scaled automatically.
476
     */
477
    if ((code = pdf_color_space(pdev, pvalue, NULL, base_space,
478
				&pdf_color_space_names, false)) < 0 ||
479
	(code = cos_array_add(pca,
480
			      cos_c_string_value(&v, 
481
						 pdf_color_space_names.Indexed
482
						 /*pcsn->Indexed*/))) < 0 ||
483
	(code = cos_array_add(pca, pvalue)) < 0 ||
484
	(code = cos_array_add_int(pca, pip->hival)) < 0 ||
485
	(code = cos_array_add_no_copy(pca,
486
				      cos_string_value(&v, table,
487
						       string_used))) < 0
488
	)
489
	return code;
490
    return 0;
491
}
492
 
493
/* 
494
 * Find a color space resource by seriialized data. 
495
 */
496
private pdf_resource_t *
497
pdf_find_cspace_resource(gx_device_pdf *pdev, const byte *serialized, uint serialized_size) 
498
{
499
    pdf_resource_t **pchain = pdev->resources[resourceColorSpace].chains;
500
    pdf_resource_t *pres;
501
    int i;
502
 
503
    for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
504
	for (pres = pchain[i]; pres != 0; pres = pres->next) {
505
	    const pdf_color_space_t *const ppcs =
506
		(const pdf_color_space_t *)pres;
507
	    if (ppcs->serialized_size != serialized_size)
508
		continue;
509
	    if (!memcmp(ppcs->serialized, serialized, ppcs->serialized_size))
510
		return pres;
511
	}
512
    }
513
    return NULL;
514
}
515
 
516
 
517
/*
518
 * Create a PDF color space corresponding to a PostScript color space.
519
 * For parameterless color spaces, set *pvalue to a (literal) string with
520
 * the color space name; for other color spaces, create a cos_array_t if
521
 * necessary and set *pvalue to refer to it.  In the latter case, if
522
 * by_name is true, return a string /Rxxxx rather than a reference to
523
 * the actual object.
524
 *
525
 * If ppranges is not NULL, then if  the domain of the color space had
526
 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
527
 * to the ranges in *ppranges, otherwise set *ppranges to 0.
528
 */
529
int
530
pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
531
		const gs_range_t **ppranges,
532
		const gs_color_space *pcs,
533
		const pdf_color_space_names_t *pcsn,
534
		bool by_name, const byte *res_name, int name_length)
535
{
536
    gs_color_space_index csi = gs_color_space_get_index(pcs);
537
    cos_array_t *pca;
538
    cos_dict_t *pcd;
539
    cos_value_t v;
540
    const gs_cie_common *pciec;
541
    gs_function_t *pfn;
542
    const gs_range_t *ranges = 0;
543
    uint serialized_size;
544
    byte *serialized = NULL, serialized0[100];
545
    pdf_resource_t *pres = NULL;
546
    int code;
547
 
548
    if (ppranges)
549
	*ppranges = 0;		/* default */
550
    switch (csi) {
551
    case gs_color_space_index_DeviceGray:
552
	cos_c_string_value(pvalue, pcsn->DeviceGray);
553
	return 0;
554
    case gs_color_space_index_DeviceRGB:
555
	cos_c_string_value(pvalue, pcsn->DeviceRGB);
556
	return 0;
557
    case gs_color_space_index_DeviceCMYK:
558
	cos_c_string_value(pvalue, pcsn->DeviceCMYK);
559
	return 0;
560
    case gs_color_space_index_Pattern:
561
	if (!pcs->params.pattern.has_base_space) {
562
	    cos_c_string_value(pvalue, "/Pattern");
563
	    return 0;
564
	}
565
	break;
566
    case gs_color_space_index_CIEICC:
567
        /*
568
	 * Take a special early exit for unrecognized ICCBased color spaces,
569
	 * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
570
	 */
571
        if (pcs->params.icc.picc_info->picc == 0 ||
572
	    pdev->CompatibilityLevel < 1.3
573
	    ) {
574
	    if (res_name != NULL)
575
		return 0; /* Ignore .includecolorspace */
576
            return pdf_color_space( pdev, pvalue, ppranges,
577
                                    (const gs_color_space *)
578
                                        &pcs->params.icc.alt_space,
579
                                    pcsn, by_name);
580
	}
581
        break;
582
    default:
583
	break;
584
    }
585
 
586
    /* Check whether we already have a PDF object for this color space. */
587
    if (pcs->id != gs_no_id)
588
	pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
589
    if (pres == NULL) {
590
	stream s;
591
 
592
	s_init(&s, pdev->memory);
593
	swrite_position_only(&s);
594
	code = cs_serialize(pcs, &s);
595
	if (code < 0)
596
	    return_error(gs_error_unregistered); /* Must not happen. */
597
	serialized_size = stell(&s);
598
	sclose(&s);
599
	if (serialized_size <= sizeof(serialized0))
600
	    serialized = serialized0;
601
	else {
602
	    serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
603
	    if (serialized == NULL)
604
		return_error(gs_error_VMerror);
605
	}
606
	swrite_string(&s, serialized, serialized_size);
607
	code = cs_serialize(pcs, &s);
608
	if (code < 0)
609
	    return_error(gs_error_unregistered); /* Must not happen. */
610
	if (stell(&s) != serialized_size) 
611
	    return_error(gs_error_unregistered); /* Must not happen. */
612
	sclose(&s);
613
	pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
614
	if (pres != NULL) {
615
	    if (serialized != serialized0)
616
		gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
617
	    serialized = NULL;
618
	}
619
    }
620
    if (pres) {
621
	const pdf_color_space_t *const ppcs =
622
	    (const pdf_color_space_t *)pres;
623
 
624
	if (ppranges != 0 && ppcs->ranges != 0)
625
	    *ppranges = ppcs->ranges;
626
	pca = (cos_array_t *)pres->object;
627
	goto ret;
628
    }
629
 
630
    /* Space has parameters -- create an array. */
631
    pca = cos_array_alloc(pdev, "pdf_color_space");
632
    if (pca == 0)
633
	return_error(gs_error_VMerror);
634
 
635
    switch (csi) {
636
 
637
    case gs_color_space_index_CIEICC:
638
	code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
639
        break;
640
 
641
    case gs_color_space_index_CIEA: {
642
	/* Check that we can represent this as a CalGray space. */
643
	const gs_cie_a *pcie = pcs->params.a;
644
	bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
645
	bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 && 
646
	                  pcie->MatrixA.w == 1);
647
	gs_vector3 expts;
648
 
649
	pciec = (const gs_cie_common *)pcie;
650
	if (!pcie->common.MatrixLMN.is_identity) {
651
	    code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
652
					 &pcie->RangeA, ONE_STEP_NOT, NULL,
653
					 &ranges);
654
	    break;
655
	}
656
	if (unitary && identityA &&
657
	    CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
658
	    CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
659
	    expts.v == expts.u && expts.w == expts.u
660
	    ) {
661
	    DO_NOTHING;
662
	} else if (unitary && identityA &&
663
		   CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
664
		   cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
665
		   ) {
666
	    DO_NOTHING;
667
	} else {
668
	    code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
669
					 &pcie->RangeA, ONE_STEP_NOT, NULL,
670
					 &ranges);
671
	    break;
672
	}
673
	code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
674
	if (code < 0)
675
	    return code;
676
	pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
677
	if (pcd == 0)
678
	    return_error(gs_error_VMerror);
679
	if (expts.u != 1) {
680
	    code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
681
	    if (code < 0)
682
		return code;
683
	}
684
    }
685
    cal:
686
    /* Finish handling a CIE-based color space (Calxxx or Lab). */
687
    if (code < 0)
688
	return code;
689
    code = pdf_finish_cie_space(pca, pcd, pciec);
690
    break;
691
 
692
    case gs_color_space_index_CIEABC: {
693
	/* Check that we can represent this as a CalRGB space. */
694
	const gs_cie_abc *pcie = pcs->params.abc;
695
	bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
696
	gs_vector3 expts;
697
	const gs_matrix3 *pmat = NULL;
698
	cie_cache_one_step_t one_step =
699
	    cie_cached_abc_is_one_step(pcie, &pmat);
700
 
701
	pciec = (const gs_cie_common *)pcie;
702
	if (unitary) {
703
	    switch (one_step) {
704
	    case ONE_STEP_ABC:
705
		if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
706
		    goto calrgb;
707
		break;
708
	    case ONE_STEP_LMN:
709
		if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
710
		    goto calrgb;
711
	    default:
712
		break;
713
	    }
714
	}
715
	if (cie_is_lab(pcie)) {
716
	    /* Represent this as a Lab space. */
717
	    pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
718
	    if (pcd == 0)
719
		return_error(gs_error_VMerror);
720
	    code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
721
	    goto cal;
722
	} else {
723
	    code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
724
					 pcie->RangeABC.ranges,
725
					 one_step, pmat, &ranges);
726
	    break;
727
	}
728
    calrgb:
729
	code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
730
	if (code < 0)
731
	    return code;
732
	pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
733
	if (pcd == 0)
734
	    return_error(gs_error_VMerror);
735
	if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
736
	    code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
737
	    if (code < 0)
738
		return code;
739
	}
740
	if (!pmat->is_identity) {
741
	    cos_array_t *pcma =
742
		cos_array_alloc(pdev, "pdf_color_space(Matrix)");
743
 
744
	    if (pcma == 0)
745
		return_error(gs_error_VMerror);
746
	    if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
747
		(code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
748
		(code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
749
		(code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
750
				     COS_OBJECT_VALUE(&v, pcma))) < 0
751
		)
752
		return code;
753
	}
754
    }
755
    goto cal;
756
 
757
    case gs_color_space_index_CIEDEF:
758
	code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
759
				     (const gs_cie_common *)pcs->params.def,
760
				     pcs->params.def->RangeDEF.ranges,
761
				     ONE_STEP_NOT, NULL, &ranges);
762
	break;
763
 
764
    case gs_color_space_index_CIEDEFG:
765
	code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
766
				     (const gs_cie_common *)pcs->params.defg,
767
				     pcs->params.defg->RangeDEFG.ranges,
768
				     ONE_STEP_NOT, NULL, &ranges);
769
	break;
770
 
771
    case gs_color_space_index_Indexed:
772
	code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
773
	break;
774
 
775
    case gs_color_space_index_DeviceN:
776
        if (pdev->CompatibilityLevel < 1.3)
777
	    return_error(gs_error_rangecheck);
778
	pfn = gs_cspace_get_devn_function(pcs);
779
	/****** CURRENTLY WE ONLY HANDLE Functions ******/
780
	if (pfn == 0)
781
	    return_error(gs_error_rangecheck);
782
	{
783
	    cos_array_t *psna = 
784
		cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
785
	    int i;
786
	    byte *name_string;
787
	    uint name_string_length;
788
 
789
	    if (psna == 0)
790
		return_error(gs_error_VMerror);
791
	    for (i = 0; i < pcs->params.device_n.num_components; ++i) {
792
	 	if ((code = pcs->params.device_n.get_colorname_string(
793
				  pdev->memory,
794
				  pcs->params.device_n.names[i], &name_string, 
795
				  &name_string_length)) < 0 ||
796
		    (code = pdf_string_to_cos_name(pdev, name_string, 
797
				  name_string_length, &v)) < 0 ||
798
		    (code = cos_array_add_no_copy(psna, &v)) < 0)
799
		    return code;
800
	    }
801
	    COS_OBJECT_VALUE(&v, psna);
802
	    if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
803
						   (const gs_color_space *)
804
					&pcs->params.device_n.alt_space,
805
					pfn, &pdf_color_space_names)) < 0)
806
		return code;
807
	}
808
	break;
809
 
810
    case gs_color_space_index_Separation:
811
	pfn = gs_cspace_get_sepr_function(pcs);
812
	/****** CURRENTLY WE ONLY HANDLE Functions ******/
813
	if (pfn == 0)
814
	    return_error(gs_error_rangecheck);
815
	{
816
	    byte *name_string;
817
	    uint name_string_length;
818
	    if ((code = pcs->params.separation.get_colorname_string(
819
				  pdev->memory, 
820
				  pcs->params.separation.sep_name, &name_string, 
821
				  &name_string_length)) < 0 ||
822
		(code = pdf_string_to_cos_name(pdev, name_string, 
823
				      name_string_length, &v)) < 0 ||
824
		(code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
825
						   (const gs_color_space *)
826
					    &pcs->params.separation.alt_space,
827
					    pfn, &pdf_color_space_names)) < 0)
828
		return code;
829
	}
830
	break;
831
 
832
    case gs_color_space_index_Pattern:
833
	if ((code = pdf_color_space(pdev, pvalue, ppranges,
834
				    (const gs_color_space *)
835
				    &pcs->params.pattern.base_space,
836
				    &pdf_color_space_names, false)) < 0 ||
837
	    (code = cos_array_add(pca,
838
				  cos_c_string_value(&v, "/Pattern"))) < 0 ||
839
	    (code = cos_array_add(pca, pvalue)) < 0
840
	    )
841
	    return code;
842
	break;
843
 
844
    default:
845
	return_error(gs_error_rangecheck);
846
    }
847
    /*
848
     * Register the color space as a resource, since it must be referenced
849
     * by name rather than directly.
850
     */
851
    {
852
	pdf_color_space_t *ppcs;
853
 
854
	if (code < 0 ||
855
	    (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
856
				       &pres, -1)) < 0
857
	    ) {
858
	    COS_FREE(pca, "pdf_color_space");
859
	    return code;
860
	}
861
	pdf_reserve_object_id(pdev, pres, 0);
862
	if (res_name != NULL) {
863
	    int l = min(name_length, sizeof(pres->rname) - 1);
864
 
865
	    memcpy(pres->rname, res_name, l);
866
	    pres->rname[l] = 0;
867
	}
868
	ppcs = (pdf_color_space_t *)pres;
869
	if (serialized == serialized0) {
870
	    serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
871
	    if (serialized == NULL)
872
		return_error(gs_error_VMerror);
873
	    memcpy(serialized, serialized0, serialized_size);
874
	}
875
	ppcs->serialized = serialized;
876
	ppcs->serialized_size = serialized_size;
877
	if (ranges) {
878
	    int num_comp = gs_color_space_num_components(pcs);
879
	    gs_range_t *copy_ranges = (gs_range_t *)
880
		gs_alloc_byte_array(pdev->pdf_memory, num_comp,
881
				    sizeof(gs_range_t), "pdf_color_space");
882
 
883
	    if (copy_ranges == 0) {
884
		COS_FREE(pca, "pdf_color_space");
885
		return_error(gs_error_VMerror);
886
	    }
887
	    memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
888
	    ppcs->ranges = copy_ranges;
889
	    if (ppranges)
890
		*ppranges = copy_ranges;
891
	} else
892
	    ppcs->ranges = 0;
893
	pca->id = pres->object->id;
894
	COS_FREE(pres->object, "pdf_color_space");
895
	pres->object = (cos_object_t *)pca;
896
	cos_write_object(COS_OBJECT(pca), pdev);
897
    }
898
 ret:
899
    if (by_name) {
900
	/* Return a resource name rather than an object reference. */
901
	discard(COS_RESOURCE_VALUE(pvalue, pca));
902
    } else
903
	discard(COS_OBJECT_VALUE(pvalue, pca));
904
    if (pres != NULL) {
905
	pres->where_used |= pdev->used_mask;
906
	code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
907
	if (code < 0)
908
	    return code;
909
    }
910
    return 0;
911
}
912
 
913
int
914
pdf_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
915
		const gs_range_t **ppranges,
916
		const gs_color_space *pcs,
917
		const pdf_color_space_names_t *pcsn,
918
		bool by_name)
919
{
920
    return pdf_color_space_named(pdev, pvalue, ppranges, pcs, pcsn, by_name, NULL, 0);
921
}
922
 
923
/* ---------------- Miscellaneous ---------------- */
924
 
925
/* Create colored and uncolored Pattern color spaces. */
926
private int
927
pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
928
		  pdf_resource_t **ppres, const char *cs_name)
929
{
930
    int code;
931
 
932
    if (!*ppres) {
933
	int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
934
					   ppres);
935
 
936
	if (code < 0)
937
	    return code;
938
	pprints1(pdev->strm, "%s\n", cs_name);
939
	pdf_end_resource(pdev);
940
	(*ppres)->object->written = true; /* don't write at end */
941
	((pdf_color_space_t *)*ppres)->ranges = 0;
942
	((pdf_color_space_t *)*ppres)->serialized = 0;
943
    }
944
    code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", *ppres);
945
    if (code < 0)
946
	return code;
947
    cos_resource_value(pvalue, (*ppres)->object);
948
    return 0;
949
}
950
int
951
pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
952
{
953
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
954
			     "[/Pattern]");
955
}
956
int
957
pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
958
{
959
    /* Only for process colors. */
960
    int ncomp = pdev->color_info.num_components;
961
    static const char *const pcs_names[5] = {
962
	0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
963
	"[/Pattern /DeviceCMYK]"
964
    };
965
 
966
    return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
967
			     pcs_names[ncomp]);
968
}
969
int
970
pdf_cs_Pattern_uncolored_hl(gx_device_pdf *pdev, 
971
		const gs_color_space *pcs, cos_value_t *pvalue)
972
{
973
    /* Only for high level colors. */
974
    return pdf_color_space(pdev, pvalue, NULL, pcs, &pdf_color_space_names, true);
975
}
976
 
977
/* Set the ProcSets bits corresponding to an image color space. */
978
void
979
pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
980
{
981
    const gs_color_space *pbcs = pcs;
982
 
983
 csw:
984
    switch (gs_color_space_get_index(pbcs)) {
985
    case gs_color_space_index_DeviceGray:
986
    case gs_color_space_index_CIEA:
987
	/* We only handle CIEBasedA spaces that map to CalGray. */
988
	pdev->procsets |= ImageB;
989
	break;
990
    case gs_color_space_index_Indexed:
991
	pdev->procsets |= ImageI;
992
	pbcs = (const gs_color_space *)&pcs->params.indexed.base_space;
993
	goto csw;
994
    default:
995
	pdev->procsets |= ImageC;
996
	break;
997
    }
998
}