/* * Mark a FontDescriptor used in a text. */ int pdf_mark_font_descriptor_used(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd) { if (pfd != NULL && pfd->common.object->id == -1) pdf_reserve_object_id(pdev, (pdf_resource_t *)&pfd->common, 0); 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; }