gdevpdfc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. /* Copyright (C) 1999, 2000, 2001 Aladdin Enterprises. All rights reserved.
  2. This file is part of AFPL Ghostscript.
  3. AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  4. distributor accepts any responsibility for the consequences of using it, or
  5. for whether it serves any particular purpose or works at all, unless he or
  6. she says so in writing. Refer to the Aladdin Free Public License (the
  7. "License") for full details.
  8. Every copy of AFPL Ghostscript must include a copy of the License, normally
  9. in a plain ASCII text file named PUBLIC. The License grants you the right
  10. to copy, modify and redistribute AFPL Ghostscript, but only under certain
  11. conditions described in the License. Among other things, the License
  12. requires that the copyright notice and this notice be preserved on all
  13. copies.
  14. */
  15. /*$Id: gdevpdfc.c,v 1.17 2001/08/03 06:43:52 lpd Exp $ */
  16. /* Color space management and writing for pdfwrite driver */
  17. #include "math_.h"
  18. #include "memory_.h"
  19. #include "gx.h"
  20. #include "gscspace.h" /* for gscie.h */
  21. #include "gscdevn.h"
  22. #include "gscie.h"
  23. #include "gscindex.h"
  24. #include "gscsepr.h"
  25. #include "stream.h"
  26. #include "gsicc.h"
  27. #include "gserrors.h"
  28. #include "gdevpdfx.h"
  29. #include "gdevpdfg.h"
  30. #include "gdevpdfo.h"
  31. #include "strimpl.h"
  32. #include "sstring.h"
  33. /* ------ CIE space testing ------ */
  34. /* Test whether a cached CIE procedure is the identity function. */
  35. #define CIE_CACHE_IS_IDENTITY(pc)\
  36. ((pc)->floats.params.is_identity)
  37. #define CIE_CACHE3_IS_IDENTITY(pca)\
  38. (CIE_CACHE_IS_IDENTITY(&(pca)[0]) &&\
  39. CIE_CACHE_IS_IDENTITY(&(pca)[1]) &&\
  40. CIE_CACHE_IS_IDENTITY(&(pca)[2]))
  41. /*
  42. * Test whether a cached CIE procedure is an exponential. A cached
  43. * procedure is exponential iff f(x) = k*(x^p). We make a very cursory
  44. * check for this: we require that f(0) = 0, set k = f(1), set p =
  45. * log[a](f(a)/k), and then require that f(b) = k*(b^p), where a and b are
  46. * two arbitrarily chosen values between 0 and 1. Naturally all this is
  47. * done with some slop.
  48. */
  49. #define CC_INDEX_A (gx_cie_cache_size / 3)
  50. #define CC_INDEX_B (gx_cie_cache_size * 2 / 3)
  51. #define CC_VALUE(i) ((i) / (double)(gx_cie_cache_size - 1))
  52. #define CCX_VALUE_A CC_VALUE(CC_INDEX_A)
  53. #define CCX_VALUE_B CC_VALUE(CC_INDEX_B)
  54. private bool
  55. cie_values_are_exponential(floatp va, floatp vb, floatp k, float *pexpt)
  56. {
  57. double p;
  58. if (fabs(k) < 0.001)
  59. return false;
  60. if (va == 0 || (va > 0) != (k > 0))
  61. return false;
  62. p = log(va / k) / log(CCX_VALUE_A);
  63. if (fabs(vb - k * pow(CCX_VALUE_B, p)) >= 0.001)
  64. return false;
  65. *pexpt = p;
  66. return true;
  67. }
  68. private bool
  69. cie_scalar_cache_is_exponential(const gx_cie_scalar_cache * pc, float *pexpt)
  70. {
  71. if (fabs(pc->floats.values[0]) >= 0.001)
  72. return false;
  73. return cie_values_are_exponential(pc->floats.values[CC_INDEX_A],
  74. pc->floats.values[CC_INDEX_B],
  75. pc->floats.values[gx_cie_cache_size - 1],
  76. pexpt);
  77. }
  78. #define CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pca, expts)\
  79. (cie_scalar_cache_is_exponential(&(pca)[0], &(expts).u) &&\
  80. cie_scalar_cache_is_exponential(&(pca)[1], &(expts).v) &&\
  81. cie_scalar_cache_is_exponential(&(pca)[2], &(expts).w))
  82. private bool
  83. cie_vector_cache_is_exponential(const gx_cie_vector_cache * pc, float *pexpt)
  84. {
  85. if (fabs(pc->vecs.values[0].u) >= 0.001)
  86. return false;
  87. return cie_values_are_exponential(pc->vecs.values[CC_INDEX_A].u,
  88. pc->vecs.values[CC_INDEX_B].u,
  89. pc->vecs.values[gx_cie_cache_size - 1].u,
  90. pexpt);
  91. }
  92. #define CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pca, expts)\
  93. (cie_vector_cache_is_exponential(&(pca)[0], &(expts).u) &&\
  94. cie_vector_cache_is_exponential(&(pca)[1], &(expts).v) &&\
  95. cie_vector_cache_is_exponential(&(pca)[2], &(expts).w))
  96. #undef CC_INDEX_A
  97. #undef CC_INDEX_B
  98. #undef CC_VALUE
  99. #undef CCX_VALUE_A
  100. #undef CCX_VALUE_B
  101. /* ------ Lab space synthesis ------ */
  102. /*
  103. * PDF doesn't have general CIEBased color spaces. However, since the
  104. * transformation from L*a*b* space to XYZ space is invertible, we can
  105. * handle any PostScript CIEBased space by transforming color values in
  106. * that space to XYZ, then inverse-transforming them to L*a*b* and using
  107. * a L*a*b* space with the same WhitePoint and BlackPoint and appropriate
  108. * ranges for a* and b*. This approach has two drawbacks:
  109. *
  110. * - Y values outside the range [0..1] can't be represented: we clamp
  111. * them.
  112. *
  113. * - For shadings, color interpolation will occur in the Lab space
  114. * rather in the original CIEBased space. We aren't going to worry
  115. * about this.
  116. */
  117. /* Transform a CIEBased color to XYZ. */
  118. private int
  119. cie_to_xyz(const double *in, double out[3], const gs_color_space *pcs)
  120. {
  121. /****** NOT IMPLEMENTED YET ******/
  122. out[0] = in[0], out[1] = in[1], out[2] = in[2]; /****** BOGUS ******/
  123. return 0;
  124. }
  125. /* Transform XYZ values to Lab. */
  126. private double
  127. lab_g_inverse(double v)
  128. {
  129. if (v >= (6.0 * 6.0 * 6.0) / (29 * 29 * 29))
  130. return pow(v, 1.0 / 3); /* use cbrt if available? */
  131. else
  132. return (v * (841.0 / 108) + 4.0 / 29);
  133. }
  134. private void
  135. xyz_to_lab(const double xyz[3], double lab[3], const gs_cie_common *pciec)
  136. {
  137. const gs_vector3 *const pWhitePoint = &pciec->points.WhitePoint;
  138. double L, lunit;
  139. /* Calculate L* first. */
  140. L = lab_g_inverse(xyz[1] / pWhitePoint->v) * 116 - 16;
  141. /* Clamp L* to the PDF range [0..100]. */
  142. if (L < 0)
  143. L = 0;
  144. else if (L > 100)
  145. L = 100;
  146. lab[1] = L;
  147. lunit = (L + 16) / 116;
  148. /* Calculate a* and b*. */
  149. lab[0] = (lab_g_inverse(xyz[0] / pWhitePoint->u) - lunit) * 500;
  150. lab[2] = (lab_g_inverse(xyz[2] / pWhitePoint->w) - lunit) * -200;
  151. }
  152. /* Create a PDF Lab color space corresponding to a CIEBased color space. */
  153. private int
  154. lab_range(double lab_min[3], double lab_max[3],
  155. const gs_color_space *pcs, const gs_cie_common *pciec)
  156. {
  157. /*
  158. * Determine the range of a* and b* by evaluating the color space
  159. * mapping at all of its extrema.
  160. */
  161. int ncomp = gs_color_space_num_components(pcs);
  162. int i, j;
  163. const gs_range *ranges;
  164. switch (gs_color_space_get_index(pcs)) {
  165. case gs_color_space_index_CIEDEFG:
  166. ranges = pcs->params.defg->RangeDEFG.ranges;
  167. break;
  168. case gs_color_space_index_CIEDEF:
  169. ranges = pcs->params.def->RangeDEF.ranges;
  170. break;
  171. case gs_color_space_index_CIEABC:
  172. ranges = pcs->params.abc->RangeABC.ranges;
  173. break;
  174. case gs_color_space_index_CIEA:
  175. ranges = &pcs->params.a->RangeA;
  176. break;
  177. default:
  178. return_error(gs_error_rangecheck);
  179. }
  180. for (j = 1; j < 3; ++j)
  181. lab_min[j] = 1000.0, lab_max[j] = -1000.0;
  182. for (i = 0; i < 1 << ncomp; ++i) {
  183. double in[4], xyz[3];
  184. for (j = 0; j < ncomp; ++j)
  185. in[j] = (i & (1 << j) ? ranges[j].rmax : ranges[j].rmin);
  186. if (cie_to_xyz(in, xyz, pcs) >= 0) {
  187. double lab[3];
  188. xyz_to_lab(xyz, lab, pciec);
  189. for (j = 1; j < 3; ++j) {
  190. lab_min[j] = min(lab_min[j], lab[j]);
  191. lab_max[j] = max(lab_max[j], lab[j]);
  192. }
  193. }
  194. }
  195. return 0;
  196. }
  197. private int
  198. pdf_lab_color_space(cos_array_t *pca, cos_dict_t *pcd,
  199. const gs_color_space *pcs, const gs_cie_common *pciec)
  200. {
  201. double lab_min[3], lab_max[3]; /* only 1 and 2 used */
  202. cos_array_t *pcar = cos_array_alloc(pca->pdev, "pdf_lab_color_space");
  203. cos_value_t v;
  204. int code;
  205. if (pcar == 0)
  206. return_error(gs_error_VMerror);
  207. if ((code = lab_range(lab_min, lab_max, pcs, pciec)) < 0 ||
  208. (code = cos_array_add(pca, cos_c_string_value(&v, "/Lab"))) < 0 ||
  209. (code = cos_array_add_real(pcar, lab_min[1])) < 0 ||
  210. (code = cos_array_add_real(pcar, lab_max[1])) < 0 ||
  211. (code = cos_array_add_real(pcar, lab_min[2])) < 0 ||
  212. (code = cos_array_add_real(pcar, lab_max[2])) < 0 ||
  213. (code = cos_dict_put_c_key_object(pcd, "/Range", COS_OBJECT(pcar))) < 0
  214. )
  215. return code;
  216. return 0;
  217. }
  218. /* ------ Color space writing ------ */
  219. /* Define standard and short color space names. */
  220. const pdf_color_space_names_t pdf_color_space_names = {
  221. PDF_COLOR_SPACE_NAMES
  222. };
  223. const pdf_color_space_names_t pdf_color_space_names_short = {
  224. PDF_COLOR_SPACE_NAMES_SHORT
  225. };
  226. /*
  227. * Create a local Device{Gray,RGB,CMYK} color space corresponding to the
  228. * given number of components.
  229. */
  230. int
  231. pdf_cspace_init_Device(gs_color_space *pcs, int num_components)
  232. {
  233. switch (num_components) {
  234. case 1: gs_cspace_init_DeviceGray(pcs); break;
  235. case 3: gs_cspace_init_DeviceRGB(pcs); break;
  236. case 4: gs_cspace_init_DeviceCMYK(pcs); break;
  237. default: return_error(gs_error_rangecheck);
  238. }
  239. return 0;
  240. }
  241. /* Add a 3-element vector to a Cos array or dictionary. */
  242. private int
  243. cos_array_add_vector3(cos_array_t *pca, const gs_vector3 *pvec)
  244. {
  245. int code = cos_array_add_real(pca, pvec->u);
  246. if (code >= 0)
  247. code = cos_array_add_real(pca, pvec->v);
  248. if (code >= 0)
  249. code = cos_array_add_real(pca, pvec->w);
  250. return code;
  251. }
  252. private int
  253. cos_dict_put_c_key_vector3(cos_dict_t *pcd, const char *key,
  254. const gs_vector3 *pvec)
  255. {
  256. cos_array_t *pca = cos_array_alloc(pcd->pdev, "cos_array_from_vector3");
  257. int code;
  258. if (pca == 0)
  259. return_error(gs_error_VMerror);
  260. code = cos_array_add_vector3(pca, pvec);
  261. if (code < 0) {
  262. COS_FREE(pca, "cos_array_from_vector3");
  263. return code;
  264. }
  265. return cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
  266. }
  267. /* Create a Separation or DeviceN color space (internal). */
  268. private int
  269. pdf_separation_color_space(gx_device_pdf *pdev,
  270. cos_array_t *pca, const char *csname,
  271. const cos_value_t *snames,
  272. const gs_color_space *alt_space,
  273. const gs_function_t *pfn,
  274. const pdf_color_space_names_t *pcsn)
  275. {
  276. cos_value_t v;
  277. int code;
  278. if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
  279. (code = cos_array_add_no_copy(pca, snames)) < 0 ||
  280. (code = pdf_color_space(pdev, &v, alt_space, pcsn, false)) < 0 ||
  281. (code = cos_array_add(pca, &v)) < 0 ||
  282. (code = pdf_function(pdev, pfn, &v)) < 0 ||
  283. (code = cos_array_add(pca, &v)) < 0
  284. )
  285. return code;
  286. return 0;
  287. }
  288. /*
  289. * Create a PDF color space corresponding to a PostScript color space.
  290. * For parameterless color spaces, set *pvalue to a (literal) string with
  291. * the color space name; for other color spaces, create a cos_dict_t if
  292. * necessary and set *pvalue to refer to it.
  293. */
  294. int
  295. pdf_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
  296. const gs_color_space *pcs,
  297. const pdf_color_space_names_t *pcsn,
  298. bool by_name)
  299. {
  300. gs_memory_t *mem = pdev->pdf_memory;
  301. gs_color_space_index csi = gs_color_space_get_index(pcs);
  302. cos_array_t *pca;
  303. cos_dict_t *pcd;
  304. cos_value_t v;
  305. const gs_cie_common *pciec;
  306. gs_function_t *pfn;
  307. int code;
  308. switch (csi) {
  309. case gs_color_space_index_DeviceGray:
  310. cos_c_string_value(pvalue, pcsn->DeviceGray);
  311. return 0;
  312. case gs_color_space_index_DeviceRGB:
  313. cos_c_string_value(pvalue, pcsn->DeviceRGB);
  314. return 0;
  315. case gs_color_space_index_DeviceCMYK:
  316. cos_c_string_value(pvalue, pcsn->DeviceCMYK);
  317. return 0;
  318. case gs_color_space_index_Pattern:
  319. if (!pcs->params.pattern.has_base_space) {
  320. cos_c_string_value(pvalue, "/Pattern");
  321. return 0;
  322. }
  323. break;
  324. case gs_color_space_index_CIEICC:
  325. /*
  326. * Take a special early exit for unrecognized ICCBased color spaces,
  327. * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
  328. */
  329. if (pcs->params.icc.picc_info->picc == 0 ||
  330. pdev->CompatibilityLevel < 1.3
  331. )
  332. return pdf_color_space( pdev, pvalue,
  333. (const gs_color_space *)
  334. &pcs->params.icc.alt_space,
  335. pcsn, by_name);
  336. break;
  337. default:
  338. break;
  339. }
  340. /* Space has parameters -- create an array. */
  341. pca = cos_array_alloc(pdev, "pdf_color_space");
  342. if (pca == 0)
  343. return_error(gs_error_VMerror);
  344. switch (csi) {
  345. case gs_color_space_index_CIEICC: {
  346. /* this would arise only in a pdf ==> pdf translation, but we
  347. * should allow for it anyway */
  348. const gs_icc_params * picc_params = &pcs->params.icc;
  349. const gs_cie_icc * picc_info = picc_params->picc_info;
  350. int ncomps = picc_info->num_components;
  351. cos_stream_t * pcstrm;
  352. int i;
  353. gs_color_space_index alt_csi;
  354. /* ICCBased color spaces are essentially copied to the output */
  355. if ((code = cos_array_add(pca, cos_c_string_value(&v, "/ICCBased"))) < 0)
  356. return code;
  357. /* create a stream for the output */
  358. if ((pcstrm = cos_stream_alloc( pdev, "pdf_color_space(stream)")) == 0)
  359. return_error(gs_error_VMerror);
  360. /* indicate the number of components */
  361. code = cos_dict_put_c_key_int(cos_stream_dict(pcstrm), "/N", ncomps);
  362. /* indicate the range, if appropriate */
  363. for (i = 0; i < ncomps && picc_info->Range.ranges[i].rmin == 0.0 &&
  364. picc_info->Range.ranges[i].rmax == 1.0; i++)
  365. ;
  366. if (code >= 0 && i != ncomps) {
  367. cos_array_t * prngca = cos_array_alloc(pdev,
  368. "pdf_color_space(Range)");
  369. if (prngca == 0)
  370. return_error(gs_error_VMerror);
  371. for (i = 0; code >= 0 && i < ncomps; i++) {
  372. code = cos_array_add_int(prngca,
  373. picc_info->Range.ranges[i].rmin);
  374. if (code >= 0)
  375. code = cos_array_add_int(prngca,
  376. picc_info->Range.ranges[i].rmax);
  377. }
  378. if (code < 0 ||
  379. (code = cos_dict_put_c_key_object(cos_stream_dict(pcstrm),
  380. "/Range",
  381. COS_OBJECT(prngca))) < 0)
  382. COS_FREE(prngca, "pcf_colos_space(Range)");
  383. }
  384. /* output the alternate color space, if necessary */
  385. alt_csi = gs_color_space_get_index(pcs);
  386. if (code >= 0 && alt_csi != gs_color_space_index_DeviceGray &&
  387. alt_csi != gs_color_space_index_DeviceRGB &&
  388. alt_csi != gs_color_space_index_DeviceCMYK) {
  389. code = pdf_color_space(pdev, pvalue,
  390. (const gs_color_space *)&picc_params->alt_space,
  391. &pdf_color_space_names, false);
  392. if (code >= 0)
  393. code = cos_dict_put_c_key(cos_stream_dict(pcstrm),
  394. "/Alternate", pvalue);
  395. }
  396. /* transfer the profile stream */
  397. while (code >= 0) {
  398. byte sbuff[256];
  399. uint cnt;
  400. code = sgets(picc_info->instrp, sbuff, sizeof(sbuff), &cnt);
  401. if (cnt == 0)
  402. break;
  403. if (code >= 0)
  404. code = cos_stream_add_bytes(pcstrm, sbuff, cnt);
  405. }
  406. if (code >= 0)
  407. code = cos_array_add(pca, COS_OBJECT_VALUE(&v, pcstrm));
  408. else
  409. COS_FREE(pcstrm, "pcf_color_space(ICCBased dictionary)");
  410. }
  411. break;
  412. case gs_color_space_index_CIEA: {
  413. /* Check that we can represent this as a CalGray space. */
  414. const gs_cie_a *pcie = pcs->params.a;
  415. gs_vector3 expts;
  416. pciec = (const gs_cie_common *)pcie;
  417. if (!(pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
  418. pcie->MatrixA.w == 1 &&
  419. pcie->common.MatrixLMN.is_identity))
  420. return_error(gs_error_rangecheck);
  421. if (CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
  422. CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
  423. expts.v == expts.u && expts.w == expts.u
  424. ) {
  425. DO_NOTHING;
  426. } else if (CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
  427. cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
  428. ) {
  429. DO_NOTHING;
  430. } else
  431. goto lab;
  432. code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
  433. if (code < 0)
  434. return code;
  435. pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
  436. if (pcd == 0)
  437. return_error(gs_error_VMerror);
  438. if (expts.u != 1) {
  439. code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
  440. if (code < 0)
  441. return code;
  442. }
  443. }
  444. cal:
  445. code = cos_dict_put_c_key_vector3(pcd, "/WhitePoint",
  446. &pciec->points.WhitePoint);
  447. if (code < 0)
  448. return code;
  449. if (pciec->points.BlackPoint.u != 0 ||
  450. pciec->points.BlackPoint.v != 0 ||
  451. pciec->points.BlackPoint.w != 0
  452. ) {
  453. code = cos_dict_put_c_key_vector3(pcd, "/BlackPoint",
  454. &pciec->points.BlackPoint);
  455. if (code < 0)
  456. return code;
  457. }
  458. code = cos_array_add(pca, COS_OBJECT_VALUE(&v, pcd));
  459. break;
  460. case gs_color_space_index_CIEABC: {
  461. /* Check that we can represent this as a CalRGB space. */
  462. const gs_cie_abc *pcie = pcs->params.abc;
  463. gs_vector3 expts;
  464. const gs_matrix3 *pmat;
  465. pciec = (const gs_cie_common *)pcie;
  466. if (pcie->common.MatrixLMN.is_identity &&
  467. CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
  468. CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC, expts)
  469. )
  470. pmat = &pcie->MatrixABC;
  471. else if (pcie->MatrixABC.is_identity &&
  472. CIE_CACHE3_IS_IDENTITY(pcie->caches.DecodeABC) &&
  473. CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts)
  474. )
  475. pmat = &pcie->common.MatrixLMN;
  476. else
  477. goto lab;
  478. code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
  479. if (code < 0)
  480. return code;
  481. pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
  482. if (pcd == 0)
  483. return_error(gs_error_VMerror);
  484. if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
  485. code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
  486. if (code < 0)
  487. return code;
  488. }
  489. if (!pmat->is_identity) {
  490. cos_array_t *pcma =
  491. cos_array_alloc(pdev, "pdf_color_space(Matrix)");
  492. if (pcma == 0)
  493. return_error(gs_error_VMerror);
  494. if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
  495. (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
  496. (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
  497. (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
  498. COS_OBJECT_VALUE(&v, pcma))) < 0
  499. )
  500. return code;
  501. }
  502. }
  503. goto cal;
  504. case gs_color_space_index_CIEDEF:
  505. pciec = (const gs_cie_common *)pcs->params.def;
  506. goto lab;
  507. case gs_color_space_index_CIEDEFG:
  508. pciec = (const gs_cie_common *)pcs->params.defg;
  509. lab:
  510. /* Convert all other CIEBased spaces to a Lab space. */
  511. /****** NOT IMPLEMENTED YET, REQUIRES TRANSFORMING VALUES ******/
  512. if (1) return_error(gs_error_rangecheck);
  513. pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
  514. if (pcd == 0)
  515. return_error(gs_error_VMerror);
  516. code = pdf_lab_color_space(pca, pcd, pcs, pciec);
  517. if (code < 0)
  518. return code;
  519. goto cal;
  520. case gs_color_space_index_Indexed: {
  521. const gs_indexed_params *pip = &pcs->params.indexed;
  522. const gs_color_space *base_space =
  523. (const gs_color_space *)&pip->base_space;
  524. int num_entries = pip->hival + 1;
  525. int num_components = gs_color_space_num_components(base_space);
  526. uint table_size = num_entries * num_components;
  527. /* Guess at the extra space needed for ASCII85 encoding. */
  528. uint string_size = 1 + table_size * 2 + table_size / 30 + 2;
  529. uint string_used;
  530. byte buf[100]; /* arbitrary */
  531. stream_AXE_state st;
  532. stream s, es;
  533. byte *table =
  534. gs_alloc_string(mem, string_size, "pdf_color_space(table)");
  535. byte *palette =
  536. gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
  537. gs_color_space cs_gray;
  538. if (table == 0 || palette == 0) {
  539. gs_free_string(mem, palette, table_size,
  540. "pdf_color_space(palette)");
  541. gs_free_string(mem, table, string_size,
  542. "pdf_color_space(table)");
  543. return_error(gs_error_VMerror);
  544. }
  545. swrite_string(&s, table, string_size);
  546. s_init(&es, NULL);
  547. s_init_state((stream_state *)&st, &s_AXE_template, NULL);
  548. s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
  549. sputc(&s, '<');
  550. if (pcs->params.indexed.use_proc) {
  551. gs_client_color cmin, cmax;
  552. byte *pnext = palette;
  553. int i, j;
  554. /* Find the legal range for the color components. */
  555. for (j = 0; j < num_components; ++j)
  556. cmin.paint.values[j] = min_long,
  557. cmax.paint.values[j] = max_long;
  558. gs_color_space_restrict_color(&cmin, base_space);
  559. gs_color_space_restrict_color(&cmax, base_space);
  560. /*
  561. * Compute the palette values, with the legal range for each
  562. * one mapped to [0 .. 255].
  563. */
  564. for (i = 0; i < num_entries; ++i) {
  565. gs_client_color cc;
  566. gs_cspace_indexed_lookup(&pcs->params.indexed, i, &cc);
  567. for (j = 0; j < num_components; ++j) {
  568. float v = (cc.paint.values[j] - cmin.paint.values[j])
  569. * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);
  570. *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
  571. }
  572. }
  573. } else
  574. memcpy(palette, pip->lookup.table.data, table_size);
  575. if (gs_color_space_get_index(base_space) ==
  576. gs_color_space_index_DeviceRGB
  577. ) {
  578. /* Check for an all-gray palette. */
  579. int i;
  580. for (i = table_size; (i -= 3) >= 0; )
  581. if (palette[i] != palette[i + 1] ||
  582. palette[i] != palette[i + 2]
  583. )
  584. break;
  585. if (i < 0) {
  586. /* Change the color space to DeviceGray. */
  587. for (i = 0; i < num_entries; ++i)
  588. palette[i] = palette[i * 3];
  589. table_size = num_entries;
  590. gs_cspace_init_DeviceGray(&cs_gray);
  591. base_space = &cs_gray;
  592. }
  593. }
  594. stream_write(&es, palette, table_size);
  595. gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
  596. sclose(&es);
  597. sflush(&s);
  598. string_used = (uint)stell(&s);
  599. table = gs_resize_string(mem, table, string_size, string_used,
  600. "pdf_color_space(table)");
  601. /*
  602. * Since the array is always referenced by name as a resource
  603. * rather than being written as a value, even for in-line images,
  604. * always use the full name for the color space.
  605. */
  606. if ((code = pdf_color_space(pdev, pvalue, base_space,
  607. &pdf_color_space_names, false)) < 0 ||
  608. (code = cos_array_add(pca,
  609. cos_c_string_value(&v,
  610. pdf_color_space_names.Indexed
  611. /*pcsn->Indexed*/))) < 0 ||
  612. (code = cos_array_add(pca, pvalue)) < 0 ||
  613. (code = cos_array_add_int(pca, pip->hival)) < 0 ||
  614. (code = cos_array_add_no_copy(pca,
  615. cos_string_value(&v, table,
  616. string_used))) < 0
  617. )
  618. return code;
  619. }
  620. break;
  621. case gs_color_space_index_DeviceN:
  622. pfn = gs_cspace_get_devn_function(pcs);
  623. /****** CURRENTLY WE ONLY HANDLE Functions ******/
  624. if (pfn == 0)
  625. return_error(gs_error_rangecheck);
  626. {
  627. cos_array_t *psna =
  628. cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
  629. int i;
  630. if (psna == 0)
  631. return_error(gs_error_VMerror);
  632. for (i = 0; i < pcs->params.device_n.num_components; ++i) {
  633. code = pdf_separation_name(pdev, &v,
  634. pcs->params.device_n.names[i]);
  635. if (code < 0 ||
  636. (code = cos_array_add_no_copy(psna, &v)) < 0)
  637. return code;
  638. }
  639. COS_OBJECT_VALUE(&v, psna);
  640. if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
  641. (const gs_color_space *)
  642. &pcs->params.device_n.alt_space,
  643. pfn, &pdf_color_space_names)) < 0)
  644. return code;
  645. }
  646. break;
  647. case gs_color_space_index_Separation:
  648. pfn = gs_cspace_get_sepr_function(pcs);
  649. /****** CURRENTLY WE ONLY HANDLE Functions ******/
  650. if (pfn == 0)
  651. return_error(gs_error_rangecheck);
  652. if ((code = pdf_separation_name(pdev, &v,
  653. pcs->params.separation.sname)) < 0 ||
  654. (code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
  655. (const gs_color_space *)
  656. &pcs->params.separation.alt_space,
  657. pfn, &pdf_color_space_names)) < 0)
  658. return code;
  659. break;
  660. case gs_color_space_index_Pattern:
  661. if ((code = pdf_color_space(pdev, pvalue,
  662. (const gs_color_space *)
  663. &pcs->params.pattern.base_space,
  664. &pdf_color_space_names, false)) < 0 ||
  665. (code = cos_array_add(pca,
  666. cos_c_string_value(&v, "/Pattern"))) < 0 ||
  667. (code = cos_array_add(pca, pvalue)) < 0
  668. )
  669. return code;
  670. break;
  671. default:
  672. return_error(gs_error_rangecheck);
  673. }
  674. /*
  675. * Register the color space as a resource, since it must be referenced
  676. * by name rather than directly.
  677. */
  678. {
  679. pdf_resource_t *pres;
  680. code =
  681. pdf_alloc_resource(pdev, resourceColorSpace, gs_no_id, &pres, 0L);
  682. if (code < 0) {
  683. COS_FREE(pca, "pdf_color_space");
  684. return code;
  685. }
  686. pca->id = pres->object->id;
  687. COS_FREE(pres->object, "pdf_color_space");
  688. pres->object = (cos_object_t *)pca;
  689. cos_write_object(COS_OBJECT(pca), pdev);
  690. }
  691. if (by_name) {
  692. /* Return a resource name rather than an object reference. */
  693. discard(COS_RESOURCE_VALUE(pvalue, pca));
  694. } else
  695. discard(COS_OBJECT_VALUE(pvalue, pca));
  696. return 0;
  697. }
  698. /* Create colored and uncolored Pattern color spaces. */
  699. private int
  700. pdf_pattern_space(gx_device_pdf *pdev, cos_value_t *pvalue,
  701. pdf_resource_t **ppres, const char *cs_name)
  702. {
  703. if (!*ppres) {
  704. int code = pdf_begin_resource_body(pdev, resourceColorSpace, gs_no_id,
  705. ppres);
  706. if (code < 0)
  707. return code;
  708. pprints1(pdev->strm, "%s\n", cs_name);
  709. pdf_end_resource(pdev);
  710. (*ppres)->object->written = true; /* don't write at end */
  711. }
  712. cos_resource_value(pvalue, (*ppres)->object);
  713. return 0;
  714. }
  715. int
  716. pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue)
  717. {
  718. return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[0],
  719. "[/Pattern]");
  720. }
  721. int
  722. pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue)
  723. {
  724. int ncomp = pdev->color_info.num_components;
  725. static const char *const pcs_names[5] = {
  726. 0, "[/Pattern /DeviceGray]", 0, "[/Pattern /DeviceRGB]",
  727. "[/Pattern /DeviceCMYK]"
  728. };
  729. return pdf_pattern_space(pdev, pvalue, &pdev->cs_Patterns[ncomp],
  730. pcs_names[ncomp]);
  731. }
  732. /* ---------------- Miscellaneous ---------------- */
  733. /* Set the ProcSets bits corresponding to an image color space. */
  734. void
  735. pdf_color_space_procsets(gx_device_pdf *pdev, const gs_color_space *pcs)
  736. {
  737. const gs_color_space *pbcs = pcs;
  738. csw:
  739. switch (gs_color_space_get_index(pbcs)) {
  740. case gs_color_space_index_DeviceGray:
  741. case gs_color_space_index_CIEA:
  742. /* We only handle CIEBasedA spaces that map to CalGray. */
  743. pdev->procsets |= ImageB;
  744. break;
  745. case gs_color_space_index_Indexed:
  746. pdev->procsets |= ImageI;
  747. pbcs = (const gs_color_space *)&pcs->params.indexed.base_space;
  748. goto csw;
  749. default:
  750. pdev->procsets |= ImageC;
  751. break;
  752. }
  753. }