Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

669 lines
18 KiB

  1. #include "stdafx.h"
  2. #include "imgutil.h"
  3. #include "cdithtbl.h"
  4. CDitherTable::CDitherTable() :
  5. m_nColors( 0 ),
  6. m_nRefCount( 0 ),
  7. m_pnDistanceBuffer( NULL )
  8. {
  9. }
  10. CDitherTable::~CDitherTable()
  11. {
  12. }
  13. BOOL CDitherTable::Match( ULONG nColors, const RGBQUAD* prgbColors )
  14. {
  15. if( m_nColors != nColors )
  16. {
  17. return( FALSE );
  18. }
  19. if( memcmp( m_argbColors, prgbColors, m_nColors*sizeof( RGBQUAD ) ) != 0 )
  20. {
  21. return( FALSE );
  22. }
  23. return( TRUE );
  24. }
  25. HRESULT CDitherTable::SetColors( ULONG nColors, const RGBQUAD* prgbColors )
  26. {
  27. HRESULT hResult;
  28. m_nColors = nColors;
  29. memcpy( m_argbColors, prgbColors, m_nColors*sizeof( RGBQUAD ) );
  30. hResult = BuildInverseMap();
  31. if( FAILED( hResult ) )
  32. {
  33. return( hResult );
  34. }
  35. return( S_OK );
  36. }
  37. /*
  38. void CDitherTable::BuildInverseMap()
  39. {
  40. ULONG r;
  41. ULONG g;
  42. ULONG b;
  43. ULONG iColor;
  44. ULONG iMapEntry;
  45. int nMinDistance;
  46. int nDistance;
  47. int nRedDistance;
  48. int nBlueDistance;
  49. int nGreenDistance;
  50. iMapEntry = 0;
  51. for( r = 0; r < 32; r++ )
  52. {
  53. for( g = 0; g < 32; g++ )
  54. {
  55. for( b = 0; b < 32; b++ )
  56. {
  57. nMinDistance = 1000000;
  58. for( iColor = 0; iColor < m_nColors; iColor++ )
  59. {
  60. nRedDistance = m_argbColors[iColor].rgbRed-((r<<3)+(r>>2));
  61. nGreenDistance = m_argbColors[iColor].rgbGreen-((g<<3)+(g>>2));
  62. nBlueDistance = m_argbColors[iColor].rgbBlue-((b<<3)+(b>>2));
  63. nDistance = (nRedDistance*nRedDistance)+(nGreenDistance*
  64. nGreenDistance)+(nBlueDistance*nBlueDistance);
  65. if( nDistance < nMinDistance )
  66. {
  67. nMinDistance = nDistance;
  68. m_abInverseMap[iMapEntry] = BYTE( iColor );
  69. }
  70. }
  71. iMapEntry++;
  72. }
  73. }
  74. }
  75. }
  76. */
  77. HRESULT CDitherTable::BuildInverseMap()
  78. {
  79. _ASSERTE( m_pnDistanceBuffer == NULL );
  80. m_pnDistanceBuffer = new ULONG[32768];
  81. if( m_pnDistanceBuffer == NULL )
  82. {
  83. return( E_OUTOFMEMORY );
  84. }
  85. inv_cmap( m_nColors, m_argbColors, 5, m_pnDistanceBuffer, m_abInverseMap );
  86. delete m_pnDistanceBuffer;
  87. m_pnDistanceBuffer = NULL;
  88. return( S_OK );
  89. }
  90. /*****************************************************************
  91. * TAG( inv_cmap )
  92. *
  93. * Compute an inverse colormap efficiently.
  94. * Inputs:
  95. * colors: Number of colors in the forward colormap.
  96. * colormap: The forward colormap.
  97. * bits: Number of quantization bits. The inverse
  98. * colormap will have (2^bits)^3 entries.
  99. * dist_buf: An array of (2^bits)^3 long integers to be
  100. * used as scratch space.
  101. * Outputs:
  102. * rgbmap: The output inverse colormap. The entry
  103. * rgbmap[(r<<(2*bits)) + (g<<bits) + b]
  104. * is the colormap entry that is closest to the
  105. * (quantized) color (r,g,b).
  106. * Assumptions:
  107. * Quantization is performed by right shift (low order bits are
  108. * truncated). Thus, the distance to a quantized color is
  109. * actually measured to the color at the center of the cell
  110. * (i.e., to r+.5, g+.5, b+.5, if (r,g,b) is a quantized color).
  111. * Algorithm:
  112. * Uses a "distance buffer" algorithm:
  113. * The distance from each representative in the forward color map
  114. * to each point in the rgb space is computed. If it is less
  115. * than the distance currently stored in dist_buf, then the
  116. * corresponding entry in rgbmap is replaced with the current
  117. * representative (and the dist_buf entry is replaced with the
  118. * new distance).
  119. *
  120. * The distance computation uses an efficient incremental formulation.
  121. *
  122. * Distances are computed "outward" from each color. If the
  123. * colors are evenly distributed in color space, the expected
  124. * number of cells visited for color I is N^3/I.
  125. * Thus, the complexity of the algorithm is O(log(K) N^3),
  126. * where K = colors, and N = 2^bits.
  127. */
  128. /*
  129. * Here's the idea: scan from the "center" of each cell "out"
  130. * until we hit the "edge" of the cell -- that is, the point
  131. * at which some other color is closer -- and stop. In 1-D,
  132. * this is simple:
  133. * for i := here to max do
  134. * if closer then buffer[i] = this color
  135. * else break
  136. * repeat above loop with i := here-1 to min by -1
  137. *
  138. * In 2-D, it's trickier, because along a "scan-line", the
  139. * region might start "after" the "center" point. A picture
  140. * might clarify:
  141. * | ...
  142. * | ... .
  143. * ... .
  144. * ... | .
  145. * . + .
  146. * . .
  147. * . .
  148. * .........
  149. *
  150. * The + marks the "center" of the above region. On the top 2
  151. * lines, the region "begins" to the right of the "center".
  152. *
  153. * Thus, we need a loop like this:
  154. * detect := false
  155. * for i := here to max do
  156. * if closer then
  157. * buffer[..., i] := this color
  158. * if !detect then
  159. * here = i
  160. * detect = true
  161. * else
  162. * if detect then
  163. * break
  164. *
  165. * Repeat the above loop with i := here-1 to min by -1. Note that
  166. * the "detect" value should not be reinitialized. If it was
  167. * "true", and center is not inside the cell, then none of the
  168. * cell lies to the left and this loop should exit
  169. * immediately.
  170. *
  171. * The outer loops are similar, except that the "closer" test
  172. * is replaced by a call to the "next in" loop; its "detect"
  173. * value serves as the test. (No assignment to the buffer is
  174. * done, either.)
  175. *
  176. * Each time an outer loop starts, the "here", "min", and
  177. * "max" values of the next inner loop should be
  178. * re-initialized to the center of the cell, 0, and cube size,
  179. * respectively. Otherwise, these values will carry over from
  180. * one "call" to the inner loop to the next. This tracks the
  181. * edges of the cell and minimizes the number of
  182. * "unproductive" comparisons that must be made.
  183. *
  184. * Finally, the inner-most loop can have the "if !detect"
  185. * optimized out of it by splitting it into two loops: one
  186. * that finds the first color value on the scan line that is
  187. * in this cell, and a second that fills the cell until
  188. * another one is closer:
  189. * if !detect then {needed for "down" loop}
  190. * for i := here to max do
  191. * if closer then
  192. * buffer[..., i] := this color
  193. * detect := true
  194. * break
  195. * for i := i+1 to max do
  196. * if closer then
  197. * buffer[..., i] := this color
  198. * else
  199. * break
  200. *
  201. * In this implementation, each level will require the
  202. * following variables. Variables labelled (l) are local to each
  203. * procedure. The ? should be replaced with r, g, or b:
  204. * cdist: The distance at the starting point.
  205. * ?center: The value of this component of the color
  206. * c?inc: The initial increment at the ?center position.
  207. * ?stride: The amount to add to the buffer
  208. * pointers (dp and rgbp) to get to the
  209. * "next row".
  210. * min(l): The "low edge" of the cell, init to 0
  211. * max(l): The "high edge" of the cell, init to
  212. * colormax-1
  213. * detect(l): True if this row has changed some
  214. * buffer entries.
  215. * i(l): The index for this row.
  216. * ?xx: The accumulated increment value.
  217. *
  218. * here(l): The starting index for this color. The
  219. * following variables are associated with here,
  220. * in the sense that they must be updated if here
  221. * is changed.
  222. * ?dist: The current distance for this level. The
  223. * value of dist from the previous level (g or r,
  224. * for level b or g) initializes dist on this
  225. * level. Thus gdist is associated with here(b)).
  226. * ?inc: The initial increment for the row.
  227. *
  228. * ?dp: Pointer into the distance buffer. The value
  229. * from the previous level initializes this level.
  230. * ?rgbp: Pointer into the rgb buffer. The value
  231. * from the previous level initializes this level.
  232. *
  233. * The blue and green levels modify 'here-associated' variables (dp,
  234. * rgbp, dist) on the green and red levels, respectively, when here is
  235. * changed.
  236. */
  237. /* Track minimum and maximum. */
  238. #define MINMAX_TRACK
  239. void CDitherTable::inv_cmap(int colors, RGBQUAD *colormap, int bits,
  240. ULONG* dist_buf, BYTE* rgbmap )
  241. {
  242. int nbits = 8 - bits;
  243. colormax = 1 << bits;
  244. x = 1 << nbits;
  245. xsqr = 1 << (2 * nbits);
  246. /* Compute "strides" for accessing the arrays. */
  247. gstride = (int) colormax;
  248. rstride = (int) (colormax * colormax);
  249. maxfill( dist_buf, colormax );
  250. for ( cindex = 0; cindex < colors; cindex++ )
  251. {
  252. /* The caller can force certain colors in the output space to be
  253. * omitted by setting a nonzero value for the color's 'x' component.
  254. * This will produce a map that never refers to those colors.
  255. * -francish, 2/16/96
  256. */
  257. if (!colormap[cindex].rgbReserved)
  258. {
  259. /*
  260. * Distance formula is
  261. * (red - map[0])^2 + (green - map[1])^2 + (blue - map[2])^2
  262. *
  263. * Because of quantization, we will measure from the center of
  264. * each quantized "cube", so blue distance is
  265. * (blue + x/2 - map[2])^2,
  266. * where x = 2^(8 - bits).
  267. * The step size is x, so the blue increment is
  268. * 2*x*blue - 2*x*map[2] + 2*x^2
  269. *
  270. * Now, b in the code below is actually blue/x, so our
  271. * increment will be 2*(b*x^2 + x^2 - x*map[2]). For
  272. * efficiency, we will maintain this quantity in a separate variable
  273. * that will be updated incrementally by adding 2*x^2 each time.
  274. */
  275. /* The initial position is the cell containing the colormap
  276. * entry. We get this by quantizing the colormap values.
  277. */
  278. rcenter = colormap[cindex].rgbRed >> nbits;
  279. gcenter = colormap[cindex].rgbGreen >> nbits;
  280. bcenter = colormap[cindex].rgbBlue >> nbits;
  281. rdist = colormap[cindex].rgbRed - (rcenter * x + x/2);
  282. gdist = colormap[cindex].rgbGreen - (gcenter * x + x/2);
  283. cdist = colormap[cindex].rgbBlue - (bcenter * x + x/2);
  284. cdist = rdist*rdist + gdist*gdist + cdist*cdist;
  285. crinc = 2 * ((rcenter + 1) * xsqr - (colormap[cindex].rgbRed*x));
  286. cginc = 2 * ((gcenter + 1) * xsqr - (colormap[cindex].rgbGreen*x));
  287. cbinc = 2 * ((bcenter + 1) * xsqr - (colormap[cindex].rgbBlue*x));
  288. /* Array starting points. */
  289. cdp = dist_buf + rcenter * rstride + gcenter * gstride + bcenter;
  290. crgbp = rgbmap + rcenter * rstride + gcenter * gstride + bcenter;
  291. (void)redloop();
  292. }
  293. }
  294. }
  295. /* redloop -- loop up and down from red center. */
  296. int CDitherTable::redloop()
  297. {
  298. int detect;
  299. int r;
  300. int first;
  301. long txsqr = xsqr + xsqr;
  302. detect = 0;
  303. /* Basic loop up. */
  304. for ( r = rcenter, rdist = cdist, rxx = crinc,
  305. rdp = cdp, rrgbp = crgbp, first = 1;
  306. r < (int) colormax;
  307. r++, rdp += rstride, rrgbp += rstride,
  308. rdist += rxx, rxx += txsqr, first = 0 )
  309. {
  310. if ( greenloop( first ) )
  311. detect = 1;
  312. else if ( detect )
  313. break;
  314. }
  315. /* Basic loop down. */
  316. for ( r = rcenter - 1, rxx = crinc - txsqr, rdist = cdist - rxx,
  317. rdp = cdp - rstride, rrgbp = crgbp - rstride, first = 1;
  318. r >= 0;
  319. r--, rdp -= rstride, rrgbp -= rstride,
  320. rxx -= txsqr, rdist -= rxx, first = 0 )
  321. {
  322. if ( greenloop( first ) )
  323. detect = 1;
  324. else if ( detect )
  325. break;
  326. }
  327. return detect;
  328. }
  329. #undef min
  330. #undef max
  331. #define here greenloop_here
  332. #define min greenloop_min
  333. #define max greenloop_max
  334. #define prevmin greenloop_prevmin
  335. #define prevmax greenloop_prevmax
  336. /* greenloop -- loop up and down from green center. */
  337. int CDitherTable::greenloop( int restart )
  338. {
  339. int detect;
  340. int g;
  341. int first;
  342. long txsqr = xsqr + xsqr;
  343. #ifdef MINMAX_TRACK
  344. int thismax, thismin;
  345. #endif
  346. if ( restart )
  347. {
  348. here = gcenter;
  349. min = 0;
  350. max = (int) colormax - 1;
  351. ginc = cginc;
  352. #ifdef MINMAX_TRACK
  353. prevmax = 0;
  354. prevmin = (int) colormax;
  355. #endif
  356. }
  357. #ifdef MINMAX_TRACK
  358. thismin = min;
  359. thismax = max;
  360. #endif
  361. detect = 0;
  362. /* Basic loop up. */
  363. for ( g = here, gcdist = gdist = rdist, gxx = ginc,
  364. gcdp = gdp = rdp, gcrgbp = grgbp = rrgbp, first = 1;
  365. g <= max;
  366. g++, gdp += gstride, gcdp += gstride, grgbp += gstride, gcrgbp += gstride,
  367. gdist += gxx, gcdist += gxx, gxx += txsqr, first = 0 )
  368. {
  369. if ( blueloop( first ) )
  370. {
  371. if ( !detect )
  372. {
  373. /* Remember here and associated data! */
  374. if ( g > here )
  375. {
  376. here = g;
  377. rdp = gcdp;
  378. rrgbp = gcrgbp;
  379. rdist = gcdist;
  380. ginc = gxx;
  381. #ifdef MINMAX_TRACK
  382. thismin = here;
  383. #endif
  384. }
  385. detect = 1;
  386. }
  387. }
  388. else if ( detect )
  389. {
  390. #ifdef MINMAX_TRACK
  391. thismax = g - 1;
  392. #endif
  393. break;
  394. }
  395. }
  396. /* Basic loop down. */
  397. for ( g = here - 1, gxx = ginc - txsqr, gcdist = gdist = rdist - gxx,
  398. gcdp = gdp = rdp - gstride, gcrgbp = grgbp = rrgbp - gstride,
  399. first = 1;
  400. g >= min;
  401. g--, gdp -= gstride, gcdp -= gstride, grgbp -= gstride, gcrgbp -= gstride,
  402. gxx -= txsqr, gdist -= gxx, gcdist -= gxx, first = 0 )
  403. {
  404. if ( blueloop( first ) )
  405. {
  406. if ( !detect )
  407. {
  408. /* Remember here! */
  409. here = g;
  410. rdp = gcdp;
  411. rrgbp = gcrgbp;
  412. rdist = gcdist;
  413. ginc = gxx;
  414. #ifdef MINMAX_TRACK
  415. thismax = here;
  416. #endif
  417. detect = 1;
  418. }
  419. }
  420. else if ( detect )
  421. {
  422. #ifdef MINMAX_TRACK
  423. thismin = g + 1;
  424. #endif
  425. break;
  426. }
  427. }
  428. #ifdef MINMAX_TRACK
  429. /* If we saw something, update the edge trackers. For now, only
  430. * tracks edges that are "shrinking" (min increasing, max
  431. * decreasing.
  432. */
  433. if ( detect )
  434. {
  435. if ( thismax < prevmax )
  436. max = thismax;
  437. prevmax = thismax;
  438. if ( thismin > prevmin )
  439. min = thismin;
  440. prevmin = thismin;
  441. }
  442. #endif
  443. return detect;
  444. }
  445. #undef min
  446. #undef max
  447. #undef here
  448. #undef prevmin
  449. #undef prevmax
  450. #define here blueloop_here
  451. #define min blueloop_min
  452. #define max blueloop_max
  453. #define prevmin blueloop_prevmin
  454. #define prevmax blueloop_prevmax
  455. /* blueloop -- loop up and down from blue center. */
  456. int CDitherTable::blueloop( int restart )
  457. {
  458. int detect;
  459. register ULONG* dp;
  460. register BYTE* rgbp;
  461. register long bdist, bxx;
  462. register int b, i = cindex;
  463. register long txsqr = xsqr + xsqr;
  464. register int lim;
  465. #ifdef MINMAX_TRACK
  466. int thismin, thismax;
  467. #endif /* MINMAX_TRACK */
  468. if ( restart )
  469. {
  470. here = bcenter;
  471. min = 0;
  472. max = (int) colormax - 1;
  473. binc = cbinc;
  474. #ifdef MINMAX_TRACK
  475. prevmin = (int) colormax;
  476. prevmax = 0;
  477. #endif /* MINMAX_TRACK */
  478. }
  479. detect = 0;
  480. #ifdef MINMAX_TRACK
  481. thismin = min;
  482. thismax = max;
  483. #endif
  484. /* Basic loop up. */
  485. /* First loop just finds first applicable cell. */
  486. for ( b = here, bdist = gdist, bxx = binc, dp = gdp, rgbp = grgbp, lim = max;
  487. b <= lim;
  488. b++, dp++, rgbp++,
  489. bdist += bxx, bxx += txsqr )
  490. {
  491. if ( *dp > (DWORD)bdist )
  492. {
  493. /* Remember new 'here' and associated data! */
  494. if ( b > here )
  495. {
  496. here = b;
  497. gdp = dp;
  498. grgbp = rgbp;
  499. gdist = bdist;
  500. binc = bxx;
  501. #ifdef MINMAX_TRACK
  502. thismin = here;
  503. #endif
  504. }
  505. detect = 1;
  506. break;
  507. }
  508. }
  509. /* Second loop fills in a run of closer cells. */
  510. for ( ;
  511. b <= lim;
  512. b++, dp++, rgbp++,
  513. bdist += bxx, bxx += txsqr )
  514. {
  515. if ( *dp > (DWORD)bdist )
  516. {
  517. *dp = bdist;
  518. *rgbp = (BYTE) i;
  519. }
  520. else
  521. {
  522. #ifdef MINMAX_TRACK
  523. thismax = b - 1;
  524. #endif
  525. break;
  526. }
  527. }
  528. /* Basic loop down. */
  529. /* Do initializations here, since the 'find' loop might not get
  530. * executed.
  531. */
  532. lim = min;
  533. b = here - 1;
  534. bxx = binc - txsqr;
  535. bdist = gdist - bxx;
  536. dp = gdp - 1;
  537. rgbp = grgbp - 1;
  538. /* The 'find' loop is executed only if we didn't already find
  539. * something.
  540. */
  541. if ( !detect )
  542. for ( ;
  543. b >= lim;
  544. b--, dp--, rgbp--,
  545. bxx -= txsqr, bdist -= bxx )
  546. {
  547. if ( *dp > (DWORD)bdist )
  548. {
  549. /* Remember here! */
  550. /* No test for b against here necessary because b <
  551. * here by definition.
  552. */
  553. here = b;
  554. gdp = dp;
  555. grgbp = rgbp;
  556. gdist = bdist;
  557. binc = bxx;
  558. #ifdef MINMAX_TRACK
  559. thismax = here;
  560. #endif
  561. detect = 1;
  562. break;
  563. }
  564. }
  565. /* The 'update' loop. */
  566. for ( ;
  567. b >= lim;
  568. b--, dp--, rgbp--,
  569. bxx -= txsqr, bdist -= bxx )
  570. {
  571. if ( *dp > (DWORD)bdist )
  572. {
  573. *dp = bdist;
  574. *rgbp = (BYTE) i;
  575. }
  576. else
  577. {
  578. #ifdef MINMAX_TRACK
  579. thismin = b + 1;
  580. #endif
  581. break;
  582. }
  583. }
  584. /* If we saw something, update the edge trackers. */
  585. #ifdef MINMAX_TRACK
  586. if ( detect )
  587. {
  588. /* Only tracks edges that are "shrinking" (min increasing, max
  589. * decreasing.
  590. */
  591. if ( thismax < prevmax )
  592. max = thismax;
  593. if ( thismin > prevmin )
  594. min = thismin;
  595. /* Remember the min and max values. */
  596. prevmax = thismax;
  597. prevmin = thismin;
  598. }
  599. #endif /* MINMAX_TRACK */
  600. return detect;
  601. }
  602. void CDitherTable::maxfill( ULONG* buffer, long side)
  603. {
  604. register unsigned long maxv = (unsigned long)~0L;
  605. register long i;
  606. register ULONG* bp;
  607. (void)side;
  608. for ( i = colormax * colormax * colormax, bp = buffer;
  609. i > 0;
  610. i--, bp++ )
  611. *bp = maxv;
  612. }