1 /*****************************************************************************\
2 ModeDeltaPlus.cpp : Implementation of ModeDeltaPlus class
4 Copyright (c) 1996 - 2009, Hewlett-Packard Co.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of Hewlett-Packard nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
31 #include "ModeDeltaPlus.h"
33 ModeDeltaPlus::ModeDeltaPlus
35 unsigned int PlaneSize
37 Compressor(PlaneSize, true),
38 pbyInputImageBuffer (NULL),
42 inputsize = PlaneSize;
43 inputsize = ((inputsize + 7) / 8) * 8;
44 m_lCurrCDRasterRow = 0;
45 m_lPrinterRasterRow = 0;
47 m_bCompressed = false;
50 } // ModeDeltaPlus::ModeDeltaPlus
52 DRIVER_ERROR ModeDeltaPlus::Init()
54 // allocate a 2X compression buffer..
55 compressBuf = new BYTE[2 * INDY_STRIP_HEIGHT * inputsize];
56 if (compressBuf == NULL)
58 return ALLOCMEM_ERROR;
60 memset (compressBuf, 0x00, 2 * INDY_STRIP_HEIGHT * inputsize);
62 pbyInputImageBuffer = new BYTE[INDY_STRIP_HEIGHT * inputsize];
63 if (pbyInputImageBuffer == NULL)
64 return ALLOCMEM_ERROR;
65 memset(pbyInputImageBuffer, 0x00, INDY_STRIP_HEIGHT * inputsize);
67 pbySeedRow = new BYTE[inputsize];
68 if (pbySeedRow == NULL)
70 return ALLOCMEM_ERROR;
72 memset (pbySeedRow, 0, inputsize * sizeof (BYTE));
76 ModeDeltaPlus::~ModeDeltaPlus ()
78 if (pbyInputImageBuffer)
80 delete [] pbyInputImageBuffer;
81 pbyInputImageBuffer = NULL;
89 } // ModeDeltaPlus::~ModeDeltaPlus
92 * The maximum width of a line, which is limited by the amount of hardware
93 * buffer space allocated to storing the seedrow.
95 #define ROW_LIMIT 7040
97 * The maximum number of literals in a single command, not counting the first
98 * pixel. This is limited by the hardware buffer used to store a literal
99 * string. For real images, I expect a value of 64 would be a suitable
100 * minimum. The minimum compression ratio will be bounded by this. Note also
101 * that the software does not need any buffer for this, so there need be no
102 * limit at all on a purely software implementation. For the sake of enabling
103 * a hardware implementation, I would strongly recommend leaving it in and set
104 * to some reasonable value (say 1023 or 255).
106 #define LITERAL_LIMIT 511
108 /* These are set up this way to make it easy to change the predictions. */
109 #define LTEST_W col > 0
110 #define LVAL_W(col) cur_row[col-1]
111 #define LTEST_NW col > 0
112 #define LVAL_NW(col) seedrow[col-1]
113 #define LTEST_WW col > 1
114 #define LVAL_WW(col) cur_row[col-2]
115 #define LTEST_NWW col > 1
116 #define LVAL_NWW(col) seedrow[col-2]
117 #define LTEST_NE (col+1) < row_width
118 #define LVAL_NE(col) seedrow[col+1]
119 #define LTEST_NEWCOL 1
120 #define LVAL_NEWCOL(col) new_color
121 #define LTEST_CACHE 1
122 #define LVAL_CACHE(col) cache
124 #define LOC1TEST LTEST_NE
125 #define LOC1VAL(col) LVAL_NE(col)
126 #define LOC2TEST LTEST_NW
127 #define LOC2VAL(col) LVAL_NW(col)
128 #define LOC3TEST LTEST_NEWCOL
129 #define LOC3VAL(col) LVAL_NEWCOL(col)
131 #define check(condition) if (!(condition)) return 0
133 #define write_comp_byte(val) \
134 check(outptr < pastoutmem); \
135 *outptr++ = (BYTE) val;
137 #define read_byte(val) \
138 check(inmem < pastinmem); \
141 #define encode_count(count, over, mem) \
145 if (count <= (uint32_t) 253) \
147 check(mem < pastoutmem); \
148 *mem++ = (BYTE) count; \
150 else if (count <= (uint32_t) (254 + 255) ) \
152 check((mem+1) < pastoutmem); \
153 check( count >= 254 ); \
154 check( (count - 254) <= 255 ); \
155 *mem++ = (BYTE) 0xFE; \
156 *mem++ = (BYTE) (count - 254); \
160 check((mem+2) < pastoutmem); \
161 check( count >= 255 ); \
162 check( (count - 255) <= 65535 ); \
164 *mem++ = (BYTE) 0xFF; \
165 *mem++ = (BYTE) (count >> 8); \
166 *mem++ = (BYTE) (count & 0xFF); \
169 #define decode_count(count, over) \
173 count += (uint32_t) inval; \
174 if (inval == (BYTE) 0xFE) \
177 count += (uint32_t) inval; \
179 else if (inval == (BYTE) 0xFF) \
182 count += (((uint32_t) inval) << 8); \
184 count += (uint32_t) inval; \
188 #define bytes_for_count(count, over) \
189 ( (count >= 255) ? 3 : (count >= over) ? 1 : 0 )
192 /* The number of bytes we should be greater than to call memset/memcpy */
193 #define memutil_thresh 15
195 BYTE* ModeDeltaPlus::encode_header(BYTE* outptr, const BYTE* pastoutmem, uint32_t isrun, uint32_t location, uint32_t seedrow_count, uint32_t run_count, const BYTE new_color)
199 check (location < 4);
200 check( (isrun == 0) || (isrun == 1) );
202 /* encode "literal" in command byte */
203 byte = (isrun << 7) | (location << 5);
205 /* write out number of seedrow bytes to copy */
206 if (seedrow_count > 2)
209 byte |= (seedrow_count << 3);
216 /* write out command byte */
217 write_comp_byte(byte);
219 /* macro to write count if it's 3 or more */
220 encode_count( seedrow_count, 3, outptr );
222 /* if required, write out color of first pixel */
225 write_comp_byte( new_color );
228 /* macro to write count if it's 7 or more */
229 encode_count( run_count, 7, outptr );
234 /******************************************************************************/
236 /******************************************************************************/
237 bool ModeDeltaPlus::compress (BYTE *outmem,
240 const uint32_t row_width,
241 const uint32_t inheight,
242 uint32_t horz_ht_dist)
244 register BYTE *outptr = outmem;
245 register uint32_t col;
247 uint32_t seedrow_count = 0;
248 uint32_t location = 0;
249 BYTE new_color = (BYTE) 0xFF;
252 const BYTE *pastoutmem = outmem + *outlen;
253 uint32_t do_word_copies;
254 /* Halftone distance must be 1-32 (but allow 0 == 1) */
255 if (horz_ht_dist > 32)
259 if (horz_ht_dist < 1)
264 seedrow = pbySeedRow;
265 do_word_copies = ((row_width % 4) == 0);
267 for (row = 0; row < inheight; row++)
269 cur_row = inmem + (row * row_width);
272 while (col < row_width)
274 /* First look for seedrow copy */
278 /* Try a fast word-based search */
279 while (((col & 3) != 0) &&
281 (cur_row[col] == seedrow[col]))
288 while (((col+3) < row_width) &&
289 *((const uint32_t*) (cur_row + col)) == *((const uint32_t*) (seedrow + col)))
296 while ((col < row_width) && (cur_row[col] == seedrow[col]))
302 /* It is possible that we have hit the end of the line already. */
303 if (col == row_width)
305 /* encode pure seed run as fake run */
306 outptr = encode_header(outptr, pastoutmem, 1 /*run*/, 1 /*location*/, seedrow_count, 0 /*runcount*/, (BYTE) 0 /*color*/);
307 /* exit the while loop for this row */
310 check(col < row_width);
312 /* determine the prediction for the current pixel */
313 if ( (LOC1TEST) && (cur_row[col] == LOC1VAL(col)) )
315 else if ( (LOC2TEST) && (cur_row[col] == LOC2VAL(col)) )
317 else if ( (LOC3TEST) && (cur_row[col] == LOC3VAL(col)) )
322 new_color = cur_row[col];
328 ((col+1) < row_width)
330 ((col+1) >= horz_ht_dist)
332 (cur_row[col+1-horz_ht_dist] == cur_row[col+1])
335 /* We found a run. Determine the length. */
336 uint32_t run_count = 0; /* Actually 2 */
338 while ( ((col+1) < row_width) && (cur_row[col+1-horz_ht_dist] == cur_row[col+1]) )
344 outptr = encode_header(outptr, pastoutmem, 1 /*run*/, location, seedrow_count, run_count, new_color);
349 /* We didn't find a run. Encode literal(s). */
351 uint32_t replacement_count = 0; /* Actually 1 */
352 const BYTE* byte_array = cur_row + col + 1;
356 * The (col+1) in this test is used because there is no need to
357 * check for literal breaks if this is the last byte of the row.
358 * Instead we just tack it on to our literal count at the end.
360 while ( (col+1) < row_width )
363 * All cases that will break with 1 unit saved. This
364 * should be the best breaking spots, since we will always
365 * gain with the break, but never break for no gain. This
366 * leads to longer strings which is good for decomp speed.
371 (cur_row[col] == seedrow[col])
376 (cur_row[col+1] == seedrow[col+1])
379 /* seedrow and predict */
381 (cur_row[col+1] == LVAL_NW(col+1))
383 (cur_row[col+1] == LVAL_NEWCOL(col+1))
387 ((col+2) < row_width)
390 /* seedrow and run */
392 ((col + 2) >= horz_ht_dist) &&
393 (cur_row[col+2-horz_ht_dist] == cur_row[col+2])
\r
396 /* seedrow and northeast predict */
397 (cur_row[col+1] == LVAL_NE(col+1))
405 (cur_row[col] != seedrow[col])
407 ((col + 1) >= horz_ht_dist)
409 (cur_row[col+1-horz_ht_dist] == cur_row[col+1])
412 /* Run of 3 or more */
414 ((col+2) < row_width)
416 ((col + 2) >= horz_ht_dist)
418 (cur_row[col+2-horz_ht_dist] == cur_row[col+2])
421 /* Predict first unit of run */
422 (cur_row[col] == LVAL_NE(col))
424 (cur_row[col] == LVAL_NW(col))
426 (cur_row[col] == LVAL_NEWCOL(col))
432 /* limited hardware buffer */
433 if (replacement_count >= LITERAL_LIMIT)
436 /* add another literal to the list */
441 /* If almost at end of block, just extend the literal by one */
442 if ( (col+1) == row_width ) {
447 outptr = encode_header(outptr, pastoutmem, 0 /*not run*/, location, seedrow_count, replacement_count, new_color);
449 /* Copy bytes from the byte array. If rc was 1, then we will
450 * have encoded a zero in the command byte, so nothing will be
451 * copied here (the 1 indicates the first pixel, which was
452 * written above or was predicted. If rc is between 2 and 7,
453 * then a value between 1 and 6 will have been written in the
454 * command byte, and we will copy it directly. If 8 or more,
455 * then we encode more counts, then finally copy all the values
459 if (replacement_count > 0)
461 /* Now insert rc bytes of data from byte_array */
462 if (replacement_count > memutil_thresh)
464 check( (outptr + replacement_count) <= pastoutmem );
465 memcpy(outptr, byte_array, (size_t) replacement_count);
466 outptr += replacement_count;
470 for (i = 0; i < replacement_count; i++)
472 write_comp_byte( byte_array[i] );
478 } /* end of column */
480 /* save current row as next row's seed row */
485 check( outptr <= pastoutmem );
486 if (outptr > pastoutmem)
488 /* We're in big trouble -- we wrote PAST the end of their memory! */
493 *outlen = (uint32_t) (outptr - outmem);
496 } /* end of deltaplus_compress2 */
499 bool ModeDeltaPlus::Process
505 (input->rasterdata[COLORTYPE_COLOR]==NULL && input->rasterdata[COLORTYPE_BLACK]==NULL)) // flushing pipeline
509 if (input->rasterdata[COLORTYPE_COLOR])
511 if (m_lCurrCDRasterRow < INDY_STRIP_HEIGHT )
513 //Copy the data to m_SourceBitmap
514 memcpy(pbyInputImageBuffer + m_lCurrCDRasterRow * inputsize, input->rasterdata[COLORTYPE_COLOR], input->rastersize[COLORTYPE_COLOR]);
515 m_lCurrCDRasterRow ++;
517 if (m_lCurrCDRasterRow == INDY_STRIP_HEIGHT || m_bLastBand)
519 m_compressedsize = 2 * inputsize * INDY_STRIP_HEIGHT;
520 bool bRet = compress (compressBuf,
529 memcpy (compressBuf, pbyInputImageBuffer, inputsize * INDY_STRIP_HEIGHT);
530 m_compressedsize = inputsize * INDY_STRIP_HEIGHT;
534 m_bCompressed = true;
537 memset(pbyInputImageBuffer, 0x00, inputsize * INDY_STRIP_HEIGHT);
539 m_lPrinterRasterRow += m_lCurrCDRasterRow;
540 m_lCurrBlockHeight = m_lCurrCDRasterRow;
541 m_lCurrCDRasterRow = 0;
553 bool ModeDeltaPlus::NextOutputRaster(RASTERDATA &next_raster)
555 if (iRastersReady==0)
558 next_raster.rastersize[COLORTYPE_COLOR] = m_compressedsize;
559 if (m_compressedsize > 0)
561 next_raster.rasterdata[COLORTYPE_COLOR] = compressBuf;
563 next_raster.rastersize[COLORTYPE_BLACK] = 0;
564 next_raster.rasterdata[COLORTYPE_BLACK] = NULL;