1 /*****************************************************************************\
2 Mode10.cpp : Implementation of Mode10 class
4 Copyright (c) 1996 - 2001, 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 \*****************************************************************************/
33 Mode10::Mode10 (unsigned int PlaneSize) : Compressor (PlaneSize, true)
35 if (constructor_error != NO_ERROR) // if error in base constructor
46 m_eEndian = LITTLEENDIAN;
47 if (uEndian.c[0] == 0x0A)
48 m_eEndian = BIGENDIAN;
50 // In the worst case, compression expands data by 50%
51 compressBuf = new BYTE[(PlaneSize + PlaneSize/2)];
52 if (compressBuf == NULL)
53 constructor_error = ALLOCMEM_ERROR;
55 memset (SeedRow, 0xFF, PlaneSize);
70 memset (SeedRow, 0xFF, inputsize);
73 inline uint32_t Mode10::get3Pixel (BYTE *pixAddress, int pixelOffset)
75 pixAddress += ((pixelOffset << 1) + pixelOffset); //pixAddress += pixelOffset * 3;
77 BYTE r = *(pixAddress);
78 BYTE g = *(pixAddress + 1);
79 BYTE b = *(pixAddress + 2);
81 return (kWhite & ((r << 16) | (g << 8) | (b)));
85 void Mode10::put3Pixel (BYTE *pixAddress, int pixelOffset, uint32_t pixel)
87 pixAddress += ((pixelOffset << 1) + pixelOffset); //pixAddress += pixelOffset * 3;
89 unsigned int temp = (pixel & kWhite);
91 *(pixAddress) = ((temp >> 16) & 0x000000FF);
92 *(pixAddress + 1) = ((temp >> 8) & 0x000000FF);
93 *(pixAddress + 2) = (temp & 0x000000FF);
98 unsigned short Mode10::ShortDelta (uint32_t lastPixel, uint32_t lastUpperPixel)
103 dr = GetRed (lastPixel) - GetRed (lastUpperPixel);
104 dg = GetGreen (lastPixel) - GetGreen (lastUpperPixel);
105 db = GetBlue (lastPixel) - GetBlue (lastUpperPixel);
107 if ((dr <= 15) && (dr >= -16) && (dg <= 15) && (dg >= -16) && (db <= 30) && (db >= -32))
108 { // Note db is divided by 2 to double it's range from -16..15 to -32..30
109 result = ((dr << 10) & 0x007C00) | (((dg << 5) & 0x0003E0) | ((db >> 1) & 0x01F) | 0x8000); // set upper bit to signify short delta
113 result = 0; // upper bit is zero to signify delta won't work
116 return (unsigned short) result;
119 bool Mode10::Process (RASTERDATA *input)
120 /****************************************************************************
121 Initially written by Elden Wood
124 Similar to mode 9, though tailored for pixel data.
125 For more information see the Bert Compression Format document.
127 This function compresses a single row per call.
128 ****************************************************************************/
131 (input->rasterdata[COLORTYPE_COLOR] == NULL && input->rasterdata[COLORTYPE_BLACK] == NULL)) // flushing pipeline
137 if (myplane == COLORTYPE_BLACK || input->rasterdata[COLORTYPE_COLOR]==NULL)
143 unsigned int originalsize = input->rastersize[myplane];
144 unsigned int size = input->rastersize[myplane];
146 unsigned char *seedRowPtr = (unsigned char *) SeedRow;
148 unsigned char *compressedDataPtr = compressBuf;
149 unsigned char *curRowPtr = (unsigned char *) input->rasterdata[myplane];
150 unsigned int rowWidthInBytes = size;
153 ASSERT(compressedDataPtr);
154 ASSERT(rowWidthInBytes >= BYTES_PER_PIXEL);
155 ASSERT((rowWidthInBytes % BYTES_PER_PIXEL) == 0);
157 unsigned char *compressedDataStart = compressedDataPtr;
158 unsigned int lastPixel = (rowWidthInBytes / BYTES_PER_PIXEL) - 1;
160 // Setup sentinal value to replace last pixel of curRow. Simplifies future end condition checking.
161 uint32_t realLastPixel = getPixel(curRowPtr, lastPixel);
163 uint32_t newLastPixel = realLastPixel;
164 while ((getPixel (curRowPtr, lastPixel - 1) == newLastPixel) ||
165 (getPixel (seedRowPtr, lastPixel) == newLastPixel))
167 putPixel (curRowPtr, lastPixel, newLastPixel += 0x100); // add one to green.
169 unsigned int curPixel = 0;
170 unsigned int seedRowPixelCopyCount;
171 unsigned int cachedColor = kWhite;
173 do // all pixels in row
175 unsigned char CMDByte = 0;
176 int replacementCount;
178 // Find seedRowPixelCopyCount for upcoming copy
179 seedRowPixelCopyCount = curPixel;
180 while (getPixel (seedRowPtr, curPixel) == getPixel (curRowPtr, curPixel))
185 seedRowPixelCopyCount = curPixel - seedRowPixelCopyCount;
186 ASSERT (curPixel <= lastPixel);
190 if (curPixel == lastPixel) // On last pixel of row. RLE could also leave us on the last pixel of the row from the previous iteration.
192 putPixel(curRowPtr, lastPixel, realLastPixel);
194 if (getPixel(seedRowPtr, curPixel) == realLastPixel)
198 else // code last pix as a literal
202 pixelSource = eeNewPixel;
203 replacementCount = 1;
207 else // prior to last pixel of row
209 ASSERT(curPixel < lastPixel);
211 replacementCount = curPixel;
212 uint32_t RLERun = getPixel (curRowPtr, curPixel);
214 curPixel++; // Adjust for next pixel.
215 while (RLERun == getPixel (curRowPtr, curPixel)) // RLE
219 curPixel--; // snap back to current.
220 replacementCount = curPixel - replacementCount;
221 ASSERT(replacementCount >= 0);
223 if (replacementCount > 0) // Adjust for total occurance and move to next pixel to do.
228 if (cachedColor == RLERun)
230 pixelSource = eeCachedColor;
232 else if (getPixel (seedRowPtr, curPixel-replacementCount + 1) == RLERun)
234 pixelSource = eeNEPixel;
236 else if ((curPixel-replacementCount > 0) &&
237 (getPixel (curRowPtr, curPixel-replacementCount - 1) == RLERun))
239 pixelSource = eeWPixel;
243 pixelSource = eeNewPixel;
244 cachedColor = RLERun;
247 CMDByte = eRLE; // Set default for later.
251 if (curPixel == lastPixel)
253 ASSERT(replacementCount > 0); // Already found some RLE pixels
255 if (realLastPixel == RLERun) // Add to current RLE. Otherwise it'll be part of the literal from the seedrow section above on the next iteration.
257 putPixel (curRowPtr, lastPixel, realLastPixel);
263 if (0 == replacementCount) // no RLE so it's a literal by default.
265 uint32_t tempPixel = getPixel (curRowPtr, curPixel);
267 ASSERT(tempPixel != getPixel (curRowPtr, curPixel + 1)); // not RLE
268 ASSERT(tempPixel != getPixel (seedRowPtr, curPixel)); // not seedrow copy
272 if (cachedColor == tempPixel)
274 pixelSource = eeCachedColor;
277 else if (getPixel (seedRowPtr, curPixel + 1) == tempPixel)
279 pixelSource = eeNEPixel;
282 else if ((curPixel > 0) && (getPixel (curRowPtr, curPixel-1) == tempPixel))
284 pixelSource = eeWPixel;
290 pixelSource = eeNewPixel;
291 cachedColor = tempPixel;
294 replacementCount = curPixel;
296 uint32_t nextPixel = getPixel (curRowPtr, curPixel+1);
299 if (++curPixel == lastPixel)
301 putPixel (curRowPtr, lastPixel, realLastPixel);
305 cachePixel = nextPixel;
307 while ((cachePixel != (nextPixel = getPixel (curRowPtr, curPixel+1))) &&
308 (cachePixel != getPixel (seedRowPtr, curPixel)));
310 replacementCount = curPixel - replacementCount;
312 ASSERT(replacementCount > 0);
316 //ASSERT(seedRowPixelCopyCount >= 0);
318 // Write out compressed data next.
319 if (eLiteral == CMDByte)
321 ASSERT(replacementCount >= 1);
323 replacementCount -= 1; // normalize it
325 CMDByte |= pixelSource; // Could put this directly into CMDByte above.
326 CMDByte |= MIN(3, seedRowPixelCopyCount) << 3;
327 CMDByte |= MIN(7, replacementCount);
329 *compressedDataPtr++ = CMDByte;
331 if (seedRowPixelCopyCount >= 3)
333 outputVLIBytesConsecutively (seedRowPixelCopyCount - 3, compressedDataPtr);
336 replacementCount += 1; // denormalize it
338 int totalReplacementCount = replacementCount;
339 int upwardPixelCount = 1;
341 if (eeNewPixel != pixelSource)
343 replacementCount -= 1; // Do not encode 1st pixel of run since it comes from an alternate location.
344 upwardPixelCount = 2;
347 for ( ; upwardPixelCount <= totalReplacementCount; upwardPixelCount++)
349 ASSERT(totalReplacementCount >= upwardPixelCount);
351 unsigned short compressedPixel = ShortDelta (getPixel (curRowPtr, curPixel - replacementCount),
352 getPixel (seedRowPtr, curPixel - replacementCount));
355 *compressedDataPtr++ = compressedPixel >> 8;
356 *compressedDataPtr++ = (unsigned char)compressedPixel;
361 uint32_t uncompressedPixel = getPixel (curRowPtr, curPixel - replacementCount);
363 uncompressedPixel >>= 1; // Lose the lsb of blue and zero out the msb of the 3 bytes.
365 *compressedDataPtr++ = (BYTE) (uncompressedPixel >> 16);
366 *compressedDataPtr++ = (BYTE) (uncompressedPixel >> 8);
367 *compressedDataPtr++ = (BYTE) (uncompressedPixel);
371 if (((upwardPixelCount-8) % 255) == 0) // See if it's time to spill a single VLI byte.
373 *compressedDataPtr++ = MIN(255, totalReplacementCount - upwardPixelCount);
381 ASSERT(replacementCount >= 2);
383 replacementCount -= 2; // normalize it
385 CMDByte |= pixelSource; // Could put this directly into CMDByte above.
386 CMDByte |= MIN(3, seedRowPixelCopyCount) << 3;
387 CMDByte |= MIN(7, replacementCount);
389 *compressedDataPtr++ = CMDByte;
391 if (seedRowPixelCopyCount >= 3)
393 outputVLIBytesConsecutively (seedRowPixelCopyCount - 3, compressedDataPtr);
396 replacementCount += 2; // denormalize it
398 if (eeNewPixel == pixelSource)
400 unsigned short compressedPixel = ShortDelta(getPixel (curRowPtr, curPixel - replacementCount),
401 getPixel (seedRowPtr, curPixel - replacementCount));
404 *compressedDataPtr++ = compressedPixel >> 8;
405 *compressedDataPtr++ = (unsigned char) compressedPixel;
409 uint32_t uncompressedPixel = getPixel (curRowPtr, curPixel - replacementCount);
411 uncompressedPixel >>= 1;
413 *compressedDataPtr++ = (BYTE) (uncompressedPixel >> 16);
414 *compressedDataPtr++ = (BYTE) (uncompressedPixel >> 8);
415 *compressedDataPtr++ = (BYTE) (uncompressedPixel);
419 if (replacementCount - 2 >= 7) outputVLIBytesConsecutively (replacementCount - (7+2), compressedDataPtr);
421 } while (curPixel <= lastPixel);
423 size = static_cast<int>(compressedDataPtr - compressedDataStart); // return # of compressed bytes.
424 compressedsize = size;
425 memcpy (SeedRow, input->rasterdata[myplane], originalsize);
431 bool Mode10::NextOutputRaster (RASTERDATA& next_raster)
433 if (iRastersReady == 0)
438 if (myplane == COLORTYPE_COLOR && compressedsize != 0)
440 next_raster.rastersize[COLORTYPE_COLOR] = compressedsize;
441 next_raster.rasterdata[COLORTYPE_COLOR] = compressBuf;
445 next_raster.rastersize[COLORTYPE_COLOR] = 0;
446 next_raster.rasterdata[COLORTYPE_COLOR] = raster.rasterdata[COLORTYPE_COLOR];
449 next_raster.rastersize[COLORTYPE_BLACK] = raster.rastersize[COLORTYPE_BLACK];
450 next_raster.rasterdata[COLORTYPE_BLACK] = raster.rasterdata[COLORTYPE_BLACK];