gdevcmap.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /* Copyright (C) 1998, 1999 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: gdevcmap.c,v 1.6 2004/05/26 04:10:58 dan Exp $ */
  14. /* Special color mapping device */
  15. #include "gx.h"
  16. #include "gserrors.h"
  17. #include "gxdevice.h"
  18. #include "gxlum.h"
  19. #include "gxfrac.h"
  20. #include "gxdcconv.h"
  21. #include "gdevcmap.h"
  22. /*
  23. * The devices in this file exist only to implement the PCL5 special
  24. * color mapping algorithms. They are not useful for PostScript.
  25. */
  26. /* GC descriptor */
  27. public_st_device_cmap();
  28. /* Device procedures */
  29. private dev_proc_get_params(cmap_get_params);
  30. private dev_proc_put_params(cmap_put_params);
  31. private dev_proc_begin_typed_image(cmap_begin_typed_image);
  32. private dev_proc_get_color_mapping_procs(cmap_get_color_mapping_procs);
  33. /*
  34. * NB: all of the device color model information will be replaced by
  35. * the target's color model information. Only the
  36. * get_color_mapping_procs method is modified (aside from
  37. * get_params/put_params).
  38. *
  39. * The begin_typed_image method is used only to force use of the default
  40. * image rendering routines if a special mapping_method (anything other
  41. * than device_cmap_identity) is requested.
  42. */
  43. private const gx_device_cmap gs_cmap_device = {
  44. std_device_dci_body(gx_device_cmap, 0, "special color mapper",
  45. 0, 0, 1, 1,
  46. 3, 24, 255, 255, 256, 256),
  47. {
  48. 0, 0, 0, 0, 0, 0, 0,
  49. gx_forward_fill_rectangle,
  50. gx_forward_tile_rectangle,
  51. gx_forward_copy_mono,
  52. gx_forward_copy_color,
  53. 0, 0,
  54. cmap_get_params,
  55. cmap_put_params,
  56. 0, 0, 0, 0,
  57. 0, 0, 0, 0, 0,
  58. 0, 0, 0, 0, 0, 0, 0,
  59. gx_default_begin_image,
  60. 0, 0, 0, 0, 0,
  61. cmap_begin_typed_image,
  62. 0, 0, 0, 0, 0, 0,
  63. 0, 0, 0, 0, 0,
  64. cmap_get_color_mapping_procs,
  65. 0, 0, 0
  66. },
  67. 0, /* target */
  68. device_cmap_identity
  69. };
  70. /* Set the color mapping method. */
  71. private int
  72. gdev_cmap_set_method(gx_device_cmap * cmdev,
  73. gx_device_color_mapping_method_t method)
  74. {
  75. gx_device *target = cmdev->target;
  76. /*
  77. * If we're transforming the color, we may need to fool the graphics
  78. * core into not halftoning.
  79. */
  80. set_dev_proc(cmdev, map_cmyk_color, gx_default_map_cmyk_color);
  81. set_dev_proc(cmdev, map_color_rgb, gx_forward_map_color_rgb);
  82. switch (method) {
  83. case device_cmap_identity:
  84. /*
  85. * In this case, and only this case, we can allow the target's
  86. * color model to propagate here.
  87. */
  88. set_dev_proc(cmdev, map_cmyk_color, gx_forward_map_cmyk_color);
  89. cmdev->color_info.max_gray = target->color_info.max_gray;
  90. cmdev->color_info.max_color = target->color_info.max_color;
  91. cmdev->color_info.max_components =
  92. target->color_info.max_components;
  93. cmdev->color_info.num_components =
  94. target->color_info.num_components;
  95. cmdev->color_info.polarity = target->color_info.polarity;
  96. cmdev->color_info.gray_index = target->color_info.gray_index;
  97. cmdev->color_info.cm_name = target->color_info.cm_name;
  98. gx_device_copy_color_procs((gx_device *)cmdev, target);
  99. break;
  100. case device_cmap_monochrome:
  101. cmdev->color_info.max_gray = target->color_info.max_gray;
  102. cmdev->color_info.max_color = target->color_info.max_color;
  103. cmdev->color_info.max_components =
  104. cmdev->color_info.num_components = 1;
  105. cmdev->color_info.cm_name = "DeviceGray";
  106. break;
  107. case device_cmap_snap_to_primaries:
  108. case device_cmap_color_to_black_over_white:
  109. cmdev->color_info.max_gray = cmdev->color_info.max_color = 4095;
  110. /*
  111. * We have to be an RGB device, otherwise "primaries" doesn't
  112. * have the proper meaning.
  113. */
  114. cmdev->color_info.max_components =
  115. cmdev->color_info.num_components = 3;
  116. cmdev->color_info.cm_name = "DeviceRGB";
  117. break;
  118. default:
  119. return_error(gs_error_rangecheck);
  120. }
  121. cmdev->mapping_method = method;
  122. return 0;
  123. }
  124. /* Initialize the device. */
  125. int
  126. gdev_cmap_init(gx_device_cmap * dev, gx_device * target,
  127. gx_device_color_mapping_method_t method)
  128. {
  129. int code;
  130. gx_device_init((gx_device *) dev, (const gx_device *)&gs_cmap_device,
  131. target->memory, true);
  132. gx_device_set_target((gx_device_forward *)dev, target);
  133. gx_device_copy_params((gx_device *)dev, target);
  134. check_device_separable((gx_device *)dev);
  135. gx_device_forward_fill_in_procs((gx_device_forward *) dev);
  136. code = gdev_cmap_set_method(dev, method);
  137. if (code < 0)
  138. return code;
  139. return 0;
  140. }
  141. /* Get parameters. */
  142. private int
  143. cmap_get_params(gx_device * dev, gs_param_list * plist)
  144. {
  145. int code = gx_forward_get_params(dev, plist);
  146. int ecode = code;
  147. gx_device_cmap * const cmdev = (gx_device_cmap *)dev;
  148. int cmm = cmdev->mapping_method;
  149. if ((code = param_write_int(plist, "ColorMappingMethod", &cmm)) < 0)
  150. ecode = code;
  151. return ecode;
  152. }
  153. /* Update parameters; copy the device information back afterwards. */
  154. private int
  155. cmap_put_params(gx_device * dev, gs_param_list * plist)
  156. {
  157. int code = gx_forward_put_params(dev, plist);
  158. int ecode = code;
  159. gx_device_cmap * const cmdev = (gx_device_cmap *)dev;
  160. int cmm = cmdev->mapping_method;
  161. const char *param_name;
  162. switch (code = param_read_int(plist, param_name = "ColorMappingMethod",
  163. &cmm)) {
  164. case 0:
  165. if (cmm < 0 || cmm > device_cmap_max_method) {
  166. code = gs_note_error(gs_error_rangecheck);
  167. } else
  168. break;
  169. default:
  170. ecode = code;
  171. param_signal_error(plist, param_name, ecode);
  172. break;
  173. case 1:
  174. break;
  175. }
  176. if (code >= 0) {
  177. gx_device_copy_params(dev, cmdev->target);
  178. gdev_cmap_set_method(cmdev, cmm);
  179. }
  180. return ecode;
  181. }
  182. /*
  183. * Handle high-level images. The only reason we do this, rather than simply
  184. * pass the operation to the target, is that the image still has to call the
  185. * cmap device to do its color mapping. As presently implemented, this
  186. * disables any high-level implementation that the target may provide.
  187. */
  188. private int
  189. cmap_begin_typed_image(gx_device * dev,
  190. const gs_imager_state * pis, const gs_matrix * pmat,
  191. const gs_image_common_t * pic, const gs_int_rect * prect,
  192. const gx_drawing_color * pdcolor,
  193. const gx_clip_path * pcpath,
  194. gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
  195. {
  196. const gx_device_cmap *const cmdev = (const gx_device_cmap *)dev;
  197. gx_device *target = cmdev->target;
  198. if (cmdev->mapping_method == device_cmap_identity)
  199. return (*dev_proc(target, begin_typed_image))
  200. (target, pis, pmat, pic, prect, pdcolor, pcpath, memory, pinfo);
  201. return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
  202. pdcolor, pcpath, memory, pinfo);
  203. }
  204. private void
  205. cmap_gray_cs_to_cm(gx_device * dev, frac gray, frac out[])
  206. {
  207. gx_device_cmap * cmdev = (gx_device_cmap *)dev;
  208. frac gx_max_color_frac = cv2frac(gx_max_color_value);
  209. switch (cmdev->mapping_method) {
  210. case device_cmap_snap_to_primaries:
  211. gray = (gray <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  212. break;
  213. case device_cmap_color_to_black_over_white:
  214. gray = (gray == 0 ? gx_max_color_frac : 0);
  215. break;
  216. }
  217. {
  218. gx_device *target = cmdev->target ? cmdev->target : dev;
  219. gx_cm_color_map_procs *cm_procs = (dev_proc( target, get_color_mapping_procs)(target));
  220. cm_procs->map_gray(target, gray, out );
  221. }
  222. }
  223. private void
  224. cmap_rgb_cs_to_cm(gx_device * dev, const gs_imager_state * pis, frac r, frac g, frac b, frac out[])
  225. {
  226. gx_device_cmap * cmdev = (gx_device_cmap *)dev;
  227. frac gx_max_color_frac = cv2frac(gx_max_color_value);
  228. switch (cmdev->mapping_method) {
  229. case device_cmap_snap_to_primaries:
  230. r = (r <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  231. g = (g <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  232. b = (b <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  233. break;
  234. case device_cmap_color_to_black_over_white:
  235. if (r == 0 && g == 0 && b == 0)
  236. r = g = b = gx_max_color_frac;
  237. else
  238. r = g = b = 0;
  239. break;
  240. case device_cmap_monochrome:
  241. r = g = b = color_rgb_to_gray(r, g, b, NULL);
  242. break;
  243. }
  244. {
  245. gx_device *target = cmdev->target ? cmdev->target : dev;
  246. gx_cm_color_map_procs *cm_procs = (dev_proc( target, get_color_mapping_procs)(target));
  247. cm_procs->map_rgb(target, pis, r, g, b, out );
  248. }
  249. }
  250. private void
  251. cmap_cmyk_cs_to_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
  252. {
  253. gx_device_cmap * cmdev = (gx_device_cmap *)dev;
  254. frac gx_max_color_frac = cv2frac(gx_max_color_value);
  255. /* We aren't sure what to do with k so we leave it alone. NB this
  256. routine is untested and does not appear to be called. More
  257. testing needed. */
  258. switch (cmdev->mapping_method) {
  259. case device_cmap_snap_to_primaries:
  260. c = (c > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  261. m = (m > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  262. y = (y > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
  263. break;
  264. case device_cmap_color_to_black_over_white:
  265. if (c == gx_max_color_frac && m == gx_max_color_frac && y == gx_max_color_frac)
  266. c = m = y = 0;
  267. else
  268. c = m = y = gx_max_color_frac;
  269. break;
  270. case device_cmap_monochrome:
  271. c = m = y = color_cmyk_to_gray(c, m, y, k, NULL);
  272. break;
  273. }
  274. {
  275. gx_device *target = cmdev->target ? cmdev->target : dev;
  276. gx_cm_color_map_procs *cm_procs = (dev_proc( target, get_color_mapping_procs)(target));
  277. cm_procs->map_cmyk(target, c, m, y, k, out );
  278. }
  279. }
  280. private const gx_cm_color_map_procs cmap_cm_procs = {
  281. cmap_gray_cs_to_cm, cmap_rgb_cs_to_cm, cmap_cmyk_cs_to_cm
  282. };
  283. private const gx_cm_color_map_procs *
  284. cmap_get_color_mapping_procs(const gx_device * dev)
  285. {
  286. return &cmap_cm_procs;
  287. }