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.

1711 lines
49 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998-2000 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Internal scan class.
  8. * Use ARGB buffer for all scan drawing, and Blt to destination when done.
  9. *
  10. * Revision History:
  11. *
  12. * 07/26/1999 t-wehunt
  13. * Created it.
  14. *
  15. \**************************************************************************/
  16. #include "precomp.hpp"
  17. #ifdef DBGALPHA
  18. const ULONG gDebugAlpha = 0;
  19. #endif
  20. #define ALPHA_BYTE_INDEX 3
  21. #define SRC_PIX_SIZE 4
  22. #define RoundDWORD(x) (x + ((x%sizeof(DWORD))>0?(sizeof(DWORD)-(x%sizeof(DWORD))):0))
  23. #define IsInteger(x) (GpFloor(x) == x)
  24. static int TranslateHTTable = 0;
  25. EpScanDIB::EpScanDIB() :
  26. BufStart(NULL),
  27. CurBuffer(NULL),
  28. MaskStart(NULL),
  29. AlphaStart(NULL),
  30. OutputWidth(-1),
  31. OutputBleed(0),
  32. NextBuffer(NULL),
  33. ZeroOutPad(2)
  34. {
  35. }
  36. /**************************************************************************\
  37. *
  38. * Function Description:
  39. *
  40. * Starts a scan.
  41. *
  42. * Arguments:
  43. *
  44. * [IN] driver - Driver interface
  45. * [IN] context - Drawing context
  46. * [IN] surface - Destination surface
  47. * [IN] compositeMode - Alpha blend mode
  48. * [OUT] nextBuffer - Points to a EpScan:: type function to return
  49. * the next buffer
  50. *
  51. * Return Value:
  52. *
  53. * FALSE if all the necessary buffers couldn't be created
  54. *
  55. * History:
  56. *
  57. * 07/13/1999 t-wehunt
  58. * Created it.
  59. *
  60. \**************************************************************************/
  61. BOOL
  62. EpScanDIB::Start(
  63. DpDriver *driver,
  64. DpContext *context,
  65. DpBitmap *surface,
  66. NEXTBUFFERFUNCTION *nextBuffer,
  67. EpScanType scanType,
  68. PixelFormatID pixFmtGeneral,
  69. PixelFormatID pixFmtOpaque,
  70. ARGB solidColor
  71. )
  72. {
  73. // Inherit initialization
  74. EpScan::Start(
  75. driver,
  76. context,
  77. surface,
  78. nextBuffer,
  79. scanType,
  80. pixFmtGeneral,
  81. pixFmtOpaque,
  82. solidColor
  83. );
  84. // Printer surfaces don't have an alpha channel.
  85. ASSERT(surface->SurfaceTransparency == TransparencyNoAlpha);
  86. *nextBuffer = NextBuffer;
  87. ASSERT(NextBuffer != NULL);
  88. // !! Add more asserts for valid state.
  89. OutputX = -1;
  90. OutputY = -1;
  91. OutputWidth = -1;
  92. OutputBleed = -1;
  93. Rasterizing = TRUE;
  94. return TRUE;
  95. }
  96. /**************************************************************************\
  97. *
  98. * Function Description:
  99. *
  100. * Denotes the end of the use of the scan buffer.
  101. *
  102. * Arguments:
  103. *
  104. * [IN] updateWidth - Number of pixels to update in the current buffer
  105. *
  106. * Return Value:
  107. *
  108. * None.
  109. *
  110. * History:
  111. *
  112. * 07/13/1999 t-wehunt
  113. * Created it.
  114. *
  115. \**************************************************************************/
  116. VOID
  117. EpScanDIB::End(INT updateWidth)
  118. {
  119. // it is the driver's job to decide what to do with us and they
  120. // MUST call ReleaseBuffer() as appropriate
  121. // Flush the last scan... This is always required, since at the very
  122. // least, we unpremultiply the scan line.
  123. Rasterizing = FALSE;
  124. if (RenderAlpha)
  125. {
  126. if (!(ScanOptions & ScanDeviceZeroOut))
  127. {
  128. (this->*NextBuffer)(
  129. DeviceBounds.X + DeviceBounds.Width,
  130. DeviceBounds.Y + DeviceBounds.Height,
  131. 0,
  132. updateWidth,
  133. 0
  134. );
  135. }
  136. else if (OutputWidth > 0)
  137. {
  138. // we must flush the last zeroArray.
  139. BYTE* bitsPtr = BufStart + CappedStride *
  140. ((CappedBounds.Height-1) - ((OutputY/ScaleY) - CappedBounds.Y));
  141. DWORD* zeroPtr = (DWORD*) ZeroStart;
  142. INT count = CappedBounds.Width;
  143. while (count--)
  144. {
  145. if (*zeroPtr++ == 0)
  146. {
  147. *bitsPtr++ = '\0';
  148. *bitsPtr++ = '\0';
  149. *bitsPtr++ = '\0';
  150. }
  151. else
  152. {
  153. bitsPtr += 3;
  154. }
  155. }
  156. }
  157. }
  158. else
  159. {
  160. (this->*NextBuffer)(
  161. CappedBounds.X + CappedBounds.Width,
  162. CappedBounds.Y + CappedBounds.Height,
  163. 0,
  164. updateWidth,
  165. 0
  166. );
  167. }
  168. // Ensure we don't flush if we're called on another band
  169. OutputWidth = -1;
  170. }
  171. /**************************************************************************\
  172. *
  173. * Function Description:
  174. *
  175. * NextBufferFunc32bpp - Handles output when we are rasterizing at capped
  176. * dpi to a 32bpp unpremultiplied DIB
  177. *
  178. * Arguments:
  179. *
  180. * [IN] x - Destination pixel coordinate in destination surface
  181. * [IN] y - ""
  182. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  183. * [IN] updateWidth - Number of pixels to update in the current buffer
  184. *
  185. * Return Value:
  186. *
  187. * Points to the resulting scan buffer
  188. *
  189. * History:
  190. *
  191. * 3/9/2k ericvan
  192. * Created it.
  193. *
  194. \**************************************************************************/
  195. VOID*
  196. EpScanDIB::NextBufferFunc32bpp(
  197. INT x,
  198. INT y,
  199. INT newWidth,
  200. INT updateWidth,
  201. INT blenderNum
  202. )
  203. {
  204. LastBlenderNum = blenderNum;
  205. ASSERT(!RenderAlpha);
  206. ASSERT(newWidth >= 0);
  207. ASSERTMSG(newWidth <= CappedBounds.Width,
  208. ("Width exceeds SetBounds() request"));
  209. ASSERT(x >= CappedBounds.X && x <= (CappedBounds.X + CappedBounds.Width));
  210. ASSERT(y >= CappedBounds.Y && y <= (CappedBounds.Y + CappedBounds.Height));
  211. ASSERT((x + newWidth) <= (CappedBounds.X + CappedBounds.Width));
  212. ASSERT((ScanOptions & ScanCappedBounds) && (ScanOptions & ScanCapped32bpp));
  213. // !! Remove this when we standardize on unpremultiplied
  214. #if 1
  215. if (OutputWidth > 0)
  216. {
  217. while (OutputWidth--)
  218. {
  219. // unpremultiply
  220. *CurBuffer = Unpremultiply(*CurBuffer);
  221. CurBuffer++;
  222. }
  223. }
  224. OutputWidth = newWidth;
  225. #endif
  226. // return pointer directly into our 32bpp buffer
  227. return (CurBuffer = (((ARGB*)BufStart) +
  228. ((CappedBounds.Height - 1) - (y - CappedBounds.Y)) *
  229. CappedBounds.Width +
  230. (x - CappedBounds.X)));
  231. }
  232. /**************************************************************************\
  233. *
  234. * Function Description:
  235. *
  236. * NextBufferFunc32bppOver - Handles output when we are rasterizing at capped
  237. * DPI to a 32bpp unpremultiplied DIB. Blends any
  238. * alpha with background WHITENESS.
  239. *
  240. * Arguments:
  241. *
  242. * [IN] x - Destination pixel coordinate in destination surface
  243. * [IN] y - ""
  244. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  245. * [IN] updateWidth - Number of pixels to update in the current buffer
  246. *
  247. * Return Value:
  248. *
  249. * Points to the resulting scan buffer
  250. *
  251. * History:
  252. *
  253. * 3/9/2k ericvan
  254. * Created it.
  255. *
  256. \**************************************************************************/
  257. VOID*
  258. EpScanDIB::NextBufferFunc32bppOver(
  259. INT x,
  260. INT y,
  261. INT newWidth,
  262. INT updateWidth,
  263. INT blenderNum
  264. )
  265. {
  266. LastBlenderNum = blenderNum;
  267. ASSERT(!RenderAlpha);
  268. ASSERT(newWidth >= 0);
  269. ASSERTMSG(newWidth <= CappedBounds.Width,
  270. ("Width exceeds SetBounds() request"));
  271. ASSERT(x >= CappedBounds.X && x <= (CappedBounds.X + CappedBounds.Width));
  272. ASSERT(y >= CappedBounds.Y && y <= (CappedBounds.Y + CappedBounds.Height));
  273. ASSERT((x + newWidth) <= (CappedBounds.X + CappedBounds.Width));
  274. ASSERT((ScanOptions & ScanCappedBounds) && (ScanOptions & ScanCapped32bppOver));
  275. // !! Remove this when we standardize on unpremultiplied
  276. #if 1
  277. if (OutputWidth > 0)
  278. {
  279. while (OutputWidth--)
  280. {
  281. // An adaptation of the blending code from Andrew Godfrey's
  282. // BlendOver function, but onto a white surface. This is done to
  283. // improve the output quality of postscript.
  284. GpColor color(*CurBuffer);
  285. UINT32 alpha = color.GetAlpha();
  286. UINT32 alphaContrib;
  287. if (alpha == 0)
  288. {
  289. *CurBuffer++ = 0x00FFFFFF;
  290. }
  291. else if (alpha == 255)
  292. {
  293. CurBuffer++;
  294. }
  295. else
  296. {
  297. // Dst = Src + (1-Alpha) * Dst
  298. UINT32 multA = 255 - alpha;
  299. UINT32 D1_000000FF = 0xFF;
  300. UINT32 D2_0000FFFF = D1_000000FF * multA + 0x00000080;
  301. UINT32 D3_000000FF = (D2_0000FFFF & 0x0000ff00) >> 8;
  302. UINT32 D4_0000FF00 = (D2_0000FFFF + D3_000000FF) & 0x0000FF00;
  303. alphaContrib = D4_0000FF00 >> 8;
  304. // store: (1-alpha)*0xFF + color for each B, G, R
  305. *CurBuffer++ = ((DWORD)(alphaContrib + color.GetBlue()) << GpColor::BlueShift) |
  306. ((DWORD)(alphaContrib + color.GetGreen()) << GpColor::GreenShift) |
  307. ((DWORD)(alphaContrib + color.GetRed()) << GpColor::RedShift) |
  308. (alpha << GpColor::AlphaShift);
  309. }
  310. }
  311. }
  312. OutputWidth = newWidth;
  313. #endif
  314. // return pointer directly into our 32bpp buffer
  315. return (CurBuffer = (((ARGB*)BufStart) +
  316. ((CappedBounds.Height - 1) - (y - CappedBounds.Y)) *
  317. CappedBounds.Width +
  318. (x - CappedBounds.X)));
  319. }
  320. /**************************************************************************\
  321. *
  322. * Function Description:
  323. *
  324. * NextBufferFunc24bpp - Handles output when we are rasterizing at capped
  325. * dpi to a 24bpp unpremultiplied DIB.
  326. *
  327. * Arguments:
  328. *
  329. * [IN] x - Destination pixel coordinate in destination surface
  330. * [IN] y - ""
  331. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  332. * [IN] updateWidth - Number of pixels to update in the current buffer
  333. *
  334. * Return Value:
  335. *
  336. * Points to the resulting scan buffer
  337. *
  338. * History:
  339. *
  340. * 3/9/2k ericvan
  341. * Created it.
  342. *
  343. \**************************************************************************/
  344. VOID*
  345. EpScanDIB::NextBufferFunc24bpp(
  346. INT x,
  347. INT y,
  348. INT newWidth,
  349. INT updateWidth,
  350. INT blenderNum
  351. )
  352. {
  353. LastBlenderNum = blenderNum;
  354. ASSERT(!RenderAlpha);
  355. ASSERT(newWidth >= 0);
  356. ASSERTMSG(newWidth <= CappedBounds.Width,
  357. ("Width exceeds SetBounds() request"));
  358. ASSERT(x >= CappedBounds.X && x <= (CappedBounds.X + CappedBounds.Width));
  359. ASSERT(y >= CappedBounds.Y && y <= (CappedBounds.Y + CappedBounds.Height));
  360. ASSERT((x + newWidth) <= (CappedBounds.X + CappedBounds.Width));
  361. ASSERT((ScanOptions & ScanCappedBounds) && !(ScanOptions & ScanCapped32bpp));
  362. if (OutputWidth > 0)
  363. {
  364. // compute destination location into 24bpp buffer
  365. BYTE* dstPos = BufStart + (OutputX - CappedBounds.X) * 3 +
  366. CappedStride * ((CappedBounds.Height - 1) -
  367. (OutputY - CappedBounds.Y));
  368. ARGB* srcPos = Buf32bpp;
  369. while (OutputWidth--)
  370. {
  371. // convert from 32 ARGB to 24bpp RGB
  372. #if 1
  373. // !! Remove this when we standardize on non-premultiplied
  374. GpColor color(Unpremultiply(*srcPos++));
  375. #else
  376. GpColor color(*srcPos++);
  377. #endif
  378. // NOTICE: Bytes are stored as Blue, Green, Red.
  379. *dstPos++ = (BYTE)color.GetBlue();
  380. *dstPos++ = (BYTE)color.GetGreen();
  381. *dstPos++ = (BYTE)color.GetRed();
  382. }
  383. }
  384. // record location of next scan
  385. OutputX = x;
  386. OutputY = y;
  387. OutputWidth = newWidth;
  388. return (ARGB*)Buf32bpp;
  389. }
  390. /**************************************************************************\
  391. *
  392. * Function Description:
  393. *
  394. * NextBufferFunc24bppBleed - Handles output when we are rasterizing at capped
  395. * dpi to a 24bpp unpremultiplied DIB. It bleeds
  396. * the output to left and right of the scanned area.
  397. * This prevents black jaggies from appearing in the
  398. * output.
  399. * Arguments:
  400. *
  401. * [IN] x - Destination pixel coordinate in destination surface
  402. * [IN] y - ""
  403. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  404. * [IN] updateWidth - Number of pixels to update in the current buffer
  405. *
  406. * Return Value:
  407. *
  408. * Points to the resulting scan buffer
  409. *
  410. * History:
  411. *
  412. * 3/9/2k ericvan
  413. * Created it.
  414. *
  415. \**************************************************************************/
  416. VOID*
  417. EpScanDIB::NextBufferFunc24bppBleed(
  418. INT x,
  419. INT y,
  420. INT newWidth,
  421. INT updateWidth,
  422. INT blenderNum
  423. )
  424. {
  425. LastBlenderNum = blenderNum;
  426. ASSERT(!RenderAlpha);
  427. ASSERT(newWidth >= 0);
  428. ASSERTMSG(newWidth <= CappedBounds.Width,
  429. ("Width exceeds SetBounds() request"));
  430. ASSERT(x >= CappedBounds.X && x <= (CappedBounds.X + CappedBounds.Width));
  431. ASSERT(y >= CappedBounds.Y && y <= (CappedBounds.Y + CappedBounds.Height));
  432. ASSERT((x + newWidth) <= (CappedBounds.X + CappedBounds.Width));
  433. ASSERT((ScanOptions & ScanCappedBounds) &&
  434. !(ScanOptions & ScanCapped32bpp) &&
  435. (ScanOptions & ScanBleedOut));
  436. if (OutputWidth > 0)
  437. {
  438. ARGB* srcPos = Buf32bpp;
  439. GpColor color(Unpremultiply(*srcPos));
  440. if ((OutputLastY == -1) && ((OutputY-CappedBounds.Y) != 0))
  441. {
  442. // Bleed up all previous subsequent scan lines.
  443. // compute destination location into 24bpp buffer
  444. BYTE* clearPos = BufStart + CappedStride * (CappedBounds.Height -
  445. (OutputY - CappedBounds.Y));
  446. INT capHeight = OutputY - CappedBounds.Y;
  447. for (int cntY=0; cntY<capHeight; cntY++)
  448. {
  449. for (int cntX=0; cntX<CappedBounds.Width; cntX++)
  450. {
  451. clearPos[cntX*3] = (BYTE)color.GetBlue();
  452. clearPos[cntX*3+1] = (BYTE)color.GetGreen();
  453. clearPos[cntX*3+2] = (BYTE)color.GetRed();
  454. }
  455. clearPos += CappedStride;
  456. }
  457. }
  458. // compute destination location into 24bpp buffer
  459. BYTE* dstPos = BufStart + (OutputBleed - CappedBounds.X) * 3 +
  460. CappedStride * ((CappedBounds.Height - 1) -
  461. (OutputY - CappedBounds.Y));
  462. // Bleed to the left
  463. INT count = OutputBleed;
  464. while (count++ < OutputX)
  465. {
  466. *dstPos++ = (BYTE)color.GetBlue();
  467. *dstPos++ = (BYTE)color.GetGreen();
  468. *dstPos++ = (BYTE)color.GetRed();
  469. }
  470. // Output source pixels into destination surface
  471. count = OutputWidth;
  472. while (count--)
  473. {
  474. // convert from 32 ARGB to 24bpp RGB
  475. GpColor refColor = color; // save last ARGB color
  476. color.SetValue(Unpremultiply(*srcPos++));
  477. // NTRAID#NTBUG9-436131-2001-07-13-jerryste "P1CD: Printing:When printing the image, noise will appear in the surrounding of the image."
  478. // Real problem: color bitmap and scaled-up alpha mask misalignment. halftoned low-alpha region let black see through
  479. // Problems in DriverPrint::DrawImage
  480. // 1) Calculation of boundsCap in integers has rounding error
  481. // 2) Low level scanline rendering code offset coordinates by 0.5 before rounding
  482. // 3) Scale integer version of boundsCap to boundsDev introduces more error
  483. // 4) Single precision floating-point number calculation can lose precision
  484. // We do not have a clean way to fix the real problem for the moment (7/28/01).
  485. // Workaround: Change color to (white+neighbour)/2 when alpha is low to remove black pixels. Neighbor is
  486. // either the previous pixel, or the next pixel if the previous pixel has a small alpha
  487. const BYTE smallalpha = 10;
  488. if ( color.GetAlpha()<smallalpha ) // if alpha is low
  489. {
  490. if ( ( refColor.GetAlpha()<smallalpha) && (count!=0) ) // if previous pixel has small alpha and there is next pixel
  491. refColor.SetValue(Unpremultiply(*srcPos)); // use next pixel
  492. if ( refColor.GetAlpha()>=smallalpha )
  493. {
  494. *dstPos++ = (BYTE) ( ( 255 + (UINT32) refColor.GetBlue() ) / 2 ); // blend with white
  495. *dstPos++ = (BYTE) ( ( 255 + (UINT32) refColor.GetGreen() ) / 2 );
  496. *dstPos++ = (BYTE) ( ( 255 + (UINT32) refColor.GetRed() ) / 2 );
  497. }
  498. else
  499. {
  500. *dstPos++ = 255; // set to white
  501. *dstPos++ = 255;
  502. *dstPos++ = 255;
  503. }
  504. }
  505. else
  506. {
  507. *dstPos++ = (BYTE)color.GetBlue();
  508. *dstPos++ = (BYTE)color.GetGreen();
  509. *dstPos++ = (BYTE)color.GetRed();
  510. }
  511. }
  512. // Bleed to the right
  513. if (y != OutputY)
  514. {
  515. count = CappedBounds.X + CappedBounds.Width - OutputX - OutputWidth;
  516. while (count--)
  517. {
  518. *dstPos++ = (BYTE)color.GetBlue();
  519. *dstPos++ = (BYTE)color.GetGreen();
  520. *dstPos++ = (BYTE)color.GetRed();
  521. }
  522. }
  523. // Bleed down all subsequent scan lines. This should only happen when called
  524. // implicitly by EpScanDIB::End()
  525. if ((newWidth == 0) &&
  526. (x == CappedBounds.X + CappedBounds.Width) &&
  527. (y == CappedBounds.Y + CappedBounds.Height) &&
  528. (OutputY != 0))
  529. {
  530. // Bleed down all previous subsequent scan lines.
  531. // compute destination location into 24bpp buffer
  532. BYTE* clearPos = BufStart;
  533. INT capHeight = (CappedBounds.Height - 1) - (OutputY - CappedBounds.Y);
  534. for (int cntY=0; cntY<capHeight; cntY++)
  535. {
  536. for (int cntX=0; cntX<CappedBounds.Width; cntX++)
  537. {
  538. clearPos[cntX*3] = (BYTE)color.GetBlue();
  539. clearPos[cntX*3+1] = (BYTE)color.GetGreen();
  540. clearPos[cntX*3+2] = (BYTE)color.GetRed();
  541. }
  542. clearPos += CappedStride;
  543. }
  544. }
  545. }
  546. // Compute size of bleed scan range
  547. if (y == OutputY)
  548. {
  549. ASSERT(x >= OutputX + OutputWidth);
  550. OutputBleed = OutputX + OutputWidth;
  551. }
  552. else
  553. {
  554. OutputBleed = CappedBounds.X;
  555. }
  556. OutputLastY = OutputY;
  557. OutputX = x;
  558. OutputY = y;
  559. OutputWidth = newWidth;
  560. return (ARGB*)Buf32bpp;
  561. }
  562. /**************************************************************************\
  563. *
  564. * Function Description:
  565. *
  566. * NextBufferFunc24bppOver - Handles output when we are rasterizing at capped
  567. * dpi to a 24bpp unpremultiplied DIB. We do an
  568. * implicit blend onto a white opaque surface.
  569. *
  570. * Arguments:
  571. *
  572. * [IN] x - Destination pixel coordinate in destination surface
  573. * [IN] y - ""
  574. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  575. * [IN] updateWidth - Number of pixels to update in the current buffer
  576. *
  577. * Return Value:
  578. *
  579. * Points to the resulting scan buffer
  580. *
  581. * History:
  582. *
  583. * 3/9/2k ericvan
  584. * Created it.
  585. *
  586. \**************************************************************************/
  587. VOID*
  588. EpScanDIB::NextBufferFunc24bppOver(
  589. INT x,
  590. INT y,
  591. INT newWidth,
  592. INT updateWidth,
  593. INT blenderNum
  594. )
  595. {
  596. LastBlenderNum = blenderNum;
  597. ASSERT(!RenderAlpha);
  598. ASSERT(newWidth >= 0);
  599. ASSERTMSG(newWidth <= CappedBounds.Width,
  600. ("Width exceeds SetBounds() request"));
  601. ASSERT(x >= CappedBounds.X && x <= (CappedBounds.X + CappedBounds.Width));
  602. ASSERT(y >= CappedBounds.Y && y <= (CappedBounds.Y + CappedBounds.Height));
  603. ASSERT((x + newWidth) <= (CappedBounds.X + CappedBounds.Width));
  604. ASSERT((ScanOptions & ScanCappedBounds) &&
  605. !(ScanOptions & ScanCapped32bpp) &&
  606. (ScanOptions & ScanCappedOver));
  607. if (OutputWidth > 0)
  608. {
  609. // compute destination location into 24bpp buffer
  610. BYTE* dstPos = BufStart + (OutputX - CappedBounds.X) * 3 +
  611. CappedStride * ((CappedBounds.Height - 1) -
  612. (OutputY - CappedBounds.Y));
  613. ARGB* srcPos = Buf32bpp;
  614. while (OutputWidth--)
  615. {
  616. // An adaptation of the blending code from Andrew Godfrey's
  617. // BlendOver function, but onto a white surface. This is done to
  618. // improve the output quality of postscript.
  619. GpColor color(*srcPos++);
  620. UINT32 alpha = color.GetAlpha();
  621. UINT32 alphaContrib;
  622. if (alpha == 0)
  623. {
  624. *dstPos++ = 0xFF;
  625. *dstPos++ = 0xFF;
  626. *dstPos++ = 0xFF;
  627. }
  628. else if (alpha == 255)
  629. {
  630. *dstPos++ = color.GetBlue();
  631. *dstPos++ = color.GetGreen();
  632. *dstPos++ = color.GetRed();
  633. }
  634. else
  635. {
  636. // Dst = Src + (1-Alpha) * Dst
  637. UINT32 multA = 255 - alpha;
  638. UINT32 D1_000000FF = 0xFF;
  639. UINT32 D2_0000FFFF = D1_000000FF * multA + 0x00000080;
  640. UINT32 D3_000000FF = (D2_0000FFFF & 0x0000ff00) >> 8;
  641. UINT32 D4_0000FF00 = (D2_0000FFFF + D3_000000FF) & 0x0000FF00;
  642. alphaContrib = D4_0000FF00 >> 8;
  643. // convert from 32 ARGB to 24bpp RGB
  644. // store: (1-alpha)*0xFF + color for each B, G, R
  645. *dstPos++ = (BYTE)(alphaContrib + color.GetBlue());
  646. *dstPos++ = (BYTE)(alphaContrib + color.GetGreen());
  647. *dstPos++ = (BYTE)(alphaContrib + color.GetRed());
  648. }
  649. }
  650. }
  651. // record location of next scan
  652. OutputX = x;
  653. OutputY = y;
  654. OutputWidth = newWidth;
  655. return (ARGB*)Buf32bpp;
  656. }
  657. /**************************************************************************\
  658. *
  659. * Function Description:
  660. *
  661. * NextBufferFuncAlpha - Handles output when we are rasterizing at device
  662. * dpi to a 1bpp mask, we generate the mask on the fly
  663. * using DonC's halftoning table.
  664. *
  665. * Arguments:
  666. *
  667. * [IN] x - Destination pixel coordinate in destination surface
  668. * [IN] y - ""
  669. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  670. * [IN] updateWidth - Number of pixels to update in the current buffer
  671. *
  672. * Return Value:
  673. *
  674. * Points to the resulting scan buffer
  675. *
  676. * History:
  677. *
  678. * 3/9/2k ericvan
  679. * Created it.
  680. *
  681. \**************************************************************************/
  682. VOID*
  683. EpScanDIB::NextBufferFuncAlpha(
  684. INT x,
  685. INT y,
  686. INT newWidth,
  687. INT updateWidth,
  688. INT blenderNum
  689. )
  690. {
  691. LastBlenderNum = blenderNum;
  692. ASSERT(RenderAlpha);
  693. ASSERT(newWidth >= 0);
  694. ASSERTMSG(newWidth <= DeviceBounds.Width,
  695. ("Width exceeds SetBounds() request"));
  696. ASSERT(x >= DeviceBounds.X && x <= (DeviceBounds.X + DeviceBounds.Width));
  697. ASSERT(y >= DeviceBounds.Y && y <= (DeviceBounds.Y + DeviceBounds.Height));
  698. ASSERT((x + newWidth) <= (DeviceBounds.X + DeviceBounds.Width));
  699. ASSERT((ScanOptions & ScanDeviceBounds) && (ScanOptions & ScanDeviceAlpha));
  700. if (OutputWidth > 0)
  701. {
  702. // update bounding box for this band
  703. if (OutputX < MinBound.X) MinBound.X = OutputX;
  704. if (OutputY < MinBound.Y) MinBound.Y = OutputY;
  705. if ((OutputX + OutputWidth) > MaxBound.X) MaxBound.X = OutputX + OutputWidth;
  706. if (OutputY > MaxBound.Y) MaxBound.Y = OutputY;
  707. INT startX = OutputX - DeviceBounds.X;
  708. INT endX = startX + OutputWidth;
  709. // !! Shift '91' into some global constant!?!
  710. INT orgX = OutputX % 91;
  711. INT orgY = (OutputY + TranslateHTTable) % 91;
  712. INT htIndex = orgY*91 + orgX;
  713. // compute destination location into 24bpp buffer
  714. #ifdef PRINT_BOTTOM_UP
  715. BYTE* dstPos = MaskStart +
  716. MaskStride * ((DeviceBounds.Height - 1) -
  717. (OutputY - DeviceBounds.Y)) + (startX >> 3);
  718. #else
  719. BYTE* dstPos = MaskStart +
  720. MaskStride * (OutputY - DeviceBounds.Y) + (startX >> 3);
  721. #endif
  722. ARGB* srcPos = AlphaStart;
  723. BYTE outByte = 0;
  724. // using FOR loop makes it easier to detect relative bit position
  725. for (INT xPos = startX; xPos < endX; xPos++)
  726. {
  727. GpColor color(*srcPos++);
  728. INT maskBit = color.GetAlpha() >
  729. HT_SuperCell_GreenMono[htIndex++] ? 1 : 0;
  730. outByte = (outByte << 1) | maskBit;
  731. if (((xPos+1) % 8) == 0)
  732. *dstPos++ |= outByte;
  733. if (++orgX >= 91)
  734. {
  735. orgX = 0;
  736. htIndex = orgY*91;
  737. }
  738. }
  739. // output the last partial byte
  740. if ((xPos % 8) != 0)
  741. {
  742. *dstPos |= outByte << (8 - (xPos % 8));
  743. }
  744. }
  745. // record location of next scan
  746. OutputX = x;
  747. OutputY = y;
  748. OutputWidth = newWidth;
  749. return (ARGB*)AlphaStart;
  750. }
  751. /**************************************************************************\
  752. *
  753. * Function Description:
  754. *
  755. * NextBufferFuncOpaque - Handles output when we are rasterizing at device
  756. * dpi to a 1bpp opaque mask (1 if alpha > 0, 0 otherwise)
  757. *
  758. * Arguments:
  759. *
  760. * [IN] x - Destination pixel coordinate in destination surface
  761. * [IN] y - ""
  762. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  763. * [IN] updateWidth - Number of pixels to update in the current buffer
  764. *
  765. * Return Value:
  766. *
  767. * Points to the resulting scan buffer
  768. *
  769. * History:
  770. *
  771. * 3/9/2k ericvan
  772. * Created it.
  773. *
  774. \**************************************************************************/
  775. VOID*
  776. EpScanDIB::NextBufferFuncOpaque(
  777. INT x,
  778. INT y,
  779. INT newWidth,
  780. INT updateWidth,
  781. INT blenderNum
  782. )
  783. {
  784. LastBlenderNum = blenderNum;
  785. ASSERT(RenderAlpha);
  786. ASSERT(newWidth >= 0);
  787. ASSERTMSG(newWidth <= DeviceBounds.Width,
  788. ("Width exceeds SetBounds() request"));
  789. ASSERT(x >= DeviceBounds.X && x <= (DeviceBounds.X + DeviceBounds.Width));
  790. ASSERT(y >= DeviceBounds.Y && y <= (DeviceBounds.Y + DeviceBounds.Height));
  791. ASSERT((x + newWidth) <= (DeviceBounds.X + DeviceBounds.Width));
  792. ASSERT((ScanOptions & ScanDeviceBounds) && !(ScanOptions & ScanDeviceAlpha));
  793. if (OutputWidth > 0)
  794. {
  795. // update bounding box for this band
  796. if (OutputX < MinBound.X) MinBound.X = OutputX;
  797. if (OutputY < MinBound.Y) MinBound.Y = OutputY;
  798. if ((OutputX + OutputWidth) > MaxBound.X) MaxBound.X = OutputX + OutputWidth;
  799. if (OutputY > MaxBound.Y) MaxBound.Y = OutputY;
  800. INT startX = OutputX - DeviceBounds.X;
  801. INT endX = startX + OutputWidth;
  802. // compute destination location into 24bpp buffer
  803. BYTE* dstPos = MaskStart +
  804. MaskStride * ((DeviceBounds.Height - 1) -
  805. (OutputY - DeviceBounds.Y)) + (startX >> 3);
  806. ARGB* srcPos = AlphaStart;
  807. BYTE outByte = 0;
  808. // using FOR loop makes it easier to detect relative bit position
  809. for (INT xPos = startX; xPos < endX; xPos++)
  810. {
  811. GpColor color(*srcPos++);
  812. INT maskBit = (color.GetAlpha() == 0) ? 0 : 1;
  813. outByte = (outByte << 1) | maskBit;
  814. if (((xPos+1) % 8) == 0)
  815. *dstPos++ |= outByte;
  816. }
  817. // output the last partial byte
  818. if ((xPos % 8) != 0)
  819. {
  820. *dstPos |= outByte << (8 - (xPos % 8));
  821. }
  822. }
  823. // record location of next scan
  824. OutputX = x;
  825. OutputY = y;
  826. OutputWidth = newWidth;
  827. return (ARGB*)AlphaStart;
  828. }
  829. /**************************************************************************\
  830. *
  831. * Function Description:
  832. *
  833. * NextBufferFuncZeroOut - Handles output where we aren't rasterizing to a
  834. * DIB section, but only zeroing out portions of the
  835. * the original 24bpp bitmap
  836. *
  837. * Arguments:
  838. *
  839. * [IN] x - Destination pixel coordinate in destination surface
  840. * [IN] y - ""
  841. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  842. * [IN] updateWidth - Number of pixels to update in the current buffer
  843. *
  844. * Return Value:
  845. *
  846. * Points to the resulting scan buffer
  847. *
  848. * History:
  849. *
  850. * 3/10/2k ericvan
  851. * Created it.
  852. *
  853. \**************************************************************************/
  854. VOID*
  855. EpScanDIB::NextBufferFuncZeroOut(
  856. INT x,
  857. INT y,
  858. INT newWidth,
  859. INT updateWidth,
  860. INT blenderNum
  861. )
  862. {
  863. LastBlenderNum = blenderNum;
  864. ASSERT(RenderAlpha);
  865. ASSERT(newWidth >= 0);
  866. ASSERTMSG(newWidth <= DeviceBounds.Width,
  867. ("Width exceeds SetBounds() request"));
  868. ASSERT(x >= DeviceBounds.X && x <= (DeviceBounds.X + DeviceBounds.Width));
  869. ASSERT(y >= DeviceBounds.Y && y <= (DeviceBounds.Y + DeviceBounds.Height));
  870. ASSERT((x + newWidth) <= (DeviceBounds.X + DeviceBounds.Width));
  871. ASSERT(!(ScanOptions & ScanDeviceBounds) && !(ScanOptions & ScanDeviceAlpha)
  872. && !(ScanOptions & (ScanCapped32bpp | ScanCapped32bppOver))
  873. && (ScanOptions & ScanDeviceZeroOut));
  874. ASSERT(ZeroOutPad >= 0);
  875. // THIS IS AN IMPORTANT CONDITION. If it's untrue, then we may fail to
  876. // generate proper masks in some cases. Also causes problems in zeroing out.
  877. ASSERT(y>=OutputY);
  878. if (newWidth > 0)
  879. {
  880. // update bounding box for this band
  881. if (x < MinBound.X)
  882. {
  883. MinBound.X = x;
  884. }
  885. if (y < MinBound.Y)
  886. {
  887. MinBound.Y = y;
  888. }
  889. if ((x + newWidth) > MaxBound.X)
  890. {
  891. MaxBound.X = x + newWidth;
  892. }
  893. if (y > MaxBound.Y)
  894. {
  895. MaxBound.Y = y;
  896. }
  897. }
  898. if (OutputWidth < 0)
  899. {
  900. OutputX = x;
  901. OutputY = y;
  902. }
  903. if ((y/ScaleY) != (OutputY/ScaleY))
  904. {
  905. // tally counts and zero out
  906. BYTE* bitsPtr = BufStart + CappedStride *
  907. ((CappedBounds.Height - 1) -
  908. ((OutputY/ScaleY) - CappedBounds.Y));
  909. DWORD* zeroPtr = (DWORD*) ZeroStart;
  910. INT count = CappedBounds.Width;
  911. while (count--)
  912. {
  913. if (*zeroPtr++ == 0)
  914. {
  915. *bitsPtr++ = '\0';
  916. *bitsPtr++ = '\0';
  917. *bitsPtr++ = '\0';
  918. }
  919. else
  920. {
  921. bitsPtr += 3;
  922. }
  923. }
  924. ZeroMemory(ZeroStart, (CappedBounds.Width+ZeroOutPad)*sizeof(DWORD));
  925. }
  926. // bleed the color ZeroOutPad pixels to left and right
  927. INT xPos = (x/ScaleX) - CappedBounds.X;
  928. INT count = (newWidth/ScaleX) + ((newWidth % ScaleX) ? 1 : 0) + 1;
  929. // Calculate how many pixels on the left we can pad
  930. INT subtract = min(xPos, ZeroOutPad);
  931. if (subtract > 0)
  932. {
  933. xPos -= subtract;
  934. count += subtract;
  935. }
  936. count = min(count+ZeroOutPad, CappedBounds.Width + ZeroOutPad - xPos);
  937. DWORD *zeroPtr = ((DWORD*)ZeroStart) + xPos;
  938. ASSERT((xPos+count) <= CappedBounds.Width + ZeroOutPad);
  939. while (count--)
  940. {
  941. *zeroPtr += 1;
  942. zeroPtr++;
  943. }
  944. // record location of next scan
  945. OutputX = x;
  946. OutputY = y;
  947. OutputWidth = newWidth;
  948. return (ARGB*)AlphaStart;
  949. }
  950. /**************************************************************************\
  951. *
  952. * Function Description:
  953. *
  954. * Sets the bounds of the current scan.
  955. *
  956. * Arguments:
  957. *
  958. * [IN] bounds - the bounds.
  959. *
  960. * Return Value:
  961. *
  962. * None.
  963. *
  964. * History:
  965. *
  966. * 07/13/1999 t-wehunt
  967. * Created it.
  968. *
  969. \**************************************************************************/
  970. VOID EpScanDIB::SetRenderMode(
  971. BOOL renderAlpha,
  972. GpRect *newBounds
  973. )
  974. {
  975. RenderAlpha = renderAlpha;
  976. MinBound.X = INFINITE_MAX;
  977. MinBound.Y = INFINITE_MAX;
  978. MaxBound.X = INFINITE_MIN;
  979. MaxBound.Y = INFINITE_MIN;
  980. if (RenderAlpha)
  981. {
  982. DeviceBounds = *newBounds;
  983. ZeroMemory(AlphaStart, DeviceBounds.Width * sizeof(ARGB));
  984. if (ScanOptions & ScanDeviceBounds)
  985. {
  986. ZeroMemory(MaskStart, MaskStride * DeviceBounds.Height);
  987. if (ScanOptions & ScanDeviceAlpha)
  988. {
  989. NextBuffer = (NEXTBUFFERFUNCTION) EpScanDIB::NextBufferFuncAlpha;
  990. }
  991. else
  992. {
  993. NextBuffer = (NEXTBUFFERFUNCTION) EpScanDIB::NextBufferFuncOpaque;
  994. }
  995. }
  996. else
  997. {
  998. ASSERT(ScanOptions & ScanDeviceZeroOut);
  999. ASSERT(!(ScanOptions & (ScanCapped32bpp | ScanCapped32bppOver)));
  1000. ZeroMemory(ZeroStart, (CappedBounds.Width + ZeroOutPad)*sizeof(DWORD));
  1001. NextBuffer = (NEXTBUFFERFUNCTION) EpScanDIB::NextBufferFuncZeroOut;
  1002. }
  1003. CurBuffer = AlphaStart;
  1004. }
  1005. else
  1006. {
  1007. CappedBounds = *newBounds;
  1008. if (ScanOptions & ScanCapped32bpp)
  1009. {
  1010. ZeroMemory(BufStart, CappedBounds.Width
  1011. * CappedBounds.Height * sizeof(ARGB));
  1012. NextBuffer = (NEXTBUFFERFUNCTION) NextBufferFunc32bpp;
  1013. }
  1014. else if (ScanOptions & ScanCapped32bppOver)
  1015. {
  1016. ZeroMemory(BufStart, CappedBounds.Width
  1017. * CappedBounds.Height * sizeof(ARGB));
  1018. NextBuffer = (NEXTBUFFERFUNCTION) NextBufferFunc32bppOver;
  1019. }
  1020. else
  1021. {
  1022. ASSERT(CappedStride != 0);
  1023. ZeroMemory(BufStart, CappedStride * CappedBounds.Height);
  1024. if (ScanOptions & ScanCappedOver)
  1025. {
  1026. NextBuffer = (NEXTBUFFERFUNCTION) NextBufferFunc24bppOver;
  1027. }
  1028. else
  1029. {
  1030. if (ScanOptions & ScanBleedOut)
  1031. {
  1032. NextBuffer = (NEXTBUFFERFUNCTION) NextBufferFunc24bppBleed;
  1033. }
  1034. else
  1035. {
  1036. NextBuffer = (NEXTBUFFERFUNCTION) NextBufferFunc24bpp;
  1037. }
  1038. }
  1039. CurBuffer = Buf32bpp;
  1040. }
  1041. }
  1042. OutputWidth = -1;
  1043. }
  1044. /**************************************************************************\
  1045. *
  1046. * Function Description:
  1047. *
  1048. * Flushes the current scan.
  1049. *
  1050. * Arguments:
  1051. *
  1052. * None.
  1053. *
  1054. * Return Value:
  1055. *
  1056. * None.
  1057. *
  1058. * History:
  1059. *
  1060. * 07/13/1999 t-wehunt
  1061. * Created it.
  1062. *
  1063. \**************************************************************************/
  1064. VOID
  1065. EpScanDIB::Flush()
  1066. {
  1067. }
  1068. /**************************************************************************\
  1069. *
  1070. * Function Description:
  1071. *
  1072. * Resets the DIBSection buffer, safely releasing resources and resetting
  1073. * them.
  1074. *
  1075. * Arguments:
  1076. *
  1077. * None.
  1078. *
  1079. * Return Value:
  1080. *
  1081. * None.
  1082. *
  1083. * History:
  1084. *
  1085. * 07/26/1999 t-wehunt
  1086. * Created it.
  1087. *
  1088. \**************************************************************************/
  1089. VOID
  1090. EpScanDIB::DestroyBufferDIB()
  1091. {
  1092. if (BufStart != NULL)
  1093. {
  1094. GpFree(BufStart);
  1095. }
  1096. if (AlphaStart != NULL)
  1097. {
  1098. GpFree(AlphaStart);
  1099. }
  1100. BufStart = NULL;
  1101. Buf32bpp = NULL;
  1102. CurBuffer = NULL;
  1103. // Transparency mask
  1104. MaskStart = NULL;
  1105. // Alpha buffer
  1106. AlphaStart = NULL;
  1107. ZeroStart = NULL;
  1108. RenderAlpha = FALSE;
  1109. ScanOptions = 0;
  1110. OutputWidth = -1;
  1111. NextBuffer = NULL;
  1112. }
  1113. /**************************************************************************\
  1114. *
  1115. * Function Description:
  1116. *
  1117. * In pre-multiplies an ARGB value
  1118. *
  1119. * Arguments:
  1120. *
  1121. *
  1122. * Return Value:
  1123. *
  1124. * GpStatus.
  1125. *
  1126. * History:
  1127. *
  1128. * 10/08/1999 ericvan
  1129. * Created it.
  1130. *
  1131. \**************************************************************************/
  1132. GpStatus
  1133. EpScanDIB::CreateBufferDIB(
  1134. const GpRect* BoundsCap,
  1135. const GpRect* BoundsDev,
  1136. DWORD options,
  1137. INT scaleX,
  1138. INT scaleY)
  1139. {
  1140. ScanOptions = options;
  1141. CappedBounds = *BoundsCap;
  1142. DeviceBounds = *BoundsDev;
  1143. ScaleX = scaleX;
  1144. ScaleY = scaleY;
  1145. if (options & ScanCappedBounds)
  1146. {
  1147. ZeroMemory(&Buf.BMI, sizeof(Buf.BMI));
  1148. Buf.BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1149. Buf.BMI.bmiHeader.biWidth = CappedBounds.Width;
  1150. Buf.BMI.bmiHeader.biHeight = CappedBounds.Height;
  1151. Buf.BMI.bmiHeader.biPlanes = 1;
  1152. if (options & (ScanCapped32bpp | ScanCapped32bppOver))
  1153. {
  1154. RGBQUAD red = { 0, 0, 0xFF, 0}; // red
  1155. RGBQUAD green = { 0, 0xFF, 0, 0}; // green
  1156. RGBQUAD blue = { 0xFF, 0, 0, 0}; // blue
  1157. Buf.BMI.bmiColors[0] = red;
  1158. Buf.BMI.bmiColors[1] = green;
  1159. Buf.BMI.bmiColors[2] = blue;
  1160. Buf.BMI.bmiHeader.biBitCount = 32;
  1161. Buf.BMI.bmiHeader.biCompression = BI_BITFIELDS;
  1162. }
  1163. else
  1164. {
  1165. Buf.BMI.bmiHeader.biHeight += 2;
  1166. Buf.BMI.bmiHeader.biBitCount = 24;
  1167. Buf.BMI.bmiHeader.biClrUsed = 0;
  1168. Buf.BMI.bmiHeader.biCompression = BI_RGB;
  1169. }
  1170. if (options & (ScanCapped32bpp | ScanCapped32bppOver))
  1171. {
  1172. CappedStride = CappedBounds.Width*sizeof(ARGB);
  1173. }
  1174. else
  1175. {
  1176. // use extra allocation at the end of DIB for temp 32bpp storage
  1177. CappedStride = RoundDWORD((CappedBounds.Width * 3));
  1178. }
  1179. BufStart = (BYTE*) GpMalloc(CappedStride *
  1180. Buf.BMI.bmiHeader.biHeight);
  1181. if (BufStart == NULL)
  1182. return OutOfMemory;
  1183. if (options & (ScanCapped32bpp | ScanCapped32bppOver))
  1184. {
  1185. Buf32bpp = NULL;
  1186. }
  1187. else
  1188. {
  1189. Buf.BMI.bmiHeader.biHeight -= 2;
  1190. Buf32bpp = (ARGB*) (BufStart + CappedStride*CappedBounds.Height);
  1191. }
  1192. }
  1193. else
  1194. {
  1195. BufStart = NULL;
  1196. Buf32bpp = NULL;
  1197. }
  1198. if (options & ScanDeviceBounds)
  1199. {
  1200. ZeroMemory(&Mask.BMI, sizeof(Mask.BMI));
  1201. // if we do zeroing out of the capped bitmap, then we require that
  1202. // their sizes be an integer ratio of each other (device>= capped).
  1203. ASSERT(!(options & ScanDeviceZeroOut) ||
  1204. ((options & ScanDeviceZeroOut) &&
  1205. IsInteger((REAL)DeviceBounds.Height/(REAL)CappedBounds.Height) &&
  1206. IsInteger((REAL)DeviceBounds.Width/(REAL)CappedBounds.Width)));
  1207. ASSERT(DeviceBounds.Height > 0);
  1208. Mask.BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1209. Mask.BMI.bmiHeader.biWidth = DeviceBounds.Width;
  1210. Mask.BMI.bmiHeader.biHeight = DeviceBounds.Height;
  1211. Mask.BMI.bmiHeader.biPlanes = 1;
  1212. Mask.BMI.bmiHeader.biBitCount = 1;
  1213. Mask.BMI.bmiHeader.biCompression = BI_RGB;
  1214. RGBQUAD opaque = { 0,0,0,0 };
  1215. RGBQUAD transparent = { 0xFF, 0xFF, 0xFF, 0xFF };
  1216. Mask.BMI.bmiColors[0] = transparent;
  1217. Mask.BMI.bmiColors[1] = opaque;
  1218. MaskStride = (DeviceBounds.Width - 1) >> 3;
  1219. MaskStride = MaskStride + (sizeof(DWORD) - MaskStride % sizeof(DWORD));
  1220. INT AlphaSize = DeviceBounds.Width * sizeof(ARGB);
  1221. AlphaStart = (ARGB*) GpMalloc(MaskStride * DeviceBounds.Height +
  1222. AlphaSize);
  1223. if (AlphaStart == NULL)
  1224. {
  1225. return OutOfMemory;
  1226. }
  1227. // device space bounds only for alpha channel
  1228. MaskStart = (BYTE*)(AlphaStart) + AlphaSize;
  1229. ASSERT(MaskStart != NULL);
  1230. ZeroStart = NULL;
  1231. }
  1232. else
  1233. {
  1234. MaskStart = NULL;
  1235. if (ScanOptions & ScanDeviceZeroOut)
  1236. {
  1237. // device space bounds only for alpha channel
  1238. AlphaStart = (ARGB*) GpMalloc(DeviceBounds.Width * sizeof(ARGB) +
  1239. (CappedBounds.Width+ZeroOutPad) * sizeof(DWORD));
  1240. if (AlphaStart == NULL)
  1241. return OutOfMemory;
  1242. // array for maintaining zero out counts
  1243. ZeroStart = (BYTE*)(AlphaStart + DeviceBounds.Width);
  1244. }
  1245. else
  1246. {
  1247. AlphaStart = NULL;
  1248. ZeroStart = NULL;
  1249. }
  1250. }
  1251. // To prevent bad output when overlapping images have same alpha value
  1252. // we increment our position in the HT Table matrix.
  1253. TranslateHTTable++;
  1254. // NOTE: We don't bother filling the monochrome DIB with 0's or 1's
  1255. return Ok;
  1256. }
  1257. BOOL EpScanDIB::GetActualBounds(GpRect *rect)
  1258. {
  1259. if (!(ScanOptions & (ScanDeviceBounds | ScanDeviceZeroOut)))
  1260. {
  1261. rect->X = 0;
  1262. rect->Y = 0;
  1263. rect->Width = DeviceBounds.Width;
  1264. rect->Height = DeviceBounds.Height;
  1265. return TRUE;
  1266. }
  1267. if (MaxBound.X <= 0)
  1268. {
  1269. return FALSE;
  1270. }
  1271. ASSERT(MaxBound.X > -1 && MaxBound.Y > -1);
  1272. GpRect tempRect;
  1273. // relative to (0, 0) in device units (not device space)
  1274. tempRect.X = (rect->X = MinBound.X - DeviceBounds.X);
  1275. tempRect.Y = (rect->Y = MinBound.Y - DeviceBounds.Y);
  1276. rect->Width = MaxBound.X - MinBound.X;
  1277. rect->Height = MaxBound.Y - MinBound.Y + 1;
  1278. // Round bounds to multiples of ScaleX, ScaleY. This is so
  1279. // We map between capped and device rectangles easily
  1280. rect->X = (rect->X / ScaleX) * ScaleX;
  1281. rect->Y = (rect->Y / ScaleY) * ScaleY;
  1282. rect->Width = rect->Width + tempRect.X - rect->X;
  1283. rect->Height = rect->Height + tempRect.Y - rect->Y;
  1284. INT remainderX = rect->Width % ScaleX;
  1285. INT remainderY = rect->Height % ScaleY;
  1286. if (remainderX > 0) rect->Width += (ScaleX - remainderX);
  1287. if (remainderY > 0) rect->Height += (ScaleY - remainderY);
  1288. ASSERT((rect->X + rect->Width) <= (DeviceBounds.Width + ScaleX));
  1289. ASSERT((rect->Y + rect->Height) <= (DeviceBounds.Height + ScaleY));
  1290. return TRUE;
  1291. }
  1292. // !! Out of commission for the time being.
  1293. #if 0
  1294. /**************************************************************************\
  1295. *
  1296. * Function Description:
  1297. *
  1298. * Creates a monochrome bitmap from the alpha channel of the DIB.
  1299. * This code uses DonC's halftoning table cells to determine the pattern
  1300. * for use in mask generation.
  1301. *
  1302. * NOTE: The mask is generated at device Dpi not capped Dpi.
  1303. *
  1304. * Arguments:
  1305. *
  1306. * zeroOut - only modify the original DIB for non-Postscript since we
  1307. * OR the dib in. For PS, we use imagemask exclusively.
  1308. *
  1309. * Return Value:
  1310. *
  1311. * GpStatus.
  1312. *
  1313. * History:
  1314. *
  1315. * 10/08/1999 ericvan
  1316. * Created it.
  1317. *
  1318. \**************************************************************************/
  1319. GpStatus
  1320. EpScanDIB::CreateAlphaMask()
  1321. {
  1322. DWORD MaskStride;
  1323. MaskStride = (ScanBounds.Width - 1) >> 3;
  1324. MaskStride = MaskStride + ( 4 - (MaskStride % 4));
  1325. // SetBounds() multiplies the ScanBounds for the DPI scaling.
  1326. INT width = ScanBounds.Width;
  1327. INT height = ScanBounds.Height;
  1328. INT orgXsrc = ScanBounds.X + TranslateHTTable;
  1329. INT orgYsrc = ScanBounds.Y + TranslateHTTable;
  1330. BYTE* dst = MaskStart;
  1331. BYTE* src = AlphaStart;
  1332. ARGB* orig = BufStart;
  1333. INT srcStride = ScanBounds.Width;
  1334. INT dstStride = MaskStride;
  1335. if (width == 0)
  1336. {
  1337. return GenericError;
  1338. }
  1339. for (INT yPos=0; yPos < height; yPos++)
  1340. {
  1341. src = AlphaStart + yPos*srcStride;
  1342. dst = MaskStart + yPos*dstStride;
  1343. INT orgX = orgXsrc % 91;
  1344. INT orgY = orgYsrc % 91;
  1345. INT htStartX = orgX;
  1346. INT htStartRow = orgY * 91;
  1347. INT htIndex = htStartRow + orgX;
  1348. BYTE outByte = 0;
  1349. for (INT xPos=0; xPos < width; xPos++)
  1350. {
  1351. // unpremultiply or zero out only once per pixel of source image
  1352. // at capped DPI
  1353. if (((yPos % MaskScaleY) == 0) && ((xPos % MaskScaleX) == 0))
  1354. {
  1355. // Check if we should ZERO out his pixel in the original
  1356. // source image. We do so if all alpha values for this pixel
  1357. // in the device DPI alpha image are 0. This is done for
  1358. // better compression in the postscript output case.
  1359. BOOL zeroIt = TRUE;
  1360. for (INT xTmp=0; xTmp < MaskScaleX; xTmp++)
  1361. {
  1362. for (INT yTmp=0; yTmp < MaskScaleY; yTmp++)
  1363. {
  1364. if (*(src + xTmp + (yTmp * srcStride)) != 0)
  1365. {
  1366. zeroIt = FALSE;
  1367. break;
  1368. }
  1369. }
  1370. }
  1371. if (zeroIt)
  1372. *orig = 0;
  1373. else
  1374. *orig = Unpremultiply(*(ARGB*)orig);
  1375. orig++;
  1376. }
  1377. INT maskBit = *src++ > HT_SuperCell_GreenMono[htIndex] ? 0 : 1;
  1378. outByte = (outByte << 1) | maskBit;
  1379. if (((xPos+1) % 8) == 0)
  1380. *dst++ = outByte;
  1381. htIndex++;
  1382. if (++orgX >= 91)
  1383. {
  1384. orgX = 0;
  1385. htIndex = htStartRow;
  1386. }
  1387. }
  1388. // output last partial byte
  1389. if ((xPos % 8) != 0)
  1390. {
  1391. // shift remaining bits & output
  1392. outByte = outByte << (8 - (xPos % 8));
  1393. *dst = outByte;
  1394. }
  1395. orgYsrc++;
  1396. }
  1397. return Ok;
  1398. }
  1399. /**************************************************************************\
  1400. *
  1401. * Function Description:
  1402. *
  1403. * Creates a 0-1 bitmap where we know the alpha channel is always
  1404. * 0x00 or 0xFF. We iterate through the bits and where-ever pixel is != 0 we
  1405. * output a 1 otherwise a 0. This is better than the Floyd-Steinberg
  1406. * which still produces spurious 0 bits even though there shouldn't really
  1407. * be any.
  1408. *
  1409. * Arguments:
  1410. *
  1411. * Return Value:
  1412. *
  1413. * GpStatus.
  1414. *
  1415. * History:
  1416. *
  1417. * 10/08/1999 ericvan
  1418. * Created it.
  1419. *
  1420. \**************************************************************************/
  1421. GpStatus
  1422. EpScanDIB::CreateOpaqueMask()
  1423. {
  1424. ARGB* orig = BufStart;
  1425. BYTE* AlphaPos = AlphaStart;
  1426. BYTE* MaskPos = MaskStart;
  1427. INT DstWidth = ScanBounds.Width;
  1428. INT DstHeight = ScanBounds.Height;
  1429. INT SrcWidth = ScanBounds.Width;
  1430. INT &Height = ScanBounds.Height;
  1431. LONG BitStride = (DstWidth - 1) >> 3;
  1432. BitStride = BitStride + (4 - (BitStride % 4));
  1433. BYTE outByte = 0;
  1434. for (INT y=0; y<DstHeight; y++)
  1435. {
  1436. AlphaPos = AlphaStart + SrcWidth*y;
  1437. MaskPos = MaskStart + BitStride*y;
  1438. for (INT x=0; x<DstWidth; x++)
  1439. {
  1440. if (((y % MaskScaleY) == 0) && ((x % MaskScaleX) == 0))
  1441. {
  1442. // Check if we should ZERO out his pixel in the original
  1443. // source image. We do so if all alpha values for this pixel
  1444. // in the device DPI alpha image are 0. This is done for
  1445. // better compression in the postscript output case.
  1446. BOOL zeroIt = TRUE;
  1447. for (INT xTmp=0; xTmp < MaskScaleX; xTmp++)
  1448. {
  1449. for (INT yTmp=0; yTmp < MaskScaleY; yTmp++)
  1450. {
  1451. if (*(AlphaPos + xTmp + (yTmp * SrcWidth)) != 0)
  1452. {
  1453. zeroIt = FALSE;
  1454. break;
  1455. }
  1456. }
  1457. }
  1458. // no need to unpremultiply since this is a 0-1 source image
  1459. if (zeroIt)
  1460. *orig = 0;
  1461. orig++;
  1462. }
  1463. BYTE alpha = *AlphaPos++;
  1464. outByte = (outByte << 1) | ((alpha != 0) ? 0:1);
  1465. if (((x + 1) % 8) == 0)
  1466. *MaskPos++ = outByte;
  1467. }
  1468. if ((x % 8) != 0)
  1469. {
  1470. *MaskPos = (BYTE)(outByte << (8 - (x % 8)));
  1471. }
  1472. }
  1473. return Ok;
  1474. }
  1475. #endif