home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* zcsindex.c */
- /* Level 2 Indexed and Separation color space support */
- #include "ghost.h"
- #include "errors.h"
- #include "oper.h"
- #include "gsstruct.h"
- #include "gscolor.h"
- #include "gscspace.h"
- #include "gxfixed.h" /* for gxcolor2.h */
- #include "gxcolor2.h"
- #include "estack.h"
- #include "ialloc.h"
- #include "igstate.h"
- #include "store.h"
-
- /* Imported from gscolor2.c */
- extern const gs_color_space_type
- gs_color_space_type_Indexed,
- gs_color_space_type_Separation;
-
- /* Forward references */
- private int begin_map(P5(gs_indexed_map **, const ref *, int,
- const gs_base_color_space *, int (*)(P1(os_ptr))));
- private int indexed_map1(P1(os_ptr));
- private int separation_map1(P1(os_ptr));
-
- /* Allocator type for indexed map */
- private_st_indexed_map();
-
- /* Free the map when freeing the gs_indexed_map structure. */
- private void
- rc_free_indexed_map(gs_memory_t *mem, char *data, client_name_t cname)
- { gs_free_object(mem, ((gs_indexed_map *)data)->values, cname);
- gs_free_object(mem, data, cname);
- }
-
- /* ------ Indexed color space ------ */
-
- /* Indexed lookup procedure that just consults the cache. */
- private int
- lookup_indexed(const gs_indexed_params *params, int index, float *values)
- { int m = params->base_space.type->num_components;
- const float *pv = ¶ms->lookup.map->values[index * m];
- switch ( m )
- {
- default: return_error(e_rangecheck);
- case 4: values[3] = pv[3];
- case 3: values[2] = pv[2];
- values[1] = pv[1];
- case 1: values[0] = pv[0];
- }
- return 0;
- }
-
- /* Get the parameters for an Indexed color space. */
- /* base_space has been set; hival has been checked, but not set. */
- int
- zcolorspace_Indexed(const ref *pcsa, gs_color_space *pcs, ref *pproc)
- { int num_entries =
- (pcs->params.indexed.hival = pcsa[1].value.intval) + 1;
- pcs->type = &gs_color_space_type_Indexed;
- if ( r_has_type(&pcsa[2], t_string) )
- { int num_values = num_entries *
- pcs->params.indexed.base_space.type->num_components;
- check_read(pcsa[2]);
- if ( r_size(&pcsa[2]) != num_values )
- return_error(e_rangecheck);
- pcs->params.indexed.lookup.table.data =
- pcsa[2].value.const_bytes;
- pcs->params.indexed.use_proc = 0;
- make_null(pproc);
- return 0;
- }
- else
- { gs_indexed_map *map;
- int code;
- check_proc(pcsa[2]);
- code = begin_map(&map, &pcsa[2], num_entries,
- &pcs->params.indexed.base_space,
- indexed_map1);
- if ( code < 0 )
- return code;
- pcs->params.indexed.use_proc = 1;
- *pproc = pcsa[2];
- map->proc.lookup_index = lookup_indexed;
- pcs->params.indexed.lookup.map = map;
- return code;
- }
- }
-
- /* Continuation procedure for saving mapped Indexed color values. */
- private int
- indexed_map1(os_ptr op)
- { /* estack: 0 = proc, -1 = index, -2 = pcs. */
- es_ptr ep = esp;
- int i = (int)esp[-1].value.intval;
- const gs_color_space *pcs = r_ptr(esp - 2, const gs_color_space);
- if ( i < 0 ) /* first time */
- { pcs = gs_currentcolorspace(igs);
- make_struct(ep - 2, a_foreign, pcs);
- }
- else
- { int m = pcs->params.indexed.base_space.type->num_components;
- int code = num_params(op, m, &pcs->params.indexed.lookup.map->values[i * m]);
- if ( code < 0 )
- return code;
- pop(m); op -= m;
- if ( i == pcs->params.indexed.hival )
- { /* All done. */
- esp -= 3;
- gs_setcolorspace(igs, (gs_color_space *)pcs);
- return o_pop_estack;
- }
- }
- push(1);
- ep[-1].value.intval = ++i;
- make_int(op, i);
- make_op_estack(ep + 1, indexed_map1);
- ep[2] = *ep; /* lookup proc */
- esp = ep + 2;
- return o_push_estack;
- }
-
- /* ------ Separation color space ------ */
-
- /* Define the separation cache size. This makes many useful tint values */
- /* map to integer cache indices. */
- #define separation_cache_size 360
-
- /* Tint transform procedure that just consults the cache. */
- private int
- lookup_tint(const gs_separation_params *params, floatp tint, float *values)
- { int m = params->alt_space.type->num_components;
- const gs_indexed_map *map = params->map;
- int value_index =
- (tint < 0 ? 0 : tint > 1 ? map->num_values - m :
- (int)(tint * separation_cache_size + 0.5) * m);
- const float *pv = &map->values[value_index];
- switch ( m )
- {
- default: return_error(e_rangecheck);
- case 4: values[3] = pv[3];
- case 3: values[2] = pv[2];
- values[1] = pv[1];
- case 1: values[0] = pv[0];
- }
- return 0;
- }
-
- /* Get the parameters for a Separation color space. */
- /* alt_space has been set; name and tint_transform have been checked, */
- /* but not set. */
- int
- zcolorspace_Separation(const ref *pcsa, gs_color_space *pcs,
- ref_separation_params *params)
- { gs_indexed_map *map;
- int code;
- code = begin_map(&map, &pcsa[2], separation_cache_size,
- &pcs->params.separation.alt_space,
- separation_map1);
- if ( code < 0 )
- return code;
- map->proc.tint_transform = lookup_tint;
- pcs->params.separation.map = map;
- params->layer_name = pcsa[0];
- params->tint_transform = pcsa[2];
- pcs->type = &gs_color_space_type_Separation;
- return code;
- }
-
- /* Continuation procedure for saving transformed tint values. */
- private int
- separation_map1(os_ptr op)
- { /* estack: 0 = proc, -1 = index, -2 = pcs. */
- es_ptr ep = esp;
- int i = (int)esp[-1].value.intval;
- const gs_color_space *pcs = r_ptr(esp - 2, const gs_color_space);
- if ( i < 0 ) /* first time */
- { pcs = gs_currentcolorspace(igs);
- make_struct(ep - 2, a_foreign, pcs);
- }
- else
- { int m = pcs->params.separation.alt_space.type->num_components;
- int code = num_params(op, m, &pcs->params.separation.map->values[i * m]);
- if ( code < 0 )
- return code;
- pop(m); op -= m;
- if ( i == separation_cache_size )
- { /* All done. */
- esp -= 3;
- gs_setcolorspace(igs, (gs_color_space *)pcs);
- return o_pop_estack;
- }
- }
- push(1);
- ep[-1].value.intval = ++i;
- make_real(op, i / (float)separation_cache_size);
- make_op_estack(ep + 1, separation_map1);
- ep[2] = *ep; /* tint_transform */
- esp = ep + 2;
- return o_push_estack;
- }
-
- /* ------ Initialization procedure ------ */
-
- op_def zcsindex_l2_op_defs[] = {
- op_def_begin_level2(),
- /* Internal operators */
- {"1%indexed_map1", indexed_map1},
- {"1%separation_map1", separation_map1},
- op_def_end(0)
- };
-
- /* ------ Internal routines ------ */
-
- /* Allocate, and prepare to load, the index or tint map. */
- private int
- begin_map(gs_indexed_map **pmap, const ref *pproc, int num_entries,
- const gs_base_color_space *base_space, int (*map1)(P1(os_ptr)))
- { gs_memory_t *mem = gs_state_memory(igs);
- int num_values = num_entries * base_space->type->num_components;
- gs_indexed_map *map;
- es_ptr ep;
- float *values;
- rc_alloc_struct_0(map, gs_indexed_map, &st_indexed_map,
- mem, return_error(e_VMerror),
- "setcolorspace(mapped)");
- values =
- (float *)gs_alloc_byte_array(mem, num_values, sizeof(float),
- "setcolorspace(mapped)");
- if ( values == 0 )
- { gs_free_object(mem, map, "setcolorspace(mapped)");
- return_error(e_VMerror);
- }
- map->rc.free = rc_free_indexed_map;
- map->num_values = num_values;
- map->values = values;
- *pmap = map;
- /* Map the entire set of color indices. Since the */
- /* o-stack may not be able to hold 4*4096 values, we have */
- /* to load them into the cache as they are generated. */
- check_estack(5); /* 1 extra for proc */
- ep = esp;
- make_string(ep + 1, 0, 0, NULL); /* pcs later */
- make_int(ep + 2, -1);
- ep[3] = *pproc;
- make_op_estack(ep + 4, map1);
- esp += 4;
- return o_push_estack;
- }
-