/* Add a /Range entry to a CIE-based color space dictionary. */
static int
pdf_cie_add_ranges(cos_dict_t *pcd, const gs_range *prange, int n, bool clamp)
{
    cos_array_t *pca = cos_array_alloc(pcd->pdev, "pdf_cie_add_ranges");
    int code = 0, i;

    if (pca == 0)
	return_error(gs_error_VMerror);
    for (i = 0; i < n; ++i) {
	floatp rmin = prange[i].rmin, rmax = prange[i].rmax;

	if (clamp) {
	    if (rmin < 0) rmin = 0;
	    if (rmax > 1) rmax = 1;
	}
	if ((code = cos_array_add_real(pca, rmin)) < 0 ||
	    (code = cos_array_add_real(pca, rmax)) < 0
	    )
	    break;
    }
    if (code >= 0)
	code = cos_dict_put_c_key_object(pcd, "/Range", COS_OBJECT(pca));
    if (code < 0)
	COS_FREE(pca, "pdf_cie_add_ranges");
    return code;
}
static int
cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
			   const gs_vector3 *pvec)
{
    cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
    int code;

    if (pca == 0)
	return_error(gs_error_VMerror);
    code = cos_array_add_vector3(pca, pvec);
    if (code < 0) {
	COS_FREE(pca, "cos_array_from_vector3");
	return code;
    }
    return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
}
Beispiel #3
0
/*
 * Push the current local namespace onto the namespace stack, and reset it
 * to an empty namespace.
 */
int
pdf_push_namespace(gx_device_pdf *pdev)
{
    int code = cos_array_add_object(pdev->Namespace_stack,
				    COS_OBJECT(pdev->local_named_objects));
    cos_dict_t *pcd =
	cos_dict_alloc(pdev, "pdf_push_namespace(local_named_objects)");
    cos_array_t *pca =
	cos_array_alloc(pdev, "pdf_push_namespace(NI_stack)");

    if (code < 0 ||
	(code = cos_array_add_object(pdev->Namespace_stack,
				     COS_OBJECT(pdev->NI_stack))) < 0
	)
	return code;
    if (pcd == 0 || pca == 0)
	return_error(gs_error_VMerror);
    pdev->local_named_objects = pcd;
    pdev->NI_stack = pca;
    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;
}