gxwts.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /* Copyright (C) 2002 artofcode LLC. 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: gxwts.c,v 1.5 2002/11/02 07:31:45 raph Exp $ */
  14. /* Rendering using Well Tempered Screening. */
  15. #include "stdpre.h"
  16. #include "memory_.h" /* for memcmp */
  17. #include <stdlib.h> /* for malloc */
  18. #include "gx.h"
  19. #include "gxstate.h"
  20. #include "gsht.h"
  21. #include "math_.h"
  22. #include "gserrors.h"
  23. #include "gxdcolor.h"
  24. #include "gxdevcli.h"
  25. #include "gxdht.h"
  26. #include "gxwts.h"
  27. #define GXWTS_USE_DOUBLE
  28. #ifndef UNIT_TEST
  29. /* device color type for wts. */
  30. /* todo: trace and relocate pointers */
  31. gs_private_st_simple(st_dc_wts, gx_device_color, "dc_wts");
  32. private dev_color_proc_save_dc(gx_dc_wts_save_dc);
  33. private dev_color_proc_get_dev_halftone(gx_dc_wts_get_dev_halftone);
  34. private dev_color_proc_load(gx_dc_wts_load);
  35. private dev_color_proc_fill_rectangle(gx_dc_wts_fill_rectangle);
  36. private dev_color_proc_equal(gx_dc_wts_equal);
  37. private dev_color_proc_write(gx_dc_wts_write);
  38. private dev_color_proc_read(gx_dc_wts_read);
  39. private dev_color_proc_get_nonzero_comps(gx_dc_wts_get_nonzero_comps);
  40. const gx_device_color_type_t gx_dc_type_data_wts = {
  41. &st_dc_wts,
  42. gx_dc_wts_save_dc, gx_dc_wts_get_dev_halftone,
  43. gx_dc_ht_get_phase,
  44. gx_dc_wts_load, gx_dc_wts_fill_rectangle,
  45. gx_dc_default_fill_masked, gx_dc_wts_equal,
  46. gx_dc_wts_write, gx_dc_wts_read,
  47. gx_dc_wts_get_nonzero_comps
  48. };
  49. #undef gx_dc_type_wts
  50. const gx_device_color_type_t *const gx_dc_type_wts =
  51. &gx_dc_type_data_wts;
  52. #endif
  53. /* Low-level implementation follows. */
  54. /**
  55. * mul_shr_16: Multiply and shift right 16.
  56. * @a: 32-bit signed number.
  57. * @b: 32-bit signed number.
  58. *
  59. * Multiply @a and @b, then shift right 16 bits. Allow intermediate value
  60. * to overflow 32 bits.
  61. *
  62. * Return value: result.
  63. **/
  64. #ifdef GXWTS_USE_DOUBLE
  65. private int
  66. mul_shr_16 (int a, int b)
  67. {
  68. return (int)floor(((double) a) * ((double) b) * (1.0 / (1 << 16)));
  69. }
  70. #else
  71. #error todo: supply mul_shr_16 based on 64 bit integer type
  72. #endif
  73. /* Implementation of wts_get_samples for rational cells. */
  74. #if 0
  75. private int
  76. wts_get_samples_rat(const wts_screen_t *ws, int x, int y,
  77. wts_screen_sample_t **samples, int *p_nsamples)
  78. {
  79. int d = y / ws->cell_height;
  80. int r = y % ws->cell_height;
  81. int x_ix = ((d * ws->cell_shift) + x) % ws->cell_width;
  82. *p_nsamples = ws->cell_width - x_ix;
  83. *samples = ws->samples + x_ix + r * ws->cell_width;
  84. return 0;
  85. }
  86. #endif
  87. /* Implementation of wts_get_samples for Screen J. */
  88. private int
  89. wts_get_samples_j(const wts_screen_t *ws, int x, int y,
  90. wts_screen_sample_t **samples, int *p_nsamples)
  91. {
  92. const wts_screen_j_t *wsj = (const wts_screen_j_t *)ws;
  93. /* int d = y / ws->cell_height; */
  94. int y_ix = y;
  95. int x_ix = x;
  96. double pad = (wsj->pa) * (1.0 / (1 << 16));
  97. double pbd = (wsj->pb) * (1.0 / (1 << 16));
  98. double afrac = x * pad;
  99. double bfrac = x * pbd;
  100. int acount = (int)floor(afrac);
  101. int bcount = (int)floor(bfrac);
  102. int ccount = mul_shr_16(y, wsj->pc);
  103. int dcount = mul_shr_16(y, wsj->pd);
  104. int nsamples;
  105. x_ix += acount * wsj->XA + bcount * wsj->XB +
  106. ccount * wsj->XC + dcount * wsj->XD;
  107. y_ix += acount * wsj->YA + bcount * wsj->YB +
  108. ccount * wsj->YC + dcount * wsj->YD;
  109. x_ix += (y_ix / ws->cell_height) * ws->cell_shift;
  110. x_ix %= ws->cell_width;
  111. y_ix %= ws->cell_height;
  112. nsamples = ws->cell_width - x_ix;
  113. if (floor (afrac + (nsamples - 1) * pad) > acount)
  114. nsamples = (int)ceil((acount + 1 - afrac) / pad);
  115. if (floor (bfrac + (nsamples - 1) * pbd) > bcount)
  116. nsamples = (int)ceil((bcount + 1 - bfrac) / pbd);
  117. #if 0
  118. printf("get_samples: (%d, %d) -> (%d, %d) %d (cc=%d)\n",
  119. x, y, x_ix, y_ix, nsamples, ccount);
  120. #endif
  121. *p_nsamples = nsamples;
  122. *samples = ws->samples + x_ix + y_ix * ws->cell_width;
  123. return 0;
  124. }
  125. private int
  126. wts_screen_h_offset(int x, double p1, int m1, int m2)
  127. {
  128. /* todo: this is a linear search; constant time should be feasible */
  129. double running_p = 0;
  130. int width_so_far;
  131. int this_width;
  132. for (width_so_far = 0;; width_so_far += this_width) {
  133. running_p += p1;
  134. if (running_p >= 0.5) {
  135. this_width = m1;
  136. running_p -= 1;
  137. } else {
  138. this_width = m2;
  139. }
  140. if (width_so_far + this_width > x)
  141. break;
  142. }
  143. return x - width_so_far + (this_width == m1 ? 0 : m1);
  144. }
  145. /* Implementation of wts_get_samples for Screen H. */
  146. private int
  147. wts_get_samples_h(const wts_screen_t *ws, int x, int y,
  148. wts_screen_sample_t **samples, int *p_nsamples)
  149. {
  150. const wts_screen_h_t *wsh = (const wts_screen_h_t *)ws;
  151. int x_ix = wts_screen_h_offset(x, wsh->px,
  152. wsh->x1, ws->cell_width - wsh->x1);
  153. int y_ix = wts_screen_h_offset(y, wsh->py,
  154. wsh->y1, ws->cell_height - wsh->y1);
  155. *p_nsamples = (x_ix >= wsh->x1 ? ws->cell_width : wsh->x1) - x_ix;
  156. *samples = ws->samples + x_ix + y_ix * ws->cell_width;
  157. return 0;
  158. }
  159. /**
  160. * wts_get_samples: Get samples from Well Tempered Screening cell.
  161. * @ws: Well Tempered Screening cell.
  162. * @x: X coordinate of starting point.
  163. * @y: Y coordinate of starting point.
  164. * @samples: Where to store pointer to samples.
  165. * @p_nsamples: Where to store number of valid samples.
  166. *
  167. * Finds samples from the cell for use in halftoning. On success,
  168. * @p_nsamples is set to the number of valid samples, ie for 0 <= i <
  169. * nsamples, samples[i] is a valid sample for coordinate (x + i, y).
  170. * p_nsamples is guaranteed to at least 1. The samples in @samples
  171. * are valid for the lifetime of the cell, or until the next garbage
  172. * collection, whichever comes first.
  173. *
  174. * Todo: describe meaning of wts_screen_sample_t (particularly edge
  175. * cases).
  176. *
  177. * Note: may want to add a "cursor" to the api as an optimization. It
  178. * can wait, though.
  179. *
  180. * Return value: 0 on success.
  181. **/
  182. int
  183. wts_get_samples(const wts_screen_t *ws, int x, int y,
  184. wts_screen_sample_t **samples, int *p_nsamples)
  185. {
  186. if (ws->type == WTS_SCREEN_J)
  187. return wts_get_samples_j(ws, x, y, samples, p_nsamples);
  188. if (ws->type == WTS_SCREEN_H)
  189. return wts_get_samples_h(ws, x, y, samples, p_nsamples);
  190. else
  191. return -1;
  192. }
  193. /* Device color methods follow. */
  194. private void
  195. gx_dc_wts_save_dc(const gx_device_color * pdevc, gx_device_color_saved * psdc)
  196. {
  197. psdc->type = pdevc->type;
  198. memcpy( psdc->colors.wts.levels,
  199. pdevc->colors.wts.levels,
  200. sizeof(psdc->colors.wts.levels) );
  201. psdc->phase = pdevc->phase;
  202. }
  203. private const gx_device_halftone *
  204. gx_dc_wts_get_dev_halftone(const gx_device_color * pdevc)
  205. {
  206. return pdevc->colors.wts.w_ht;
  207. }
  208. private int
  209. gx_dc_wts_load(gx_device_color *pdevc, const gs_imager_state * pis,
  210. gx_device *ignore_dev, gs_color_select_t select)
  211. {
  212. return 0;
  213. }
  214. /**
  215. * wts_draw: Draw a halftoned shade into a 1 bit deep buffer.
  216. * @ws: WTS screen.
  217. * @shade: Gray shade to draw.
  218. * @data: Destination buffer.
  219. * @data_raster: Rowstride for destination buffer.
  220. * @x, @y, @w, @h: coordinates of rectangle to draw.
  221. *
  222. * This is close to an implementation of the "draw" method for the
  223. * gx_ht_order class. Currently, only WTS screens implement this
  224. * method, and only WTS device colors invoke it. However, implementing
  225. * this for legacy order objects is probably a good idea, to improve
  226. * halftoning performance as the cell size scales up.
  227. *
  228. * However, it's not exactly an implementation of the "draw" method
  229. * for the gx_ht_order class because the "self" type would need to be
  230. * gx_ht_order. Currently, however, device colors don't hold a pointer
  231. * to the order object. Some amount of refactoring seems to be in
  232. * order.
  233. *
  234. * Return value: 0 on success.
  235. **/
  236. private int
  237. wts_draw(wts_screen_t *ws, wts_screen_sample_t shade,
  238. byte *data, int data_raster,
  239. int x, int y, int w, int h)
  240. {
  241. int xo, yo;
  242. unsigned char *line_start = data;
  243. for (yo = 0; yo < h; yo++) {
  244. unsigned char *line_ptr = line_start;
  245. int mask = 0x80;
  246. unsigned char b = 0;
  247. int imax;
  248. for (xo = 0; xo < w; xo += imax) {
  249. wts_screen_sample_t *samples;
  250. int n_samples, i;
  251. wts_get_samples(ws, x + xo, y + yo, &samples, &n_samples);
  252. imax = min(w - xo, n_samples);
  253. for (i = 0; i < imax; i++) {
  254. if (shade > samples[i])
  255. b |= mask;
  256. mask >>= 1;
  257. if (mask == 0) {
  258. *line_ptr++ = b;
  259. b = 0;
  260. mask = 0x80;
  261. }
  262. }
  263. }
  264. if (mask != 0x80)
  265. *line_ptr = b;
  266. line_start += data_raster;
  267. }
  268. return 0;
  269. }
  270. /**
  271. * Special case implementation for one component. When we do plane_mask,
  272. * we'll want to generalize this to handle any single-bit plane_mask.
  273. **/
  274. private int
  275. gx_dc_wts_fill_rectangle_1(const gx_device_color *pdevc,
  276. int x, int y, int w, int h,
  277. gx_device *dev, gs_logical_operation_t lop,
  278. const gx_rop_source_t *source)
  279. {
  280. /* gx_rop_source_t no_source; */
  281. int tile_raster = ((w + 31) & -32) >> 3;
  282. int tile_size = tile_raster * h;
  283. unsigned char *tile_data;
  284. int code = 0;
  285. gx_ht_order_component *components = pdevc->colors.wts.w_ht->components;
  286. wts_screen_t *ws = components[0].corder.wts;
  287. wts_screen_sample_t shade = pdevc->colors.wts.levels[0];
  288. gx_color_index color0, color1;
  289. color0 = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ? 0 :
  290. pdevc->colors.wts.plane_vector[1];
  291. color1 = pdevc->colors.wts.plane_vector[0];
  292. tile_data = malloc(tile_size);
  293. wts_draw(ws, shade, tile_data, tile_raster, x, y, w, h);
  294. /* See gx_dc_ht_binary_fill_rectangle() for explanation. */
  295. if (dev->color_info.depth > 1)
  296. lop &= ~lop_T_transparent;
  297. /* Interesting question: should data_x be (x & 7), rather than 0,
  298. to improve alignment? */
  299. if (source == NULL && lop_no_S_is_T(lop))
  300. code = (*dev_proc(dev, copy_mono))
  301. (dev, tile_data, 0, tile_raster, gx_no_bitmap_id,
  302. x, y, w, h, color0, color1);
  303. free(tile_data);
  304. return code;
  305. }
  306. private int
  307. gx_dc_wts_write(
  308. const gx_device_color * pdevc,
  309. const gx_device_color_saved * psdc,
  310. const gx_device * dev,
  311. byte * pdata,
  312. uint * psize )
  313. {
  314. /* not yet implemented */
  315. return_error(gs_error_unknownerror);
  316. }
  317. private int
  318. gx_dc_wts_read(
  319. gx_device_color * pdevc,
  320. const gs_imager_state * pis,
  321. const gx_device_color * prior_devc,
  322. const gx_device * dev,
  323. const byte * pdata,
  324. uint size,
  325. gs_memory_t * mem )
  326. {
  327. /* not yet implemented */
  328. return_error(gs_error_unknownerror);
  329. }
  330. /**
  331. * wts_repack_tile_4: Repack four 1-bit tiles into chunky nibbles.
  332. * Note: argument list will change. plane_mask and base_color will
  333. * probably get added as an optimization.
  334. *
  335. * Note: we round w up to an even value. We're counting on the
  336. * subsequent copy_color to ignore any extra bits.
  337. **/
  338. private void
  339. wts_repack_tile_4(unsigned char *ctile_data, int ctile_raster,
  340. const unsigned char **tile_data, int tile_raster,
  341. const gx_color_index *plane_vector, bool invert,
  342. int w, int h)
  343. {
  344. int y;
  345. int tile_idx_start = 0;
  346. unsigned char *ctile_start = ctile_data;
  347. byte inv_byte = invert ? 0xff : 0;
  348. for (y = 0; y < h; y++) {
  349. int x;
  350. int tile_idx = tile_idx_start;
  351. for (x = 0; x < w; x += 2) {
  352. byte b = 0;
  353. byte m0 = 0x80 >> (x & 6);
  354. byte m1 = m0 >> 1;
  355. byte td;
  356. td = tile_data[0][tile_idx] ^ inv_byte;
  357. if (td & m0) b |= plane_vector[0] << 4;
  358. if (td & m1) b |= plane_vector[0];
  359. td = tile_data[1][tile_idx] ^ inv_byte;
  360. if (td & m0) b |= plane_vector[1] << 4;
  361. if (td & m1) b |= plane_vector[1];
  362. td = tile_data[2][tile_idx] ^ inv_byte;
  363. if (td & m0) b |= plane_vector[2] << 4;
  364. if (td & m1) b |= plane_vector[2];
  365. td = tile_data[3][tile_idx] ^ inv_byte;
  366. if (td & m0) b |= plane_vector[3] << 4;
  367. if (td & m1) b |= plane_vector[3];
  368. if ((x & 6) == 6)
  369. tile_idx++;
  370. ctile_start[x >> 1] = b;
  371. }
  372. tile_idx_start += tile_raster;
  373. ctile_start += ctile_raster;
  374. }
  375. }
  376. /* Special case implementation for four components. Intermediate color
  377. * to the order objecttile (for copy_color) is packed 2 to a byte.
  378. *
  379. * Looking at this code, it should generalize to more than four
  380. * components. Probably the repack code should get factored out.
  381. */
  382. private int
  383. gx_dc_wts_fill_rectangle_4(const gx_device_color *pdevc,
  384. int x, int y, int w, int h,
  385. gx_device *dev, gs_logical_operation_t lop,
  386. const gx_rop_source_t *source)
  387. {
  388. int num_comp = pdevc->colors.wts.num_components;
  389. /* gx_rop_source_t no_source; */
  390. int tile_raster = ((w + 31) & -32) >> 3;
  391. int tile_size = tile_raster * h;
  392. unsigned char *tile_data[4];
  393. int ctile_raster = ((w + 7) & -8) >> 1;
  394. int ctile_size = ctile_raster * h;
  395. unsigned char *ctile_data;
  396. int code = 0;
  397. bool invert = 0 && dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
  398. int i;
  399. for (i = 0; i < num_comp; i++) {
  400. wts_screen_sample_t shade = pdevc->colors.wts.levels[i];
  401. gx_ht_order_component *components = pdevc->colors.wts.w_ht->components;
  402. wts_screen_t *ws = components[i].corder.wts;
  403. tile_data[i] = malloc(tile_size);
  404. wts_draw(ws, shade, tile_data[i], tile_raster, x, y, w, h);
  405. }
  406. ctile_data = malloc(ctile_size);
  407. wts_repack_tile_4(ctile_data, ctile_raster,
  408. (const unsigned char **)tile_data, tile_raster,
  409. pdevc->colors.wts.plane_vector, invert, w, h);
  410. /* See gx_dc_ht_binary_fill_rectangle() for explanation. */
  411. if (dev->color_info.depth > 1)
  412. lop &= ~lop_T_transparent;
  413. if (source == NULL && lop_no_S_is_T(lop))
  414. code = (*dev_proc(dev, copy_color))
  415. (dev, ctile_data, 0, ctile_raster, gx_no_bitmap_id,
  416. x, y, w, h);
  417. free(ctile_data);
  418. for (i = 0; i < num_comp; i++) {
  419. free(tile_data[i]);
  420. }
  421. return code;
  422. }
  423. private int
  424. gx_dc_wts_fill_rectangle(const gx_device_color *pdevc,
  425. int x, int y, int w, int h,
  426. gx_device *dev, gs_logical_operation_t lop,
  427. const gx_rop_source_t *source)
  428. {
  429. int num_comp = pdevc->colors.wts.num_components;
  430. if (num_comp == 1)
  431. return gx_dc_wts_fill_rectangle_1(pdevc, x, y, w, h, dev, lop, source);
  432. else if (num_comp <= 4)
  433. return gx_dc_wts_fill_rectangle_4(pdevc, x, y, w, h, dev, lop, source);
  434. else
  435. return -1;
  436. }
  437. /* Compare two wts colors for equality. */
  438. private int
  439. gx_dc_wts_equal(const gx_device_color *pdevc1,
  440. const gx_device_color *pdevc2)
  441. {
  442. uint num_comp = pdevc1->colors.wts.num_components;
  443. if (pdevc2->type != pdevc1->type ||
  444. pdevc1->phase.x != pdevc2->phase.x ||
  445. pdevc1->phase.y != pdevc2->phase.y ||
  446. num_comp != pdevc2->colors.wts.num_components
  447. )
  448. return false;
  449. return
  450. !memcmp(pdevc1->colors.wts.levels,
  451. pdevc2->colors.wts.levels,
  452. num_comp * sizeof(pdevc1->colors.wts.levels[0]));
  453. }
  454. /*
  455. * Get the nonzero components of a wts halftone. This is used to
  456. * distinguish components that are given zero intensity due to halftoning
  457. * from those for which the original color intensity was in fact zero.
  458. */
  459. int
  460. gx_dc_wts_get_nonzero_comps(
  461. const gx_device_color * pdevc,
  462. const gx_device * dev_ignored,
  463. gx_color_index * pcomp_bits )
  464. {
  465. int i, ncomps = pdevc->colors.wts.num_components;
  466. gx_color_index comp_bits = 0; /* todo: plane_mask */
  467. for (i = 0; i < ncomps; i++) {
  468. if (pdevc->colors.wts.levels[i] != 0)
  469. comp_bits |= ((gx_color_index)1) << i;
  470. }
  471. *pcomp_bits = comp_bits;
  472. return 0;
  473. }