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.

1251 lines
29 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. Module Name:
  4. compress.c
  5. Abstract:
  6. This module contains all data compression functions which analyze source
  7. scan line data and determines which compressin method (if any) is best to
  8. send the RTL data to the target device with a minimum number of bytes.
  9. Author:
  10. 18-Feb-1994 Fri 09:50:08 created
  11. [Environment:]
  12. GDI Device Driver - Plotter.
  13. [Notes:]
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #define DBG_PLOTFILENAME DbgCompress
  19. #define DBG_TIFF 0x00000001
  20. #define DBG_DELTA 0x00000002
  21. #define DBG_COMPRESS 0x00000004
  22. #define DBG_OUTRTLSCAN 0x00000008
  23. #define DBG_FLUSHADAPTBUF 0x00000010
  24. #define DBG_ENTERRTLSCANS 0x00000020
  25. #define DBG_DELTA_OFFSET0 0x00000040
  26. #define DBG_NO_DELTA 0x40000000
  27. #define DBG_NO_TIFF 0x80000000
  28. DEFINE_DBGVAR(0);
  29. #define TIFF_MIN_REPEATS 3
  30. #define TIFF_MAX_REPEATS 128
  31. #define TIFF_MAX_LITERAL 128
  32. #define DELTA_MAX_ONE_REPLACE 8
  33. #define DELTA_MAX_1ST_OFFSET 31
  34. #define MIN_BLOCK_MODE_SIZE 8
  35. //
  36. // The MAX_ADAPT_SIZE is used to leave room for SET_ADAPT_CONTROL
  37. //
  38. #if (OUTPUT_BUFFER_SIZE >= (1024 * 32))
  39. #define MAX_ADAPT_SIZE ((1024 * 32) - 16)
  40. #else
  41. #define MAX_ADAPT_SIZE (OUTPUT_BUFFER_SIZE - 16)
  42. #endif
  43. #define ADAPT_METHOD_ZERO 4
  44. #define ADAPT_METHOD_DUP 5
  45. #define SIZE_ADAPT_CONTROL 3
  46. #define SET_ADAPT_CONTROL(pPDev, m, c) \
  47. { \
  48. BYTE bAdaptCtrl[4]; \
  49. \
  50. bAdaptCtrl[0] = (BYTE)(m); \
  51. bAdaptCtrl[1] = (BYTE)(((c) >> 8) & 0xFF); \
  52. bAdaptCtrl[2] = (BYTE)(((c) ) & 0xFF); \
  53. OutputBytes(pPDev, bAdaptCtrl, 3); \
  54. }
  55. BOOL
  56. FlushAdaptBuf(
  57. PPDEV pPDev,
  58. PRTLSCANS pRTLScans,
  59. BOOL FlushEmptyDup
  60. )
  61. /*++
  62. Routine Description:
  63. This function flushes the adaptive encoding buffer mode.
  64. Arguments:
  65. pPDev - Pointer to our PDEV
  66. pRTLScans - Pointer to the RTLSCANS data structure
  67. FlushEmptyDup - TRUE if cEmptyDup need to be flush out also
  68. Return Value:
  69. TRUE if OK,
  70. Author:
  71. 09-Mar-1994 Wed 20:32:31 created
  72. Revision History:
  73. --*/
  74. {
  75. DWORD Count;
  76. WORD cEmptyDup;
  77. BOOL Ok = TRUE;
  78. Count = pPDev->cbBufferBytes;
  79. if (cEmptyDup = (FlushEmptyDup) ? pRTLScans->cEmptyDup : 0) {
  80. Count += SIZE_ADAPT_CONTROL;
  81. }
  82. if (Count) {
  83. DWORD cbBufferBytes;
  84. BYTE TmpBuf[32];
  85. PLOTDBG(DBG_FLUSHADAPTBUF, ("FlushAdaptBuf: Flush total %ld byte block",
  86. Count));
  87. //
  88. // SAVE the OutputBuffer for this temporary header
  89. //
  90. CopyMemory(TmpBuf, pPDev->pOutBuffer, sizeof(TmpBuf));
  91. cbBufferBytes = pPDev->cbBufferBytes;
  92. pPDev->cbBufferBytes = 0;
  93. //
  94. // Now output the header
  95. //
  96. OutputBytes(pPDev, "\033*b", 3);
  97. if (!pRTLScans->cAdaptBlk) {
  98. pRTLScans->cAdaptBlk++;
  99. OutputBytes(pPDev, "5m", 2);
  100. }
  101. OutputFormatStr(pPDev, "#dW", Count);
  102. //
  103. // FLUSH OUTPUT BUFFER AND RESTORE BACK the OutputBuffer for this
  104. // temporary header
  105. //
  106. PLOTDBG(DBG_FLUSHADAPTBUF, ("FlushAdaptBuf: Flush TmpBuf[%ld] bytes of HEADER",
  107. pPDev->cbBufferBytes));
  108. FlushOutBuffer(pPDev);
  109. CopyMemory(pPDev->pOutBuffer, TmpBuf, sizeof(TmpBuf));
  110. pPDev->cbBufferBytes = cbBufferBytes;
  111. if (cEmptyDup) {
  112. PLOTDBG(DBG_FLUSHADAPTBUF, ("FlushAdaptBuf: Add %ld EmptyDup [%ld]",
  113. (DWORD)cEmptyDup, (DWORD)pRTLScans->AdaptMethod));
  114. SET_ADAPT_CONTROL(pPDev, pRTLScans->AdaptMethod, cEmptyDup);
  115. pRTLScans->cEmptyDup = 0;
  116. }
  117. Ok = FlushOutBuffer(pPDev);
  118. //
  119. // After the block been sent the seed row is back to zero
  120. //
  121. ZeroMemory(pRTLScans->pbSeedRows[0],
  122. (DWORD)pRTLScans->cxBytes * (DWORD)pRTLScans->Planes);
  123. }
  124. return(Ok);
  125. }
  126. VOID
  127. ExitRTLScans(
  128. PPDEV pPDev,
  129. PRTLSCANS pRTLScans
  130. )
  131. /*++
  132. Routine Description:
  133. This function completes processing of the SCANS data.
  134. Arguments:
  135. pPDev - Pointer to our PDEV
  136. pRTLScans - Pointer to the RTLSCANS data structure to be initialized
  137. Return Value:
  138. TRUE if sucessful, FALSE if failed
  139. Author:
  140. 22-Feb-1994 Tue 12:14:17 created
  141. Revision History:
  142. --*/
  143. {
  144. if (pRTLScans->CompressMode == COMPRESS_MODE_ADAPT) {
  145. FlushAdaptBuf(pPDev, pRTLScans, TRUE);
  146. }
  147. if (pRTLScans->pbCompress) {
  148. LocalFree(pRTLScans->pbCompress);
  149. }
  150. ZeroMemory(pRTLScans, sizeof(RTLSCANS));
  151. }
  152. VOID
  153. EnterRTLScans(
  154. PPDEV pPDev,
  155. PRTLSCANS pRTLScans,
  156. DWORD cx,
  157. DWORD cy,
  158. BOOL MonoBmp
  159. )
  160. /*++
  161. Routine Description:
  162. This function initializes the RTLSCANS structure and determines which
  163. compression of the available compressions is best.
  164. Arguments:
  165. pPDev - Pointer to our PDEV
  166. pRTLScans - Pointer to the RTLSCANS data structure to be initialized
  167. cx - Width of pixel per scans
  168. cy - Height of pixel data
  169. MonoBmp - True if a monochrome bitmap.
  170. Return Value:
  171. TRUE if sucessful, FALSE if failed
  172. Author:
  173. 22-Feb-1994 Tue 12:14:17 created
  174. 11-Mar-1994 Fri 19:23:34 updated
  175. Only flush the output buffer if we are really in ADAPTIVE mode
  176. Revision History:
  177. --*/
  178. {
  179. RTLSCANS RTLScans;
  180. DWORD AllocSize;
  181. DWORD MinBlkSize;
  182. RTLScans.Flags = (RTLScans.cScans = cy) ? RTLSF_MORE_SCAN : 0;
  183. RTLScans.pbCompress =
  184. RTLScans.pbSeedRows[0] =
  185. RTLScans.pbSeedRows[1] =
  186. RTLScans.pbSeedRows[2] = NULL;
  187. RTLScans.cEmptyDup = 0;
  188. RTLScans.AdaptMethod = 0xFF;
  189. RTLScans.cAdaptBlk = 0;
  190. RTLScans.cxBytes = (DWORD)((cx + 7) >> 3);
  191. RTLScans.CompressMode = COMPRESS_MODE_ROW;
  192. RTLScans.MaxAdaptBufSize = MAX_ADAPT_SIZE;
  193. if (!(RTLScans.Mask = (BYTE)(~(0xFF >> (cx & 0x07))))) {
  194. //
  195. // Exact at byte boundary
  196. //
  197. RTLScans.Mask = 0xFF;
  198. }
  199. MinBlkSize = 8;
  200. if (MonoBmp) {
  201. RTLScans.Planes = 1;
  202. AllocSize = (DWORD)(RTLScans.cxBytes << 1);
  203. if (RTLMONOENCODE_5(pPDev)) {
  204. PLOTDBG(DBG_ENTERRTLSCANS, ("EnterRTLScans: Using Adaptive Mode Compression"));
  205. RTLScans.CompressMode = COMPRESS_MODE_ADAPT;
  206. MinBlkSize = 4;
  207. }
  208. } else {
  209. RTLScans.Planes = 3;
  210. AllocSize = (DWORD)(RTLScans.cxBytes << 2);
  211. }
  212. if ((RTLScans.cxBytes <= MinBlkSize) ||
  213. (!(RTLScans.pbCompress = (LPBYTE)LocalAlloc(LPTR, AllocSize)))) {
  214. BYTE Buf[4];
  215. RTLScans.CompressMode = COMPRESS_MODE_BLOCK;
  216. OutputFormatStr(pPDev,
  217. "\033*b4m#dW",
  218. 4 + (RTLScans.cxBytes * RTLScans.Planes * cy));
  219. Buf[0] = (BYTE)((cx >> 24) & 0xFF);
  220. Buf[1] = (BYTE)((cx >> 16) & 0xFF);
  221. Buf[2] = (BYTE)((cx >> 8) & 0xFF);
  222. Buf[3] = (BYTE)((cx ) & 0xFF);
  223. OutputBytes(pPDev, Buf, 4);
  224. } else if (RTLScans.CompressMode == COMPRESS_MODE_ADAPT) {
  225. //
  226. // We first need to flush the current output buffer in order to make
  227. // room for the Adaptive method
  228. //
  229. FlushOutBuffer(pPDev);
  230. }
  231. if (RTLScans.pbCompress) {
  232. RTLScans.pbSeedRows[0] = RTLScans.pbCompress + RTLScans.cxBytes;
  233. if (!MonoBmp) {
  234. RTLScans.pbSeedRows[1] = RTLScans.pbSeedRows[0] + RTLScans.cxBytes;
  235. RTLScans.pbSeedRows[2] = RTLScans.pbSeedRows[1] + RTLScans.cxBytes;
  236. }
  237. }
  238. *pRTLScans = RTLScans;
  239. }
  240. LONG
  241. CompressToDelta(
  242. LPBYTE pbSrc,
  243. LPBYTE pbSeedRow,
  244. LPBYTE pbDst,
  245. LONG Size
  246. )
  247. /*++
  248. Routine Description:
  249. This function compresses the input scan data with delta encoding, by
  250. determining the differences from the current seed row.
  251. Arguments:
  252. pbSrc - Pointer to the source to be compressed
  253. pbSeedRow - Pointer to the previous seed row
  254. pbDst - Pointer to the compress buffer
  255. Size - Size of the pointers
  256. Return Value:
  257. LONG - the compress buffer size
  258. >0 - Size of the buffer
  259. =0 - The data is same as previouse line
  260. <0 - Size is larger than the Size passed
  261. Author:
  262. 22-Feb-1994 Tue 14:41:18 created
  263. Revision History:
  264. --*/
  265. {
  266. LPBYTE pbDstBeg;
  267. LPBYTE pbDstEnd;
  268. LPBYTE pbTmp;
  269. LONG cSrcBytes;
  270. LONG Offset;
  271. UINT cReplace;
  272. BOOL DoReplace;
  273. #if DBG
  274. if (DBG_PLOTFILENAME & DBG_NO_DELTA) {
  275. return(-Size);
  276. }
  277. #endif
  278. cSrcBytes = Size;
  279. pbDstBeg = pbDst;
  280. pbDstEnd = pbDst + Size;
  281. cReplace = 0;
  282. pbTmp = pbSrc;
  283. while (cSrcBytes--) {
  284. //
  285. // We need to do byte replacement now
  286. //
  287. if (*pbSrc != *pbSeedRow) {
  288. if (++cReplace == 1) {
  289. //
  290. // The pbTmp is the next byte to the last replacement byte.
  291. // After we find the first difference, between the seed row
  292. // and the current row pbTmp becomes the first byte of the
  293. // source data that is different than the seed.
  294. //
  295. Offset = (LONG)(pbSrc - pbTmp);
  296. pbTmp = pbSrc;
  297. }
  298. DoReplace = (BOOL)((cReplace >= DELTA_MAX_ONE_REPLACE) ||
  299. (!cSrcBytes));
  300. } else {
  301. DoReplace = (BOOL)cReplace;
  302. }
  303. if (DoReplace) {
  304. //
  305. // At the very least we need one command byte and a replace count
  306. // byte.
  307. //
  308. if ((LONG)(pbDstEnd - pbDst) <= (LONG)cReplace) {
  309. PLOTDBG(DBG_DELTA, ("CompressToDelta: 1ST_OFF: Dest Size is larger, give up"));
  310. return(-Size);
  311. }
  312. PLOTDBG(DBG_DELTA, ("CompressToDelta: Replace=%ld, Offset=%ld",
  313. (DWORD)cReplace, (DWORD)Offset));
  314. //
  315. // Set commmand byte to replacement count
  316. //
  317. *pbDst = (BYTE)((cReplace - 1) << 5);
  318. //
  319. // Add in the offset to the same destination byte
  320. //
  321. if (Offset < DELTA_MAX_1ST_OFFSET) {
  322. *pbDst++ |= (BYTE)Offset;
  323. } else {
  324. //
  325. // We need to send more than one offset, NOTE: We must
  326. // send an extra 0 if the offset is equal to 31 or 255
  327. //
  328. *pbDst++ |= (BYTE)DELTA_MAX_1ST_OFFSET;
  329. Offset -= DELTA_MAX_1ST_OFFSET;
  330. do {
  331. if (!Offset) {
  332. PLOTDBG(DBG_DELTA_OFFSET0,
  333. ("CompressToDelta: Extra 0 offset SENT"));
  334. }
  335. if (pbDst >= pbDstEnd) {
  336. PLOTDBG(DBG_DELTA, ("CompressToDelta: Dest Size is larger, give up"));
  337. return(-Size);
  338. }
  339. *pbDst++ = (BYTE)((Offset >= 255) ? 255 : Offset);
  340. } while ((Offset -= 255) >= 0);
  341. }
  342. //
  343. // Now copy down the replacement bytes, if we mess up then this
  344. // pb1stDiff will be NULL
  345. //
  346. CopyMemory(pbDst, pbTmp, cReplace);
  347. pbDst += cReplace;
  348. pbTmp += cReplace;
  349. cReplace = 0;
  350. }
  351. //
  352. // Advanced source/seed row pointers
  353. //
  354. ++pbSrc;
  355. ++pbSeedRow;
  356. }
  357. PLOTDBG(DBG_DELTA, ("CompressToDelta: Compress from %ld to %ld, save=%ld",
  358. Size, (DWORD)(pbDst - pbDstBeg),
  359. Size - (DWORD)(pbDst - pbDstBeg)));
  360. return((LONG)(pbDst - pbDstBeg));
  361. }
  362. LONG
  363. CompressToTIFF(
  364. LPBYTE pbSrc,
  365. LPBYTE pbDst,
  366. LONG Size
  367. )
  368. /*++
  369. Routine Description:
  370. This function takes the source data and compresses it into the TIFF
  371. packbits format into the destination buffer pbDst.
  372. The TIFF packbits compression format consists of a CONTROL byte followed
  373. by the BYTE data. The CONTROL byte has the following range.
  374. -1 to -127 = The data byte followed by the control byte is repeated
  375. ( -(Control Byte) + 1 ) times.
  376. 0 to 127 = There are 1 to 128 literal bytes following the CONTROL byte.
  377. The count is = (Control Byte + 1)
  378. -128 = NOP
  379. Arguments:
  380. pbSrc - The source data to be compressed
  381. pbDst - The compressed TIFF packbits format data
  382. Size - Count of the data in the source and destination
  383. Return Value:
  384. >0 - Compress sucessful and return value is the total bytes in pbDst
  385. =0 - All bytes are zero nothing to be compressed.
  386. <0 - Compress data is larger than the source, compression failed and
  387. pbDst has no valid data.
  388. Author:
  389. 18-Feb-1994 Fri 09:54:47 created
  390. 24-Feb-1994 Thu 10:43:01 updated
  391. Changed the logic so when multiple MAX repeats count is sent and last
  392. repeat chunck is less than TIFF_MIN_REPEATS then we will treat that as
  393. literal to save more space
  394. Revision History:
  395. --*/
  396. {
  397. LPBYTE pbSrcBeg;
  398. LPBYTE pbSrcEnd;
  399. LPBYTE pbDstBeg;
  400. LPBYTE pbDstEnd;
  401. LPBYTE pbLastRepeat;
  402. LPBYTE pbTmp;
  403. LONG RepeatCount;
  404. LONG LiteralCount;
  405. LONG CurSize;
  406. BYTE LastSrc;
  407. #if DBG
  408. if (DBG_PLOTFILENAME & DBG_NO_TIFF) {
  409. return(-Size);
  410. }
  411. #endif
  412. pbSrcBeg = pbSrc;
  413. pbSrcEnd = pbSrc + Size;
  414. pbDstBeg = pbDst;
  415. pbDstEnd = pbDst + Size;
  416. pbLastRepeat = pbSrc;
  417. while (pbSrcBeg < pbSrcEnd) {
  418. pbTmp = pbSrcBeg;
  419. LastSrc = *pbTmp++;
  420. while ((pbTmp < pbSrcEnd) &&
  421. (*pbTmp == LastSrc)) {
  422. ++pbTmp;
  423. }
  424. if (((RepeatCount = (LONG)(pbTmp - pbSrcBeg)) >= TIFF_MIN_REPEATS) ||
  425. (pbTmp >= pbSrcEnd)) {
  426. //
  427. // Check to see if we are repeating ZERO's to the end of the
  428. // scan line, if such is the case. Simply mark the line as
  429. // autofill ZERO to the end, and exit.
  430. //
  431. LiteralCount = (LONG)(pbSrcBeg - pbLastRepeat);
  432. if ((pbTmp >= pbSrcEnd) &&
  433. (RepeatCount) &&
  434. (LastSrc == 0)) {
  435. if (RepeatCount == Size) {
  436. PLOTDBG(DBG_TIFF,
  437. ("CompressToTIFF: All data = 0, size=%ld", Size));
  438. return(0);
  439. }
  440. PLOTDBG(DBG_TIFF,
  441. ("CompressToTIFF: Last Chunck of Repeats (%ld) is Zeros, Skip it",
  442. RepeatCount));
  443. RepeatCount = 0;
  444. } else if (RepeatCount < TIFF_MIN_REPEATS) {
  445. //
  446. // If we have repeating data, but not enough to make it
  447. // worthwhile to encode, then treat the data as literal and
  448. // don't compress.
  449. LiteralCount += RepeatCount;
  450. RepeatCount = 0;
  451. }
  452. PLOTDBG(DBG_TIFF, ("CompressToTIFF: Literal=%ld, Repeats=%ld",
  453. LiteralCount, RepeatCount));
  454. //
  455. // Setting literal count
  456. //
  457. while (LiteralCount) {
  458. if ((CurSize = LiteralCount) > TIFF_MAX_LITERAL) {
  459. CurSize = TIFF_MAX_LITERAL;
  460. }
  461. if ((pbDstEnd - pbDst) <= CurSize) {
  462. PLOTDBG(DBG_TIFF,
  463. ("CompressToTIFF: [LITERAL] Dest Size is larger, give up"));
  464. return(-Size);
  465. }
  466. //
  467. // Set literal control bytes from 0-127
  468. //
  469. *pbDst++ = (BYTE)(CurSize - 1);
  470. CopyMemory(pbDst, pbLastRepeat, CurSize);
  471. pbDst += CurSize;
  472. pbLastRepeat += CurSize;
  473. LiteralCount -= CurSize;
  474. }
  475. //
  476. // Setting repeat count if any
  477. //
  478. while (RepeatCount) {
  479. if ((CurSize = RepeatCount) > TIFF_MAX_REPEATS) {
  480. CurSize = TIFF_MAX_REPEATS;
  481. }
  482. if ((pbDstEnd - pbDst) < 2) {
  483. PLOTDBG(DBG_TIFF,
  484. ("CompressToTIFF: [REPEATS] Dest Size is larger, give up"));
  485. return(-Size);
  486. }
  487. //
  488. // Set Repeat Control bytes from -1 to -127
  489. //
  490. *pbDst++ = (BYTE)(1 - CurSize);
  491. *pbDst++ = (BYTE)LastSrc;
  492. //
  493. // If we have more than TIFF_MAX_REPEATS then we want to make
  494. // sure we used the most efficient method to send. If we have
  495. // remaining repeated bytes less than TIFF_MIN_REPEATS then
  496. // we want to skip those bytes and use literal for the next run
  497. // since that is more efficient.
  498. //
  499. if ((RepeatCount -= CurSize) < TIFF_MIN_REPEATS) {
  500. PLOTDBG(DBG_TIFF,
  501. ("CompressToTIFF: Replaced Last REPEATS (%ld) for LITERAL",
  502. RepeatCount));
  503. pbTmp -= RepeatCount;
  504. RepeatCount = 0;
  505. }
  506. }
  507. pbLastRepeat = pbTmp;
  508. }
  509. pbSrcBeg = pbTmp;
  510. }
  511. PLOTDBG(DBG_TIFF, ("CompressToTIFF: Compress from %ld to %ld, save=%ld",
  512. Size, (DWORD)(pbDst - pbDstBeg),
  513. Size - (DWORD)(pbDst - pbDstBeg)));
  514. return((LONG)(pbDst - pbDstBeg));
  515. }
  516. LONG
  517. RTLCompression(
  518. LPBYTE pbSrc,
  519. LPBYTE pbSeedRow,
  520. LPBYTE pbDst,
  521. LONG Size,
  522. LPBYTE pCompressMode
  523. )
  524. /*++
  525. Routine Description:
  526. This function determines which RTL compression method results in the
  527. least number of bytes to send to the target device and uses that method.
  528. Arguments:
  529. pbSrc - pointer to the source scan
  530. pbSeedRow - Pointer to the seed row for the current source scan
  531. pbDst - Pointer to the compressed result will be stored
  532. Size - size in bytes for pbSrc/pbSeedRow/pbDst
  533. pCompressMode - Pointer to current compression mode, it will ALWAYS be
  534. updated to a new compression mode upon return
  535. Return Value:
  536. >0 - Use *pCompressMode returned and output that many bytes
  537. =0 - Use *pCompressMode returned and output ZERO byte
  538. <0 - Use *pCompressMode returned and output original source and size
  539. Author:
  540. 25-Feb-1994 Fri 12:49:29 created
  541. Revision History:
  542. --*/
  543. {
  544. LONG cDelta;
  545. LONG cTiff;
  546. LONG RetSize;
  547. BYTE CompressMode;
  548. if ((cDelta = CompressToDelta(pbSrc, pbSeedRow, pbDst, Size)) == 0) {
  549. //
  550. // Exact duplicate of the previous row, and seed row remained the same
  551. //
  552. PLOTDBG(DBG_COMPRESS, ("RTLCompression: Duplicate the ROW"));
  553. *pCompressMode = (BYTE)COMPRESS_MODE_DELTA;
  554. return(0);
  555. }
  556. if ((cTiff = CompressToTIFF(pbSrc, pbDst, Size)) == 0) {
  557. //
  558. // Since a '*0W' for the delta means repeat last row so we must change
  559. // to other mode, but we just want reset seed rows to all zeros
  560. //
  561. PLOTDBG(DBG_COMPRESS, ("RTLCompression: Row is all ZEROs"));
  562. if (*pCompressMode == (BYTE)COMPRESS_MODE_DELTA) {
  563. *pCompressMode = (BYTE)COMPRESS_MODE_ROW;
  564. }
  565. ZeroMemory(pbSeedRow, Size);
  566. return(0);
  567. }
  568. if (cTiff < 0) {
  569. if (cDelta < 0) {
  570. PLOTDBG(DBG_COMPRESS, ("RTLCompression: Using COMPRESS_MODE_ROW"));
  571. CompressMode = (BYTE)COMPRESS_MODE_ROW;
  572. RetSize = -Size;
  573. } else {
  574. CompressMode = (BYTE)COMPRESS_MODE_DELTA;
  575. }
  576. } else {
  577. //
  578. // If we are here, cTiff is greater than zero
  579. //
  580. CompressMode = (BYTE)(((cDelta < 0) || (cTiff <= cDelta)) ?
  581. COMPRESS_MODE_TIFF : COMPRESS_MODE_DELTA);
  582. }
  583. if ((*pCompressMode = CompressMode) == COMPRESS_MODE_DELTA) {
  584. //
  585. // We must redo the DELTA again, since pbDst was destroyed by the
  586. // TIFF compression
  587. //
  588. PLOTDBG(DBG_COMPRESS, ("RTLCompression: Using COMPRESS_MODE_DELTA"));
  589. RetSize = CompressToDelta(pbSrc, pbSeedRow, pbDst, Size);
  590. } else if (CompressMode == COMPRESS_MODE_TIFF) {
  591. PLOTDBG(DBG_COMPRESS, ("RTLCompression: Using COMPRESS_MODE_TIFF"));
  592. RetSize = cTiff;
  593. }
  594. //
  595. // We need to have current source (Original SIZE) as the new seed row
  596. //
  597. CopyMemory(pbSeedRow, pbSrc, Size);
  598. return(RetSize);
  599. }
  600. BOOL
  601. AdaptCompression(
  602. PPDEV pPDev,
  603. PRTLSCANS pRTLScans,
  604. LPBYTE pbSrc,
  605. LPBYTE pbSeedRow,
  606. LPBYTE pbDst,
  607. LONG Size
  608. )
  609. /*++
  610. Routine Description:
  611. This function implements adaptive compression, which allows the mixing
  612. of different compression types in a higher level compression mode that
  613. is defined ahead of time.
  614. Arguments:
  615. pPDev - Pointer to our PDEV
  616. pRTLScans - Pointer to the RTLSCANS data structure
  617. pbSrc - pointer to the source scan
  618. pbSeedRow - Pointer to the seed row for the current source scan
  619. pbDst - Pointer to the compressed result will be stored
  620. Size - size in bytes for pbSrc/pbSeedRow/pbDst
  621. Return Value:
  622. >0 - Use *pCompressMode returned and output that many bytes
  623. =0 - Use *pCompressMode returned and output ZERO byte
  624. <0 - Use *pCompressMode returned and output original source and size
  625. Author:
  626. 25-Feb-1994 Fri 12:49:29 created
  627. Revision History:
  628. --*/
  629. {
  630. LPBYTE pbOrgDst;
  631. LONG Count;
  632. BOOL Ok;
  633. BYTE AdaptMethod;
  634. pbOrgDst = pbDst;
  635. AdaptMethod = COMPRESS_MODE_ROW;
  636. if (Count = RTLCompression(pbSrc, pbSeedRow, pbDst, Size, &AdaptMethod)) {
  637. if (Count < 0) {
  638. pbDst = pbSrc;
  639. Count = -Count;
  640. }
  641. } else {
  642. AdaptMethod = (AdaptMethod == COMPRESS_MODE_DELTA) ? ADAPT_METHOD_DUP :
  643. ADAPT_METHOD_ZERO;
  644. }
  645. if ((Ok = (BOOL)(pRTLScans->cEmptyDup == 0xFFFF)) ||
  646. ((pPDev->cbBufferBytes + Count) > MAX_ADAPT_SIZE)) {
  647. if (!(Ok = FlushAdaptBuf(pPDev, pRTLScans, Ok))) {
  648. return(FALSE);
  649. }
  650. //
  651. // Because the Seed ROW was reset to zero, we must recalculate it.
  652. //
  653. if (Count = RTLCompression(pbSrc,
  654. pbSeedRow,
  655. pbOrgDst,
  656. Size,
  657. &AdaptMethod)) {
  658. if (Count < 0) {
  659. pbDst = pbSrc;
  660. Count = -Count;
  661. }
  662. } else {
  663. AdaptMethod = (AdaptMethod == COMPRESS_MODE_DELTA) ?
  664. ADAPT_METHOD_DUP : ADAPT_METHOD_ZERO;
  665. }
  666. } else {
  667. Ok = TRUE;
  668. }
  669. //
  670. // If we are switching compression modes, do it now.
  671. //
  672. if (AdaptMethod != pRTLScans->AdaptMethod) {
  673. if (pRTLScans->cEmptyDup) {
  674. SET_ADAPT_CONTROL(pPDev,
  675. pRTLScans->AdaptMethod,
  676. pRTLScans->cEmptyDup);
  677. pRTLScans->cEmptyDup = 0;
  678. }
  679. pRTLScans->AdaptMethod = AdaptMethod;
  680. }
  681. if (Count) {
  682. SET_ADAPT_CONTROL(pPDev, pRTLScans->AdaptMethod, Count);
  683. OutputBytes(pPDev, pbDst, Count);
  684. } else {
  685. ++(pRTLScans->cEmptyDup);
  686. }
  687. return(Ok);
  688. }
  689. BOOL
  690. OutputRTLScans(
  691. PPDEV pPDev,
  692. LPBYTE pbPlane1,
  693. LPBYTE pbPlane2,
  694. LPBYTE pbPlane3,
  695. PRTLSCANS pRTLScans
  696. )
  697. /*++
  698. Routine Description:
  699. This function will output one scan line of RTL data and compress it if
  700. it can.
  701. Arguments:
  702. pPDev - Pointer to our PDEV
  703. pbPlane1 - First plane of scan data
  704. pbPlane2 - 2nd plane of scan data
  705. pbPlane3 - 3rd plane of scan data
  706. pRTLScans - Pointer to the RTLSCANS data structure
  707. Return Value:
  708. BOOLEAN
  709. Author:
  710. 18-Feb-1994 Fri 15:52:42 created
  711. 21-Feb-1994 Mon 13:20:00 updated
  712. Make if output faster in scan line output
  713. 16-Mar-1994 Wed 15:38:23 updated
  714. Update so the source mask so it is restored after mask
  715. Revision History:
  716. --*/
  717. {
  718. LPBYTE pbCurScan;
  719. LPBYTE pbCompress;
  720. LPBYTE pbScans[3];
  721. RTLSCANS RTLScans;
  722. LONG Count;
  723. UINT i;
  724. BYTE EndGrafCH;
  725. static BYTE BegGrafCmd[] = { 0x1B, '*', 'b' };
  726. if (PLOT_CANCEL_JOB(pPDev)) {
  727. PLOTWARN(("OutputRTLScans: JOB CANCELD. exit NOW"));
  728. pRTLScans->Flags &= ~RTLSF_MORE_SCAN;
  729. return(TRUE);
  730. }
  731. //
  732. // If we are at the last scan line, turn the flag off so we are forced to
  733. // exit.
  734. //
  735. if (!(--pRTLScans->cScans)) {
  736. pRTLScans->Flags &= ~RTLSF_MORE_SCAN;
  737. }
  738. RTLScans = *pRTLScans;
  739. Count = (LONG)(RTLScans.cxBytes - 1);
  740. *(pbPlane1 + Count) &= RTLScans.Mask;
  741. if ((i = (UINT)RTLScans.Planes) > 1) {
  742. *(pbPlane2 + Count) &= RTLScans.Mask;
  743. *(pbPlane3 + Count) &= RTLScans.Mask;
  744. pbScans[2] = pbPlane1;
  745. pbScans[1] = pbPlane2;
  746. pbScans[0] = pbPlane3;
  747. } else {
  748. pbScans[0] = pbPlane1;
  749. }
  750. while (i--) {
  751. EndGrafCH = (i) ? 'V' : 'W';
  752. pbCurScan = pbScans[i];
  753. if (RTLScans.CompressMode == COMPRESS_MODE_BLOCK) {
  754. OutputBytes(pPDev, pbCurScan, RTLScans.cxBytes);
  755. } else if (RTLScans.CompressMode == COMPRESS_MODE_ADAPT) {
  756. AdaptCompression(pPDev,
  757. pRTLScans,
  758. pbCurScan,
  759. RTLScans.pbSeedRows[i],
  760. RTLScans.pbCompress,
  761. RTLScans.cxBytes);
  762. } else {
  763. if ((Count = RTLCompression(pbCurScan,
  764. RTLScans.pbSeedRows[i],
  765. pbCompress = RTLScans.pbCompress,
  766. RTLScans.cxBytes,
  767. &(pRTLScans->CompressMode))) < 0) {
  768. pbCompress = pbCurScan;
  769. Count = RTLScans.cxBytes;
  770. }
  771. //
  772. // Now output graphic header
  773. //
  774. OutputBytes(pPDev, BegGrafCmd, sizeof(BegGrafCmd));
  775. //
  776. // If we changed compression modes then send the command out
  777. // and record the change.
  778. //
  779. if (pRTLScans->CompressMode != RTLScans.CompressMode) {
  780. PLOTDBG(DBG_OUTRTLSCAN, ("OutputRTLScan: Switch CompressMode from %ld to %ld",
  781. (DWORD)RTLScans.CompressMode,
  782. (DWORD)pRTLScans->CompressMode));
  783. RTLScans.CompressMode = pRTLScans->CompressMode;
  784. OutputFormatStr(pPDev, "#dm", (LONG)RTLScans.CompressMode);
  785. }
  786. OutputLONGParams(pPDev, &Count, 1, 'd');
  787. OutputBytes(pPDev, &EndGrafCH, 1);
  788. if (Count) {
  789. OutputBytes(pPDev, pbCompress, Count);
  790. }
  791. }
  792. }
  793. return(TRUE);
  794. }