Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1992, 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: gscolor2.c,v 1.20 2004/04/08 07:59:19 igor Exp $ */
18
/* Level 2 color operators for Ghostscript library */
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gxarith.h"
23
#include "gxfixed.h"		/* ditto */
24
#include "gxmatrix.h"		/* for gzstate.h */
25
#include "gxcspace.h"		/* for gscolor2.h */
26
#include "gxcolor2.h"
27
#include "gzstate.h"
28
#include "gxpcolor.h"
29
#include "stream.h"
30
 
31
/* ---------------- General colors and color spaces ---------------- */
32
 
33
/* setcolorspace */
34
int
35
gs_setcolorspace(gs_state * pgs, const gs_color_space * pcs)
36
{
37
    int             code = 0;
38
    gs_color_space  cs_old = *pgs->color_space;
39
    gs_client_color cc_old = *pgs->ccolor;
40
 
41
    if (pgs->in_cachedevice)
42
	return_error(gs_error_undefined);
43
 
44
    if (pcs->id != pgs->color_space->id) {
45
        pcs->type->adjust_cspace_count(pcs, 1);
46
        *pgs->color_space = *pcs;
47
        if ( (code = pcs->type->install_cspace(pcs, pgs)) < 0          ||
48
              (pgs->overprint && (code = gs_do_set_overprint(pgs)) < 0)  ) {
49
            *pgs->color_space = cs_old;
50
            pcs->type->adjust_cspace_count(pcs, -1);
51
        } else
52
            cs_old.type->adjust_cspace_count(&cs_old, -1);
53
    }
54
 
55
    if (code >= 0) {
56
        cs_full_init_color(pgs->ccolor, pcs);
57
        cs_old.type->adjust_color_count(&cc_old, &cs_old, -1);
58
        gx_unset_dev_color(pgs);
59
    }
60
 
61
    return code;
62
}
63
 
64
/* currentcolorspace */
65
const gs_color_space *
66
gs_currentcolorspace(const gs_state * pgs)
67
{
68
    return pgs->color_space;
69
}
70
 
71
/* setcolor */
72
int
73
gs_setcolor(gs_state * pgs, const gs_client_color * pcc)
74
{
75
    gs_color_space *    pcs = pgs->color_space;
76
    gs_client_color     cc_old = *pgs->ccolor;
77
 
78
   if (pgs->in_cachedevice)
79
	return_error(gs_error_undefined); /* PLRM3 page 215. */
80
    gx_unset_dev_color(pgs);
81
    (*pcs->type->adjust_color_count)(pcc, pcs, 1);
82
    *pgs->ccolor = *pcc;
83
    (*pcs->type->restrict_color)(pgs->ccolor, pcs);
84
    (*pcs->type->adjust_color_count)(&cc_old, pcs, -1);
85
 
86
    return 0;
87
}
88
 
89
/* currentcolor */
90
const gs_client_color *
91
gs_currentcolor(const gs_state * pgs)
92
{
93
    return pgs->ccolor;
94
}
95
 
96
/* ------ Internal procedures ------ */
97
 
98
/* GC descriptors */
99
private_st_indexed_map();
100
 
101
/* Define a lookup_index procedure that just returns the map values. */
102
int
103
lookup_indexed_map(const gs_indexed_params * params, int index, float *values)
104
{
105
    int m = cs_num_components((const gs_color_space *)&params->base_space);
106
    const float *pv = &params->lookup.map->values[index * m];
107
 
108
    memcpy(values, pv, sizeof(*values) * m);
109
    return 0;
110
}
111
 
112
/* Free an indexed map and its values when the reference count goes to 0. */
113
void
114
free_indexed_map(gs_memory_t * pmem, void *pmap, client_name_t cname)
115
{
116
    gs_free_object(pmem, ((gs_indexed_map *) pmap)->values, cname);
117
    gs_free_object(pmem, pmap, cname);
118
}
119
 
120
/*
121
 * Allocate an indexed map for an Indexed or Separation color space.
122
 */
123
int
124
alloc_indexed_map(gs_indexed_map ** ppmap, int nvals, gs_memory_t * pmem,
125
		  client_name_t cname)
126
{
127
    gs_indexed_map *pimap;
128
 
129
    rc_alloc_struct_1(pimap, gs_indexed_map, &st_indexed_map, pmem,
130
		      return_error(gs_error_VMerror), cname);
131
    if (nvals > 0) {
132
	pimap->values =
133
	    (float *)gs_alloc_byte_array(pmem, nvals, sizeof(float), cname);
134
 
135
	if (pimap->values == 0) {
136
	    gs_free_object(pmem, pimap, cname);
137
	    return_error(gs_error_VMerror);
138
	}
139
    } else
140
	pimap->values = 0;
141
    pimap->rc.free = free_indexed_map;
142
    pimap->proc_data = 0;	/* for GC */
143
    pimap->num_values = nvals;
144
    *ppmap = pimap;
145
    return 0;
146
}
147
 
148
/* ---------------- Indexed color spaces ---------------- */
149
 
150
gs_private_st_composite(st_color_space_Indexed, gs_paint_color_space,
151
     "gs_color_space_Indexed", cs_Indexed_enum_ptrs, cs_Indexed_reloc_ptrs);
152
 
153
/* ------ Color space ------ */
154
 
155
/* Define the Indexed color space type. */
156
private cs_proc_base_space(gx_base_space_Indexed);
157
private cs_proc_restrict_color(gx_restrict_Indexed);
158
private cs_proc_concrete_space(gx_concrete_space_Indexed);
159
private cs_proc_concretize_color(gx_concretize_Indexed);
160
private cs_proc_install_cspace(gx_install_Indexed);
161
private cs_proc_set_overprint(gx_set_overprint_Indexed);
162
private cs_proc_adjust_cspace_count(gx_adjust_cspace_Indexed);
163
private cs_proc_serialize(gx_serialize_Indexed);
164
const gs_color_space_type gs_color_space_type_Indexed = {
165
    gs_color_space_index_Indexed, false, false,
166
    &st_color_space_Indexed, gx_num_components_1,
167
    gx_base_space_Indexed,
168
    gx_init_paint_1, gx_restrict_Indexed,
169
    gx_concrete_space_Indexed,
170
    gx_concretize_Indexed, NULL,
171
    gx_default_remap_color, gx_install_Indexed,
172
    gx_set_overprint_Indexed,
173
    gx_adjust_cspace_Indexed, gx_no_adjust_color_count,
174
    gx_serialize_Indexed,
175
    gx_cspace_is_linear_default
176
};
177
 
178
/* GC procedures. */
179
 
180
private uint
181
indexed_table_size(const gs_color_space *pcs)
182
{
183
    return (pcs->params.indexed.hival + 1) *
184
	cs_num_components((const gs_color_space *)
185
			  &pcs->params.indexed.base_space);
186
 
187
}
188
private 
189
ENUM_PTRS_WITH(cs_Indexed_enum_ptrs, gs_color_space *pcs)
190
{
191
    return ENUM_USING(*pcs->params.indexed.base_space.type->stype,
192
		      &pcs->params.indexed.base_space,
193
		      sizeof(pcs->params.indexed.base_space), index - 1);
194
}
195
case 0:
196
if (pcs->params.indexed.use_proc)
197
    ENUM_RETURN((void *)pcs->params.indexed.lookup.map);
198
else
199
    return ENUM_CONST_STRING2(pcs->params.indexed.lookup.table.data,
200
			      indexed_table_size(pcs));
201
ENUM_PTRS_END
202
private RELOC_PTRS_WITH(cs_Indexed_reloc_ptrs, gs_color_space *pcs)
203
{
204
    RELOC_USING(*pcs->params.indexed.base_space.type->stype,
205
		&pcs->params.indexed.base_space,
206
		sizeof(gs_base_color_space));
207
    if (pcs->params.indexed.use_proc)
208
	RELOC_PTR(gs_color_space, params.indexed.lookup.map);
209
    else {
210
	gs_const_string table;
211
 
212
	table.data = pcs->params.indexed.lookup.table.data;
213
	table.size = indexed_table_size(pcs);
214
	RELOC_CONST_STRING_VAR(table);
215
	pcs->params.indexed.lookup.table.data = table.data;
216
    }
217
}
218
RELOC_PTRS_END
219
 
220
/* Return the base space of an Indexed color space. */
221
private const gs_color_space *
222
gx_base_space_Indexed(const gs_color_space * pcs)
223
{
224
    return (const gs_color_space *)&(pcs->params.indexed.base_space);
225
}
226
 
227
 
228
/* Color space installation ditto. */
229
 
230
private int
231
gx_install_Indexed(const gs_color_space * pcs, gs_state * pgs)
232
{
233
    return (*pcs->params.indexed.base_space.type->install_cspace)
234
	((const gs_color_space *) & pcs->params.indexed.base_space, pgs);
235
}
236
 
237
/* Color space overprint setting ditto. */
238
 
239
private int
240
gx_set_overprint_Indexed(const gs_color_space * pcs, gs_state * pgs)
241
{
242
    return (*pcs->params.indexed.base_space.type->set_overprint)
243
	((const gs_color_space *)&pcs->params.indexed.base_space, pgs);
244
}
245
 
246
/* Color space reference count adjustment ditto. */
247
 
248
private void
249
gx_adjust_cspace_Indexed(const gs_color_space * pcs, int delta)
250
{
251
    if (pcs->params.indexed.use_proc) {
252
	rc_adjust_const(pcs->params.indexed.lookup.map, delta,
253
			"gx_adjust_Indexed");
254
    }
255
    (*pcs->params.indexed.base_space.type->adjust_cspace_count)
256
	((const gs_color_space *)&pcs->params.indexed.base_space, delta);
257
}
258
 
259
/*
260
 * Default palette mapping functions for indexed color maps. These just
261
 * return the values already in the palette.
262
 *
263
 * For performance reasons, we provide four functions: special cases for 1,
264
 * 3, and 4 entry palettes, and a general case. Note that these procedures
265
 * do not range-check their input values.
266
 */
267
private int
268
map_palette_entry_1(const gs_indexed_params * params, int indx, float *values)
269
{
270
    values[0] = params->lookup.map->values[indx];
271
    return 0;
272
}
273
 
274
private int
275
map_palette_entry_3(const gs_indexed_params * params, int indx, float *values)
276
{
277
    const float *pv = &(params->lookup.map->values[3 * indx]);
278
 
279
    values[0] = pv[0];
280
    values[1] = pv[1];
281
    values[2] = pv[2];
282
    return 0;
283
}
284
 
285
private int
286
map_palette_entry_4(const gs_indexed_params * params, int indx, float *values)
287
{
288
    const float *pv = &(params->lookup.map->values[4 * indx]);
289
 
290
    values[0] = pv[0];
291
    values[1] = pv[1];
292
    values[2] = pv[2];
293
    values[3] = pv[3];
294
    return 0;
295
}
296
 
297
private int
298
map_palette_entry_n(const gs_indexed_params * params, int indx, float *values)
299
{
300
    int m = cs_num_components((const gs_color_space *)&params->base_space);
301
 
302
    memcpy((void *)values,
303
	   (const void *)(params->lookup.map->values + indx * m),
304
	   m * sizeof(float)
305
    );
306
 
307
    return 0;
308
}
309
 
310
/*
311
 * Allocate an indexed map to be used as a palette for indexed color space.
312
 */
313
private gs_indexed_map *
314
alloc_indexed_palette(
315
			 const gs_color_space * pbase_cspace,
316
			 int nvals,
317
			 gs_memory_t * pmem
318
)
319
{
320
    int num_comps = gs_color_space_num_components(pbase_cspace);
321
    gs_indexed_map *pimap;
322
    int code =
323
    alloc_indexed_map(&pimap, nvals * num_comps, pmem,
324
		      "alloc_indexed_palette");
325
 
326
    if (code < 0)
327
	return 0;
328
    if (num_comps == 1)
329
	pimap->proc.lookup_index = map_palette_entry_1;
330
    else if (num_comps == 3)
331
	pimap->proc.lookup_index = map_palette_entry_3;
332
    else if (num_comps == 4)
333
	pimap->proc.lookup_index = map_palette_entry_4;
334
    else
335
	pimap->proc.lookup_index = map_palette_entry_n;
336
    return pimap;
337
}
338
 
339
/*
340
 * Build an indexed color space.
341
 */
342
int
343
gs_cspace_build_Indexed(
344
			   gs_color_space ** ppcspace,
345
			   const gs_color_space * pbase_cspace,
346
			   uint num_entries,
347
			   const gs_const_string * ptbl,
348
			   gs_memory_t * pmem
349
)
350
{
351
    gs_color_space *pcspace = 0;
352
    gs_indexed_params *pindexed = 0;
353
    int code;
354
 
355
    if ((pbase_cspace == 0) || !pbase_cspace->type->can_be_base_space)
356
	return_error(gs_error_rangecheck);
357
 
358
    code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Indexed, pmem);
359
    if (code < 0)
360
	return code;
361
    pindexed = &(pcspace->params.indexed);
362
    if (ptbl == 0) {
363
	pindexed->lookup.map =
364
	    alloc_indexed_palette(pbase_cspace, num_entries, pmem);
365
	if (pindexed->lookup.map == 0) {
366
	    gs_free_object(pmem, pcspace, "gs_cspace_build_Indexed");
367
	    return_error(gs_error_VMerror);
368
	}
369
	pindexed->use_proc = true;
370
    } else {
371
	pindexed->lookup.table = *ptbl;
372
	pindexed->use_proc = false;
373
    }
374
    gs_cspace_init_from((gs_color_space *) & (pindexed->base_space),
375
			pbase_cspace);
376
    pindexed->hival = num_entries - 1;
377
    *ppcspace = pcspace;
378
    return 0;
379
}
380
 
381
/*
382
 * Return the number of entries in an indexed color space.
383
 */
384
int
385
gs_cspace_indexed_num_entries(const gs_color_space * pcspace)
386
{
387
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed)
388
	return 0;
389
    return pcspace->params.indexed.hival + 1;
390
}
391
 
392
/*
393
 * Get the palette for an indexed color space. This will return a null
394
 * pointer if the color space is not an indexed color space or if the
395
 * color space does not use the mapped index palette.
396
 */
397
float *
398
gs_cspace_indexed_value_array(const gs_color_space * pcspace)
399
{
400
    if ((gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed) ||
401
	pcspace->params.indexed.use_proc
402
	)
403
	return 0;
404
    return pcspace->params.indexed.lookup.map->values;
405
}
406
 
407
/*
408
 * Set the lookup procedure to be used with an indexed color space.
409
 */
410
int
411
gs_cspace_indexed_set_proc(
412
			   gs_color_space * pcspace,
413
			   int (*proc)(const gs_indexed_params *, int, float *)
414
)
415
{
416
    if ((gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed) ||
417
	!pcspace->params.indexed.use_proc
418
	)
419
	return_error(gs_error_rangecheck);
420
    pcspace->params.indexed.lookup.map->proc.lookup_index = proc;
421
    return 0;
422
}
423
 
424
/* ------ Colors ------ */
425
 
426
/* Force an Indexed color into legal range. */
427
private void
428
gx_restrict_Indexed(gs_client_color * pcc, const gs_color_space * pcs)
429
{
430
    float value = pcc->paint.values[0];
431
 
432
    pcc->paint.values[0] =
433
	(is_fneg(value) ? 0 :
434
	 value >= pcs->params.indexed.hival ? pcs->params.indexed.hival :
435
	 value);
436
}
437
 
438
/* Color remapping for Indexed color spaces. */
439
private const gs_color_space *
440
gx_concrete_space_Indexed(const gs_color_space * pcs,
441
			  const gs_imager_state * pis)
442
{
443
    const gs_color_space *pbcs =
444
    (const gs_color_space *)&pcs->params.indexed.base_space;
445
 
446
    return cs_concrete_space(pbcs, pis);
447
}
448
 
449
private int
450
gx_concretize_Indexed(const gs_client_color * pc, const gs_color_space * pcs,
451
		      frac * pconc, const gs_imager_state * pis)
452
{
453
    float value = pc->paint.values[0];
454
    int index =
455
	(is_fneg(value) ? 0 :
456
	 value >= pcs->params.indexed.hival ? pcs->params.indexed.hival :
457
	 (int)value);
458
    const gs_color_space *pbcs =
459
	(const gs_color_space *)&pcs->params.indexed.base_space;
460
    gs_client_color cc;
461
    int code = gs_cspace_indexed_lookup(&pcs->params.indexed, index, &cc);
462
 
463
    if (code < 0)
464
	return code;
465
    return (*pbcs->type->concretize_color) (&cc, pbcs, pconc, pis);
466
}
467
 
468
/* Look up an index in an Indexed color space. */
469
int
470
gs_cspace_indexed_lookup(const gs_indexed_params *pip, int index,
471
			 gs_client_color *pcc)
472
{
473
    if (pip->use_proc) {
474
	return pip->lookup.map->proc.lookup_index
475
	    (pip, index, &pcc->paint.values[0]);
476
    } else {
477
	const gs_color_space *pbcs = (const gs_color_space *)&pip->base_space;
478
	int m = cs_num_components(pbcs);
479
	const byte *pcomp = pip->lookup.table.data + m * index;
480
 
481
	switch (m) {
482
	    default: {		/* DeviceN */
483
		int i;
484
 
485
		for (i = 0; i < m; ++i)
486
		    pcc->paint.values[i] = pcomp[i] * (1.0 / 255.0);
487
	    }
488
		break;
489
	    case 4:
490
		pcc->paint.values[3] = pcomp[3] * (1.0 / 255.0);
491
	    case 3:
492
		pcc->paint.values[2] = pcomp[2] * (1.0 / 255.0);
493
	    case 2:
494
		pcc->paint.values[1] = pcomp[1] * (1.0 / 255.0);
495
	    case 1:
496
		pcc->paint.values[0] = pcomp[0] * (1.0 / 255.0);
497
	}
498
	return 0;
499
    }
500
}
501
 
502
/* ---------------- Serialization. -------------------------------- */
503
 
504
private int 
505
gx_serialize_Indexed(const gs_color_space * pcs, stream * s)
506
{
507
    const gs_indexed_params * p = &pcs->params.indexed;
508
    uint n;
509
    int code = gx_serialize_cspace_type(pcs, s);
510
 
511
    if (code < 0)
512
	return code;
513
    code = cs_serialize((const gs_color_space *)&p->base_space, s);
514
    if (code < 0)
515
	return code;
516
    code = sputs(s, (const byte *)&p->hival, sizeof(p->hival), &n);
517
    if (code < 0)
518
	return code;
519
    code = sputs(s, (const byte *)&p->use_proc, sizeof(p->use_proc), &n);
520
    if (code < 0)
521
	return code;
522
    if (p->use_proc) {
523
	code = sputs(s, (const byte *)&p->lookup.map->num_values, 
524
		sizeof(p->lookup.map->num_values), &n);
525
	if (code < 0)
526
	    return code;
527
	code = sputs(s, (const byte *)&p->lookup.map->values[0], 
528
		sizeof(p->lookup.map->values[0]) * p->lookup.map->num_values, &n);
529
    } else {
530
	code = sputs(s, (const byte *)&p->lookup.table.size, 
531
			sizeof(p->lookup.table.size), &n);
532
	if (code < 0)
533
	    return code;
534
	code = sputs(s, p->lookup.table.data, p->lookup.table.size, &n);
535
    }
536
    return code;
537
}
538
 
539
/* ---------------- High level device support -------------------------------- */
540
 
541
/*
542
 * This special function forces a device to include the current
543
 * color space into the output. Returns 'rangecheck' if the device can't handle it.
544
 * The primary reason is to include DefaultGray, DefaultRGB, DefaultCMYK into PDF.
545
 * Should be called for each page that requires the resource.
546
 * Redundant calls per page with same cspace id are allowed.
547
 * Redundant calls per page with different cspace id are are allowed but 
548
 * highly undesirable.
549
 * No need to call it with color spaces explicitly referred by the document,
550
 * because they are included automatically.
551
 * res_name and name_length passes the resource name.
552
 */
553
int
554
gs_includecolorspace(gs_state * pgs, const byte *res_name, int name_length)
555
{
556
    return (*dev_proc(pgs->device, include_color_space))(pgs->device, pgs->color_space, res_name, name_length);
557
}