Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1994, 2000 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: gscsepr.c,v 1.27 2004/08/04 19:36:12 stefan Exp $ */
18
/* Separation color space and operation definition */
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsfunc.h"
23
#include "gsrefct.h"
24
#include "gsmatrix.h"		/* for gscolor2.h */
25
#include "gscsepr.h"
26
#include "gxcspace.h"
27
#include "gxfixed.h"		/* for gxcolor2.h */
28
#include "gxcolor2.h"		/* for gs_indexed_map */
29
#include "gzstate.h"		/* for pgs->overprint */
30
#include "gscdevn.h"		/* for alloc_device_n_map */
31
#include "gxcdevn.h"		/* for gs_device_n_map_s */
32
#include "gxcmap.h"
33
#include "gxdevcli.h"
34
#include "gsovrc.h"
35
#include "stream.h"
36
 
37
/* ---------------- Color space ---------------- */
38
 
39
gs_private_st_composite(st_color_space_Separation, gs_paint_color_space,
40
			"gs_color_space_Separation",
41
			cs_Separation_enum_ptrs, cs_Separation_reloc_ptrs);
42
 
43
/* Define the Separation color space type. */
44
private cs_proc_base_space(gx_alt_space_Separation);
45
private cs_proc_init_color(gx_init_Separation);
46
private cs_proc_concrete_space(gx_concrete_space_Separation);
47
private cs_proc_concretize_color(gx_concretize_Separation);
48
private cs_proc_remap_concrete_color(gx_remap_concrete_Separation);
49
private cs_proc_remap_color(gx_remap_Separation);
50
private cs_proc_install_cspace(gx_install_Separation);
51
private cs_proc_set_overprint(gx_set_overprint_Separation);
52
private cs_proc_adjust_cspace_count(gx_adjust_cspace_Separation);
53
private cs_proc_serialize(gx_serialize_Separation);
54
const gs_color_space_type gs_color_space_type_Separation = {
55
    gs_color_space_index_Separation, true, false,
56
    &st_color_space_Separation, gx_num_components_1,
57
    gx_alt_space_Separation,
58
    gx_init_Separation, gx_restrict01_paint_1,
59
    gx_concrete_space_Separation,
60
    gx_concretize_Separation, gx_remap_concrete_Separation,
61
    gx_remap_Separation, gx_install_Separation,
62
    gx_set_overprint_Separation,
63
    gx_adjust_cspace_Separation, gx_no_adjust_color_count,
64
    gx_serialize_Separation,
65
    gx_cspace_is_linear_default
66
};
67
 
68
/* GC procedures */
69
 
70
private 
71
ENUM_PTRS_WITH(cs_Separation_enum_ptrs, gs_color_space *pcs)
72
{
73
    return ENUM_USING(*pcs->params.separation.alt_space.type->stype,
74
		      &pcs->params.separation.alt_space,
75
		      sizeof(pcs->params.separation.alt_space), index - 1);
76
}
77
ENUM_PTR(0, gs_color_space, params.separation.map);
78
ENUM_PTRS_END
79
private RELOC_PTRS_WITH(cs_Separation_reloc_ptrs, gs_color_space *pcs)
80
{
81
    RELOC_PTR(gs_color_space, params.separation.map);
82
    RELOC_USING(*pcs->params.separation.alt_space.type->stype,
83
		&pcs->params.separation.alt_space,
84
		sizeof(gs_base_color_space));
85
}
86
RELOC_PTRS_END
87
 
88
/* Get the alternate space for a Separation space. */
89
private const gs_color_space *
90
gx_alt_space_Separation(const gs_color_space * pcs)
91
{
92
    return pcs->params.separation.use_alt_cspace
93
	   ? (const gs_color_space *)&(pcs->params.separation.alt_space)
94
    	   : NULL;
95
}
96
 
97
/* Get the concrete space for a Separation space. */
98
private const gs_color_space *
99
gx_concrete_space_Separation(const gs_color_space * pcs,
100
			     const gs_imager_state * pis)
101
{
102
#ifdef DEBUG
103
    /* 
104
     * Verify that the color space and imager state info match.
105
     */
106
    if (pcs->id != pis->color_component_map.cspace_id)
107
	dprintf("gx_concretze_space_Separation: color space id mismatch");
108
#endif
109
 
110
    /*
111
     * Check if we are using the alternate color space.
112
     */
113
    if (pis->color_component_map.use_alt_cspace) {
114
        const gs_color_space *pacs =
115
	    (const gs_color_space *)&pcs->params.separation.alt_space;
116
 
117
        return cs_concrete_space(pacs, pis);
118
    }
119
    /*
120
     * Separation color spaces are concrete (when not using alt. color space).
121
     */
122
    return pcs;
123
}
124
 
125
private int
126
check_Separation_component_name(const gs_color_space * pcs, gs_state * pgs);
127
 
128
/* Install a Separation color space. */
129
private int
130
gx_install_Separation(const gs_color_space * pcs, gs_state * pgs)
131
{
132
    int code = check_Separation_component_name(pcs, pgs);
133
 
134
    if (code < 0)
135
       return code;
136
    pgs->color_space->params.separation.use_alt_cspace =
137
	using_alt_color_space(pgs);
138
    if (pgs->color_space->params.separation.use_alt_cspace)
139
        code = (*pcs->params.separation.alt_space.type->install_cspace)
140
	((const gs_color_space *) & pcs->params.separation.alt_space, pgs);
141
    /*
142
     * Give the device an opportunity to capture equivalent colors for any
143
     * spot colors which might be present in the color space.
144
     */
145
    if (code >= 0)
146
        code = dev_proc(pgs->device, update_spot_equivalent_colors)
147
							(pgs->device, pgs);
148
    return code;
149
}
150
 
151
/* Set the overprint information appropriate to a separation color space */
152
private int
153
gx_set_overprint_Separation(const gs_color_space * pcs, gs_state * pgs)
154
{
155
    gs_devicen_color_map *  pcmap = &pgs->color_component_map;
156
 
157
    if (pcmap->use_alt_cspace)
158
        return gx_spot_colors_set_overprint( 
159
                   (const gs_color_space *)&pcs->params.separation.alt_space,
160
                   pgs );
161
    else {
162
        gs_overprint_params_t   params;
163
 
164
        params.retain_any_comps = pgs->overprint &&
165
                                  pcs->params.separation.sep_type != SEP_ALL;
166
        if (params.retain_any_comps) {
167
            params.retain_spot_comps = false;
168
            params.drawn_comps = 0;
169
            if (pcs->params.separation.sep_type != SEP_NONE) {
170
                int     mcomp = pcmap->color_map[0];
171
 
172
                if (mcomp >= 0)
173
		    gs_overprint_set_drawn_comp( params.drawn_comps, mcomp);
174
            }
175
        }
176
 
177
        pgs->effective_overprint_mode = 0;
178
        return gs_state_update_overprint(pgs, &params);
179
    }
180
}
181
 
182
/* Adjust the reference count of a Separation color space. */
183
private void
184
gx_adjust_cspace_Separation(const gs_color_space * pcs, int delta)
185
{
186
    rc_adjust_const(pcs->params.separation.map, delta,
187
		    "gx_adjust_Separation");
188
    (*pcs->params.separation.alt_space.type->adjust_cspace_count)
189
	((const gs_color_space *)&pcs->params.separation.alt_space, delta);
190
}
191
 
192
/* ------ Constructors/accessors ------ */
193
 
194
/*
195
 * Build a separation color space.
196
 */
197
int
198
gs_build_Separation(
199
		    gs_color_space * pcspace,
200
		    const gs_color_space * palt_cspace,
201
		    gs_memory_t * pmem
202
)
203
{
204
    gs_separation_params * pcssepr = &pcspace->params.separation;
205
    int code;
206
 
207
    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
208
	return_error(gs_error_rangecheck);
209
 
210
    code = alloc_device_n_map(&pcssepr->map, pmem, "gs_cspace_build_Separation");
211
    if (pcssepr->map == NULL) {
212
	gs_free_object(pmem, pcspace, "gs_cspace_build_Separation");
213
	return_error(gs_error_VMerror);
214
    }
215
    return 0;
216
}
217
 
218
/*
219
 * Build a separation color space.
220
 *
221
 * The values array provided with separation color spaces is actually cached
222
 * information, but filled in by the client. The alternative space is the
223
 * color space in which the tint procedure will provide alternative colors.
224
 */
225
int
226
gs_cspace_build_Separation(
227
			      gs_color_space ** ppcspace,
228
			      gs_separation_name sname,
229
			      const gs_color_space * palt_cspace,
230
			      int cache_size,
231
			      gs_memory_t * pmem
232
)
233
{
234
    gs_color_space *pcspace = NULL;
235
    gs_separation_params *pcssepr = NULL;
236
    int code;
237
 
238
    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
239
	return_error(gs_error_rangecheck);
240
 
241
    code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Separation, pmem);
242
    if (code < 0)
243
	return code;
244
 
245
    code = gs_build_Separation(pcspace, palt_cspace, pmem);
246
    if (code < 0) {
247
	gs_free_object(pmem, pcspace, "gs_cspace_build_Separation");
248
	return code;
249
    }
250
    pcssepr->sep_name = sname;
251
    gs_cspace_init_from((gs_color_space *) & pcssepr->alt_space, palt_cspace);
252
    *ppcspace = pcspace;
253
    return 0;
254
}
255
 
256
#if 0 /* Unused; Unsupported by gx_serialize_device_n_map. */
257
/*
258
 * Set the tint transformation procedure used by a Separation color space.
259
 */
260
int
261
gs_cspace_set_sepr_proc(gs_color_space * pcspace,
262
			int (*proc)(const float *,
263
                                    float *,
264
                                    const gs_imager_state *,
265
                                    void *
266
				    ),
267
			void *proc_data
268
			)
269
{
270
    gs_device_n_map *pimap;
271
 
272
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
273
	return_error(gs_error_rangecheck);
274
    pimap = pcspace->params.separation.map;
275
    pimap->tint_transform = proc;
276
    pimap->tint_transform_data = proc_data;
277
    pimap->cache_valid = false;
278
 
279
    return 0;
280
}
281
#endif
282
 
283
/*
284
 * Set the Separation tint transformation procedure to a Function.
285
 */
286
int
287
gs_cspace_set_sepr_function(const gs_color_space *pcspace, gs_function_t *pfn)
288
{
289
    gs_device_n_map *pimap;
290
 
291
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation ||
292
	pfn->params.m != 1 || pfn->params.n !=
293
	  gs_color_space_num_components((const gs_color_space *)
294
					&pcspace->params.separation.alt_space)
295
	)
296
	return_error(gs_error_rangecheck);
297
    pimap = pcspace->params.separation.map;
298
    pimap->tint_transform = map_devn_using_function;
299
    pimap->tint_transform_data = pfn;
300
    pimap->cache_valid = false;
301
    return 0;
302
}
303
 
304
/*
305
 * If the Separation tint transformation procedure is a Function,
306
 * return the function object, otherwise return 0.
307
 */
308
gs_function_t *
309
gs_cspace_get_sepr_function(const gs_color_space *pcspace)
310
{
311
    if (gs_color_space_get_index(pcspace) == gs_color_space_index_Separation &&
312
	pcspace->params.separation.map->tint_transform ==
313
	  map_devn_using_function)
314
	return pcspace->params.separation.map->tint_transform_data;
315
    return 0;
316
}
317
 
318
/* ------ Internal procedures ------ */
319
 
320
/* Initialize a Separation color. */
321
private void
322
gx_init_Separation(gs_client_color * pcc, const gs_color_space * pcs)
323
{
324
    pcc->paint.values[0] = 1.0;
325
}
326
 
327
/* Remap a Separation color. */
328
 
329
private int
330
gx_remap_Separation(const gs_client_color * pcc, const gs_color_space * pcs,
331
	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
332
		       gs_color_select_t select)
333
{
334
    int code = 0;
335
 
336
    if (pcs->params.separation.sep_type != SEP_NONE)
337
	code = gx_default_remap_color(pcc, pcs, pdc, pis, dev, select);
338
    else {
339
        color_set_null(pdc);
340
    }
341
    /* Save original color space and color info into dev color */
342
    pdc->ccolor.paint.values[0] = pcc->paint.values[0];
343
    pdc->ccolor_valid = true;
344
    return code;
345
}
346
 
347
private int
348
gx_concretize_Separation(const gs_client_color *pc, const gs_color_space *pcs,
349
			 frac *pconc, const gs_imager_state *pis)
350
{
351
    float ftemp;
352
    int code;
353
    gs_client_color cc;
354
    const gs_color_space *pacs =
355
	(const gs_color_space *)&pcs->params.separation.alt_space;
356
 
357
    if (pcs->params.separation.sep_type == SEP_OTHER &&
358
        pcs->params.separation.use_alt_cspace) {
359
        gs_device_n_map *map = pcs->params.separation.map;
360
 
361
	/* Check the 1-element cache first. */
362
	if (map->cache_valid && map->tint[0] == pc->paint.values[0]) {
363
	    int i, num_out = gs_color_space_num_components(pacs);
364
 
365
	    for (i = 0; i < num_out; ++i)
366
		pconc[i] = map->conc[i];
367
	    return 0;
368
	}
369
        code = (*pcs->params.separation.map->tint_transform)
370
	    (pc->paint.values, &cc.paint.values[0],
371
	     pis, pcs->params.separation.map->tint_transform_data);
372
        if (code < 0)
373
	    return code;
374
	return cs_concretize_color(&cc, pacs, pconc, pis);
375
    }
376
    else {
377
    	pconc[0] = unit_frac(pc->paint.values[0], ftemp);
378
    }
379
    return 0;
380
}
381
 
382
private int
383
gx_remap_concrete_Separation(const frac * pconc,  const gs_color_space * pcs,
384
	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
385
			     gs_color_select_t select)
386
{
387
#ifdef DEBUG
388
    /* 
389
     * Verify that the color space and imager state info match.
390
     */
391
    if (pcs->id != pis->color_component_map.cspace_id)
392
	dprintf("gx_remap_concrete_Separation: color space id mismatch");
393
#endif
394
 
395
    if (pis->color_component_map.use_alt_cspace) {
396
        const gs_color_space *pacs =
397
	    (const gs_color_space *)&pcs->params.separation.alt_space;
398
 
399
	return (*pacs->type->remap_concrete_color)
400
				(pconc, pacs, pdc, pis, dev, select);
401
    }
402
    else {
403
        gx_remap_concrete_separation(pconc[0], pdc, pis, dev, select);
404
        return 0;
405
    }
406
}
407
 
408
/*
409
 * Check that the color component name for a Separation color space
410
 * matches the device colorant names.  Also build a gs_devicen_color_map
411
 * structure.
412
 */
413
private int
414
check_Separation_component_name(const gs_color_space * pcs, gs_state * pgs)
415
{
416
    const gs_separation_name name = pcs->params.separation.sep_name;
417
    int colorant_number;
418
    byte * pname;
419
    uint name_size;
420
    gs_devicen_color_map * pcolor_component_map
421
	= &pgs->color_component_map;
422
    gx_device * dev = pgs->device;
423
 
424
    pcolor_component_map->num_components = 1;
425
    pcolor_component_map->cspace_id = pcs->id;
426
    pcolor_component_map->num_colorants = dev->color_info.num_components;
427
    pcolor_component_map->sep_type = pcs->params.separation.sep_type;
428
    /*
429
     * If this is a None or All separation then we do not need to
430
     * use the alternate color space.
431
     */
432
    if (pcs->params.separation.sep_type != SEP_OTHER) {
433
	pcolor_component_map->use_alt_cspace = false;
434
	return 0;
435
    }
436
    /*
437
     * Always use the alternate color space if the current device is
438
     * using an additive color model.  Separations are only for use
439
     * with a subtractive color model.
440
     */
441
    if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
442
	pcolor_component_map->use_alt_cspace = true;
443
	return 0;
444
    }
445
    /*
446
     * Get the character string and length for the component name.
447
     */
448
    pcs->params.separation.get_colorname_string(dev->memory, name, &pname, &name_size);
449
    /*
450
     * Compare the colorant name to the device's.  If the device's
451
     * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
452
     * colorant is in the SeparationNames list but not in the
453
     * SeparationOrder list.
454
     */
455
    colorant_number = (*dev_proc(dev, get_color_comp_index))
456
		(dev, (const char *)pname, name_size, SEPARATION_NAME);
457
    if (colorant_number >= 0) {		/* If valid colorant name */
458
	pcolor_component_map->color_map[0] =
459
		    (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
460
		    					   : colorant_number;
461
	pcolor_component_map->use_alt_cspace = false;
462
    }
463
    else
464
	pcolor_component_map->use_alt_cspace = true;
465
    return 0;
466
}
467
 
468
 
469
/* ---------------- Notes on real Separation colors ---------------- */
470
 
471
typedef ulong gs_separation;	/* BOGUS */
472
 
473
#define gs_no_separation ((gs_separation)(-1L))
474
 
475
#define dev_proc_lookup_separation(proc)\
476
  gs_separation proc(gx_device *dev, const byte *sname, uint len,\
477
    gx_color_value *num_levels)
478
 
479
#define dev_proc_map_tint_color(proc)\
480
  gx_color_index proc(gx_device *dev, gs_separation sepr, bool overprint,\
481
    gx_color_value tint)
482
 
483
/*
484
 * This next comment is outdated since the Separation color space no longer
485
 * has the multi element cache (lookup table) however the remainder is
486
 * still appropriate.
487
 *
488
 * In principle, setting a Separation color space, or setting the device
489
 * when the current color space is a Separation space, calls the
490
 * lookup_separation device procedure to obtain the separation ID and
491
 * the number of achievable levels.  Currently, the only hooks for doing
492
 * this are unsuitable: gx_set_cmap_procs isn't called when the color
493
 * space changes, and doing it in gx_remap_Separation is inefficient.
494
 * Probably the best approach is to call gx_set_cmap_procs whenever the
495
 * color space changes.  In fact, if we do this, we can probably short-cut
496
 * two levels of procedure call in color remapping (gx_remap_color, by
497
 * turning it into a macro, and gx_remap_DeviceXXX, by calling the
498
 * cmap_proc procedure directly).  Some care will be required for the
499
 * implicit temporary resetting of the color space in [color]image.
500
 */
501
 
502
/* ---------------- Serialization. -------------------------------- */
503
 
504
private int 
505
gx_serialize_Separation(const gs_color_space * pcs, stream * s)
506
{
507
    const gs_separation_params * p = &pcs->params.separation;
508
    uint n;
509
    int code = gx_serialize_cspace_type(pcs, s);
510
 
511
    if (code < 0)
512
	return code;
513
    code = sputs(s, (const byte *)&p->sep_name, sizeof(p->sep_name), &n);
514
    if (code < 0)
515
	return code;
516
    code = cs_serialize((const gs_color_space *)&p->alt_space, s);
517
    if (code < 0)
518
	return code;
519
    code = gx_serialize_device_n_map(pcs, p->map, s);
520
    if (code < 0)
521
	return code;
522
    return sputs(s, (const byte *)&p->sep_type, sizeof(p->sep_type), &n);
523
    /* p->use_alt_cspace isn't a property of the space. */
524
}