/* Returns true if rescale was done */
bool
rescale_cie_colors(const gs_color_space * pcs, gs_client_color *cc)
{
    int num, k;
    gs_range *ranges;

    if (!check_cie_range(pcs)) {
        switch(gs_color_space_get_index(pcs)) {
            case gs_color_space_index_CIEDEFG:
                num = 4;
                ranges = &(pcs->params.defg->RangeDEFG.ranges[0]);
                break;
            case gs_color_space_index_CIEDEF:
                num = 3;
                ranges = &(pcs->params.def->RangeDEF.ranges[0]);
                break;
            case gs_color_space_index_CIEABC:
                num = 3;
                ranges = &(pcs->params.abc->RangeABC.ranges[0]);
                break;
            case gs_color_space_index_CIEA:
                num = 1;
                ranges = &(pcs->params.a->RangeA);
                break;
            default:
                return false;
        }
        for (k = 0; k < num; k++) {
            cc->paint.values[k] = (cc->paint.values[k] - ranges[k].rmin) /
                                    (ranges[k].rmax - ranges[k].rmin);
        }
        return true;
    }
    return false;
}
Exemple #2
0
/* Call for cases where the equivalent icc color space needs to be set */
int
gs_colorspace_set_icc_equivalent(gs_color_space *pcs, bool *islab,
                                 gs_memory_t *memory)
{
     gs_color_space_index color_space_index = gs_color_space_get_index(pcs);
     gs_color_space *picc_cs;

     *islab = false;  /* For non CIEABC cases */
     if (pcs->icc_equivalent != NULL || !gs_color_space_is_PSCIE(pcs)) {
         return(0);
}
     switch( color_space_index ) {
       case gs_color_space_index_CIEDEFG:
            gx_ciedefg_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        case gs_color_space_index_CIEDEF:
            gx_ciedef_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        case gs_color_space_index_CIEABC:
            gx_cieabc_to_icc(&picc_cs, pcs, islab, memory->stable_memory);
            break;
        case gs_color_space_index_CIEA:
            gx_ciea_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        default:
             /* do nothing.  Sould never happen */
             break;
     }
    return(0);
}
Exemple #3
0
/*
 *   <dict>  .seticcspace  -
 *
 * Create an ICCBased color space and set it to be the current color space.
 *
 * The PostScript structure of an ICCBased color space is that same as that
 * for a CIEBased* color space:
 *
 *     [ /ICCBased <dictionary> ]
 *
 * As is the for other .setcie*space operators, the operand dictionary rather
 * than the complete color space array is on the stack when this operator
 * is inovked.
 *
 * At the time this procedure is called, the alternative color space for
 * the ICCBased color space is expected to be the current color space,
 * whether that space was explicitly specified or implied by the number
 * of components in the ICCBased color space dictionary. This is consistent
 * with the handling of alternative spaces in Separation, DeviceN, and
 * Indexed color spaces. Unlike the "zset*space" routines for those spaces,
 * however, the current code does not attempt to build the color space
 * "in place" in the graphic state.
 *
 * The procedure that invokes this operator will already have checked that
 * the operand is a dictionary, is readable, and defines the key /N
 * (number of components).
 */
static int
zseticcspace(i_ctx_t * i_ctx_p)
{
    os_ptr                  op = osp;
    int                     code;
    gs_color_space *  palt_cs;
    ref *                   pnval;
    ref *                   pstrmval;
    stream *                s;
    int                     i, ncomps;
    float                   range_buff[8];
    static const float      dflt_range[8] = { 0, 1,   0, 1,   0, 1,   0, 1 };

    code = dict_find_string(op, "N", &pnval);
    if (code < 0)
        return code;
    ncomps = pnval->value.intval;
    if (2*ncomps > sizeof(range_buff)/sizeof(range_buff[0]))
        return_error(e_rangecheck);
    /* verify the DataSource entry */
    if (dict_find_string(op, "DataSource", &pstrmval) <= 0)
        return_error(e_undefined);
    check_read_file(i_ctx_p, s, pstrmval);
    /*
     * Verify that the current color space can be a alternative color space.
     * The check for ICCBased color space is a hack to avoid introducing yet
     * another category indicator into the gs_color_space_type structur.
     */
    palt_cs = gs_currentcolorspace(igs);
    if ( !palt_cs->type->can_be_alt_space                                ||
         gs_color_space_get_index(palt_cs) == gs_color_space_index_ICC  )
        return_error(e_rangecheck);
    /*
     * Fetch and verify the Range array.
     *
     * The PDF documentation is unclear as to the purpose of this array.
     * Essentially all that is stated is that "These values must match the
     * information in the ICC profile" (PDF Reference, 2nd ed., p. 174).
     * If that is the case, why not use the information in the profile?
     * The only reason we can think of is range specification is intended
     * to be used to limit the range of values passed to the alternate
     * color space (the range may be smaller than the native range of values
     * provided by that color space).
     *
     * Because the cms code will perform normalization based on color
     * space, we use the range values only to restrict the set of input
     * values; they are not used for normalization.
     */
    code = dict_floats_param( imemory,
                              op,
                              "Range",
                              2 * ncomps,
                              range_buff,
                              dflt_range );
    for (i = 0; i < 2 * ncomps && range_buff[i + 1] >= range_buff[i]; i += 2)
        ;
    if (i != 2 * ncomps)
        return_error(e_rangecheck);
    return seticc(i_ctx_p, ncomps, op, range_buff);
}
Exemple #4
0
/*
 * If the Separation tint transformation procedure is a Function,
 * return the function object, otherwise return 0.
 */
gs_function_t *
gs_cspace_get_sepr_function(const gs_color_space *pcspace)
{
    if (gs_color_space_get_index(pcspace) == gs_color_space_index_Separation &&
        pcspace->params.separation.map->tint_transform ==
          map_devn_using_function)
        return pcspace->params.separation.map->tint_transform_data;
    return 0;
}
Exemple #5
0
/* According to PLRM 3rd ed, p. 264  "indexed color space is not
 * allowed in any shading whose color values are generated by a function;
 * this applies to any shading dictionary that contains a Function entry."
 * Adobe interpreters follow PLRM in this respect and we follow them.
 */
static int
check_indexed_vs_function(i_ctx_t *i_ctx_p, const ref *op,
                          const gs_color_space *pcs, const gs_function_t *funct)
{ if (funct && gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
    static const char fn[] = "Function";
    ref *f;
    if (dict_find_string(op, fn, &f) > 0)
        gs_errorinfo_put_pair(i_ctx_p, fn, sizeof(fn) - 1, f);
    return_error(gs_error_typecheck);  /* CET 12-14a */
  }
  return 0;
}
Exemple #6
0
int
gx_begin_transparency_group(gs_imager_state * pis, gx_device * pdev,
                                const gs_pdf14trans_params_t * pparams)
{
    gs_transparency_group_params_t tgp = {0};
    gs_rect bbox;

    if (pparams->Background_components != 0 &&
        pparams->Background_components != pdev->color_info.num_components)
        return_error(gs_error_rangecheck);
    tgp.Isolated = pparams->Isolated;
    tgp.Knockout = pparams->Knockout;
    tgp.idle = pparams->idle;
    tgp.mask_id = pparams->mask_id;

    /* Needed so that we do proper blending */
    tgp.group_color = pparams->group_color;
    tgp.group_color_numcomps = pparams->group_color_numcomps;
    tgp.iccprofile = pparams->iccprofile;
    tgp.icc_hashcode = pparams->icc_hash;

    pis->opacity.alpha = pparams->opacity.alpha;
    pis->shape.alpha = pparams->shape.alpha;
    pis->blend_mode = pparams->blend_mode;
    bbox = pparams->bbox;
#ifdef DEBUG
    if (gs_debug_c('v')) {
        static const char *const cs_names[] = {
            GS_COLOR_SPACE_TYPE_NAMES
        };
        dmlprintf6(pdev->memory, "[v](0x%lx)gx_begin_transparency_group [%g %g %g %g] Num_grp_clr_comp = %d\n",
                  (ulong)pis, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y,
                        pparams->group_color_numcomps);
        if (tgp.ColorSpace)
            dmprintf1(pdev->memory, "     CS = %s",
                cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]);
        else
            dmputs(pdev->memory, "     (no CS)");
        dmprintf2(pdev->memory, "  Isolated = %d  Knockout = %d\n",
                 tgp.Isolated, tgp.Knockout);
        if (tgp.iccprofile)
            dmprintf(pdev->memory, "     Have ICC Profile for blending\n");
    }
#endif
    if (dev_proc(pdev, begin_transparency_group) != 0)
        return (*dev_proc(pdev, begin_transparency_group)) (pdev, &tgp, &bbox, pis,
                                                            NULL);
    else
        return 0;
}
Exemple #7
0
/* Note that, to support PDF, ICCBased color spaces may be used to substitute
 * for the Device* color spaces (previously, only CIEBased color spaces could
 * be used for this purpose). */
int
gs_setsubstitutecolorspace(gs_state *pgs, gs_color_space_index csi,
			   const gs_color_space *pcs)
{
    int index = (int)csi;
    static const uint masks[3] = {
	(1 << gs_color_space_index_DeviceGray) |
	  (1 << gs_color_space_index_CIEA),
	(1 << gs_color_space_index_DeviceRGB) |
	  (1 << gs_color_space_index_CIEABC) |
	  (1 << gs_color_space_index_CIEDEF),
	(1 << gs_color_space_index_DeviceCMYK) |
	  (1 << gs_color_space_index_CIEDEFG)
    };
    const gs_color_space *pcs_old;

    if (index < 0 || index > 2)
	return_error(gs_error_rangecheck);
    if (pcs) {
        if (gs_color_space_get_index(pcs) == gs_color_space_index_CIEICC) {
            static const byte dev_ncomps[3] = {1, 3, 4};

             if (dev_ncomps[index] != cs_num_components(pcs))
                 return_error(gs_error_rangecheck);
        } else if (!masks[index] && (1 << gs_color_space_get_index(pcs)))
	    return_error(gs_error_rangecheck);
    }
    pcs_old = pgs->device_color_spaces.indexed[index];
    if (pcs_old == 0 &&	(pcs == 0 || gs_color_space_get_index(pcs) == csi))
	return 0;
    rc_assign(pgs->device_color_space.indexed[index],
	      (pcs ? pcs :
	       pgs->shared->device_color_spaces.indexed[index]),
	      "gs_setsubstitutecolorspace");
    return 0;
}
Exemple #8
0
gs_range*
get_cie_range( const gs_color_space * pcs )
{
    switch(gs_color_space_get_index(pcs)){
        case gs_color_space_index_CIEDEFG:
            return(&(pcs->params.defg->RangeDEFG.ranges[0]));
        case gs_color_space_index_CIEDEF:
            return(&(pcs->params.def->RangeDEF.ranges[0]));
        case gs_color_space_index_CIEABC:
            return(&(pcs->params.abc->RangeABC.ranges[0]));
        case gs_color_space_index_CIEA:
            return(&(pcs->params.a->RangeA));
        default:
            return NULL;
    }
}
Exemple #9
0
/* Returns false if range is not 0 1 */
bool
check_cie_range( const gs_color_space * pcs )
{
    switch(gs_color_space_get_index(pcs)){
        case gs_color_space_index_CIEDEFG:
            return(check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4));
        case gs_color_space_index_CIEDEF:
            return(check_range(&(pcs->params.def->RangeDEF.ranges[0]), 3));
        case gs_color_space_index_CIEABC:
            return(check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3));
        case gs_color_space_index_CIEA:
            return(check_range(&(pcs->params.a->RangeA), 1));
        default:
            return true;
    }
}
Exemple #10
0
/*
 * Set the Separation tint transformation procedure to a Function.
 */
int
gs_cspace_set_sepr_function(const gs_color_space *pcspace, gs_function_t *pfn)
{
    gs_device_n_map *pimap;

    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation ||
        pfn->params.m != 1 || pfn->params.n !=
          gs_color_space_num_components(pcspace->base_space)
        )
        return_error(gs_error_rangecheck);
    pimap = pcspace->params.separation.map;
    pimap->tint_transform = map_devn_using_function;
    pimap->tint_transform_data = pfn;
    pimap->cache_valid = false;
    return 0;
}
int
gs_begin_transparency_group(gs_state *pgs,
			    const gs_transparency_group_params_t *ptgp,
			    const gs_rect *pbbox)
{
    gs_pdf14trans_params_t params = { 0 };

#ifdef DEBUG
    if (gs_debug_c('v')) {
	static const char *const cs_names[] = {
	    GS_COLOR_SPACE_TYPE_NAMES
	};

	dlprintf5("[v](0x%lx)begin_transparency_group [%g %g %g %g]\n",
		  (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y);
	if (ptgp->ColorSpace)
	    dprintf1("     CS = %s",
		cs_names[(int)gs_color_space_get_index(ptgp->ColorSpace)]);
	else
	    dputs("     (no CS)");
	dprintf2("  Isolated = %d  Knockout = %d\n",
		 ptgp->Isolated, ptgp->Knockout);
    }
#endif
    /*
     * Put parameters into a compositor parameter and then call the
     * create_compositor.  This will pass the data to the PDF 1.4
     * transparency device.
     */
    params.pdf14_op = PDF14_BEGIN_TRANS_GROUP;
    params.Isolated = ptgp->Isolated;
    params.Knockout = ptgp->Knockout;
    params.image_with_SMask = ptgp->image_with_SMask;
    params.opacity = pgs->opacity;
    params.shape = pgs->shape;
    params.blend_mode = pgs->blend_mode;
    /*
     * We are currently doing nothing with the colorspace.  Currently
     * the blending colorspace is based upon the processs color model
     * of the output device.
     */
    params.bbox = *pbbox;
    return gs_state_update_pdf14trans(pgs, &params);
}
Exemple #12
0
/*
 * Set the DeviceN tint transformation procedure.
 */
int
gs_cspace_set_devn_proc(gs_color_space * pcspace,
                        int (*proc)(const float *,
                                    float *,
                                    const gs_imager_state *,
                                    void *
                                    ),
                        void *proc_data
                        )
{
    gs_device_n_map *pimap;

    if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN)
        return_error(gs_error_rangecheck);
    pimap = pcspace->params.device_n.map;
    pimap->tint_transform = proc;
    pimap->tint_transform_data = proc_data;
    pimap->cache_valid = false;
    return 0;
}
int
gx_begin_transparency_group(gs_imager_state * pis, gx_device * pdev,
				const gs_pdf14trans_params_t * pparams)
{
    gs_transparency_group_params_t tgp = {0};
    gs_rect bbox;

    if (pparams->Background_components != 0 && 
	pparams->Background_components != pdev->color_info.num_components)
	return_error(gs_error_rangecheck);
    tgp.Isolated = pparams->Isolated;
    tgp.Knockout = pparams->Knockout;
    tgp.idle = pparams->idle;
    tgp.mask_id = pparams->mask_id;
    pis->opacity.alpha = pparams->opacity.alpha;
    pis->shape.alpha = pparams->shape.alpha;
    pis->blend_mode = pparams->blend_mode;
    bbox = pparams->bbox;
#ifdef DEBUG
    if (gs_debug_c('v')) {
	static const char *const cs_names[] = {
	    GS_COLOR_SPACE_TYPE_NAMES
	};

	dlprintf5("[v](0x%lx)gx_begin_transparency_group [%g %g %g %g]\n",
		  (ulong)pis, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
	if (tgp.ColorSpace)
	    dprintf1("     CS = %s",
		cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]);
	else
	    dputs("     (no CS)");
	dprintf2("  Isolated = %d  Knockout = %d\n",
		 tgp.Isolated, tgp.Knockout);
    }
#endif
    if (dev_proc(pdev, begin_transparency_group) != 0)
	return (*dev_proc(pdev, begin_transparency_group)) (pdev, &tgp,
							&bbox, pis, NULL, NULL);
    else
	return 0;
}
/* Set the ProcSets bits corresponding to an image color space. */
void
pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
{
    const gs_color_space *pbcs = pcs;

 csw:
    switch (gs_color_space_get_index(pbcs)) {
    case gs_color_space_index_DeviceGray:
    case gs_color_space_index_CIEA:
	/* We only handle CIEBasedA spaces that map to CalGray. */
	pdev->procsets |= ImageB;
	break;
    case gs_color_space_index_Indexed:
	pdev->procsets |= ImageI;
	pbcs = pcs->base_space;
	goto csw;
    default:
	pdev->procsets |= ImageC;
	break;
    }
}
Exemple #15
0
/*
 *	Width, encoded as a variable-length uint
 *	Height, encoded ditto
 *	ImageMatrix (if A = 1), per gs_matrix_store/fetch
 *	Decode (if D = 1): blocks of up to 4 components
 *	    aabbccdd, where each xx is decoded as:
 *		00 = default, 01 = swapped default,
 *		10 = (0,V), 11 = (U,V)
 *	    non-defaulted components (up to 8 floats)
 */
int
gx_pixel_image_sput(const gs_pixel_image_t *pim, stream *s,
		    const gs_color_space **ppcs, int extra)
{
    const gs_color_space *pcs = pim->ColorSpace;
    int bpc = pim->BitsPerComponent;
    int num_components = gs_color_space_num_components(pcs);
    int num_decode;
    uint control = extra << PI_BITS;
    float decode_default_1 = 1;
    int i;
    uint ignore;

    /* Construct the control word. */

    if (!gx_image_matrix_is_default((const gs_data_image_t *)pim))
	control |= PI_ImageMatrix;
    switch (pim->format) {
    case gs_image_format_chunky:
    case gs_image_format_component_planar:
	switch (bpc) {
	case 1: case 2: case 4: case 8: case 12: break;
	default: return_error(gs_error_rangecheck);
	}
	break;
    case gs_image_format_bit_planar:
	if (bpc < 1 || bpc > 8)
	    return_error(gs_error_rangecheck);
    }
    control |= (bpc - 1) << PI_BPC_SHIFT;
    control |= pim->format << PI_FORMAT_SHIFT;
    num_decode = num_components * 2;
    if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
	decode_default_1 = (float)pcs->params.indexed.hival;
    for (i = 0; i < num_decode; ++i)
	if (pim->Decode[i] != DECODE_DEFAULT(i, decode_default_1)) {
	    control |= PI_Decode;
	    break;
	}
    if (pim->Interpolate)
	control |= PI_Interpolate;
    if (pim->CombineWithColor)
	control |= PI_CombineWithColor;

    /* Write the encoding on the stream. */

    if_debug3('b', "[b]put control=0x%x, Width=%d, Height=%d\n",
	      control, pim->Width, pim->Height);
    sput_variable_uint(s, control);
    sput_variable_uint(s, (uint)pim->Width);
    sput_variable_uint(s, (uint)pim->Height);
    if (control & PI_ImageMatrix) {
	debug_b_print_matrix(pim);
	sput_matrix(s, &pim->ImageMatrix);
    }
    if (control & PI_Decode) {
	int i;
	uint dflags = 1;
	float decode[8];
	int di = 0;

	debug_b_print_decode(pim, num_decode);
	for (i = 0; i < num_decode; i += 2) {
	    float u = pim->Decode[i], v = pim->Decode[i + 1];
	    float dv = DECODE_DEFAULT(i + 1, decode_default_1);

	    if (dflags >= 0x100) {
		sputc(s, (byte)(dflags & 0xff));
		sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
		dflags = 1;
		di = 0;
	    }
	    dflags <<= 2;
	    if (u == 0 && v == dv)
		DO_NOTHING;
	    else if (u == dv && v == 0)
		dflags += 1;
	    else {
		if (u != 0) {
		    dflags++;
		    decode[di++] = u;
		}
		dflags += 2;
		decode[di++] = v;
	    }
	}
	sputc(s, (byte)((dflags << (8 - num_decode)) & 0xff));
	sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
    }
    *ppcs = pcs;
    return 0;
}
Exemple #16
0
int
gs_begin_transparency_group(gs_state *pgs,
                            const gs_transparency_group_params_t *ptgp,
                            const gs_rect *pbbox)
{
    gs_pdf14trans_params_t params = { 0 };
    const gs_color_space *blend_color_space;
    gs_imager_state * pis = (gs_imager_state *)pgs;
    cmm_profile_t *profile;

    if (check_for_nontrans_pattern(pgs,
                  (unsigned char *)"gs_begin_transparency_group")) {
        return(0);
    }
    /*
     * Put parameters into a compositor parameter and then call the
     * create_compositor.  This will pass the data to the PDF 1.4
     * transparency device.
     */
    params.pdf14_op = PDF14_BEGIN_TRANS_GROUP;
    params.Isolated = ptgp->Isolated;
    params.Knockout = ptgp->Knockout;
    params.image_with_SMask = ptgp->image_with_SMask;
    params.opacity = pgs->opacity;
    params.shape = pgs->shape;
    params.blend_mode = pgs->blend_mode;
    /* This function is called during the c-list writer side.
       Store some information so that we know what the color space is
       so that we can adjust according later during the clist reader.
       We currently will use the concrete space for any space other than a
       device space.  However, if the device is a sep device it will blend
       in DeviceN color space as required.  */
    blend_color_space = gs_currentcolorspace_inline(pgs);
    if (gs_color_space_get_index(blend_color_space) > gs_color_space_index_DeviceCMYK) {
        /* ICC and PS CIE based case.  Note that unidirectional PS CIE color
           spaces should not be allowed but end up occuring when processing
           PDF files with -dUseCIEColor.  We will end up using the appropriate
           ICC default color space in these cases. */
        blend_color_space = gs_currentcolorspace_inline(pgs);
    } else {
        blend_color_space = cs_concrete_space(blend_color_space, pis);
    }
    /* Note that if the /CS parameter was NOT present in the push
       of the transparency group, then we must actually inherent
       the previous group color space, or the color space of the
       target device (process color model).  Here we just want
       to set it as a unknown type for clist writing, as we will take care
       of using the parent group color space later during clist reading.
       Also, if the group was not isolated we MUST use the parent group 
       color space regardless of what the group color space is specified to be
       */
    if (ptgp->ColorSpace == NULL || params.Isolated != true) {
        params.group_color = UNKNOWN;
        params.group_color_numcomps = 0;
    } else {
        /* The /CS parameter was present.  Use what was set.  Currently
           all our Device spaces are actually ICC based.  The other options
           are if -dUseCIEColor is set, in which case it could be
           coming in as a PS CIE color space, which should not be allowed
           but should default to one of the default ICC color spaces.  Note
           that CalRGB and CalGray, which are valid bidirectional color spaces
           are converted to ICC profiles during installation. PS CIE building
           to ICC is delayed. */
        if ( gs_color_space_is_ICC(blend_color_space) ) {
            /* Blending space is ICC based.  If we are doing c-list rendering
               we will need to write this color space into the clist.
               */
            params.group_color = ICC;
            params.group_color_numcomps =
                blend_color_space->cmm_icc_profile_data->num_comps;
            /* Get the ICC profile */
            params.iccprofile = blend_color_space->cmm_icc_profile_data;
            params.icc_hash = blend_color_space->cmm_icc_profile_data->hashcode;
        } else {
            /* Color space was NOT ICC based.  PS CIE space and DeviceN are the only
               other option.  Use the ICC default based upon the component count. */
            switch (cs_num_components(blend_color_space)) {
                case 1:
                    profile =  pgs->icc_manager->default_gray;
                    break;
                case 3:
                    profile =  pgs->icc_manager->default_rgb;
                    break;
                case 4:
                    profile =  pgs->icc_manager->default_cmyk;
                break;
                default:
                    /* We can end up here if we are in a deviceN color space and
                       we have a sep output device */
                    profile = NULL;
                    params.group_color = DEVICEN;
                    params.group_color_numcomps = cs_num_components(blend_color_space);
                break;
            }
            if (profile != NULL) {
                params.group_color = ICC;
                params.group_color_numcomps = profile->num_comps;
                params.iccprofile = profile;
                params.icc_hash = profile->hashcode;
            }
        }
    }
#ifdef DEBUG
    if (gs_debug_c('v')) {
        static const char *const cs_names[] = {
            GS_COLOR_SPACE_TYPE_NAMES
        };
        dmlprintf6(pgs->memory, "[v](0x%lx)begin_transparency_group [%g %g %g %g] Num_grp_clr_comp = %d\n",
                  (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y,params.group_color_numcomps);
        if (ptgp->ColorSpace)
            dmprintf1(pgs->memory, "     CS = %s",
                cs_names[(int)gs_color_space_get_index(ptgp->ColorSpace)]);
        else
            dmputs(pgs->memory, "     (no CS)");

        dmprintf2(pgs->memory, "  Isolated = %d  Knockout = %d\n",
                 ptgp->Isolated, ptgp->Knockout);
    }
#endif
    params.bbox = *pbbox;
    return gs_state_update_pdf14trans(pgs, &params);
}
Exemple #17
0
/* Create a Separation or DeviceN color space (internal). */
static int
pdf_separation_color_space(gx_device_pdf *pdev,
                           cos_array_t *pca, const char *csname,
                           const cos_value_t *snames,
                           const gs_color_space *alt_space,
                           const gs_function_t *pfn,
                           const pdf_color_space_names_t *pcsn,
                           const cos_value_t *v_attributes)
{
    cos_value_t v;
    const gs_range_t *ranges;
    int code, csi;

    /* We need to think about the alternate space. If we are producing
     * PDF/X or PDF/A we can't produce some device spaces, and the code in
     * pdf_color_space_named always allows device spaces. We could alter
     * that code, but by then we don't know its an Alternate space, and have
     * lost the tin transform procedure. So instead we check here.
     */
    csi = gs_color_space_get_index(alt_space);
    /* Note that if csi is ICC, check to see if this was one of
       the default substitutes that we introduced for DeviceGray,
       DeviceRGB or DeviceCMYK.  If it is, then just write
       the default color.  Depending upon the flavor of PDF,
       or other options, we may want to actually have all
       the colors defined by ICC profiles and not do the following
       substituion of the Device space. */
    if (csi == gs_color_space_index_ICC) {
        csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data);
    }
    if (csi == gs_color_space_index_DeviceRGB && (pdev->PDFX ||
            (pdev->PDFA && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) {

        /* We have a DeviceRGB alternate, but are producing either PDF/X or
         * PDF/A with a DeviceCMYK process color model. So we need to convert
         * the alternate space into CMYK. We do this by evaluating the function
         * at each end of the Separation space (0 and 1), convert the resulting
         * RGB colours into CMYK and create a new function which linearly
         * interpolates between these points.
         */
        gs_function_t *new_pfn = 0;
        float in[1] = {0.0f};
        float out_low[4];
        float out_high[4];

        code = gs_function_evaluate(pfn, in, out_low);
        if (code < 0)
            return code;
        pdf_SepRGB_ConvertToCMYK((float *)&out_low, (float *)&out_low);

        in[0] = 1.0f;
        code = gs_function_evaluate(pfn, in, out_high);
        if (code < 0)
            return code;
        pdf_SepRGB_ConvertToCMYK((float *)&out_high, (float *)&out_high);

        code = pdf_make_base_space_function(pdev, &new_pfn, 4, out_low, out_high);
        if (code < 0)
            return code;
        if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
                (code = cos_array_add_no_copy(pca, snames)) < 0 ||
                (code = (int)cos_c_string_value(&v, (const char *)pcsn->DeviceCMYK)) < 0 ||
                (code = cos_array_add(pca, &v)) < 0 ||
                (code = pdf_function_scaled(pdev, new_pfn, 0x00, &v)) < 0 ||
                (code = cos_array_add(pca, &v)) < 0 ||
                (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
           ) {}
        pdf_delete_base_space_function(pdev, new_pfn);
        return code;
    }
    if (csi == gs_color_space_index_DeviceCMYK &&
            (pdev->PDFA && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) {
        /* We have a DeviceCMYK alternate, but are producingPDF/A with a
         * DeviceRGB process color model. See comment above re DviceRGB.
         */
        gs_function_t *new_pfn = 0;
        float in[1] = {0.0f};
        float out_low[4];
        float out_high[4];

        code = gs_function_evaluate(pfn, in, out_low);
        if (code < 0)
            return code;
        pdf_SepCMYK_ConvertToRGB((float *)&out_low, (float *)&out_low);

        in[0] = 1.0f;
        code = gs_function_evaluate(pfn, in, out_high);
        if (code < 0)
            return code;
        pdf_SepCMYK_ConvertToRGB((float *)&out_high, (float *)&out_high);

        code = pdf_make_base_space_function(pdev, &new_pfn, 3, out_low, out_high);
        if (code < 0)
            return code;
        if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
                (code = cos_array_add_no_copy(pca, snames)) < 0 ||
                (code = (int)cos_c_string_value(&v, pcsn->DeviceRGB)) < 0 ||
                (code = cos_array_add(pca, &v)) < 0 ||
                (code = pdf_function_scaled(pdev, new_pfn, 0x00, &v)) < 0 ||
                (code = cos_array_add(pca, &v)) < 0 ||
                (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
           ) {}
        pdf_delete_base_space_function(pdev, new_pfn);
        return code;
    }

    if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
            (code = cos_array_add_no_copy(pca, snames)) < 0 ||
            (code = pdf_color_space_named(pdev, &v, &ranges, alt_space, pcsn, false, NULL, 0)) < 0 ||
            (code = cos_array_add(pca, &v)) < 0 ||
            (code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
            (code = cos_array_add(pca, &v)) < 0 ||
            (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
       )
        return code;
    return 0;
}
Exemple #18
0
/*
 * Read generic pixel image parameters.
 */
int
gx_pixel_image_sget(gs_pixel_image_t *pim, stream *s,
		    gs_color_space *pcs)
{
    uint control;
    float decode_default_1 = 1;
    int num_components, num_decode;
    int i;
    int code;
    uint ignore;

    if ((code = sget_variable_uint(s, &control)) < 0 ||
	(code = sget_variable_uint(s, (uint *)&pim->Width)) < 0 ||
	(code = sget_variable_uint(s, (uint *)&pim->Height)) < 0
	)
	return code;
    if_debug3('b', "[b]get control=0x%x, Width=%d, Height=%d\n",
	      control, pim->Width, pim->Height);
    if (control & PI_ImageMatrix) {
	if ((code = sget_matrix(s, &pim->ImageMatrix)) < 0)
	    return code;
	debug_b_print_matrix(pim);
    } else
	gx_image_matrix_set_default((gs_data_image_t *)pim);
    pim->BitsPerComponent = ((control >> PI_BPC_SHIFT) & PI_BPC_MASK) + 1;
    pim->format = (control >> PI_FORMAT_SHIFT) & PI_FORMAT_MASK;
    pim->ColorSpace = pcs;
    num_components = gs_color_space_num_components(pcs);
    num_decode = num_components * 2;
    if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
	decode_default_1 = (float)pcs->params.indexed.hival;
    if (control & PI_Decode) {
	uint dflags = 0x10000;
	float *dp = pim->Decode;

	for (i = 0; i < num_decode; i += 2, dp += 2, dflags <<= 2) {
	    if (dflags >= 0x10000) {
		dflags = sgetc(s) + 0x100;
		if (dflags < 0x100)
		    return_error(gs_error_ioerror);
	    }
	    switch (dflags & 0xc0) {
	    case 0x00:
		dp[0] = 0, dp[1] = DECODE_DEFAULT(i + 1, decode_default_1);
		break;
	    case 0x40:
		dp[0] = DECODE_DEFAULT(i + 1, decode_default_1), dp[1] = 0;
		break;
	    case 0x80:
		dp[0] = 0;
		if (sgets(s, (byte *)(dp + 1), sizeof(float), &ignore) < 0)
		    return_error(gs_error_ioerror);
		break;
	    case 0xc0:
		if (sgets(s, (byte *)dp, sizeof(float) * 2, &ignore) < 0)
		    return_error(gs_error_ioerror);
		break;
	    }
	}
	debug_b_print_decode(pim, num_decode);
    } else {
        for (i = 0; i < num_decode; ++i)
	    pim->Decode[i] = DECODE_DEFAULT(i, decode_default_1);
    }
    pim->Interpolate = (control & PI_Interpolate) != 0;
    pim->CombineWithColor = (control & PI_CombineWithColor) != 0;
    return control >> PI_BITS;
}
/*
 * Create an ICCBased color space object (internal).  The client must write
 * the profile data on *ppcstrm.
 */
static int
pdf_make_iccbased(gx_device_pdf *pdev, cos_array_t *pca, int ncomps,
		  const gs_range *prange /*[4]*/,
		  const gs_color_space *pcs_alt,
		  cos_stream_t **ppcstrm,
		  const gs_range_t **pprange /* if scaling is needed */)

{
    cos_value_t v;
    int code;
    cos_stream_t * pcstrm = 0;
    cos_array_t * prngca = 0;
    bool std_ranges = true;
    bool scale_inputs = false;
    int i;

    /* Check the ranges. */
    if (pprange)
	*pprange = 0;
    for (i = 0; i < ncomps; ++i) {
	double rmin = prange[i].rmin, rmax = prange[i].rmax;

	if (rmin < 0.0 || rmax > 1.0) {
	    /* We'll have to scale the inputs.  :-( */
	    if (pprange == 0)
		return_error(gs_error_rangecheck); /* scaling not allowed */
	    *pprange = prange;
	    scale_inputs = true;
	}
	else if (rmin > 0.0 || rmax < 1.0)
	    std_ranges = false;
    }

    /* ICCBased color spaces are essentially copied to the output. */
    if ((code = cos_array_add(pca, cos_c_string_value(&v, "/ICCBased"))) < 0)
	return code;

    /* Create a stream for the output. */
    if ((pcstrm = cos_stream_alloc(pdev, "pdf_make_iccbased(stream)")) == 0) {
	code = gs_note_error(gs_error_VMerror);
	goto fail;
    }

    /* Indicate the number of components. */
    code = cos_dict_put_c_key_int(cos_stream_dict(pcstrm), "/N", ncomps);
    if (code < 0)
	goto fail;

    /* Indicate the range, if needed. */
    if (!std_ranges && !scale_inputs) {
	code = pdf_cie_add_ranges(cos_stream_dict(pcstrm), prange, ncomps, true);
	if (code < 0)
	    goto fail;
    }

    /* Output the alternate color space, if necessary. */
    switch (gs_color_space_get_index(pcs_alt)) {
    case gs_color_space_index_DeviceGray:
    case gs_color_space_index_DeviceRGB:
    case gs_color_space_index_DeviceCMYK:
	break;			/* implicit (default) */
    default:
	if ((code = pdf_color_space(pdev, &v, NULL, pcs_alt,
				    &pdf_color_space_names, false)) < 0 ||
	    (code = cos_dict_put_c_key(cos_stream_dict(pcstrm), "/Alternate",
				       &v)) < 0
	    )
	    goto fail;
    }

    /* Wrap up. */
    if ((code = cos_array_add_object(pca, COS_OBJECT(pcstrm))) < 0)
	goto fail;
    *ppcstrm = pcstrm;
    return code;
 fail:
    if (prngca)
	COS_FREE(prngca, "pdf_make_iccbased(Range)");
    if (pcstrm)
	COS_FREE(pcstrm, "pdf_make_iccbased(stream)");
    return code;
}
/*
 * Create an Indexed color space.  This is a single-use procedure,
 * broken out only for readability.
 */
static int
pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
			const gs_color_space *pcs, cos_array_t *pca)
{
    const gs_indexed_params *pip = &pcs->params.indexed;
    const gs_color_space *base_space = pcs->base_space;
    int num_entries = pip->hival + 1;
    int num_components = gs_color_space_num_components(base_space);
    uint table_size = num_entries * num_components;
    /* Guess at the extra space needed for PS string encoding. */
    uint string_size = 2 + table_size * 4;
    uint string_used;
    byte buf[100];		/* arbitrary */
    stream_AXE_state st;
    stream s, es;
    gs_memory_t *mem = pdev->pdf_memory;
    byte *table;
    byte *palette;
    cos_value_t v;
    int code;

    /* PDF doesn't support Indexed color spaces with more than 256 entries. */
    if (num_entries > 256)
	return_error(gs_error_rangecheck);
    if (pdev->CompatibilityLevel < 1.3) {
	switch (gs_color_space_get_index(pcs)) {
	    case gs_color_space_index_Pattern:
	    case gs_color_space_index_Separation:
	    case gs_color_space_index_Indexed:
	    case gs_color_space_index_DeviceN:
		return_error(gs_error_rangecheck);
	    default: DO_NOTHING; 
	}

    }
    table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
    palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
    if (table == 0 || palette == 0) {
	gs_free_string(mem, palette, table_size,
		       "pdf_color_space(palette)");
	gs_free_string(mem, table, string_size,
		       "pdf_color_space(table)");
	return_error(gs_error_VMerror);
    }
    s_init(&s, mem);
    swrite_string(&s, table, string_size);
    s_init(&es, mem);
    s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
    s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
    sputc(&s, '(');
    if (pcs->params.indexed.use_proc) {
	gs_client_color cmin, cmax;
	byte *pnext = palette;
	int i, j;

	/* Find the legal range for the color components. */
	for (j = 0; j < num_components; ++j)
	    cmin.paint.values[j] = (float)min_long,
		cmax.paint.values[j] = (float)max_long;
	gs_color_space_restrict_color(&cmin, base_space);
	gs_color_space_restrict_color(&cmax, base_space);
	/*
	 * Compute the palette values, with the legal range for each
	 * one mapped to [0 .. 255].
	 */
	for (i = 0; i < num_entries; ++i) {
	    gs_client_color cc;

	    gs_cspace_indexed_lookup(pcs, i, &cc);
	    for (j = 0; j < num_components; ++j) {
		float v = (cc.paint.values[j] - cmin.paint.values[j])
		    * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);

		*pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
	    }
	}
    } else
	memcpy(palette, pip->lookup.table.data, table_size);
    if (gs_color_space_get_index(base_space) ==
	gs_color_space_index_DeviceRGB
	) {
	/* Check for an all-gray palette3. */
	int i;

	for (i = table_size; (i -= 3) >= 0; )
	    if (palette[i] != palette[i + 1] ||
		palette[i] != palette[i + 2]
		)
		break;
	if (i < 0) {
	    /* Change the color space to DeviceGray. */
	    for (i = 0; i < num_entries; ++i)
		palette[i] = palette[i * 3];
	    table_size = num_entries;
	    base_space = gs_cspace_new_DeviceGray(mem);
	}
    }
    stream_write(&es, palette, table_size);
    gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
    sclose(&es);
    sflush(&s);
    string_used = (uint)stell(&s);
    table = gs_resize_string(mem, table, string_size, string_used,
			     "pdf_color_space(table)");
    /*
     * Since the array is always referenced by name as a resource
     * rather than being written as a value, even for in-line images,
     * always use the full name for the color space.
     *
     * We don't have to worry about the range of the base space:
     * in PDF, unlike PostScript, the values from the lookup table are
     * scaled automatically.
     */
    if ((code = pdf_color_space(pdev, pvalue, NULL, base_space,
				&pdf_color_space_names, false)) < 0 ||
	(code = cos_array_add(pca,
			      cos_c_string_value(&v, 
						 pdf_color_space_names.Indexed
						 /*pcsn->Indexed*/))) < 0 ||
	(code = cos_array_add(pca, pvalue)) < 0 ||
	(code = cos_array_add_int(pca, pip->hival)) < 0 ||
	(code = cos_array_add_no_copy(pca,
				      cos_string_value(&v, table,
						       string_used))) < 0
	)
	return code;
    return 0;
}
/*
 * Create a PDF color space corresponding to a PostScript color space.
 * For parameterless color spaces, set *pvalue to a (literal) string with
 * the color space name; for other color spaces, create a cos_array_t if
 * necessary and set *pvalue to refer to it.  In the latter case, if
 * by_name is true, return a string /Rxxxx rather than a reference to
 * the actual object.
 *
 * If ppranges is not NULL, then if  the domain of the color space had
 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
 * to the ranges in *ppranges, otherwise set *ppranges to 0.
 */
int
pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
		const gs_range_t **ppranges,
		const gs_color_space *pcs,
		const pdf_color_space_names_t *pcsn,
		bool by_name, const byte *res_name, int name_length)
{
    gs_color_space_index csi = gs_color_space_get_index(pcs);
    cos_array_t *pca;
    cos_dict_t *pcd;
    cos_value_t v;
    const gs_cie_common *pciec;
    gs_function_t *pfn;
    const gs_range_t *ranges = 0;
    uint serialized_size;
    byte *serialized = NULL, serialized0[100];
    pdf_resource_t *pres = NULL;
    int code;

    if (ppranges)
	*ppranges = 0;		/* default */
    switch (csi) {
    case gs_color_space_index_DeviceGray:
	cos_c_string_value(pvalue, pcsn->DeviceGray);
	return 0;
    case gs_color_space_index_DeviceRGB:
	cos_c_string_value(pvalue, pcsn->DeviceRGB);
	return 0;
    case gs_color_space_index_DeviceCMYK:
	cos_c_string_value(pvalue, pcsn->DeviceCMYK);
	return 0;
    case gs_color_space_index_Pattern:
	if (!pcs->params.pattern.has_base_space) {
	    cos_c_string_value(pvalue, "/Pattern");
	    return 0;
	}
	break;
    case gs_color_space_index_CIEICC:
        /*
	 * Take a special early exit for unrecognized ICCBased color spaces,
	 * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
	 */
        if (pcs->params.icc.picc_info->picc == 0 ||
	    pdev->CompatibilityLevel < 1.3
	    ) {
	    if (res_name != NULL)
		return 0; /* Ignore .includecolorspace */
            return pdf_color_space( pdev, pvalue, ppranges,
                                    pcs->base_space,
                                    pcsn, by_name);
	}
        break;
    default:
	break;
    }
    if (pdev->params.ColorConversionStrategy == ccs_CMYK && 
	    csi != gs_color_space_index_DeviceCMYK &&
	    csi != gs_color_space_index_DeviceGray &&
	    csi != gs_color_space_index_Pattern)
	return_error(gs_error_rangecheck);
    if (pdev->params.ColorConversionStrategy == ccs_sRGB && 
	    csi != gs_color_space_index_DeviceRGB && 
	    csi != gs_color_space_index_DeviceGray &&
	    csi != gs_color_space_index_Pattern)
	return_error(gs_error_rangecheck);
    if (pdev->params.ColorConversionStrategy == ccs_Gray && 
	    csi != gs_color_space_index_DeviceGray &&
	    csi != gs_color_space_index_Pattern)
	return_error(gs_error_rangecheck);
    /* Check whether we already have a PDF object for this color space. */
    if (pcs->id != gs_no_id)
	pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
    if (pres == NULL) {
	stream s;

	s_init(&s, pdev->memory);
	swrite_position_only(&s);
	code = cs_serialize(pcs, &s);
	if (code < 0)
	    return_error(gs_error_unregistered); /* Must not happen. */
	serialized_size = stell(&s);
	sclose(&s);
	if (serialized_size <= sizeof(serialized0))
	    serialized = serialized0;
	else {
	    serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
	    if (serialized == NULL)
		return_error(gs_error_VMerror);
	}
	swrite_string(&s, serialized, serialized_size);
	code = cs_serialize(pcs, &s);
	if (code < 0)
	    return_error(gs_error_unregistered); /* Must not happen. */
	if (stell(&s) != serialized_size) 
	    return_error(gs_error_unregistered); /* Must not happen. */
	sclose(&s);
	pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
	if (pres != NULL) {
	    if (serialized != serialized0)
		gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
	    serialized = NULL;
	}
    }
    if (pres) {
	const pdf_color_space_t *const ppcs =
	    (const pdf_color_space_t *)pres;

	if (ppranges != 0 && ppcs->ranges != 0)
	    *ppranges = ppcs->ranges;
	pca = (cos_array_t *)pres->object;
	goto ret;
    }

    /* Space has parameters -- create an array. */
    pca = cos_array_alloc(pdev, "pdf_color_space");
    if (pca == 0)
	return_error(gs_error_VMerror);

    switch (csi) {

    case gs_color_space_index_CIEICC:
	code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
        break;

    case gs_color_space_index_CIEA: {
	/* Check that we can represent this as a CalGray space. */
	const gs_cie_a *pcie = pcs->params.a;
	bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
	bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 && 
	                  pcie->MatrixA.w == 1);
	gs_vector3 expts;

	pciec = (const gs_cie_common *)pcie;
	if (!pcie->common.MatrixLMN.is_identity) {
	    code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
					 &pcie->RangeA, ONE_STEP_NOT, NULL,
					 &ranges);
	    break;
	}
	if (unitary && identityA &&
	    CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
	    CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
	    expts.v == expts.u && expts.w == expts.u
	    ) {
	    DO_NOTHING;
	} else if (unitary && identityA &&
		   CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
		   cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
		   ) {
	    DO_NOTHING;
	} else {
	    code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
					 &pcie->RangeA, ONE_STEP_NOT, NULL,
					 &ranges);
	    break;
	}
	code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
	if (code < 0)
	    return code;
	pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
	if (pcd == 0)
	    return_error(gs_error_VMerror);
	if (expts.u != 1) {
	    code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
	    if (code < 0)
		return code;
	}
    }
    cal:
    /* Finish handling a CIE-based color space (Calxxx or Lab). */
    if (code < 0)
	return code;
    code = pdf_finish_cie_space(pca, pcd, pciec);
    break;

    case gs_color_space_index_CIEABC: {
	/* Check that we can represent this as a CalRGB space. */
	const gs_cie_abc *pcie = pcs->params.abc;
	bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
	gs_vector3 expts;
	const gs_matrix3 *pmat = NULL;
	cie_cache_one_step_t one_step =
	    cie_cached_abc_is_one_step(pcie, &pmat);

	pciec = (const gs_cie_common *)pcie;
	if (unitary) {
	    switch (one_step) {
	    case ONE_STEP_ABC:
		if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
		    goto calrgb;
		break;
	    case ONE_STEP_LMN:
		if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
		    goto calrgb;
	    default:
		break;
	    }
	}
	if (cie_is_lab(pcie)) {
	    /* Represent this as a Lab space. */
	    pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
	    if (pcd == 0)
		return_error(gs_error_VMerror);
	    code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
	    goto cal;
	} else {
	    code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
					 pcie->RangeABC.ranges,
					 one_step, pmat, &ranges);
	    break;
	}
    calrgb:
	code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
	if (code < 0)
	    return code;
	pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
	if (pcd == 0)
	    return_error(gs_error_VMerror);
	if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
	    code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
	    if (code < 0)
		return code;
	}
	if (!pmat->is_identity) {
	    cos_array_t *pcma =
		cos_array_alloc(pdev, "pdf_color_space(Matrix)");

	    if (pcma == 0)
		return_error(gs_error_VMerror);
	    if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
		(code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
		(code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
		(code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
				     COS_OBJECT_VALUE(&v, pcma))) < 0
		)
		return code;
	}
    }
    goto cal;

    case gs_color_space_index_CIEDEF:
	code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
				     (const gs_cie_common *)pcs->params.def,
				     pcs->params.def->RangeDEF.ranges,
				     ONE_STEP_NOT, NULL, &ranges);
	break;

    case gs_color_space_index_CIEDEFG:
	code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
				     (const gs_cie_common *)pcs->params.defg,
				     pcs->params.defg->RangeDEFG.ranges,
				     ONE_STEP_NOT, NULL, &ranges);
	break;

    case gs_color_space_index_Indexed:
	code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
	break;

    case gs_color_space_index_DeviceN:
        if (pdev->CompatibilityLevel < 1.3)
	    return_error(gs_error_rangecheck);
	pfn = gs_cspace_get_devn_function(pcs);
	/****** CURRENTLY WE ONLY HANDLE Functions ******/
	if (pfn == 0)
	    return_error(gs_error_rangecheck);
	{
	    cos_array_t *psna = 
		cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
	    int i;
	    byte *name_string;
	    uint name_string_length;
	    cos_value_t v_attriburtes, *va = NULL;

	    if (psna == 0)
		return_error(gs_error_VMerror);
	    for (i = 0; i < pcs->params.device_n.num_components; ++i) {
	 	if ((code = pcs->params.device_n.get_colorname_string(
				  pdev->memory,
				  pcs->params.device_n.names[i], &name_string, 
				  &name_string_length)) < 0 ||
		    (code = pdf_string_to_cos_name(pdev, name_string, 
				  name_string_length, &v)) < 0 ||
		    (code = cos_array_add_no_copy(psna, &v)) < 0)
		    return code;
	    }
	    COS_OBJECT_VALUE(&v, psna);
	    if (pcs->params.device_n.colorants != NULL) {
		cos_dict_t *colorants  = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
		cos_value_t v_colorants, v_separation, v_colorant_name;
		const gs_device_n_attributes *csa;
		pdf_resource_t *pres_attributes;

		if (colorants == NULL)
		    return_error(gs_error_VMerror);
		code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1);
		if (code < 0)
		    return code;
		cos_become(pres_attributes->object, cos_type_dict);
		COS_OBJECT_VALUE(&v_colorants, colorants);
		code = cos_dict_put((cos_dict_t *)pres_attributes->object, 
		    (const byte *)"/Colorants", 10, &v_colorants);
		if (code < 0)
		    return code;
		for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) {
	 	    code = pcs->params.device_n.get_colorname_string(pdev->memory,
				  csa->colorant_name, &name_string, &name_string_length);
		    if (code < 0)
			return code;
		    code = pdf_color_space(pdev, &v_separation, NULL, csa->cspace, pcsn, false);
		    if (code < 0)
			return code;
		    code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name);
		    if (code < 0)
			return code;
		    code = cos_dict_put(colorants, v_colorant_name.contents.chars.data, 
					v_colorant_name.contents.chars.size, &v_separation);
		    if (code < 0)
			return code;
		}
    		code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true);
		if (code < 0)
		    return code;
		va = &v_attriburtes;
		COS_OBJECT_VALUE(va, pres_attributes->object);
	    }
	    if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
						   pcs->base_space,
					pfn, &pdf_color_space_names, va)) < 0)
		return code;
	}
	break;

    case gs_color_space_index_Separation:
	pfn = gs_cspace_get_sepr_function(pcs);
	/****** CURRENTLY WE ONLY HANDLE Functions ******/
	if (pfn == 0)
	    return_error(gs_error_rangecheck);
	{
	    byte *name_string;
	    uint name_string_length;
	    if ((code = pcs->params.separation.get_colorname_string(
				  pdev->memory, 
				  pcs->params.separation.sep_name, &name_string, 
				  &name_string_length)) < 0 ||
		(code = pdf_string_to_cos_name(pdev, name_string, 
				      name_string_length, &v)) < 0 ||
		(code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
					    pcs->base_space,
					    pfn, &pdf_color_space_names, NULL)) < 0)
		return code;
	}
	break;

    case gs_color_space_index_Pattern:
	if ((code = pdf_color_space(pdev, pvalue, ppranges,
				    pcs->base_space,
				    &pdf_color_space_names, false)) < 0 ||
	    (code = cos_array_add(pca,
				  cos_c_string_value(&v, "/Pattern"))) < 0 ||
	    (code = cos_array_add(pca, pvalue)) < 0
	    )
	    return code;
	break;

    default:
	return_error(gs_error_rangecheck);
    }
    /*
     * Register the color space as a resource, since it must be referenced
     * by name rather than directly.
     */
    {
	pdf_color_space_t *ppcs;

	if (code < 0 ||
	    (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
				       &pres, -1)) < 0
	    ) {
	    COS_FREE(pca, "pdf_color_space");
	    return code;
	}
	pdf_reserve_object_id(pdev, pres, 0);
	if (res_name != NULL) {
	    int l = min(name_length, sizeof(pres->rname) - 1);
	    
	    memcpy(pres->rname, res_name, l);
	    pres->rname[l] = 0;
	}
	ppcs = (pdf_color_space_t *)pres;
	if (serialized == serialized0) {
	    serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
	    if (serialized == NULL)
		return_error(gs_error_VMerror);
	    memcpy(serialized, serialized0, serialized_size);
	}
	ppcs->serialized = serialized;
	ppcs->serialized_size = serialized_size;
	if (ranges) {
	    int num_comp = gs_color_space_num_components(pcs);
	    gs_range_t *copy_ranges = (gs_range_t *)
		gs_alloc_byte_array(pdev->pdf_memory, num_comp,
				    sizeof(gs_range_t), "pdf_color_space");

	    if (copy_ranges == 0) {
		COS_FREE(pca, "pdf_color_space");
		return_error(gs_error_VMerror);
	    }
	    memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
	    ppcs->ranges = copy_ranges;
	    if (ppranges)
		*ppranges = copy_ranges;
	} else
	    ppcs->ranges = 0;
	pca->id = pres->object->id;
	COS_FREE(pres->object, "pdf_color_space");
	pres->object = (cos_object_t *)pca;
	cos_write_object(COS_OBJECT(pca), pdev);
    }
 ret:
    if (by_name) {
	/* Return a resource name rather than an object reference. */
	discard(COS_RESOURCE_VALUE(pvalue, pca));
    } else
	discard(COS_OBJECT_VALUE(pvalue, pca));
    if (pres != NULL) {
	pres->where_used |= pdev->used_mask;
	code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
	if (code < 0)
	    return code;
    }
    return 0;
}