gscdevn.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: gscdevn.c,v 1.21 2004/08/04 19:36:12 stefan Exp $ */
  14. /* DeviceN color space and operation definition */
  15. #include "memory_.h"
  16. #include "string_.h"
  17. #include "gx.h"
  18. #include "gserrors.h"
  19. #include "gscdevn.h"
  20. #include "gsfunc.h"
  21. #include "gsrefct.h"
  22. #include "gsmatrix.h" /* for gscolor2.h */
  23. #include "gsstruct.h"
  24. #include "gxcspace.h"
  25. #include "gxcdevn.h"
  26. #include "gxfarith.h"
  27. #include "gxfrac.h"
  28. #include "gxcmap.h"
  29. #include "gxistate.h"
  30. #include "gscoord.h"
  31. #include "gzstate.h"
  32. #include "gxdevcli.h"
  33. #include "gsovrc.h"
  34. #include "stream.h"
  35. /* ---------------- Color space ---------------- */
  36. /* GC descriptors */
  37. gs_private_st_composite(st_color_space_DeviceN, gs_paint_color_space,
  38. "gs_color_space_DeviceN", cs_DeviceN_enum_ptrs, cs_DeviceN_reloc_ptrs);
  39. private_st_device_n_map();
  40. /* Define the DeviceN color space type. */
  41. private cs_proc_num_components(gx_num_components_DeviceN);
  42. private cs_proc_base_space(gx_alt_space_DeviceN);
  43. private cs_proc_init_color(gx_init_DeviceN);
  44. private cs_proc_restrict_color(gx_restrict_DeviceN);
  45. private cs_proc_concrete_space(gx_concrete_space_DeviceN);
  46. private cs_proc_concretize_color(gx_concretize_DeviceN);
  47. private cs_proc_remap_concrete_color(gx_remap_concrete_DeviceN);
  48. private cs_proc_install_cspace(gx_install_DeviceN);
  49. private cs_proc_set_overprint(gx_set_overprint_DeviceN);
  50. private cs_proc_adjust_cspace_count(gx_adjust_cspace_DeviceN);
  51. private cs_proc_serialize(gx_serialize_DeviceN);
  52. const gs_color_space_type gs_color_space_type_DeviceN = {
  53. gs_color_space_index_DeviceN, true, false,
  54. &st_color_space_DeviceN, gx_num_components_DeviceN,
  55. gx_alt_space_DeviceN,
  56. gx_init_DeviceN, gx_restrict_DeviceN,
  57. gx_concrete_space_DeviceN,
  58. gx_concretize_DeviceN, gx_remap_concrete_DeviceN,
  59. gx_default_remap_color, gx_install_DeviceN,
  60. gx_set_overprint_DeviceN,
  61. gx_adjust_cspace_DeviceN, gx_no_adjust_color_count,
  62. gx_serialize_DeviceN,
  63. gx_cspace_is_linear_default
  64. };
  65. /* GC procedures */
  66. private
  67. ENUM_PTRS_WITH(cs_DeviceN_enum_ptrs, gs_color_space *pcs)
  68. {
  69. return ENUM_USING(*pcs->params.device_n.alt_space.type->stype,
  70. &pcs->params.device_n.alt_space,
  71. sizeof(pcs->params.device_n.alt_space), index - 2);
  72. }
  73. ENUM_PTR(0, gs_color_space, params.device_n.names);
  74. ENUM_PTR(1, gs_color_space, params.device_n.map);
  75. ENUM_PTRS_END
  76. private RELOC_PTRS_WITH(cs_DeviceN_reloc_ptrs, gs_color_space *pcs)
  77. {
  78. RELOC_PTR(gs_color_space, params.device_n.names);
  79. RELOC_PTR(gs_color_space, params.device_n.map);
  80. RELOC_USING(*pcs->params.device_n.alt_space.type->stype,
  81. &pcs->params.device_n.alt_space,
  82. sizeof(gs_base_color_space));
  83. }
  84. RELOC_PTRS_END
  85. /* ------ Public procedures ------ */
  86. /*
  87. * Build a DeviceN color space. Not including allocation and
  88. * initialization of the color space.
  89. */
  90. int
  91. gs_build_DeviceN(
  92. gs_color_space *pcspace,
  93. uint num_components,
  94. const gs_color_space *palt_cspace,
  95. gs_memory_t *pmem
  96. )
  97. {
  98. gs_device_n_params *pcsdevn = pcsdevn = &pcspace->params.device_n;
  99. gs_separation_name *pnames = 0;
  100. int code;
  101. if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
  102. return_error(gs_error_rangecheck);
  103. /* Allocate space for color names list. */
  104. code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
  105. if (code < 0) {
  106. return code;
  107. }
  108. /* Allocate space for color names list. */
  109. pnames = (gs_separation_name *)
  110. gs_alloc_byte_array(pmem, num_components, sizeof(gs_separation_name),
  111. ".gs_cspace_build_DeviceN(names)");
  112. if (pnames == 0) {
  113. gs_free_object(pmem, pcsdevn->map, ".gs_cspace_build_DeviceN(map)");
  114. return_error(gs_error_VMerror);
  115. }
  116. pcsdevn->names = pnames;
  117. pcsdevn->num_components = num_components;
  118. return 0;
  119. }
  120. /*
  121. * Build a DeviceN color space. Including allocation and initialization
  122. * of the color space.
  123. */
  124. int
  125. gs_cspace_build_DeviceN(
  126. gs_color_space **ppcspace,
  127. gs_separation_name *psnames,
  128. uint num_components,
  129. const gs_color_space *palt_cspace,
  130. gs_memory_t *pmem
  131. )
  132. {
  133. gs_color_space *pcspace = 0; /* bogus initialization */
  134. gs_device_n_params *pcsdevn = 0; /* bogus initialization */
  135. int code;
  136. code = gs_cspace_alloc(&pcspace, &gs_color_space_type_DeviceN, pmem);
  137. if (code < 0)
  138. return code;
  139. code = gs_build_DeviceN(pcspace, num_components, palt_cspace, pmem);
  140. if (code < 0) {
  141. gs_free_object(pmem, pcspace, "gs_cspace_build_DeviceN");
  142. return code;
  143. }
  144. gs_cspace_init_from((gs_color_space *)&pcsdevn->alt_space, palt_cspace);
  145. *ppcspace = pcspace;
  146. return 0;
  147. }
  148. /* Allocate and initialize a DeviceN map. */
  149. int
  150. alloc_device_n_map(gs_device_n_map ** ppmap, gs_memory_t * mem,
  151. client_name_t cname)
  152. {
  153. gs_device_n_map *pimap;
  154. rc_alloc_struct_1(pimap, gs_device_n_map, &st_device_n_map, mem,
  155. return_error(gs_error_VMerror), cname);
  156. pimap->tint_transform = 0;
  157. pimap->tint_transform_data = 0;
  158. pimap->cache_valid = false;
  159. *ppmap = pimap;
  160. return 0;
  161. }
  162. #if 0 /* Unused; Unsupported by gx_serialize_device_n_map. */
  163. /*
  164. * Set the DeviceN tint transformation procedure.
  165. */
  166. int
  167. gs_cspace_set_devn_proc(gs_color_space * pcspace,
  168. int (*proc)(const float *,
  169. float *,
  170. const gs_imager_state *,
  171. void *
  172. ),
  173. void *proc_data
  174. )
  175. {
  176. gs_device_n_map *pimap;
  177. if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN)
  178. return_error(gs_error_rangecheck);
  179. pimap = pcspace->params.device_n.map;
  180. pimap->tint_transform = proc;
  181. pimap->tint_transform_data = proc_data;
  182. pimap->cache_valid = false;
  183. return 0;
  184. }
  185. #endif
  186. /*
  187. * Check if we are using the alternate color space.
  188. */
  189. bool
  190. using_alt_color_space(const gs_state * pgs)
  191. {
  192. return (pgs->color_component_map.use_alt_cspace);
  193. }
  194. /* Map a DeviceN color using a Function. */
  195. int
  196. map_devn_using_function(const float *in, float *out,
  197. const gs_imager_state *pis, void *data)
  198. {
  199. gs_function_t *const pfn = data;
  200. return gs_function_evaluate(pfn, in, out);
  201. }
  202. /*
  203. * Set the DeviceN tint transformation procedure to a Function.
  204. */
  205. int
  206. gs_cspace_set_devn_function(gs_color_space *pcspace, gs_function_t *pfn)
  207. {
  208. gs_device_n_map *pimap;
  209. if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN ||
  210. pfn->params.m != pcspace->params.device_n.num_components ||
  211. pfn->params.n !=
  212. gs_color_space_num_components((gs_color_space *)
  213. &pcspace->params.device_n.alt_space)
  214. )
  215. return_error(gs_error_rangecheck);
  216. pimap = pcspace->params.device_n.map;
  217. pimap->tint_transform = map_devn_using_function;
  218. pimap->tint_transform_data = pfn;
  219. pimap->cache_valid = false;
  220. return 0;
  221. }
  222. /*
  223. * If the DeviceN tint transformation procedure is a Function,
  224. * return the function object, otherwise return 0.
  225. */
  226. gs_function_t *
  227. gs_cspace_get_devn_function(const gs_color_space *pcspace)
  228. {
  229. if (gs_color_space_get_index(pcspace) == gs_color_space_index_DeviceN &&
  230. pcspace->params.device_n.map->tint_transform ==
  231. map_devn_using_function)
  232. return pcspace->params.device_n.map->tint_transform_data;
  233. return 0;
  234. }
  235. /* ------ Color space implementation ------ */
  236. /* Return the number of components of a DeviceN space. */
  237. private int
  238. gx_num_components_DeviceN(const gs_color_space * pcs)
  239. {
  240. return pcs->params.device_n.num_components;
  241. }
  242. /* Return the alternate space of a DeviceN space. */
  243. private const gs_color_space *
  244. gx_alt_space_DeviceN(const gs_color_space * pcs)
  245. {
  246. return pcs->params.device_n.use_alt_cspace
  247. ? (const gs_color_space *)&(pcs->params.device_n.alt_space)
  248. : NULL;
  249. }
  250. /* Initialize a DeviceN color. */
  251. private void
  252. gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
  253. {
  254. uint i;
  255. for (i = 0; i < pcs->params.device_n.num_components; ++i)
  256. pcc->paint.values[i] = 1.0;
  257. }
  258. /* Force a DeviceN color into legal range. */
  259. private void
  260. gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
  261. {
  262. uint i;
  263. for (i = 0; i < pcs->params.device_n.num_components; ++i) {
  264. floatp value = pcc->paint.values[i];
  265. pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value);
  266. }
  267. }
  268. /* Remap a DeviceN color. */
  269. private const gs_color_space *
  270. gx_concrete_space_DeviceN(const gs_color_space * pcs,
  271. const gs_imager_state * pis)
  272. {
  273. #ifdef DEBUG
  274. /*
  275. * Verify that the color space and imager state info match.
  276. */
  277. if (pcs->id != pis->color_component_map.cspace_id)
  278. dprintf("gx_concrete_space_DeviceN: color space id mismatch");
  279. #endif
  280. /*
  281. * Check if we are using the alternate color space.
  282. */
  283. if (pis->color_component_map.use_alt_cspace) {
  284. const gs_color_space *pacs =
  285. (const gs_color_space *)&pcs->params.device_n.alt_space;
  286. return cs_concrete_space(pacs, pis);
  287. }
  288. /*
  289. * DeviceN color spaces are concrete (when not using alt. color space).
  290. */
  291. return pcs;
  292. }
  293. private int
  294. gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
  295. frac * pconc, const gs_imager_state * pis)
  296. {
  297. int code, tcode = 0;
  298. gs_client_color cc;
  299. const gs_color_space *pacs =
  300. (const gs_color_space *)&pcs->params.device_n.alt_space;
  301. gs_device_n_map *map = pcs->params.device_n.map;
  302. #ifdef DEBUG
  303. /*
  304. * Verify that the color space and imager state info match.
  305. */
  306. if (pcs->id != pis->color_component_map.cspace_id)
  307. dprintf("gx_concretize_DeviceN: color space id mismatch");
  308. #endif
  309. /*
  310. * Check if we need to map into the alternate color space.
  311. * We must preserve tcode for implementing a semi-hack in the interpreter.
  312. */
  313. if (pis->color_component_map.use_alt_cspace) {
  314. /* Check the 1-element cache first. */
  315. if (map->cache_valid) {
  316. int i;
  317. for (i = pcs->params.device_n.num_components; --i >= 0;) {
  318. if (map->tint[i] != pc->paint.values[i])
  319. break;
  320. }
  321. if (i < 0) {
  322. int num_out = gs_color_space_num_components(pacs);
  323. for (i = 0; i < num_out; ++i)
  324. pconc[i] = map->conc[i];
  325. return 0;
  326. }
  327. }
  328. tcode = (*pcs->params.device_n.map->tint_transform)
  329. (pc->paint.values, &cc.paint.values[0],
  330. pis, pcs->params.device_n.map->tint_transform_data);
  331. if (tcode < 0)
  332. return tcode;
  333. code = cs_concretize_color(&cc, pacs, pconc, pis);
  334. }
  335. else {
  336. float ftemp;
  337. int i;
  338. for (i = pcs->params.device_n.num_components; --i >= 0;)
  339. pconc[i] = unit_frac(pc->paint.values[i], ftemp);
  340. return 0;
  341. }
  342. return (code < 0 || tcode == 0 ? code : tcode);
  343. }
  344. private int
  345. gx_remap_concrete_DeviceN(const frac * pconc, const gs_color_space * pcs,
  346. gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
  347. gs_color_select_t select)
  348. {
  349. #ifdef DEBUG
  350. /*
  351. * Verify that the color space and imager state info match.
  352. */
  353. if (pcs->id != pis->color_component_map.cspace_id)
  354. dprintf("gx_remap_concrete_DeviceN: color space id mismatch");
  355. #endif
  356. if (pis->color_component_map.use_alt_cspace) {
  357. const gs_color_space *pacs =
  358. (const gs_color_space *)&pcs->params.device_n.alt_space;
  359. return (*pacs->type->remap_concrete_color)
  360. (pconc, pacs, pdc, pis, dev, select);
  361. }
  362. else {
  363. gx_remap_concrete_devicen(pconc, pdc, pis, dev, select);
  364. return 0;
  365. }
  366. }
  367. /*
  368. * Check that the color component names for a DeviceN color space
  369. * match the device colorant names. Also build a gs_devicen_color_map
  370. * structure.
  371. */
  372. private int
  373. check_DeviceN_component_names(const gs_color_space * pcs, gs_state * pgs)
  374. {
  375. const gs_separation_name *names = pcs->params.device_n.names;
  376. int num_comp = pcs->params.device_n.num_components;
  377. int i, j;
  378. int colorant_number;
  379. byte * pname;
  380. uint name_size;
  381. gs_devicen_color_map * pcolor_component_map
  382. = &pgs->color_component_map;
  383. gx_device * dev = pgs->device;
  384. const char none_str[] = "None";
  385. const uint none_size = strlen(none_str);
  386. bool non_match = false;
  387. pcolor_component_map->num_components = num_comp;
  388. pcolor_component_map->cspace_id = pcs->id;
  389. pcolor_component_map->num_colorants = dev->color_info.num_components;
  390. pcolor_component_map->sep_type = SEP_OTHER;
  391. /*
  392. * Always use the alternate color space if the current device is
  393. * using an additive color model.
  394. */
  395. if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
  396. pcolor_component_map->use_alt_cspace = true;
  397. return 0;
  398. }
  399. /*
  400. * Now check the names of the color components.
  401. */
  402. non_match = false;
  403. for(i = 0; i < num_comp; i++ ) {
  404. /*
  405. * Get the character string and length for the component name.
  406. */
  407. pcs->params.device_n.get_colorname_string(dev->memory, names[i], &pname, &name_size);
  408. /*
  409. * Postscript does not accept /None as a color component but it is
  410. * allowed in PDF so we accept it. It is also accepted as a
  411. * separation name.
  412. */
  413. if (name_size == none_size &&
  414. (strncmp(none_str, (const char *)pname, name_size) == 0)) {
  415. pcolor_component_map->color_map[i] = -1;
  416. }
  417. else {
  418. /*
  419. * Check for duplicated names. Except for /None, no components
  420. * are allowed to have duplicated names.
  421. */
  422. for (j = 0; j < i; j++) {
  423. if (names[i] == names[j])
  424. return_error(gs_error_rangecheck);
  425. }
  426. /*
  427. * Compare the colorant name to the device's. If the device's
  428. * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
  429. * colorant is in the SeparationNames list but not in the
  430. * SeparationOrder list.
  431. */
  432. colorant_number = (*dev_proc(dev, get_color_comp_index))
  433. (dev, (const char *)pname, name_size, SEPARATION_NAME);
  434. if (colorant_number >= 0) { /* If valid colorant name */
  435. pcolor_component_map->color_map[i] =
  436. (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
  437. : colorant_number;
  438. }
  439. else
  440. non_match = true;
  441. }
  442. }
  443. pcolor_component_map->use_alt_cspace = non_match;
  444. return 0;
  445. }
  446. /* Install a DeviceN color space. */
  447. private int
  448. gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs)
  449. {
  450. int code = check_DeviceN_component_names(pcs, pgs);
  451. if (code < 0)
  452. return code;
  453. pgs->color_space->params.device_n.use_alt_cspace =
  454. using_alt_color_space(pgs);
  455. if (pgs->color_space->params.device_n.use_alt_cspace)
  456. code = (*pcs->params.device_n.alt_space.type->install_cspace)
  457. ((const gs_color_space *) & pcs->params.device_n.alt_space, pgs);
  458. /*
  459. * Give the device an opportunity to capture equivalent colors for any
  460. * spot colors which might be present in the color space.
  461. */
  462. if (code >= 0)
  463. code = dev_proc(pgs->device, update_spot_equivalent_colors)
  464. (pgs->device, pgs);
  465. return code;
  466. }
  467. /* Set overprint information for a DeviceN color space */
  468. private int
  469. gx_set_overprint_DeviceN(const gs_color_space * pcs, gs_state * pgs)
  470. {
  471. gs_devicen_color_map * pcmap = &pgs->color_component_map;
  472. if (pcmap->use_alt_cspace)
  473. return gx_spot_colors_set_overprint(
  474. (const gs_color_space *)&pcs->params.device_n.alt_space,
  475. pgs );
  476. else {
  477. gs_overprint_params_t params;
  478. if ((params.retain_any_comps = pgs->overprint)) {
  479. int i, ncomps = pcs->params.device_n.num_components;
  480. params.retain_spot_comps = false;
  481. params.drawn_comps = 0;
  482. for (i = 0; i < ncomps; i++) {
  483. int mcomp = pcmap->color_map[i];
  484. if (mcomp >= 0)
  485. gs_overprint_set_drawn_comp( params.drawn_comps, mcomp);
  486. }
  487. }
  488. pgs->effective_overprint_mode = 0;
  489. return gs_state_update_overprint(pgs, &params);
  490. }
  491. }
  492. /* Adjust the reference count of a DeviceN color space. */
  493. private void
  494. gx_adjust_cspace_DeviceN(const gs_color_space * pcs, int delta)
  495. {
  496. rc_adjust_const(pcs->params.device_n.map, delta, "gx_adjust_DeviceN");
  497. (*pcs->params.device_n.alt_space.type->adjust_cspace_count)
  498. ((const gs_color_space *)&pcs->params.device_n.alt_space, delta);
  499. }
  500. /* ---------------- Serialization. -------------------------------- */
  501. int
  502. gx_serialize_device_n_map(const gs_color_space * pcs, gs_device_n_map * m, stream * s)
  503. {
  504. const gs_function_t *pfn;
  505. if (m->tint_transform != map_devn_using_function)
  506. return_error(gs_error_unregistered); /* Unimplemented. */
  507. pfn = (const gs_function_t *)m->tint_transform_data;
  508. return gs_function_serialize(pfn, s);
  509. }
  510. private int
  511. gx_serialize_DeviceN(const gs_color_space * pcs, stream * s)
  512. {
  513. const gs_device_n_params * p = &pcs->params.device_n;
  514. uint n;
  515. int code = gx_serialize_cspace_type(pcs, s);
  516. if (code < 0)
  517. return code;
  518. code = sputs(s, (const byte *)&p->num_components, sizeof(p->num_components), &n);
  519. if (code < 0)
  520. return code;
  521. code = sputs(s, (const byte *)&p->names[0], sizeof(p->names[0]) * p->num_components, &n);
  522. if (code < 0)
  523. return code;
  524. code = cs_serialize((const gs_color_space *)&p->alt_space, s);
  525. if (code < 0)
  526. return code;
  527. return gx_serialize_device_n_map(pcs, p->map, s);
  528. /* p->use_alt_cspace isn't a property of the space. */
  529. }