gswts.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  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: gswts.c,v 1.5 2003/08/26 15:38:50 igor Exp $ */
  14. /* Screen generation for Well Tempered Screening. */
  15. #include "stdpre.h"
  16. #include <stdlib.h> /* for malloc */
  17. #include "gx.h"
  18. #include "gxstate.h"
  19. #include "gsht.h"
  20. #include "math_.h"
  21. #include "gserrors.h"
  22. #include "gxfrac.h"
  23. #include "gxwts.h"
  24. #include "gswts.h"
  25. #define VERBOSE
  26. #ifdef UNIT_TEST
  27. /**
  28. * This file can be compiled independently for unit testing purposes.
  29. * Try this invocation:
  30. *
  31. * gcc -I../obj -DUNIT_TEST gswts.c gxwts.c -o test_gswts -lm
  32. * ./test_gswts | sed '/P5/,$!d' | xv -
  33. **/
  34. #undef printf
  35. #undef stdout
  36. #undef dlprintf1
  37. #define dlprintf1 printf
  38. #undef dlprintf2
  39. #define dlprintf2 printf
  40. #undef dlprintf3
  41. #define dlprintf3 printf
  42. #undef dlprintf4
  43. #define dlprintf4 printf
  44. #undef dlprintf5
  45. #define dlprintf5 printf
  46. #undef dlprintf6
  47. #define dlprintf6 printf
  48. #undef dlprintf7
  49. #define dlprintf7 printf
  50. #endif
  51. /* A datatype used for representing the product of two 32 bit integers.
  52. If a 64 bit integer type is available, it may be a better choice. */
  53. typedef double wts_bigint;
  54. typedef struct gx_wts_cell_params_j_s gx_wts_cell_params_j_t;
  55. typedef struct gx_wts_cell_params_h_s gx_wts_cell_params_h_t;
  56. struct gx_wts_cell_params_j_s {
  57. gx_wts_cell_params_t base;
  58. int shift;
  59. double ufast_a;
  60. double vfast_a;
  61. double uslow_a;
  62. double vslow_a;
  63. /* Probabilities of "jumps". A and B jumps can happen when moving
  64. one pixel to the right. C and D can happen when moving one pixel
  65. down. */
  66. double pa;
  67. double pb;
  68. double pc;
  69. double pd;
  70. int xa;
  71. int ya;
  72. int xb;
  73. int yb;
  74. int xc;
  75. int yc;
  76. int xd;
  77. int yd;
  78. };
  79. struct gx_wts_cell_params_h_s {
  80. gx_wts_cell_params_t base;
  81. /* This is the exact value that x1 and (width-x1) approximates. */
  82. double px;
  83. /* Ditto y1 and (height-y1). */
  84. double py;
  85. int x1;
  86. int y1;
  87. };
  88. #define WTS_EXTRA_SORT_BITS 9
  89. #define WTS_SORTED_MAX (((frac_1) << (WTS_EXTRA_SORT_BITS)) - 1)
  90. typedef struct {
  91. int u;
  92. int v;
  93. int k;
  94. int l;
  95. } wts_vec_t;
  96. private void
  97. wts_vec_set(wts_vec_t *wv, int u, int v, int k, int l)
  98. {
  99. wv->u = u;
  100. wv->v = v;
  101. wv->k = k;
  102. wv->l = l;
  103. }
  104. private wts_bigint
  105. wts_vec_smag(const wts_vec_t *a)
  106. {
  107. wts_bigint u = a->u;
  108. wts_bigint v = a->v;
  109. return u * u + v * v;
  110. }
  111. private void
  112. wts_vec_add(wts_vec_t *a, const wts_vec_t *b, const wts_vec_t *c)
  113. {
  114. a->u = b->u + c->u;
  115. a->v = b->v + c->v;
  116. a->k = b->k + c->k;
  117. a->l = b->l + c->l;
  118. }
  119. private void
  120. wts_vec_sub(wts_vec_t *a, const wts_vec_t *b, const wts_vec_t *c)
  121. {
  122. a->u = b->u - c->u;
  123. a->v = b->v - c->v;
  124. a->k = b->k - c->k;
  125. a->l = b->l - c->l;
  126. }
  127. /**
  128. * wts_vec_gcd3: Compute 3-way "gcd" of three vectors.
  129. * @a, @b, @c: Vectors.
  130. *
  131. * Compute pair of vectors satisfying three constraints:
  132. * They are integer combinations of the source vectors.
  133. * The source vectors are integer combinations of the results.
  134. * The magnitude of the vectors is minimized.
  135. *
  136. * The algorithm for this computation is quite reminiscent of the
  137. * classic Euclid GCD algorithm for integers.
  138. *
  139. * On return, @a and @b contain the result. @c is destroyed.
  140. **/
  141. private void
  142. wts_vec_gcd3(wts_vec_t *a, wts_vec_t *b, wts_vec_t *c)
  143. {
  144. wts_vec_t d, e;
  145. double ra, rb, rc, rd, re;
  146. wts_vec_set(&d, 0, 0, 0, 0);
  147. wts_vec_set(&e, 0, 0, 0, 0);
  148. for (;;) {
  149. ra = wts_vec_smag(a);
  150. rb = wts_vec_smag(b);
  151. rc = wts_vec_smag(c);
  152. wts_vec_sub(&d, a, b);
  153. wts_vec_add(&e, a, b);
  154. rd = wts_vec_smag(&d);
  155. re = wts_vec_smag(&e);
  156. if (re && re < rd) {
  157. d = e;
  158. rd = re;
  159. }
  160. if (rd && rd < ra && ra >= rb) *a = d;
  161. else if (rd < rb && rb > ra) *b = d;
  162. else {
  163. wts_vec_sub(&d, a, c);
  164. wts_vec_add(&e, a, c);
  165. rd = wts_vec_smag(&d);
  166. re = wts_vec_smag(&e);
  167. if (re < rd) {
  168. d = e;
  169. rd = re;
  170. }
  171. if (rd && rd < ra && ra >= rc) *a = d;
  172. else if (rd < rc && rc > ra) *c = d;
  173. else {
  174. wts_vec_sub(&d, b, c);
  175. wts_vec_add(&e, b, c);
  176. rd = wts_vec_smag(&d);
  177. re = wts_vec_smag(&e);
  178. if (re < rd) {
  179. d = e;
  180. rd = re;
  181. }
  182. if (rd && rd < rb && rb >= rc) *b = d;
  183. else if (rd < rc && rc > rb) *c = d;
  184. else
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. private wts_bigint
  191. wts_vec_cross(const wts_vec_t *a, const wts_vec_t *b)
  192. {
  193. wts_bigint au = a->u;
  194. wts_bigint av = a->v;
  195. wts_bigint bu = b->u;
  196. wts_bigint bv = b->v;
  197. return au * bv - av * bu;
  198. }
  199. private void
  200. wts_vec_neg(wts_vec_t *a)
  201. {
  202. a->u = -a->u;
  203. a->v = -a->v;
  204. a->k = -a->k;
  205. a->l = -a->l;
  206. }
  207. /* compute k mod m */
  208. private void
  209. wts_vec_modk(wts_vec_t *a, int m)
  210. {
  211. while (a->k < 0) a->k += m;
  212. while (a->k >= m) a->k -= m;
  213. }
  214. /* Compute modulo in rational cell. */
  215. private void
  216. wts_vec_modkls(wts_vec_t *a, int m, int i, int s)
  217. {
  218. while (a->l < 0) {
  219. a->l += i;
  220. a->k -= s;
  221. }
  222. while (a->l >= i) {
  223. a->l -= i;
  224. a->k += s;
  225. }
  226. while (a->k < 0) a->k += m;
  227. while (a->k >= m) a->k -= m;
  228. }
  229. private void
  230. wts_set_mat(gx_wts_cell_params_t *wcp, double sratiox, double sratioy,
  231. double sangledeg)
  232. {
  233. double sangle = sangledeg * M_PI / 180;
  234. wcp->ufast = cos(sangle) / sratiox;
  235. wcp->vfast = -sin(sangle) / sratiox;
  236. wcp->uslow = sin(sangle) / sratioy;
  237. wcp->vslow = cos(sangle) / sratioy;
  238. }
  239. /**
  240. * Calculate Screen H cell sizes.
  241. **/
  242. private void
  243. wts_cell_calc_h(double inc, int *px1, int *pxwidth, double *pp1, double memw)
  244. {
  245. double minrep = pow(2, memw) * 50 / pow(2, 7.5);
  246. int m1 = 0, m2 = 0;
  247. double e1, e2;
  248. int uacc;
  249. e1 = 1e5;
  250. e2 = 1e5;
  251. for (uacc = (int)ceil(minrep * inc); uacc <= floor(2 * minrep * inc); uacc++) {
  252. int mt;
  253. double et;
  254. mt = (int)floor(uacc / inc + 1e-5);
  255. et = uacc / inc - mt + mt * 0.001;
  256. if (et < e1) {
  257. e1 = et;
  258. m1 = mt;
  259. }
  260. mt = (int)ceil(uacc / inc - 1e-5);
  261. et = mt - uacc / inc + mt * 0.001;
  262. if (et < e2) {
  263. e2 = et;
  264. m2 = mt;
  265. }
  266. }
  267. if (m1 == m2) {
  268. *px1 = m1;
  269. *pxwidth = m1;
  270. *pp1 = 1.0;
  271. } else {
  272. *px1 = m1;
  273. *pxwidth = m1 + m2;
  274. e1 = fabs(m1 * inc - floor(0.5 + m1 * inc));
  275. e2 = fabs(m2 * inc - floor(0.5 + m2 * inc));
  276. *pp1 = e2 / (e1 + e2);
  277. }
  278. }
  279. /* Implementation for Screen H. This is optimized for 0 and 45 degree
  280. rotations. */
  281. private gx_wts_cell_params_t *
  282. wts_pick_cell_size_h(double sratiox, double sratioy, double sangledeg,
  283. double memw)
  284. {
  285. gx_wts_cell_params_h_t *wcph;
  286. double xinc, yinc;
  287. wcph = malloc(sizeof(gx_wts_cell_params_h_t));
  288. if (wcph == NULL)
  289. return NULL;
  290. wcph->base.t = WTS_SCREEN_H;
  291. wts_set_mat(&wcph->base, sratiox, sratioy, sangledeg);
  292. xinc = fabs(wcph->base.ufast);
  293. if (xinc == 0)
  294. xinc = fabs(wcph->base.vfast);
  295. wts_cell_calc_h(xinc, &wcph->x1, &wcph->base.width, &wcph->px, memw);
  296. yinc = fabs(wcph->base.uslow);
  297. if (yinc == 0)
  298. yinc = fabs(wcph->base.vslow);
  299. wts_cell_calc_h(yinc, &wcph->y1, &wcph->base.height, &wcph->py, memw);
  300. return &wcph->base;
  301. }
  302. private double
  303. wts_qart(double r, double rbase, double p, double pbase)
  304. {
  305. if (p < 1e-5) {
  306. return ((r + rbase) * p);
  307. } else {
  308. return ((r + rbase) * (p + pbase) - rbase * pbase);
  309. }
  310. }
  311. #ifdef VERBOSE
  312. private void
  313. wts_print_j_jump(const gx_wts_cell_params_j_t *wcpj, const char *name,
  314. double pa, int xa, int ya)
  315. {
  316. dlprintf6("jump %s: (%d, %d) %f, actual (%f, %f)\n",
  317. name, xa, ya, pa,
  318. wcpj->ufast_a * xa + wcpj->uslow_a * ya,
  319. wcpj->vfast_a * xa + wcpj->vslow_a * ya);
  320. }
  321. private void
  322. wts_j_add_jump(const gx_wts_cell_params_j_t *wcpj, double *pu, double *pv,
  323. double pa, int xa, int ya)
  324. {
  325. double jump_u = wcpj->ufast_a * xa + wcpj->uslow_a * ya;
  326. double jump_v = wcpj->vfast_a * xa + wcpj->vslow_a * ya;
  327. jump_u -= floor(jump_u + 0.5);
  328. jump_v -= floor(jump_v + 0.5);
  329. *pu += pa * jump_u;
  330. *pv += pa * jump_v;
  331. }
  332. private void
  333. wts_print_j(const gx_wts_cell_params_j_t *wcpj)
  334. {
  335. double uf, vf;
  336. double us, vs;
  337. dlprintf3("cell = %d x %d, shift = %d\n",
  338. wcpj->base.width, wcpj->base.height, wcpj->shift);
  339. wts_print_j_jump(wcpj, "a", wcpj->pa, wcpj->xa, wcpj->ya);
  340. wts_print_j_jump(wcpj, "b", wcpj->pb, wcpj->xb, wcpj->yb);
  341. wts_print_j_jump(wcpj, "c", wcpj->pc, wcpj->xc, wcpj->yc);
  342. wts_print_j_jump(wcpj, "d", wcpj->pd, wcpj->xd, wcpj->yd);
  343. uf = wcpj->ufast_a;
  344. vf = wcpj->vfast_a;
  345. us = wcpj->uslow_a;
  346. vs = wcpj->vslow_a;
  347. wts_j_add_jump(wcpj, &uf, &vf, wcpj->pa, wcpj->xa, wcpj->ya);
  348. wts_j_add_jump(wcpj, &uf, &vf, wcpj->pb, wcpj->xb, wcpj->yb);
  349. wts_j_add_jump(wcpj, &us, &vs, wcpj->pc, wcpj->xc, wcpj->yc);
  350. wts_j_add_jump(wcpj, &us, &vs, wcpj->pd, wcpj->xd, wcpj->yd);
  351. dlprintf6("d: %f, %f; a: %f, %f; err: %g, %g\n",
  352. wcpj->base.ufast, wcpj->base.vfast,
  353. wcpj->ufast_a, wcpj->vfast_a,
  354. wcpj->base.ufast - uf, wcpj->base.vfast - vf);
  355. dlprintf6("d: %f, %f; a: %f, %f; err: %g, %g\n",
  356. wcpj->base.uslow, wcpj->base.vslow,
  357. wcpj->uslow_a, wcpj->vslow_a,
  358. wcpj->base.uslow - us, wcpj->base.vslow - vs);
  359. }
  360. #endif
  361. /**
  362. * wts_set_scr_jxi_try: Try a width for setting Screen J parameters.
  363. * @wcpj: Screen J parameters.
  364. * @m: Width to try.
  365. * @qb: Best quality score seen so far.
  366. * @jmem: Weight given to memory usage.
  367. *
  368. * Evaluate the quality for width @i. If the quality is better than
  369. * @qb, then set the rest of the parameters in @wcpj.
  370. *
  371. * This routine corresponds to SetScrJXITrySP in the WTS source.
  372. *
  373. * Return value: Quality score for parameters chosen.
  374. **/
  375. private double
  376. wts_set_scr_jxi_try(gx_wts_cell_params_j_t *wcpj, int m, double qb,
  377. double jmem)
  378. {
  379. const double uf = wcpj->base.ufast;
  380. const double vf = wcpj->base.vfast;
  381. const double us = wcpj->base.uslow;
  382. const double vs = wcpj->base.vslow;
  383. wts_vec_t a, b, c;
  384. double ufj, vfj;
  385. const double rbase = 0.1;
  386. const double pbase = 0.001;
  387. double ug, vg;
  388. double pp, pa, pb;
  389. double rf;
  390. double xa, ya, ra, xb, yb, rb;
  391. double q, qx, qw, qxl, qbi;
  392. double pya, pyb;
  393. int i;
  394. bool jumpok;
  395. wts_vec_set(&a, (int)floor(uf * m + 0.5), (int)floor(vf * m + 0.5), 1, 0);
  396. if (a.u == 0 && a.v == 0)
  397. return qb + 1;
  398. ufj = a.u / (double)m;
  399. vfj = a.v / (double)m;
  400. /* (ufj, vfj) = movement in UV space from (0, 1) in XY space */
  401. wts_vec_set(&b, m, 0, 0, 0);
  402. wts_vec_set(&c, 0, m, 0, 0);
  403. wts_vec_gcd3(&a, &b, &c);
  404. ug = (uf - ufj) * m;
  405. vg = (vf - vfj) * m;
  406. pp = 1.0 / wts_vec_cross(&b, &a);
  407. pa = (b.u * vg - ug * b.v) * pp;
  408. pb = (ug * a.v - a.u * vg) * pp;
  409. if (pa < 0) {
  410. wts_vec_neg(&a);
  411. pa = -pa;
  412. }
  413. if (pb < 0) {
  414. wts_vec_neg(&b);
  415. pb = -pb;
  416. }
  417. wts_vec_modk(&a, m);
  418. wts_vec_modk(&b, m);
  419. /* Prefer nontrivial jumps. */
  420. jumpok = (wcpj->xa == 0 && wcpj->ya == 0) ||
  421. (wcpj->xb == 0 && wcpj->yb == 0) ||
  422. (a.k != 0 && b.k != 0);
  423. rf = (uf * uf + vf * vf) * m;
  424. xa = (a.u * uf + a.v * vf) / rf;
  425. ya = (a.v * uf - a.u * vf) / rf;
  426. xb = (b.u * uf + b.v * vf) / rf;
  427. yb = (b.v * uf - b.u * vf) / rf;
  428. ra = sqrt(xa * xa + 0.0625 * ya * ya);
  429. rb = sqrt(xb * xb + 0.0625 * yb * yb);
  430. qx = 0.5 * (wts_qart(ra, rbase, pa, pbase) +
  431. wts_qart(rb, rbase, pb, pbase));
  432. if (qx < 1.0 / 4000.0)
  433. qx *= 0.25;
  434. else
  435. qx -= 0.75 / 4000.0;
  436. if (m < 7500)
  437. qw = 0;
  438. else
  439. qw = 0.00025; /* cache penalty */
  440. qxl = qx + qw;
  441. if (qxl > qb)
  442. return qxl;
  443. /* width is ok, now try heights */
  444. pp = m / (double)wts_vec_cross(&b, &a);
  445. pya = (b.u * vs - us * b.v) * pp;
  446. pyb = (us * a.v - a.u * vs) * pp;
  447. qbi = qb;
  448. for (i = 1; qxl + m * i * jmem < qbi; i++) {
  449. int s = m * i;
  450. int ca, cb;
  451. double usj, vsj;
  452. double usg, vsg;
  453. wts_vec_t a1, b1, a2, b2;
  454. double pc, pd;
  455. int ck;
  456. double qy, qm;
  457. ca = (int)floor(i * pya + 0.5);
  458. cb = (int)floor(i * pyb + 0.5);
  459. wts_vec_set(&c, ca * a.u + cb * b.u, ca * a.v + cb * b.v, 0, 1);
  460. usj = c.u / (double)s;
  461. vsj = c.v / (double)s;
  462. usg = (us - usj);
  463. vsg = (vs - vsj);
  464. a1 = a;
  465. b1 = b;
  466. a1.u *= i;
  467. a1.v *= i;
  468. b1.u *= i;
  469. b1.v *= i;
  470. wts_vec_gcd3(&a1, &b1, &c);
  471. a2 = a1;
  472. b2 = b1;
  473. pp = s / (double)wts_vec_cross(&b1, &a1);
  474. pc = (b1.u * vsg - usg * b1.v) * pp;
  475. pd = (usg * a1.v - a1.u * vsg) * pp;
  476. if (pc < 0) {
  477. wts_vec_neg(&a1);
  478. pc = -pc;
  479. }
  480. if (pd < 0) {
  481. wts_vec_neg(&b1);
  482. pd = -pd;
  483. }
  484. ck = ca * a.k + cb * b.k;
  485. while (ck < 0) ck += m;
  486. while (ck >= m) ck -= m;
  487. wts_vec_modkls(&a1, m, i, ck);
  488. wts_vec_modkls(&b1, m, i, ck);
  489. rf = (us * us - vs * vs) * s;
  490. xa = (a1.u * us + a1.v * vs) / rf;
  491. ya = (a1.v * us - a1.u * vs) / rf;
  492. xb = (b1.u * us + b1.v * vs) / rf;
  493. yb = (b1.v * us - b1.u * vs) / rf;
  494. ra = sqrt(xa * xa + 0.0625 * ya * ya);
  495. rb = sqrt(xb * xb + 0.0625 * yb * yb);
  496. qy = 0.5 * (wts_qart(ra, rbase, pc, pbase) +
  497. wts_qart(rb, rbase, pd, pbase));
  498. if (qy < 1.0 / 100.0)
  499. qy *= 0.025;
  500. else
  501. qy -= 0.75 / 100.0;
  502. qm = s * jmem;
  503. /* first try a and b jumps within the scanline */
  504. q = qm + qw + qx + qy;
  505. if (q < qbi && jumpok) {
  506. #ifdef VERBOSE
  507. dlprintf7("m = %d, n = %d, q = %d, qx = %d, qy = %d, qm = %d, qw = %d\n",
  508. m, i, (int)(q * 1e6), (int)(qx * 1e6), (int)(qy * 1e6), (int)(qm * 1e6), (int)(qw * 1e6));
  509. #endif
  510. qbi = q;
  511. wcpj->base.width = m;
  512. wcpj->base.height = i;
  513. wcpj->shift = ck;
  514. wcpj->ufast_a = ufj;
  515. wcpj->vfast_a = vfj;
  516. wcpj->uslow_a = usj;
  517. wcpj->vslow_a = vsj;
  518. wcpj->xa = a.k;
  519. wcpj->ya = 0;
  520. wcpj->xb = b.k;
  521. wcpj->yb = 0;
  522. wcpj->xc = a1.k;
  523. wcpj->yc = a1.l;
  524. wcpj->xd = b1.k;
  525. wcpj->yd = b1.l;
  526. wcpj->pa = pa;
  527. wcpj->pb = pb;
  528. wcpj->pc = pc;
  529. wcpj->pd = pd;
  530. #ifdef VERBOSE
  531. wts_print_j(wcpj);
  532. #endif
  533. }
  534. /* then try unconstrained a and b jumps */
  535. if (i > 1) {
  536. double pa2, pb2, pp2;
  537. double qx2, qw2, q2;
  538. pp2 = pp;
  539. pa2 = (b2.u * vg - ug * b2.v) * pp2;
  540. pb2 = (ug * a2.v - a2.u * vg) * pp2;
  541. rf = (uf * uf + vf * vf) * s;
  542. xa = (a2.u * uf + a2.v * vf) / rf;
  543. ya = (a2.v * uf - a2.u * vf) / rf;
  544. xb = (b2.u * uf + b2.v * vf) / rf;
  545. yb = (b2.v * uf - b2.u * vf) / rf;
  546. ra = sqrt(xa * xa + 0.0625 * ya * ya);
  547. rb = sqrt(xb * xb + 0.0625 * yb * yb);
  548. if (pa2 < 0) {
  549. pa2 = -pa2;
  550. wts_vec_neg(&a2);
  551. }
  552. if (pb2 < 0) {
  553. pb2 = -pb2;
  554. wts_vec_neg(&b2);
  555. }
  556. wts_vec_modkls(&a2, m, i, ck);
  557. wts_vec_modkls(&b2, m, i, ck);
  558. qx2 = 0.5 * (wts_qart(ra, rbase, pa2, pbase) +
  559. wts_qart(rb, rbase, pb2, pbase));
  560. if (qx2 < 1.0 / 4000.0)
  561. qx2 *= 0.25;
  562. else
  563. qx2 -= 0.75 / 4000.0;
  564. if (s < 7500)
  565. qw2 = 0;
  566. else
  567. qw2 = 0.00025; /* cache penalty */
  568. q2 = qm + qw2 + qx2 + qy;
  569. if (q2 < qbi) {
  570. #ifdef VERBOSE
  571. dlprintf7("m = %d, n = %d, q = %d, qx2 = %d, qy = %d, qm = %d, qw2 = %d\n",
  572. m, i, (int)(q * 1e6), (int)(qx * 1e6), (int)(qy * 1e6), (int)(qm * 1e6), (int)(qw2 * 1e6));
  573. #endif
  574. if (qxl > qw2 + qx2)
  575. qxl = qw2 + qx2;
  576. qbi = q2;
  577. wcpj->base.width = m;
  578. wcpj->base.height = i;
  579. wcpj->shift = ck;
  580. wcpj->ufast_a = ufj;
  581. wcpj->vfast_a = vfj;
  582. wcpj->uslow_a = usj;
  583. wcpj->vslow_a = vsj;
  584. wcpj->xa = a2.k;
  585. wcpj->ya = a2.l;
  586. wcpj->xb = b2.k;
  587. wcpj->yb = a2.l;
  588. wcpj->xc = a1.k;
  589. wcpj->yc = a1.l;
  590. wcpj->xd = b1.k;
  591. wcpj->yd = b1.l;
  592. wcpj->pa = pa2;
  593. wcpj->pb = pb2;
  594. wcpj->pc = pc;
  595. wcpj->pd = pd;
  596. #ifdef VERBOSE
  597. wts_print_j(wcpj);
  598. #endif
  599. }
  600. } /* if (i > 1) */
  601. if (qx > 10 * qy)
  602. break;
  603. }
  604. return qbi;
  605. }
  606. private int
  607. wts_double_to_int_cap(double d)
  608. {
  609. if (d > 0x7fffffff)
  610. return 0x7fffffff;
  611. else return (int)d;
  612. }
  613. /**
  614. * wts_set_scr_jxi: Choose Screen J parameters.
  615. * @wcpj: Screen J parameters.
  616. * @jmem: Weight given to memory usage.
  617. *
  618. * Chooses a cell size based on the [uv]{fast,slow} parameters,
  619. * setting the rest of the parameters in @wcpj. Essentially, this
  620. * algorithm iterates through all plausible widths for the cell.
  621. *
  622. * This routine corresponds to SetScrJXISP in the WTS source.
  623. *
  624. * Return value: Quality score for parameters chosen.
  625. **/
  626. private double
  627. wts_set_scr_jxi(gx_wts_cell_params_j_t *wcpj, double jmem)
  628. {
  629. int i, imax;
  630. double q, qb;
  631. wcpj->xa = 0;
  632. wcpj->ya = 0;
  633. wcpj->xb = 0;
  634. wcpj->yb = 0;
  635. wcpj->xc = 0;
  636. wcpj->yc = 0;
  637. wcpj->xd = 0;
  638. wcpj->yd = 0;
  639. qb = 1.0;
  640. imax = wts_double_to_int_cap(qb / jmem);
  641. for (i = 1; i <= imax; i++) {
  642. if (i > 1) {
  643. q = wts_set_scr_jxi_try(wcpj, i, qb, jmem);
  644. if (q < qb) {
  645. qb = q;
  646. imax = wts_double_to_int_cap(q / jmem);
  647. if (imax >= 7500)
  648. imax = wts_double_to_int_cap((q - 0.00025) / jmem);
  649. if (imax < 7500) {
  650. imax = 7500;
  651. }
  652. }
  653. }
  654. }
  655. return qb;
  656. }
  657. /* Implementation for Screen J. This is optimized for general angles. */
  658. private gx_wts_cell_params_t *
  659. wts_pick_cell_size_j(double sratiox, double sratioy, double sangledeg,
  660. double memw)
  661. {
  662. gx_wts_cell_params_j_t *wcpj;
  663. double code;
  664. wcpj = malloc(sizeof(gx_wts_cell_params_j_t));
  665. if (wcpj == NULL)
  666. return NULL;
  667. wcpj->base.t = WTS_SCREEN_J;
  668. wts_set_mat(&wcpj->base, sratiox, sratioy, sangledeg);
  669. code = wts_set_scr_jxi(wcpj, pow(0.1, memw));
  670. if (code < 0) {
  671. free(wcpj);
  672. return NULL;
  673. }
  674. return &wcpj->base;
  675. }
  676. /**
  677. * wts_pick_cell_size: Choose cell size for WTS screen.
  678. * @ph: The halftone parameters.
  679. * @pmat: Transformation from 1/72" Y-up coords to device coords.
  680. *
  681. * Return value: The WTS cell parameters, or NULL on error.
  682. **/
  683. gx_wts_cell_params_t *
  684. wts_pick_cell_size(gs_screen_halftone *ph, const gs_matrix *pmat)
  685. {
  686. gx_wts_cell_params_t *result;
  687. /* todo: deal with landscape and mirrored coordinate systems */
  688. double sangledeg = ph->angle;
  689. double sratiox = 72.0 * fabs(pmat->xx) / ph->frequency;
  690. double sratioy = 72.0 * fabs(pmat->yy) / ph->frequency;
  691. double octangle;
  692. double memw = 8.0;
  693. octangle = sangledeg;
  694. while (octangle >= 45.0) octangle -= 45.0;
  695. while (octangle < -45.0) octangle += 45.0;
  696. if (fabs(octangle) < 1e-4)
  697. result = wts_pick_cell_size_h(sratiox, sratioy, sangledeg, memw);
  698. else
  699. result = wts_pick_cell_size_j(sratiox, sratioy, sangledeg, memw);
  700. if (result != NULL) {
  701. ph->actual_frequency = ph->frequency;
  702. ph->actual_angle = ph->angle;
  703. }
  704. return result;
  705. }
  706. struct gs_wts_screen_enum_s {
  707. wts_screen_type t;
  708. bits32 *cell;
  709. int width;
  710. int height;
  711. int size;
  712. int idx;
  713. };
  714. typedef struct {
  715. gs_wts_screen_enum_t base;
  716. const gx_wts_cell_params_j_t *wcpj;
  717. } gs_wts_screen_enum_j_t;
  718. typedef struct {
  719. gs_wts_screen_enum_t base;
  720. const gx_wts_cell_params_h_t *wcph;
  721. /* an argument can be made that these should be in the params */
  722. double ufast1, vfast1;
  723. double ufast2, vfast2;
  724. double uslow1, vslow1;
  725. double uslow2, vslow2;
  726. } gs_wts_screen_enum_h_t;
  727. private gs_wts_screen_enum_t *
  728. gs_wts_screen_enum_j_new(gx_wts_cell_params_t *wcp)
  729. {
  730. gs_wts_screen_enum_j_t *wsej;
  731. wsej = malloc(sizeof(gs_wts_screen_enum_j_t));
  732. wsej->base.t = WTS_SCREEN_J;
  733. wsej->wcpj = (const gx_wts_cell_params_j_t *)wcp;
  734. wsej->base.width = wcp->width;
  735. wsej->base.height = wcp->height;
  736. wsej->base.size = wcp->width * wcp->height;
  737. wsej->base.cell = malloc(wsej->base.size * sizeof(wsej->base.cell[0]));
  738. wsej->base.idx = 0;
  739. return (gs_wts_screen_enum_t *)wsej;
  740. }
  741. private int
  742. gs_wts_screen_enum_j_currentpoint(gs_wts_screen_enum_t *self,
  743. gs_point *ppt)
  744. {
  745. gs_wts_screen_enum_j_t *z = (gs_wts_screen_enum_j_t *)self;
  746. const gx_wts_cell_params_j_t *wcpj = z->wcpj;
  747. int x, y;
  748. double u, v;
  749. if (z->base.idx == z->base.size) {
  750. return 1;
  751. }
  752. x = z->base.idx % wcpj->base.width;
  753. y = z->base.idx / wcpj->base.width;
  754. u = wcpj->ufast_a * x + wcpj->uslow_a * y;
  755. v = wcpj->vfast_a * x + wcpj->vslow_a * y;
  756. u -= floor(u);
  757. v -= floor(v);
  758. ppt->x = 2 * u - 1;
  759. ppt->y = 2 * v - 1;
  760. return 0;
  761. }
  762. private gs_wts_screen_enum_t *
  763. gs_wts_screen_enum_h_new(gx_wts_cell_params_t *wcp)
  764. {
  765. gs_wts_screen_enum_h_t *wseh;
  766. const gx_wts_cell_params_h_t *wcph = (const gx_wts_cell_params_h_t *)wcp;
  767. int x1 = wcph->x1;
  768. int x2 = wcp->width - x1;
  769. int y1 = wcph->y1;
  770. int y2 = wcp->height - y1;
  771. wseh = malloc(sizeof(gs_wts_screen_enum_h_t));
  772. wseh->base.t = WTS_SCREEN_H;
  773. wseh->wcph = wcph;
  774. wseh->base.width = wcp->width;
  775. wseh->base.height = wcp->height;
  776. wseh->base.size = wcp->width * wcp->height;
  777. wseh->base.cell = malloc(wseh->base.size * sizeof(wseh->base.cell[0]));
  778. wseh->base.idx = 0;
  779. wseh->ufast1 = floor(0.5 + wcp->ufast * x1) / x1;
  780. wseh->vfast1 = floor(0.5 + wcp->vfast * x1) / x1;
  781. if (x2 > 0) {
  782. wseh->ufast2 = floor(0.5 + wcp->ufast * x2) / x2;
  783. wseh->vfast2 = floor(0.5 + wcp->vfast * x2) / x2;
  784. }
  785. wseh->uslow1 = floor(0.5 + wcp->uslow * y1) / y1;
  786. wseh->vslow1 = floor(0.5 + wcp->vslow * y1) / y1;
  787. if (y2 > 0) {
  788. wseh->uslow2 = floor(0.5 + wcp->uslow * y2) / y2;
  789. wseh->vslow2 = floor(0.5 + wcp->vslow * y2) / y2;
  790. }
  791. return &wseh->base;
  792. }
  793. private int
  794. gs_wts_screen_enum_h_currentpoint(gs_wts_screen_enum_t *self,
  795. gs_point *ppt)
  796. {
  797. gs_wts_screen_enum_h_t *z = (gs_wts_screen_enum_h_t *)self;
  798. const gx_wts_cell_params_h_t *wcph = z->wcph;
  799. int x, y;
  800. double u, v;
  801. if (self->idx == self->size) {
  802. return 1;
  803. }
  804. x = self->idx % wcph->base.width;
  805. y = self->idx / wcph->base.width;
  806. if (x < wcph->x1) {
  807. u = z->ufast1 * x;
  808. v = z->vfast1 * x;
  809. } else {
  810. u = z->ufast2 * (x - wcph->x1);
  811. v = z->vfast2 * (x - wcph->x1);
  812. }
  813. if (y < wcph->y1) {
  814. u += z->uslow1 * y;
  815. v += z->vslow1 * y;
  816. } else {
  817. u += z->uslow2 * (y - wcph->y1);
  818. v += z->vslow2 * (y - wcph->y1);
  819. }
  820. u -= floor(u);
  821. v -= floor(v);
  822. ppt->x = 2 * u - 1;
  823. ppt->y = 2 * v - 1;
  824. return 0;
  825. }
  826. gs_wts_screen_enum_t *
  827. gs_wts_screen_enum_new(gx_wts_cell_params_t *wcp)
  828. {
  829. if (wcp->t == WTS_SCREEN_J)
  830. return gs_wts_screen_enum_j_new(wcp);
  831. else if (wcp->t == WTS_SCREEN_H)
  832. return gs_wts_screen_enum_h_new(wcp);
  833. else
  834. return NULL;
  835. }
  836. int
  837. gs_wts_screen_enum_currentpoint(gs_wts_screen_enum_t *wse, gs_point *ppt)
  838. {
  839. if (wse->t == WTS_SCREEN_J)
  840. return gs_wts_screen_enum_j_currentpoint(wse, ppt);
  841. if (wse->t == WTS_SCREEN_H)
  842. return gs_wts_screen_enum_h_currentpoint(wse, ppt);
  843. else
  844. return -1;
  845. }
  846. int
  847. gs_wts_screen_enum_next(gs_wts_screen_enum_t *wse, floatp value)
  848. {
  849. bits32 sample;
  850. if (value < -1.0 || value > 1.0)
  851. return_error(gs_error_rangecheck);
  852. sample = (bits32) ((value + 1) * 0x7fffffff);
  853. wse->cell[wse->idx] = sample;
  854. wse->idx++;
  855. return 0;
  856. }
  857. /* Run the enum with a square dot. This is useful for testing. */
  858. #ifdef UNIT_TEST
  859. private void
  860. wts_run_enum_squaredot(gs_wts_screen_enum_t *wse)
  861. {
  862. int code;
  863. gs_point pt;
  864. floatp spot;
  865. for (;;) {
  866. code = gs_wts_screen_enum_currentpoint(wse, &pt);
  867. if (code)
  868. break;
  869. spot = 0.5 * (cos(pt.x * M_PI) + cos(pt.y * M_PI));
  870. gs_wts_screen_enum_next(wse, spot);
  871. }
  872. }
  873. #endif /* UNIT_TEST */
  874. private int
  875. wts_sample_cmp(const void *av, const void *bv) {
  876. const bits32 *const *a = (const bits32 *const *)av;
  877. const bits32 *const *b = (const bits32 *const *)bv;
  878. if (**a > **b) return 1;
  879. if (**a < **b) return -1;
  880. return 0;
  881. }
  882. /* This implementation simply sorts the threshold values (evening the
  883. distribution), without applying any moire reduction. */
  884. int
  885. wts_sort_cell(gs_wts_screen_enum_t *wse)
  886. {
  887. int size = wse->width * wse->height;
  888. bits32 *cell = wse->cell;
  889. bits32 **pcell;
  890. int i;
  891. pcell = malloc(size * sizeof(bits32 *));
  892. if (pcell == NULL)
  893. return -1;
  894. for (i = 0; i < size; i++)
  895. pcell[i] = &cell[i];
  896. qsort(pcell, size, sizeof(bits32 *), wts_sample_cmp);
  897. for (i = 0; i < size; i++)
  898. *pcell[i] = (bits32)floor(WTS_SORTED_MAX * (i + 0.5) / size);
  899. free(pcell);
  900. return 0;
  901. }
  902. /**
  903. * wts_blue_bump: Generate bump function for BlueDot.
  904. *
  905. * Return value: newly allocated bump.
  906. **/
  907. private bits32 *
  908. wts_blue_bump(gs_wts_screen_enum_t *wse)
  909. {
  910. const gx_wts_cell_params_t *wcp;
  911. int width = wse->width;
  912. int height = wse->height;
  913. int shift;
  914. int size = width * height;
  915. bits32 *bump;
  916. int i;
  917. double uf, vf;
  918. double am, eg;
  919. int z;
  920. int x0, y0;
  921. int x, y;
  922. if (wse->t == WTS_SCREEN_J) {
  923. gs_wts_screen_enum_j_t *wsej = (gs_wts_screen_enum_j_t *)wse;
  924. shift = wsej->wcpj->shift;
  925. wcp = &wsej->wcpj->base;
  926. } else if (wse->t == WTS_SCREEN_H) {
  927. gs_wts_screen_enum_h_t *wseh = (gs_wts_screen_enum_h_t *)wse;
  928. shift = 0;
  929. wcp = &wseh->wcph->base;
  930. } else
  931. return NULL;
  932. bump = (bits32 *)malloc(size * sizeof(bits32));
  933. if (bump == NULL)
  934. return NULL;
  935. for (i = 0; i < size; i++)
  936. bump[i] = 0;
  937. /* todo: more intelligence for anisotropic scaling */
  938. uf = wcp->ufast;
  939. vf = wcp->vfast;
  940. am = uf * uf + vf * vf;
  941. eg = (1 << 24) * 2.0 * sqrt (am);
  942. z = (int)(5 / sqrt (am));
  943. x0 = -(z / width) * shift - z;
  944. y0 = -(z % width);
  945. while (y0 < 0) {
  946. x0 -= shift;
  947. y0 += height;
  948. }
  949. while (x0 < 0) x0 += width;
  950. for (y = -z; y <= z; y++) {
  951. int x1 = x0;
  952. for (x = -z; x <= z; x++) {
  953. bump[y0 * width + x1] += (bits32)(eg * exp (-am * (x * x + y * y)));
  954. x1++;
  955. if (x1 == width)
  956. x1 = 0;
  957. }
  958. y0++;
  959. if (y0 == height) {
  960. x0 += shift;
  961. if (x0 >= width) x0 -= width;
  962. y0 = 0;
  963. }
  964. }
  965. return bump;
  966. }
  967. /**
  968. * wts_sort_blue: Sort cell using BlueDot.
  969. **/
  970. int
  971. wts_sort_blue(gs_wts_screen_enum_t *wse)
  972. {
  973. bits32 *cell = wse->cell;
  974. int width = wse->width;
  975. int height = wse->height;
  976. int shift;
  977. int size = width * height;
  978. bits32 *ref;
  979. bits32 **pcell;
  980. bits32 *bump;
  981. int i;
  982. if (wse->t == WTS_SCREEN_J) {
  983. gs_wts_screen_enum_j_t *wsej = (gs_wts_screen_enum_j_t *)wse;
  984. shift = wsej->wcpj->shift;
  985. } else
  986. shift = 0;
  987. ref = (bits32 *)malloc(size * sizeof(bits32));
  988. pcell = (bits32 **)malloc(size * sizeof(bits32 *));
  989. bump = wts_blue_bump(wse);
  990. if (ref == NULL || pcell == NULL || bump == NULL) {
  991. free(ref);
  992. free(pcell);
  993. free(bump);
  994. return -1;
  995. }
  996. for (i = 0; i < size; i++)
  997. pcell[i] = &cell[i];
  998. qsort(pcell, size, sizeof(bits32 *), wts_sample_cmp);
  999. /* set ref to sorted cell; pcell will now point to ref */
  1000. for (i = 0; i < size; i++) {
  1001. pcell[i] = (pcell[i] - cell) + ref;
  1002. *pcell[i] = (bits32)floor((1 << 24) * (i + 0.5) / size);
  1003. cell[i] = 0;
  1004. }
  1005. for (i = 0; i < size; i++) {
  1006. bits32 gmin = *pcell[i];
  1007. int j;
  1008. int j_end = i + 5000;
  1009. int jmin = i;
  1010. int ix;
  1011. int x0, y0;
  1012. int x, y;
  1013. int ref_ix, bump_ix;
  1014. /* find minimum cell value, but prune search */
  1015. if (j_end > size) j_end = size;
  1016. for (j = i + 1; j < j_end; j++) {
  1017. if (*pcell[j] < gmin) {
  1018. gmin = *pcell[j];
  1019. jmin = j;
  1020. }
  1021. }
  1022. ix = pcell[jmin] - ref;
  1023. pcell[jmin] = pcell[i];
  1024. cell[ix] = (bits32)floor(WTS_SORTED_MAX * (i + 0.5) / size);
  1025. x0 = ix % width;
  1026. y0 = ix / width;
  1027. /* Add in bump, centered at (x0, y0) */
  1028. ref_ix = y0 * width;
  1029. bump_ix = 0;
  1030. for (y = 0; y < height; y++) {
  1031. for (x = x0; x < width; x++)
  1032. ref[ref_ix + x] += bump[bump_ix++];
  1033. for (x = 0; x < x0; x++)
  1034. ref[ref_ix + x] += bump[bump_ix++];
  1035. ref_ix += width;
  1036. y0++;
  1037. if (y0 == height) {
  1038. x0 += shift;
  1039. if (x0 >= width) x0 -= width;
  1040. y0 = 0;
  1041. ref_ix = 0;
  1042. }
  1043. }
  1044. /* Remove DC component to avoid integer overflow. */
  1045. if ((i & 255) == 255 && i + 1 < size) {
  1046. bits32 gmin = *pcell[i + 1];
  1047. int j;
  1048. for (j = i + 2; j < size; j++) {
  1049. if (*pcell[j] < gmin) {
  1050. gmin = *pcell[j];
  1051. }
  1052. }
  1053. #ifdef VERBOSE
  1054. if_debug1('h', "[h]gmin = %d\n", gmin);
  1055. #endif
  1056. for (j = i + 1; j < size; j++)
  1057. *pcell[j] -= gmin;
  1058. }
  1059. }
  1060. free(ref);
  1061. free(pcell);
  1062. free(bump);
  1063. return 0;
  1064. }
  1065. private wts_screen_t *
  1066. wts_screen_from_enum_j(const gs_wts_screen_enum_t *wse)
  1067. {
  1068. const gs_wts_screen_enum_j_t *wsej = (const gs_wts_screen_enum_j_t *)wse;
  1069. wts_screen_j_t *wsj;
  1070. wts_screen_sample_t *samples;
  1071. int size;
  1072. int i;
  1073. wsj = malloc(sizeof(wts_screen_j_t));
  1074. wsj->base.type = WTS_SCREEN_J;
  1075. wsj->base.cell_width = wsej->base.width;
  1076. wsj->base.cell_height = wsej->base.height;
  1077. size = wsj->base.cell_width * wsj->base.cell_height;
  1078. wsj->base.cell_shift = wsej->wcpj->shift;
  1079. wsj->pa = (int)floor(wsej->wcpj->pa * (1 << 16) + 0.5);
  1080. wsj->pb = (int)floor(wsej->wcpj->pb * (1 << 16) + 0.5);
  1081. wsj->pc = (int)floor(wsej->wcpj->pc * (1 << 16) + 0.5);
  1082. wsj->pd = (int)floor(wsej->wcpj->pd * (1 << 16) + 0.5);
  1083. wsj->XA = wsej->wcpj->xa;
  1084. wsj->YA = wsej->wcpj->ya;
  1085. wsj->XB = wsej->wcpj->xb;
  1086. wsj->YB = wsej->wcpj->yb;
  1087. wsj->XC = wsej->wcpj->xc;
  1088. wsj->YC = wsej->wcpj->yc;
  1089. wsj->XD = wsej->wcpj->xd;
  1090. wsj->YD = wsej->wcpj->yd;
  1091. samples = malloc(sizeof(wts_screen_sample_t) * size);
  1092. wsj->base.samples = samples;
  1093. for (i = 0; i < size; i++) {
  1094. samples[i] = wsej->base.cell[i] >> WTS_EXTRA_SORT_BITS;
  1095. }
  1096. return &wsj->base;
  1097. }
  1098. private wts_screen_t *
  1099. wts_screen_from_enum_h(const gs_wts_screen_enum_t *wse)
  1100. {
  1101. const gs_wts_screen_enum_h_t *wseh = (const gs_wts_screen_enum_h_t *)wse;
  1102. wts_screen_h_t *wsh;
  1103. wts_screen_sample_t *samples;
  1104. int size;
  1105. int i;
  1106. /* factor some of this out into a common init routine? */
  1107. wsh = malloc(sizeof(wts_screen_h_t));
  1108. wsh->base.type = WTS_SCREEN_H;
  1109. wsh->base.cell_width = wseh->base.width;
  1110. wsh->base.cell_height = wseh->base.height;
  1111. size = wsh->base.cell_width * wsh->base.cell_height;
  1112. wsh->base.cell_shift = 0;
  1113. wsh->px = wseh->wcph->px;
  1114. wsh->py = wseh->wcph->py;
  1115. wsh->x1 = wseh->wcph->x1;
  1116. wsh->y1 = wseh->wcph->y1;
  1117. samples = malloc(sizeof(wts_screen_sample_t) * size);
  1118. wsh->base.samples = samples;
  1119. for (i = 0; i < size; i++) {
  1120. samples[i] = wseh->base.cell[i] >> WTS_EXTRA_SORT_BITS;
  1121. }
  1122. return &wsh->base;
  1123. }
  1124. wts_screen_t *
  1125. wts_screen_from_enum(const gs_wts_screen_enum_t *wse)
  1126. {
  1127. if (wse->t == WTS_SCREEN_J)
  1128. return wts_screen_from_enum_j(wse);
  1129. else if (wse->t == WTS_SCREEN_H)
  1130. return wts_screen_from_enum_h(wse);
  1131. else
  1132. return NULL;
  1133. }
  1134. void
  1135. gs_wts_free_enum(gs_wts_screen_enum_t *wse)
  1136. {
  1137. free(wse);
  1138. }
  1139. void
  1140. gs_wts_free_screen(wts_screen_t * wts)
  1141. {
  1142. free(wts);
  1143. }
  1144. #ifdef UNIT_TEST
  1145. private int
  1146. dump_thresh(const wts_screen_t *ws, int width, int height)
  1147. {
  1148. int x, y;
  1149. wts_screen_sample_t *s0;
  1150. int dummy;
  1151. wts_get_samples(ws, 0, 0, &s0, &dummy);
  1152. printf("P5\n%d %d\n255\n", width, height);
  1153. for (y = 0; y < height; y++) {
  1154. for (x = 0; x < width;) {
  1155. wts_screen_sample_t *samples;
  1156. int n_samples, i;
  1157. wts_get_samples(ws, x, y, &samples, &n_samples);
  1158. #if 1
  1159. for (i = 0; x + i < width && i < n_samples; i++)
  1160. fputc(samples[i] >> 7, stdout);
  1161. #else
  1162. printf("(%d, %d): %d samples at %d\n",
  1163. x, y, n_samples, samples - s0);
  1164. #endif
  1165. x += n_samples;
  1166. }
  1167. }
  1168. return 0;
  1169. }
  1170. int
  1171. main (int argc, char **argv)
  1172. {
  1173. gs_screen_halftone h;
  1174. gs_matrix mat;
  1175. double xres = 1200;
  1176. double yres = 1200;
  1177. gx_wts_cell_params_t *wcp;
  1178. gs_wts_screen_enum_t *wse;
  1179. wts_screen_t *ws;
  1180. mat.xx = xres / 72.0;
  1181. mat.xy = 0;
  1182. mat.yx = 0;
  1183. mat.yy = yres / 72.0;
  1184. h.frequency = 121;
  1185. h.angle = 45;
  1186. wcp = wts_pick_cell_size(&h, &mat);
  1187. dlprintf2("cell size = %d x %d\n", wcp->width, wcp->height);
  1188. wse = gs_wts_screen_enum_new(wcp);
  1189. wts_run_enum_squaredot(wse);
  1190. #if 1
  1191. wts_sort_blue(wse);
  1192. #else
  1193. wts_sort_cell(wse);
  1194. #endif
  1195. ws = wts_screen_from_enum(wse);
  1196. dump_thresh(ws, 512, 512);
  1197. return 0;
  1198. }
  1199. #endif