1 ////////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 1996 - 2008, Hewlett-Packard Development Company, L.P.
3 // All rights reserved.
5 // This software is licensed solely for use with HP products. Redistribution
6 // and use with HP products in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // - Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // - Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // - Neither the name of Hewlett-Packard nor the names of its contributors
15 // may be used to endorse or promote products derived from this software
16 // without specific prior written permission.
17 // - Redistributors making defect corrections to source code grant to
18 // Hewlett-Packard the right to use and redistribute such defect
21 // This software contains technology licensed from third parties; use with
22 // non-HP products is at your own risk and may require a royalty.
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL HEWLETT-PACKARD OR ITS
28 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 ////////////////////////////////////////////////////////////////////////////////
39 // copied from vob \di_research on 10/31/00
40 // MODIFICATIONS BY GE:
41 // 0. remove Windows header references
43 // 2. set iRastersReady, iRastersDelivered in submitrowtofilter
44 // 3. (constructor) allocate (and delete in destructor) buffers for m_row_ptrs
45 // (instead of setting it to input buffers, since we reuse input buffers)
46 // 4. copy data into m_row_ptrs in submitrowtofilter
48 //#define assert ASSERT
50 #include "ErnieFilter.h"
53 #if defined(__APPLE__) || defined(__linux)
59 extern int blockStats[];
62 #if ((kMemWritesOptimize != 1) && (kMemWritesOptimize != 0))
63 #error "kMemWritesOptimize must be 0 or 1"
66 inline void AverageNRound(bool roundGreenDown, int &rFinal, int &r0, int &r1, int &gFinal, int &g0, int &g1, int &bFinal, int &b0, int &b1);
67 inline void AverageNRound(bool roundGreenDown, int &rFinal, int &r0, int &r1, int &gFinal, int &g0, int &g1, int &bFinal, int &b0, int &b1)
69 // By rounding G in the other direction than R and B L* variations are minimized while mathematically alternate rounding is accomplished. EGW 2 Dec. 1999.
72 rFinal = (r0 + r1 + 1) / 2;
73 gFinal = (g0 + g1) / 2;
74 bFinal = (b0 + b1 + 1) / 2;
78 rFinal = (r0 + r1) / 2;
79 gFinal = (g0 + g1 + 1) / 2;
80 bFinal = (b0 + b1) / 2;
85 // Filter1RawRow. To be used to filter an odd row for which we don't have a pair,
86 // found at the bottom of bands that aren't divisable by 2. This routine
87 // filters its row horizontally forming 4x1 and 2x1 blocks.
88 void ErnieFilter::Filter1RawRow(unsigned char *currPtr, int rowWidthInPixels, unsigned int *flagsPtr)
91 ASSERT(rowWidthInPixels > 0);
93 int R0, G0, B0, R1, G1, B1, lastR, lastG, lastB;
94 const unsigned int maxErrorForFourPixels = m_max_error_for_two_pixels / 2;
95 // const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
97 // int currPixel, lastPixel;
98 uint32_t currPixel, lastPixel;
99 bool lastPairAveraged = false;
100 bool last2by2Averaged = false;
103 for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
105 if ((pixelNum & 0x03) == 0x00) // 0,4,8...
107 last2by2Averaged = false; // Reinitialize every four columns;
110 currPixel = get4Pixel(currPtr);
112 flagsPtr[0] = (e11n|e11s); // Initialize in case nothing is found for this column
114 if (isWhite(currPixel))
117 #if kGatherStats == 1
118 blockStats[esWhiteFound]++;
122 // Currently we bail entirely if there is white. Later we may still do RLE on the non white pixel if one is present.
123 if (flagsPtr[0] == (e11n|e11s))
125 R1 = GetRed(currPixel);
126 G1 = GetGreen(currPixel);
127 B1 = GetBlue(currPixel);
129 // Can only horizontally average every other pixel, much like the 2x2 blocks.
132 // do horizontal on current raster
133 lastPixel = get4Pixel(currPtr,-1);
134 lastR = GetRed(lastPixel);
135 lastG = GetGreen(lastPixel);
136 lastB = GetBlue(lastPixel);
137 if ((m_max_error_for_two_pixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1, lastB, B1, m_max_error_for_two_pixels)))
143 int didNotBuild4by1 = true;
144 #if kGatherStats == 1
145 blockStats[es21nw]++;
147 AverageNRound(isOdd(pixelNum), lastR, lastR, R1, lastG, lastG, G1, lastB, lastB, B1);
148 if ((pixelNum >= 3) && (flagsPtr[-3] & e21nw)) // 4,5,6,7,12,13,14,15,20...
151 ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
153 lastPixel = get4Pixel(currPtr,-3);
154 R0 = GetRed(lastPixel);
155 G0 = GetGreen(lastPixel);
156 B0 = GetBlue(lastPixel);
157 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0, lastB, B0, maxErrorForFourPixels)))
163 #if kGatherStats == 1
164 blockStats[es41ni]++;
166 didNotBuild4by1 = false;
167 AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
169 if(m_eEndian == LITTLEENDIAN)
170 currPixel = (lastR<<16) + (lastG<<8) + lastB;
171 else if(m_eEndian == BIGENDIAN)
172 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
174 #if kMemWritesOptimize == 0
175 put4Pixel(currPtr, -3, currPixel);
176 put4Pixel(currPtr, -2, currPixel);
177 put4Pixel(currPtr, -1, currPixel);
178 put4Pixel(currPtr, 0, currPixel);
180 put4Pixel(currPtr, -3, currPixel);
182 flagsPtr[-3] = (flagsPtr[-3] & ~eNorths) | e41ni;
183 flagsPtr[-2] = (flagsPtr[-2] & ~eNorths) | e41n;
184 flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e41n;
185 flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e41n;
189 if (didNotBuild4by1) // Not a 4x1 so output 2x1.
191 ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
193 if(m_eEndian == LITTLEENDIAN)
194 currPixel = (lastR<<16) + (lastG<<8) + lastB;
195 else if(m_eEndian == BIGENDIAN)
196 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
198 #if kMemWritesOptimize == 0
199 put4Pixel(currPtr, -1, currPixel);
200 put4Pixel(currPtr, 0, currPixel);
202 put4Pixel(currPtr, -1, currPixel);
204 flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
205 flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
207 } // If DeltaE... Looking for two by one
210 else // no flag bits set.
212 lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
215 currPtr += eBufferedPixelWidthInBytes;
217 } // for each pixel...
220 // Filter2RawRows: Looks filter two raw rows together to form blocks. Vertical
221 // blocks are prefered over horizontal ones. The routine will create 1x2 blocks
222 // before it will create 4x1's. In total this routine will create 1x2, 2x2, 4x2,
223 // 4x1, and 2x1 blocks sizes, with the potential for two seperate 4x1's or 2x1's
224 // in the upper and lower rasters.
225 void ErnieFilter::Filter2RawRows(unsigned char *currPtr, unsigned char *upPtr, int rowWidthInPixels, unsigned int *flagsPtr)
229 ASSERT(rowWidthInPixels > 0);
231 int R0, G0, B0, R1, G1, B1, lastR, lastG, lastB;
232 const unsigned int maxErrorForFourPixels = m_max_error_for_two_pixels / 2;
233 const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
235 // int currPixel, upPixel, lastPixel;
236 uint32_t currPixel, upPixel, lastPixel;
237 bool lastPairAveraged = false;
238 bool last2by2Averaged = false;
240 for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
242 if ((pixelNum & 0x03) == 0x00) // 0,4,8...
244 last2by2Averaged = false; // Reinitialize every four columns;
247 upPixel = get4Pixel(upPtr);
248 currPixel = get4Pixel(currPtr);
250 flagsPtr[0] = (e11n|e11s); // Initialize in case nothing is found for this column
252 if (isWhite(upPixel) && isWhite(currPixel)) // both white?
255 #if kGatherStats == 1
256 blockStats[esWhiteFound]++;
260 // Do vertical average on the current 2 pixel high column
262 // Currently we bail entirely if there is white. Later we may still do RLE on the non white pixel if one is present.
263 if (flagsPtr[0] == (e11n|e11s))
265 R1 = GetRed(currPixel);
266 G1 = GetGreen(currPixel);
267 B1 = GetBlue(currPixel);
269 R0 = GetRed(upPixel);
270 G0 = GetGreen(upPixel);
271 B0 = GetBlue(upPixel);
273 if ((m_max_error_for_two_pixels >= 3) && (NewDeltaE(R0, R1, G0, G1, B0, B1, m_max_error_for_two_pixels)))
280 ASSERT(flagsPtr[0] == (e11n|e11s));
282 #if kGatherStats == 1
285 R1 = GetRed(currPixel);
286 G1 = GetGreen(currPixel);
287 B1 = GetBlue(currPixel);
289 R0 = GetRed(upPixel);
290 G0 = GetGreen(upPixel);
291 B0 = GetBlue(upPixel);
293 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
295 // look for a 2x2 block average on every other column
297 { // It looks like we are at the end of a 2x2 block
298 if (lastPairAveraged)
300 // Last pair was averaged so it's ok to try to make a 2x2 block
301 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1,lastB, B1, maxErrorForFourPixels)))
308 ASSERT(flagsPtr[-1] == e12);
309 int didNotBuild4by2 = true;
310 #if kGatherStats == 1
316 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, lastR, G1, G1, lastG, B1, B1, lastB); // 2,3,6,7... Alternate between rounding up and down for these 2x2 blocks
318 if ((pixelNum & 0x03) == 0x03) // 3,7,11,15... Looking for a 4x2 block to average
320 if (last2by2Averaged)
323 | | | | We have two 2x2s.
328 lastPixel = get4Pixel(upPtr, -3); // Go back to previous 2x2 block and get the pixel
329 lastR = GetRed(lastPixel);
330 lastG = GetGreen(lastPixel);
331 lastB = GetBlue(lastPixel);
332 if ((maxErrorForEightPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1,lastB, B1, maxErrorForEightPixels)))
341 #if kGatherStats == 1
344 didNotBuild4by2 = false;
347 flagsPtr[-2] = flagsPtr[-1] = flagsPtr[0] = e42;
349 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, lastR, G1, G1, lastG, B1, B1, lastB); // 4,5,6,7,12,13,14,15,20... Alternate between rounding up down for these 4x2 blocks
351 if(m_eEndian == LITTLEENDIAN)
352 currPixel = (R1<<16) + (G1<<8) + B1;
353 else if(m_eEndian == BIGENDIAN)
354 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
356 #if kMemWritesOptimize == 0
357 put4Pixel(upPtr, -3, currPixel);
358 put4Pixel(upPtr, -2, currPixel);
359 put4Pixel(upPtr, -1, currPixel);
360 put4Pixel(upPtr, 0, currPixel);
361 put4Pixel(currPtr, -3, currPixel);
362 put4Pixel(currPtr, -2, currPixel);
363 put4Pixel(currPtr, -1, currPixel);
364 put4Pixel(currPtr, 0, currPixel);
366 put4Pixel(upPtr, -3, currPixel);
372 { // The first 2x2 block of this pair of 2x2 blocks wasn't averaged.
374 |X X| | | not averaged block and averaged 2x2.
379 last2by2Averaged = true;
381 if(m_eEndian == LITTLEENDIAN)
382 currPixel = (R1<<16) + (G1<<8) + B1;
383 else if(m_eEndian == BIGENDIAN)
384 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
386 #if kMemWritesOptimize == 0
387 put4Pixel(upPtr, -1, currPixel);
388 put4Pixel(upPtr, 0, currPixel);
389 put4Pixel(currPtr, -1, currPixel);
390 put4Pixel(currPtr, 0, currPixel);
392 put4Pixel(upPtr, -1, currPixel);
396 else // Not looking for a 4x2 block yet so just output this 2x2 block for now.
399 | | |? ?| 1st 2x2 and maybe another later.
404 last2by2Averaged = true;
406 if(m_eEndian == LITTLEENDIAN)
407 currPixel = (R1<<16) + (G1<<8) + B1;
408 else if(m_eEndian == BIGENDIAN)
409 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
411 #if kMemWritesOptimize == 0
412 put4Pixel(upPtr, -1, currPixel);
413 put4Pixel(upPtr, 0, currPixel);
414 put4Pixel(currPtr, -1, currPixel);
415 put4Pixel(currPtr, 0, currPixel);
417 put4Pixel(upPtr, -1, currPixel);
421 else // The two averaged columns are not close enough in Delta E
429 last2by2Averaged = false;
431 if(m_eEndian == LITTLEENDIAN)
432 currPixel = (R1<<16) + (G1<<8) + B1;
433 else if(m_eEndian == BIGENDIAN)
434 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
436 #if kMemWritesOptimize == 0
437 put4Pixel(upPtr, 0, currPixel);
438 put4Pixel(currPtr, 0, currPixel);
440 put4Pixel(upPtr,0, currPixel);
446 lastPairAveraged = true;
448 else // This is the right place for 2x2 averaging but the previous column wasn't averaged
451 X | | Two non averaged pixels and a 1x2.
455 last2by2Averaged = false;
456 lastPairAveraged = true;
461 if(m_eEndian == LITTLEENDIAN)
462 currPixel = (R1<<16) + (G1<<8) + B1;
463 else if(m_eEndian == BIGENDIAN)
464 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
466 #if kMemWritesOptimize == 0
467 put4Pixel(upPtr, 0, currPixel);
468 put4Pixel(currPtr, 0, currPixel);
470 put4Pixel(upPtr, 0, currPixel);
474 else // Not on the boundary for a 2x2 block, so just output current averaged 1x2 column
482 lastPairAveraged = true;
487 if(m_eEndian == LITTLEENDIAN)
488 currPixel = (R1<<16) + (G1<<8) + B1;
489 else if(m_eEndian == BIGENDIAN)
490 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
492 #if kMemWritesOptimize == 0
493 put4Pixel(upPtr, 0, currPixel);
494 put4Pixel(currPtr, 0, currPixel);
496 put4Pixel(upPtr, 0, currPixel);
500 else if (lastPairAveraged)
501 { // This is the case where we can't average current column and the last column was averaged.
502 // Don't do anything if last pair was averaged and this one can't be
505 | | X 1x2 averaged block and two non averaged pixels.
510 lastPairAveraged = false;
513 // can't vertically average current column so look for some horizontal averaging as a fallback
514 // Only do it if the last pair wasn't averaged either because we don't want to mess up a vertical averaging
515 // just to create a possible horizontal averaging.
517 // Can only horizontally average every other pixel, much like the 2x2 blocks.
520 // do horizontal averaging on previous raster
521 lastPixel = get4Pixel(upPtr,-1);
522 lastR = GetRed(lastPixel);
523 lastG = GetGreen(lastPixel);
524 lastB = GetBlue(lastPixel);
525 if (((m_max_error_for_two_pixels >= 3)) && (NewDeltaE(lastR, R0, lastG, G0,lastB, B0, m_max_error_for_two_pixels)))
531 #if kGatherStats == 1
532 blockStats[es21nw]++;
534 int didNotBuild4by1 = true;
536 AverageNRound(isOdd(pixelNum), lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0);
538 if ((pixelNum >= 3) && (flagsPtr[-3] & e21nw)) // 4,5,6,7,12,13,14,15,20...
540 ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
542 // Attempt an upper 4x1
543 lastPixel = get4Pixel(upPtr,-3);
544 R0 = GetRed(lastPixel);
545 G0 = GetGreen(lastPixel);
546 B0 = GetBlue(lastPixel);
547 if ( (maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0,lastB, B0, maxErrorForFourPixels)))
553 #if kGatherStats == 1
554 blockStats[es41ni]++;
556 didNotBuild4by1 = false;
557 AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
559 if(m_eEndian == LITTLEENDIAN)
560 currPixel = (lastR<<16) + (lastG<<8) + lastB;
561 else if(m_eEndian == BIGENDIAN)
562 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
564 #if kMemWritesOptimize == 0
565 put4Pixel(upPtr, -3, currPixel);
566 put4Pixel(upPtr, -2, currPixel);
567 put4Pixel(upPtr, -1, currPixel);
568 put4Pixel(upPtr, 0, currPixel);
570 put4Pixel(upPtr, -3, currPixel);
573 ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
575 flagsPtr[-3] = (flagsPtr[-3] & ~eNorths) | e41ni;
576 flagsPtr[-2] = (flagsPtr[-2] & ~eNorths) | e41n;
577 flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e41n;
578 flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e41n;
582 if (didNotBuild4by1) // Not an upper 4x1 so output upper 2x1.
584 if(m_eEndian == LITTLEENDIAN)
585 currPixel = (lastR<<16) + (lastG<<8) + lastB;
586 else if(m_eEndian == BIGENDIAN)
587 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
589 #if kMemWritesOptimize == 0
590 put4Pixel(upPtr, -1, currPixel);
591 put4Pixel(upPtr, 0, currPixel);
593 put4Pixel(upPtr, -1, currPixel);
595 ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
596 flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
597 flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
601 // do horizontal on current raster
602 lastPixel = get4Pixel(currPtr,-1);
603 lastR = GetRed(lastPixel);
604 lastG = GetGreen(lastPixel);
605 lastB = GetBlue(lastPixel);
606 if ((m_max_error_for_two_pixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1, lastB, B1, m_max_error_for_two_pixels)))
612 int didNotBuild4by1 = true;
613 #if kGatherStats == 1
614 blockStats[es21sw]++;
616 AverageNRound(isOdd(pixelNum), lastR, lastR, R1, lastG, lastG, G1, lastB, lastB, B1);
617 if ((pixelNum >= 3) && (flagsPtr[-3] & e21sw)) // 4,5,6,7,12,13,14,15,20...
619 // Look for a lower 4x1
620 ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
622 lastPixel = get4Pixel(currPtr,-3);
623 R0 = GetRed(lastPixel);
624 G0 = GetGreen(lastPixel);
625 B0 = GetBlue(lastPixel);
626 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0, lastB, B0, maxErrorForFourPixels)))
632 #if kGatherStats == 1
633 blockStats[es41si]++;
635 didNotBuild4by1 = false;
636 AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
638 if(m_eEndian == LITTLEENDIAN)
639 currPixel = (lastR<<16) + (lastG<<8) + lastB;
640 else if(m_eEndian == BIGENDIAN)
641 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
643 #if kMemWritesOptimize == 0
644 put4Pixel(currPtr, -3, currPixel);
645 put4Pixel(currPtr, -2, currPixel);
646 put4Pixel(currPtr, -1, currPixel);
647 put4Pixel(currPtr, 0, currPixel);
649 put4Pixel(currPtr, -3, currPixel);
651 flagsPtr[-3] = (flagsPtr[-3] & ~eSouths) | e41si;
652 flagsPtr[-2] = (flagsPtr[-2] & ~eSouths) | e41s;
653 flagsPtr[-1] = (flagsPtr[-1] & ~eSouths) | e41s;
654 flagsPtr[0] = (flagsPtr[0] & ~eSouths) | e41s;
658 if (didNotBuild4by1) // Not a lower 4x1 so output lower 2x1.
660 ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
662 if(m_eEndian == LITTLEENDIAN)
663 currPixel = (lastR<<16) + (lastG<<8) + lastB;
664 else if(m_eEndian == BIGENDIAN)
665 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
667 #if kMemWritesOptimize == 0
668 put4Pixel(currPtr, -1, currPixel);
669 put4Pixel(currPtr, 0, currPixel);
671 put4Pixel(currPtr, -1, currPixel);
674 flagsPtr[-1] = (flagsPtr[-1] & ~eSouths) | e21sw;
675 flagsPtr[0] = (flagsPtr[0] & ~eSouths) | e21se;
677 } // If DeltaE... Looking for two by one
681 else // no flag bits set.
683 lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
686 upPtr += eBufferedPixelWidthInBytes;
687 currPtr += eBufferedPixelWidthInBytes;
689 } // for each pixel...
692 // Filter2PairsOfFilteredRows. This routine takes 2 pairs of rows that
693 // have been through the Filter2RawRows routine and puts blocks together
694 // to make bigger blocks. It prefers taking 2 high blocks and putting
695 // them together to make four high blocks, but as a last resort it will
696 // take try to take a 1 high blocks from the second and third rasters and
697 // create 2 high blocks. The possible block sizes this routine could
698 // create are 8x4, 4x4, 2x4, and 1x4, and then with the second and third rasters
699 // 4x2, 2x2, and 1x2.
700 void ErnieFilter::Filter2PairsOfFilteredRows(unsigned char *row1Ptr, unsigned char *row2Ptr, unsigned char *row3Ptr, unsigned char *row4Ptr)
702 const unsigned int maxErrorForFourPixels = m_max_error_for_two_pixels / 2;
703 const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
704 const unsigned int maxErrorForSixteenPixels = maxErrorForEightPixels / 2;
705 const unsigned int maxErrorForThirtyTwoPixels = maxErrorForSixteenPixels / 2;
707 for (int pixelNum = 0; pixelNum < (m_row_width_in_pixels-3);) // Make sure we have four pixels to work with
709 int currPixel, upPixel;
710 int R0, G0, B0, R1, G1, B1;
712 if ((m_pixel_filtered_flags[0][pixelNum] & e42i) && (m_pixel_filtered_flags[1][pixelNum] & e42i))
717 - - - - We have two 4x2s.
723 ASSERT(m_pixel_filtered_flags[0][pixelNum] == e42i && m_pixel_filtered_flags[0][pixelNum+1] == e42 && m_pixel_filtered_flags[0][pixelNum+2] == e42 && m_pixel_filtered_flags[0][pixelNum+3] == e42);
724 ASSERT(m_pixel_filtered_flags[1][pixelNum] == e42i && m_pixel_filtered_flags[1][pixelNum+1] == e42 && m_pixel_filtered_flags[1][pixelNum+2] == e42 && m_pixel_filtered_flags[1][pixelNum+3] == e42);
726 upPixel = get4Pixel(row1Ptr);
727 currPixel = get4Pixel(row3Ptr);
729 R1 = GetRed(currPixel);
730 G1 = GetGreen(currPixel);
731 B1 = GetBlue(currPixel);
733 R0 = GetRed(upPixel);
734 G0 = GetGreen(upPixel);
735 B0 = GetBlue(upPixel);
737 if((maxErrorForSixteenPixels >= 3) &&(NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForSixteenPixels)))
746 #if kGatherStats == 1
747 blockStats[es44ni]++;
749 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0); // 4,5,6,7,12,13,14,15,20... Alternate between rounding up down
751 if(m_eEndian == LITTLEENDIAN)
752 currPixel = (R1<<16) + (G1<<8) + B1;
753 else if(m_eEndian == BIGENDIAN)
754 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
756 #if kMemWritesOptimize == 0
757 put4Pixel(row1Ptr, 0, currPixel);
758 put4Pixel(row1Ptr, 1, currPixel);
759 put4Pixel(row1Ptr, 2, currPixel);
760 put4Pixel(row1Ptr, 3, currPixel);
761 put4Pixel(row2Ptr, 0, currPixel);
762 put4Pixel(row2Ptr, 1, currPixel);
763 put4Pixel(row2Ptr, 2, currPixel);
764 put4Pixel(row2Ptr, 3, currPixel);
765 put4Pixel(row3Ptr, 0, currPixel);
766 put4Pixel(row3Ptr, 1, currPixel);
767 put4Pixel(row3Ptr, 2, currPixel);
768 put4Pixel(row3Ptr, 3, currPixel);
769 put4Pixel(row4Ptr, 0, currPixel);
770 put4Pixel(row4Ptr, 1, currPixel);
771 put4Pixel(row4Ptr, 2, currPixel);
772 put4Pixel(row4Ptr, 3, currPixel);
774 put4Pixel(row1Ptr, 0, currPixel);
776 row1Ptr += 4*eBufferedPixelWidthInBytes;
777 row2Ptr += 4*eBufferedPixelWidthInBytes;
778 row3Ptr += 4*eBufferedPixelWidthInBytes;
779 row4Ptr += 4*eBufferedPixelWidthInBytes;
781 m_pixel_filtered_flags[0][pixelNum] = e44ni;
782 m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+2] = m_pixel_filtered_flags[0][pixelNum+3] = e44n;
783 m_pixel_filtered_flags[1][pixelNum] = e44si;
784 m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+2] = m_pixel_filtered_flags[1][pixelNum+3] = e44s;
786 if ((pixelNum >= 4) && (m_pixel_filtered_flags[1][pixelNum-4] & e44si)) // 4,5,6,7,12,13,14,15,20...
790 | | | | We have two 4x4s.
795 ASSERT(m_pixel_filtered_flags[0][pixelNum-4] == e44ni && m_pixel_filtered_flags[0][pixelNum-3] == e44n && m_pixel_filtered_flags[0][pixelNum-2] == e44n && m_pixel_filtered_flags[0][pixelNum-1] == e44n);
796 ASSERT(m_pixel_filtered_flags[1][pixelNum-4] == e44si && m_pixel_filtered_flags[1][pixelNum-3] == e44s && m_pixel_filtered_flags[1][pixelNum-2] == e44s && m_pixel_filtered_flags[1][pixelNum-1] == e44s);
798 upPixel = get4Pixel(row1Ptr, -8);
800 R0 = GetRed(upPixel);
801 G0 = GetGreen(upPixel);
802 B0 = GetBlue(upPixel);
804 if( (maxErrorForThirtyTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForThirtyTwoPixels)))
813 #if kGatherStats == 1
814 blockStats[es84ni]++;
816 AverageNRound((pixelNum & 0x08) == 0x08, R1, R1, R0, G1, G1, G0, B1, B1, B0);
817 if(m_eEndian == LITTLEENDIAN)
818 currPixel = (R1<<16) + (G1<<8) + B1;
819 else if(m_eEndian == BIGENDIAN)
820 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
822 #if kMemWritesOptimize == 0
823 put4Pixel(row1Ptr, -8, currPixel);
824 put4Pixel(row1Ptr, -7, currPixel);
825 put4Pixel(row1Ptr, -6, currPixel);
826 put4Pixel(row1Ptr, -5, currPixel);
827 put4Pixel(row1Ptr, -4, currPixel);
828 put4Pixel(row1Ptr, -3, currPixel);
829 put4Pixel(row1Ptr, -2, currPixel);
830 put4Pixel(row1Ptr, -1, currPixel);
831 put4Pixel(row2Ptr, -8, currPixel);
832 put4Pixel(row2Ptr, -7, currPixel);
833 put4Pixel(row2Ptr, -6, currPixel);
834 put4Pixel(row2Ptr, -5, currPixel);
835 put4Pixel(row2Ptr, -4, currPixel);
836 put4Pixel(row2Ptr, -3, currPixel);
837 put4Pixel(row2Ptr, -2, currPixel);
838 put4Pixel(row2Ptr, -1, currPixel);
839 put4Pixel(row3Ptr, -8, currPixel);
840 put4Pixel(row3Ptr, -7, currPixel);
841 put4Pixel(row3Ptr, -6, currPixel);
842 put4Pixel(row3Ptr, -5, currPixel);
843 put4Pixel(row3Ptr, -4, currPixel);
844 put4Pixel(row3Ptr, -3, currPixel);
845 put4Pixel(row3Ptr, -2, currPixel);
846 put4Pixel(row3Ptr, -1, currPixel);
847 put4Pixel(row4Ptr, -8, currPixel);
848 put4Pixel(row4Ptr, -7, currPixel);
849 put4Pixel(row4Ptr, -6, currPixel);
850 put4Pixel(row4Ptr, -5, currPixel);
851 put4Pixel(row4Ptr, -4, currPixel);
852 put4Pixel(row4Ptr, -3, currPixel);
853 put4Pixel(row4Ptr, -2, currPixel);
854 put4Pixel(row4Ptr, -1, currPixel);
856 put4Pixel(row1Ptr, -8, currPixel);
858 m_pixel_filtered_flags[0][pixelNum-4] = e84ni;
859 m_pixel_filtered_flags[0][pixelNum-3] = m_pixel_filtered_flags[0][pixelNum-2] = m_pixel_filtered_flags[0][pixelNum-1] = m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+2] = m_pixel_filtered_flags[0][pixelNum+3] = e84n;
860 m_pixel_filtered_flags[1][pixelNum-4] = e84si;
861 m_pixel_filtered_flags[1][pixelNum-3] = m_pixel_filtered_flags[1][pixelNum-2] = m_pixel_filtered_flags[1][pixelNum-1] = m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+2] = m_pixel_filtered_flags[1][pixelNum+3] = e84s;
865 else // could not build 4x4 so move forward past the stacked 4x2s.
867 row1Ptr += 4*eBufferedPixelWidthInBytes;
868 row2Ptr += 4*eBufferedPixelWidthInBytes;
869 row3Ptr += 4*eBufferedPixelWidthInBytes;
870 row4Ptr += 4*eBufferedPixelWidthInBytes;
874 else if ((m_pixel_filtered_flags[0][pixelNum] & e22w) && (m_pixel_filtered_flags[1][pixelNum] & e22w))
885 ASSERT(m_pixel_filtered_flags[0][pixelNum] == e22w && m_pixel_filtered_flags[0][pixelNum+1] == e22e);
886 ASSERT(m_pixel_filtered_flags[1][pixelNum] == e22w && m_pixel_filtered_flags[1][pixelNum+1] == e22e);
888 upPixel = get4Pixel(row1Ptr);
889 currPixel = get4Pixel(row3Ptr);
891 R1 = GetRed(currPixel);
892 G1 = GetGreen(currPixel);
893 B1 = GetBlue(currPixel);
895 R0 = GetRed(upPixel);
896 G0 = GetGreen(upPixel);
897 B0 = GetBlue(upPixel);
899 if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
908 #if kGatherStats == 1
909 blockStats[es24nw]++;
911 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
913 if(m_eEndian == LITTLEENDIAN)
914 currPixel = (R1<<16) + (G1<<8) + B1;
915 else if(m_eEndian == BIGENDIAN)
916 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
918 #if kMemWritesOptimize == 0
919 put4Pixel(row1Ptr, 0, currPixel);
920 put4Pixel(row1Ptr, 1, currPixel);
921 put4Pixel(row2Ptr, 0, currPixel);
922 put4Pixel(row2Ptr, 1, currPixel);
923 put4Pixel(row3Ptr, 0, currPixel);
924 put4Pixel(row3Ptr, 1, currPixel);
925 put4Pixel(row4Ptr, 0, currPixel);
926 put4Pixel(row4Ptr, 1, currPixel);
928 put4Pixel(row1Ptr, 0, currPixel);
930 row1Ptr += 2*eBufferedPixelWidthInBytes;
931 row2Ptr += 2*eBufferedPixelWidthInBytes;
932 row3Ptr += 2*eBufferedPixelWidthInBytes;
933 row4Ptr += 2*eBufferedPixelWidthInBytes;
935 m_pixel_filtered_flags[0][pixelNum] = e24nw;
936 m_pixel_filtered_flags[0][pixelNum+1] = e24ne;
937 m_pixel_filtered_flags[1][pixelNum] = e24sw;
938 m_pixel_filtered_flags[1][pixelNum+1] = e24se;
942 row1Ptr += 2*eBufferedPixelWidthInBytes;
943 row2Ptr += 2*eBufferedPixelWidthInBytes;
944 row3Ptr += 2*eBufferedPixelWidthInBytes;
945 row4Ptr += 2*eBufferedPixelWidthInBytes;
949 else if ((m_pixel_filtered_flags[0][pixelNum] & e12) && (m_pixel_filtered_flags[1][pixelNum] & e12))
960 ASSERT(m_pixel_filtered_flags[0][pixelNum] == e12);
961 ASSERT(m_pixel_filtered_flags[1][pixelNum] == e12);
963 upPixel = get4Pixel(row1Ptr);
964 currPixel = get4Pixel(row3Ptr);
966 R1 = GetRed(currPixel);
967 G1 = GetGreen(currPixel);
968 B1 = GetBlue(currPixel);
970 R0 = GetRed(upPixel);
971 G0 = GetGreen(upPixel);
972 B0 = GetBlue(upPixel);
974 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
983 #if kGatherStats == 1
986 AverageNRound((pixelNum & 0x01) == 0x01, R1, R1, R0, G1, G1, G0, B1, B1, B0);
988 if(m_eEndian == LITTLEENDIAN)
989 currPixel = (R1<<16) + (G1<<8) + B1;
990 else if(m_eEndian == BIGENDIAN)
991 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
993 #if kMemWritesOptimize == 0
994 put4Pixel(row1Ptr, 0, currPixel);
995 put4Pixel(row2Ptr, 0, currPixel);
996 put4Pixel(row3Ptr, 0, currPixel);
997 put4Pixel(row4Ptr, 0, currPixel);
999 put4Pixel(row1Ptr, 0, currPixel);
1001 m_pixel_filtered_flags[0][pixelNum] = e14n;
1002 m_pixel_filtered_flags[1][pixelNum] = e14s;
1005 row1Ptr += eBufferedPixelWidthInBytes;
1006 row2Ptr += eBufferedPixelWidthInBytes;
1007 row3Ptr += eBufferedPixelWidthInBytes;
1008 row4Ptr += eBufferedPixelWidthInBytes;
1012 else if ((m_pixel_filtered_flags[0][pixelNum] & e41si)
1013 && (m_pixel_filtered_flags[1][pixelNum] & e41ni))
1017 - - - - We have two 4x1s.
1023 upPixel = get4Pixel(row2Ptr);
1024 currPixel = get4Pixel(row3Ptr);
1026 R1 = GetRed(currPixel);
1027 G1 = GetGreen(currPixel);
1028 B1 = GetBlue(currPixel);
1030 R0 = GetRed(upPixel);
1031 G0 = GetGreen(upPixel);
1032 B0 = GetBlue(upPixel);
1035 if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1043 #if kGatherStats == 1
1044 blockStats[es42w]++;
1046 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1048 if(m_eEndian == LITTLEENDIAN)
1049 currPixel = (R1<<16) + (G1<<8) + B1;
1050 else if(m_eEndian == BIGENDIAN)
1051 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1053 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1054 put4Pixel(row2Ptr, 0, currPixel);
1055 put4Pixel(row2Ptr, 1, currPixel);
1056 put4Pixel(row2Ptr, 2, currPixel);
1057 put4Pixel(row2Ptr, 3, currPixel);
1058 put4Pixel(row3Ptr, 0, currPixel);
1059 put4Pixel(row3Ptr, 1, currPixel);
1060 put4Pixel(row3Ptr, 2, currPixel);
1061 put4Pixel(row3Ptr, 3, currPixel);
1063 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e41si;
1064 m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1065 m_pixel_filtered_flags[0][pixelNum+2] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1066 m_pixel_filtered_flags[0][pixelNum+3] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1068 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e41ni; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1069 m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1070 m_pixel_filtered_flags[1][pixelNum+2] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1071 m_pixel_filtered_flags[1][pixelNum+3] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1075 row1Ptr += 4*eBufferedPixelWidthInBytes;
1076 row2Ptr += 4*eBufferedPixelWidthInBytes;
1077 row3Ptr += 4*eBufferedPixelWidthInBytes;
1078 row4Ptr += 4*eBufferedPixelWidthInBytes;
1080 else if ((m_pixel_filtered_flags[0][pixelNum] & e21sw)
1081 && (m_pixel_filtered_flags[1][pixelNum] & e21nw))
1085 - - We have two 2x1s.
1090 ASSERT(!((m_pixel_filtered_flags[0][pixelNum] & e11s) | (m_pixel_filtered_flags[0][pixelNum+1] & e11s)));
1091 ASSERT(!((m_pixel_filtered_flags[1][pixelNum] & e11n) | (m_pixel_filtered_flags[1][pixelNum+1] & e11n)));
1093 upPixel = get4Pixel(row2Ptr);
1094 currPixel = get4Pixel(row3Ptr);
1096 R1 = GetRed(currPixel);
1097 G1 = GetGreen(currPixel);
1098 B1 = GetBlue(currPixel);
1100 R0 = GetRed(upPixel);
1101 G0 = GetGreen(upPixel);
1102 B0 = GetBlue(upPixel);
1104 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1111 #if kGatherStats == 1
1112 blockStats[es22w]++;
1114 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1116 if(m_eEndian == LITTLEENDIAN)
1117 currPixel = (R1<<16) + (G1<<8) + B1;
1118 else if(m_eEndian == BIGENDIAN)
1119 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1121 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1122 put4Pixel(row2Ptr, 0, currPixel);
1123 put4Pixel(row2Ptr, 1, currPixel);
1124 put4Pixel(row3Ptr, 0, currPixel);
1125 put4Pixel(row3Ptr, 1, currPixel);
1127 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e21sw;
1128 m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+1] & ~e21se;
1130 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e21nw; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1131 m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+1] & ~e21ne;
1136 row1Ptr += 2*eBufferedPixelWidthInBytes;
1137 row2Ptr += 2*eBufferedPixelWidthInBytes;
1138 row3Ptr += 2*eBufferedPixelWidthInBytes;
1139 row4Ptr += 2*eBufferedPixelWidthInBytes;
1141 else if ((m_pixel_filtered_flags[0][pixelNum] & e11s)
1142 && (m_pixel_filtered_flags[1][pixelNum] & e11n))
1152 upPixel = get4Pixel(row2Ptr);
1153 currPixel = get4Pixel(row3Ptr);
1155 R1 = GetRed(currPixel);
1156 G1 = GetGreen(currPixel);
1157 B1 = GetBlue(currPixel);
1159 R0 = GetRed(upPixel);
1160 G0 = GetGreen(upPixel);
1161 B0 = GetBlue(upPixel);
1163 if ((m_max_error_for_two_pixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, m_max_error_for_two_pixels)))
1170 #if kGatherStats == 1
1171 blockStats[es12w]++;
1173 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1175 if(m_eEndian == LITTLEENDIAN)
1176 currPixel = (R1<<16) + (G1<<8) + B1;
1177 else if(m_eEndian == BIGENDIAN)
1178 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1180 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1181 put4Pixel(row2Ptr, 0, currPixel);
1182 put4Pixel(row3Ptr, 0, currPixel);
1184 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e11s;
1186 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e11n; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1191 row1Ptr += eBufferedPixelWidthInBytes;
1192 row2Ptr += eBufferedPixelWidthInBytes;
1193 row3Ptr += eBufferedPixelWidthInBytes;
1194 row4Ptr += eBufferedPixelWidthInBytes;
1196 else // Do no vertical filtering here.
1200 row1Ptr += eBufferedPixelWidthInBytes;
1201 row2Ptr += eBufferedPixelWidthInBytes;
1202 row3Ptr += eBufferedPixelWidthInBytes;
1203 row4Ptr += eBufferedPixelWidthInBytes;
1208 // Filter3FilteredRows. This routine only exists for the case of the odd size band
1209 // with three rasters left over. I'm not sure how much extra benifit we really
1210 // get from running this, but for now I'm leaving it in. Since Ernie deals with
1211 // block sizes that are powers of two its rather difficult to filter 3 rows together,
1212 // about all I've been able to do is look for 1 high blocks in the second and third
1213 // rasters to put together into 2 high blocks. This routine will create 4x2, 2x2, and
1214 // 1x2 blocks from those second and third rasters.
1215 void ErnieFilter::Filter3FilteredRows(unsigned char *row1Ptr, unsigned char *row2Ptr, unsigned char *row3Ptr)
1217 const unsigned int maxErrorForFourPixels = m_max_error_for_two_pixels / 2;
1218 const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
1219 // const unsigned int maxErrorForSixteenPixels = maxErrorForEightPixels / 2;
1220 // const unsigned int maxErrorForThirtyTwoPixels = maxErrorForSixteenPixels / 2;
1222 for (int pixelNum = 0; pixelNum < (m_row_width_in_pixels-3);) // Make sure we have four pixels to work with
1224 // int currPixel, upPixel;
1225 uint32_t currPixel, upPixel;
1226 int R0, G0, B0, R1, G1, B1;
1228 if ((m_pixel_filtered_flags[0][pixelNum] & e41si)
1229 && (m_pixel_filtered_flags[1][pixelNum] & e41ni))
1233 - - - - We have two 4x1s.
1238 ASSERT(!((m_pixel_filtered_flags[0][pixelNum] & e11s) | (m_pixel_filtered_flags[0][pixelNum+1] & e11s)));
1239 ASSERT(!((m_pixel_filtered_flags[1][pixelNum] & e11n) | (m_pixel_filtered_flags[1][pixelNum+1] & e11n)));
1241 upPixel = get4Pixel(row2Ptr);
1242 currPixel = get4Pixel(row3Ptr);
1244 R1 = GetRed(currPixel);
1245 G1 = GetGreen(currPixel);
1246 B1 = GetBlue(currPixel);
1248 R0 = GetRed(upPixel);
1249 G0 = GetGreen(upPixel);
1250 B0 = GetBlue(upPixel);
1253 if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1261 #if kGatherStats == 1
1262 blockStats[es42w]++;
1264 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1266 if(m_eEndian == LITTLEENDIAN)
1267 currPixel = (R1<<16) + (G1<<8) + B1;
1268 else if(m_eEndian == BIGENDIAN)
1269 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1271 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1272 put4Pixel(row2Ptr, 0, currPixel);
1273 put4Pixel(row2Ptr, 1, currPixel);
1274 put4Pixel(row2Ptr, 2, currPixel);
1275 put4Pixel(row2Ptr, 3, currPixel);
1276 put4Pixel(row3Ptr, 0, currPixel);
1277 put4Pixel(row3Ptr, 1, currPixel);
1278 put4Pixel(row3Ptr, 2, currPixel);
1279 put4Pixel(row3Ptr, 3, currPixel);
1281 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e41si;
1282 m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1283 m_pixel_filtered_flags[0][pixelNum+2] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1284 m_pixel_filtered_flags[0][pixelNum+3] = m_pixel_filtered_flags[0][pixelNum+1] & ~e41s;
1286 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e41ni; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1287 m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1288 m_pixel_filtered_flags[1][pixelNum+2] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1289 m_pixel_filtered_flags[1][pixelNum+3] = m_pixel_filtered_flags[1][pixelNum+1] & ~e41n;
1293 row1Ptr += 4*eBufferedPixelWidthInBytes;
1294 row2Ptr += 4*eBufferedPixelWidthInBytes;
1295 row3Ptr += 4*eBufferedPixelWidthInBytes;
1297 else if ((m_pixel_filtered_flags[0][pixelNum] & e21sw)
1298 && (m_pixel_filtered_flags[1][pixelNum] & e21nw))
1302 - - We have two 2x1s.
1307 ASSERT(!((m_pixel_filtered_flags[0][pixelNum] & e11s) | (m_pixel_filtered_flags[0][pixelNum+1] & e11s)));
1308 ASSERT(!((m_pixel_filtered_flags[1][pixelNum] & e11n) | (m_pixel_filtered_flags[1][pixelNum+1] & e11n)));
1310 upPixel = get4Pixel(row2Ptr);
1311 currPixel = get4Pixel(row3Ptr);
1313 R1 = GetRed(currPixel);
1314 G1 = GetGreen(currPixel);
1315 B1 = GetBlue(currPixel);
1317 R0 = GetRed(upPixel);
1318 G0 = GetGreen(upPixel);
1319 B0 = GetBlue(upPixel);
1321 if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1328 #if kGatherStats == 1
1329 blockStats[es22w]++;
1331 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1333 if(m_eEndian == LITTLEENDIAN)
1334 currPixel = (R1<<16) + (G1<<8) + B1;
1335 else if(m_eEndian == BIGENDIAN)
1336 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1338 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1339 put4Pixel(row2Ptr, 0, currPixel);
1340 put4Pixel(row2Ptr, 1, currPixel);
1341 put4Pixel(row3Ptr, 0, currPixel);
1342 put4Pixel(row3Ptr, 1, currPixel);
1344 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e21sw;
1345 m_pixel_filtered_flags[0][pixelNum+1] = m_pixel_filtered_flags[0][pixelNum+1] & ~e21se;
1347 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e21nw; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1348 m_pixel_filtered_flags[1][pixelNum+1] = m_pixel_filtered_flags[1][pixelNum+1] & ~e21ne;
1353 row1Ptr += 2*eBufferedPixelWidthInBytes;
1354 row2Ptr += 2*eBufferedPixelWidthInBytes;
1355 row3Ptr += 2*eBufferedPixelWidthInBytes;
1357 else if ((m_pixel_filtered_flags[0][pixelNum] & e11s)
1358 && (m_pixel_filtered_flags[1][pixelNum] & e11n))
1368 upPixel = get4Pixel(row2Ptr);
1369 currPixel = get4Pixel(row3Ptr);
1371 R1 = GetRed(currPixel);
1372 G1 = GetGreen(currPixel);
1373 B1 = GetBlue(currPixel);
1375 R0 = GetRed(upPixel);
1376 G0 = GetGreen(upPixel);
1377 B0 = GetBlue(upPixel);
1379 if ((m_max_error_for_two_pixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, m_max_error_for_two_pixels)))
1386 #if kGatherStats == 1
1387 blockStats[es12w]++;
1389 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1391 if(m_eEndian == LITTLEENDIAN)
1392 currPixel = (R1<<16) + (G1<<8) + B1;
1393 else if(m_eEndian == BIGENDIAN)
1394 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1396 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1397 put4Pixel(row2Ptr, 0, currPixel);
1398 put4Pixel(row3Ptr, 0, currPixel);
1400 m_pixel_filtered_flags[0][pixelNum] = m_pixel_filtered_flags[0][pixelNum] & ~e11s;
1402 m_pixel_filtered_flags[1][pixelNum] = m_pixel_filtered_flags[1][pixelNum] & ~e11n; // Note that we just formed a 2x2 in the middle of the filtered sets of rows (and do not remember it). We then remove the 2x1s that the 2x2 eliminated.
1407 row1Ptr += eBufferedPixelWidthInBytes;
1408 row2Ptr += eBufferedPixelWidthInBytes;
1409 row3Ptr += eBufferedPixelWidthInBytes;
1411 else // Do no vertical filtering here.
1415 row1Ptr += eBufferedPixelWidthInBytes;
1416 row2Ptr += eBufferedPixelWidthInBytes;
1417 row3Ptr += eBufferedPixelWidthInBytes;
1422 #define NEWTEST true
1424 inline bool ErnieFilter::NewDeltaE(int dr0, int dr1, int dg0, int dg1, int db0, int db1, int tolerance)
1426 int Y0, Y1, dY, Cr0, Cr1, Cb0, Cb1, dCr, dCb;
1428 // new Delta E stuff from Jay
1430 Y0 = 5*dr0 + 9*dg0 + 2*db0;
1431 Y1 = 5*dr1 + 9*dg1 + 2*db1;
1433 dY = ABS(Y0 - Y1) >> 4;
1435 if(dY > tolerance) {
1440 Cr0 = (dr0 << 4) - Y0;
1441 Cr1 = (dr1 << 4) - Y1;
1442 dCr = ABS(Cr0 - Cr1) >> 5;
1449 Cb0 = (db0 << 4) - Y0;
1450 Cb1 = (db1 << 4) - Y1;
1451 dCb = ABS(Cb0 - Cb1) >> 6;
1461 ErnieFilter::ErnieFilter(int rowWidthInPixels, pixelTypes pixelType, unsigned int maxErrorForTwoPixels)
1464 m_input_bytes_per_pixel = 3;
1465 ASSERT(rowWidthInPixels > 0);
1466 ASSERT(pixelType == eBGRPixelData);
1474 m_eEndian = LITTLEENDIAN;
1475 if (uEndian.c[0] == 0x0A)
1476 m_eEndian = BIGENDIAN;
1478 m_internal_bytes_per_pixel = 4;
1480 m_pixel_offsets_index = 0;
1481 m_row_width_in_pixels = rowWidthInPixels;
1482 m_row_width_in_bytes = m_row_width_in_pixels*m_internal_bytes_per_pixel;
1483 m_max_error_for_two_pixels = maxErrorForTwoPixels;
1485 for (index = 0; index < 4; index++)
1487 m_row_bufs[index] = new uint32_t[rowWidthInPixels];
1488 ASSERT(m_row_bufs[index]);
1490 m_row_ptrs[index] = new unsigned char[rowWidthInPixels*m_input_bytes_per_pixel];
1491 ASSERT(m_row_ptrs[index]);
1493 m_black_row_ptrs[index] = new BYTE[rowWidthInPixels*m_input_bytes_per_pixel];
1494 ASSERT(m_black_row_ptrs[index]);
1496 m_black_raster_sizes[index] = 0;
1499 for (index = 0; index < 2; index++)
1501 m_pixel_filtered_flags[index] = new unsigned int[rowWidthInPixels];
1502 ASSERT(m_pixel_filtered_flags[index]);
1505 // The least compressible image will be all raw pixels. Maximum compressed size is:
1506 // full size + a bloat of Cmd byte + 1 VLI byte per 255 pixels rounded up to nearest integer.
1508 int maxCompressionBufSize = m_row_width_in_bytes + 1 + ((int)ceil((double) MAX((rowWidthInPixels-2)/255, 0)));
1510 m_compression_out_buf = new unsigned char[maxCompressionBufSize];
1511 ASSERT(m_compression_out_buf);
1513 m_buffered_row_count = 0;
1515 m_pixel_offsets[0] = 0;
1516 m_pixel_offsets[1] = 5;
1517 m_pixel_offsets[2] = 2;
1518 m_pixel_offsets[3] = 7;
1519 m_pixel_offsets[4] = 1;
1520 m_pixel_offsets[5] = 4;
1521 m_pixel_offsets[6] = 6;
1522 m_pixel_offsets[7] = 3;
1528 ErnieFilter::~ErnieFilter()
1530 // Deallocate memory next.
1533 for (index = 0; index < 4; index++)
1535 delete [] m_row_bufs[index];
1536 delete [] m_row_ptrs[index];
1537 delete [] m_black_row_ptrs[index];
1540 for (index = 0; index < 2; index++)
1542 delete [] m_pixel_filtered_flags[index];
1545 delete [] m_compression_out_buf;
1548 void ErnieFilter::writeBufferedRows()
1552 // We just have one lonely raster left. Nothing
1553 // we can do but filter it horizontally.
1554 if( 1 == m_buffered_row_count)
1557 int offset2 = m_pixel_offsets[m_pixel_offsets_index];
1559 Filter1RawRow( (unsigned char*)(m_row_bufs[0] + offset2),
1560 m_row_width_in_pixels - m_pixel_offsets[m_pixel_offsets_index],
1561 m_pixel_filtered_flags[0] + m_pixel_offsets[m_pixel_offsets_index]);
1564 unsigned char *rowPtr = m_row_ptrs[0];
1569 memcpy(rowPtr, &m_row_bufs[0][pixelIndex], 3);
1571 } while (++pixelIndex < m_row_width_in_pixels);
1574 // If we've got a pair of rasters in the buffer, that pair
1575 // has already been filtered somewhat. So lets just write them
1576 // out, some filtering is better than none.
1577 else if (2 == m_buffered_row_count)
1579 // Write the two rows back out.
1581 for (k = 0; k < 2; k++)
1583 unsigned char *rowPtr = m_row_ptrs[k];
1588 memcpy(rowPtr, &m_row_bufs[k][pixelIndex], 3);
1590 } while (++pixelIndex < m_row_width_in_pixels);
1593 // Okay, if we had three rasters in the buffer, the pair
1594 // should have already been written out above, so lets
1595 // just run the odd raster through Ernie with to
1596 // get the horizontal filtering. [Need to look to see
1597 // if there's something more we can do with filtering
1598 // all three together.]
1599 else if (3 == m_buffered_row_count)
1602 int offset2 = m_pixel_offsets[m_pixel_offsets_index];
1604 Filter1RawRow( (unsigned char*)(m_row_bufs[2] + offset2),
1605 m_row_width_in_pixels - m_pixel_offsets[m_pixel_offsets_index],
1606 m_pixel_filtered_flags[1] + m_pixel_offsets[m_pixel_offsets_index]);
1609 Filter3FilteredRows( (unsigned char*)m_row_bufs[0],
1610 (unsigned char*)m_row_bufs[1],
1611 (unsigned char*)m_row_bufs[2]);
1614 for (k = 0; k < 3; k++)
1616 unsigned char *rowPtr = m_row_ptrs[k];
1621 memcpy(rowPtr, &m_row_bufs[k][pixelIndex], 3);
1623 } while (++pixelIndex < m_row_width_in_pixels);
1628 void ErnieFilter::submitRowToFilter(unsigned char *rowPtr)
1630 memcpy(m_row_ptrs[m_buffered_row_count], rowPtr, m_row_width_in_pixels*m_input_bytes_per_pixel);
1633 uint32_t *RowPtrDest = m_row_bufs[m_buffered_row_count];
1642 if(m_eEndian == LITTLEENDIAN)
1643 RowPtrDest[pixelIndex] = ((byte3 << 16) | (byte2 << 8) | (byte1)) & 0x00FFFFFF;
1644 else if(m_eEndian == BIGENDIAN)
1645 RowPtrDest[pixelIndex] = ((byte1 << 24) | (byte2 << 16) | (byte3 << 8)) & 0xFFFFFF00;
1646 } while (++pixelIndex < m_row_width_in_pixels);
1648 m_buffered_row_count++;
1651 iRastersDelivered=0;
1653 // Next see about filtering & compression.
1654 // NOTE 1: as an optimization only do subsections of the raster at a time to stay in cache.
1655 // NOTE 2: Could filter the pixels left of the offset.
1656 if (2 == m_buffered_row_count)
1658 int offset2 = m_pixel_offsets[m_pixel_offsets_index];
1660 Filter2RawRows( (unsigned char*)(m_row_bufs[1] + offset2),
1661 (unsigned char*)(m_row_bufs[0] + offset2),
1662 m_row_width_in_pixels - m_pixel_offsets[m_pixel_offsets_index],
1663 m_pixel_filtered_flags[0] + m_pixel_offsets[m_pixel_offsets_index]);
1666 if (4 == m_buffered_row_count)
1668 int offset4 = m_pixel_offsets[m_pixel_offsets_index];
1669 Filter2RawRows( (unsigned char*)(m_row_bufs[3] + offset4),
1670 (unsigned char*)(m_row_bufs[2] + offset4),
1671 m_row_width_in_pixels - m_pixel_offsets[m_pixel_offsets_index],
1672 m_pixel_filtered_flags[1] + m_pixel_offsets[m_pixel_offsets_index]);
1674 Filter2PairsOfFilteredRows( (unsigned char*)m_row_bufs[0],
1675 (unsigned char*)m_row_bufs[1],
1676 (unsigned char*)m_row_bufs[2],
1677 (unsigned char*)m_row_bufs[3]);
1679 #if kMemWritesOptimize == 1
1680 // Writing the blocks out on a post processing step in this manner could leave the last 3 rows
1681 // unfiltered. This is a trade off we make for simplicity. The resulting loss in compression is small.
1685 m_pixel_offsets_index = (m_pixel_offsets_index + 1) % 8; // cycle the offset index.
1688 for (k = 0; k < m_pixel_offsets[m_pixel_offsets_index]; k++) // Clear out the flags that we're offsetting past for this next iteration.
1690 m_pixel_filtered_flags[0][k] = eDone;
1691 m_pixel_filtered_flags[1][k] = eDone;
1694 // Write the four rows back out.
1695 for (k = 0; k < 4; k++)
1697 unsigned char *rowPtr = m_row_ptrs[k];
1702 memcpy(rowPtr, &m_row_bufs[k][pixelIndex], m_input_bytes_per_pixel);
1703 rowPtr += m_input_bytes_per_pixel;
1704 } while (++pixelIndex < m_row_width_in_pixels);
1707 m_buffered_row_count = 0;
1712 #if kMemWritesOptimize == 1
1714 At this point the color for the entire block is stored in the top left
1715 corner of the block. This routine takes that pixel and smears it into the
1718 void ErnieFilter::WriteBlockPixels(void)
1720 unsigned char *row1Ptr = (unsigned char*)m_row_bufs[0];
1721 unsigned char *row2Ptr = (unsigned char*)m_row_bufs[1];
1722 unsigned char *row3Ptr = (unsigned char*)m_row_bufs[2];
1723 unsigned char *row4Ptr = (unsigned char*)m_row_bufs[3];
1725 for (int flagSet = 0; flagSet <= 1; flagSet++)
1727 unsigned int *flagsPtr = m_pixel_filtered_flags[0];
1728 unsigned char *rowA = (unsigned char*)m_row_bufs[0];
1729 unsigned char *rowB = (unsigned char*)m_row_bufs[1];
1733 flagsPtr = m_pixel_filtered_flags[1];
1734 rowA = (unsigned char*)m_row_bufs[2];
1735 rowB = (unsigned char*)m_row_bufs[3];
1738 for (int rowIndex = 0; rowIndex < m_row_width_in_pixels;)
1740 unsigned int currentFlags = flagsPtr[rowIndex];
1742 #ifndef NDEBUG /* only done for debug builds */
1743 int numberOfBitsSet = 0;
1744 unsigned int currentFlagsCopy = currentFlags & eTopLeftOfBlocks;
1745 while (currentFlagsCopy)
1747 if (currentFlagsCopy & 1) numberOfBitsSet++;
1748 currentFlagsCopy >>= 1;
1750 ASSERT( (numberOfBitsSet <= 1) ||
1751 ((numberOfBitsSet == 2) &&
1752 (((currentFlags & eTopLeftOfBlocks) & ~(e21nw|e21sw|e41ni|e41si))==0)));
1755 if (currentFlags & eTopLeftOfBlocks) // Avoids doing a lot of checks if nothing is set.
1757 // unsigned int pixel;
1759 // The three possible scenerios are:
1760 // 1: No top left of block bits are set.
1761 // 2: 1 top left block bit is set.
1762 // 3: 2 top left block bits are set. They are 21nw and 21sw.
1764 // Note: Due to possibly having two groups tracked by this flag we require the north checks to occur before the south checks.
1765 if (currentFlags & e22w)
1767 pixel = get4Pixel(rowA, rowIndex);
1769 put4Pixel(rowB, rowIndex, pixel);
1771 put4Pixel(rowA, rowIndex, pixel);
1772 put4Pixel(rowB, rowIndex, pixel);
1778 if (currentFlags & e12)
1780 put4Pixel(rowB, rowIndex, get4Pixel(rowA, rowIndex));
1786 if (currentFlags & e42i)
1788 pixel = get4Pixel(rowA, rowIndex);
1790 put4Pixel(rowB, rowIndex, pixel);
1793 put4Pixel(rowA, rowIndex, pixel);
1794 put4Pixel(rowB, rowIndex, pixel);
1797 put4Pixel(rowB, rowIndex, pixel);
1798 put4Pixel(rowA, rowIndex, pixel);
1801 put4Pixel(rowA, rowIndex, pixel);
1802 put4Pixel(rowB, rowIndex, pixel);
1808 if (currentFlags & e84ni)
1810 pixel = get4Pixel(rowA, rowIndex);
1812 put4Pixel(row2Ptr, rowIndex, pixel);
1813 put4Pixel(row3Ptr, rowIndex, pixel);
1814 put4Pixel(row4Ptr, rowIndex, pixel);
1817 put4Pixel(row1Ptr, rowIndex, pixel);
1818 put4Pixel(row2Ptr, rowIndex, pixel);
1819 put4Pixel(row3Ptr, rowIndex, pixel);
1820 put4Pixel(row4Ptr, rowIndex, pixel);
1823 put4Pixel(row1Ptr, rowIndex, pixel);
1824 put4Pixel(row2Ptr, rowIndex, pixel);
1825 put4Pixel(row3Ptr, rowIndex, pixel);
1826 put4Pixel(row4Ptr, rowIndex, pixel);
1829 put4Pixel(row1Ptr, rowIndex, pixel);
1830 put4Pixel(row2Ptr, rowIndex, pixel);
1831 put4Pixel(row3Ptr, rowIndex, pixel);
1832 put4Pixel(row4Ptr, rowIndex, pixel);
1835 put4Pixel(row1Ptr, rowIndex, pixel);
1836 put4Pixel(row2Ptr, rowIndex, pixel);
1837 put4Pixel(row3Ptr, rowIndex, pixel);
1838 put4Pixel(row4Ptr, rowIndex, pixel);
1841 put4Pixel(row1Ptr, rowIndex, pixel);
1842 put4Pixel(row2Ptr, rowIndex, pixel);
1843 put4Pixel(row3Ptr, rowIndex, pixel);
1844 put4Pixel(row4Ptr, rowIndex, pixel);
1847 put4Pixel(row1Ptr, rowIndex, pixel);
1848 put4Pixel(row2Ptr, rowIndex, pixel);
1849 put4Pixel(row3Ptr, rowIndex, pixel);
1850 put4Pixel(row4Ptr, rowIndex, pixel);
1853 put4Pixel(row1Ptr, rowIndex, pixel);
1854 put4Pixel(row2Ptr, rowIndex, pixel);
1855 put4Pixel(row3Ptr, rowIndex, pixel);
1856 put4Pixel(row4Ptr, rowIndex, pixel);
1863 if (currentFlags & e24nw)
1865 pixel = get4Pixel(row1Ptr, rowIndex);
1867 put4Pixel(row2Ptr, rowIndex, pixel);
1868 put4Pixel(row3Ptr, rowIndex, pixel);
1869 put4Pixel(row4Ptr, rowIndex, pixel);
1872 put4Pixel(row1Ptr, rowIndex, pixel);
1873 put4Pixel(row2Ptr, rowIndex, pixel);
1874 put4Pixel(row3Ptr, rowIndex, pixel);
1875 put4Pixel(row4Ptr, rowIndex, pixel);
1881 if (currentFlags & e44ni)
1883 pixel = get4Pixel(row1Ptr, rowIndex);
1885 put4Pixel(row2Ptr, rowIndex, pixel);
1886 put4Pixel(row3Ptr, rowIndex, pixel);
1887 put4Pixel(row4Ptr, rowIndex, pixel);
1890 put4Pixel(row1Ptr, rowIndex, pixel);
1891 put4Pixel(row2Ptr, rowIndex, pixel);
1892 put4Pixel(row3Ptr, rowIndex, pixel);
1893 put4Pixel(row4Ptr, rowIndex, pixel);
1896 put4Pixel(row1Ptr, rowIndex, pixel);
1897 put4Pixel(row2Ptr, rowIndex, pixel);
1898 put4Pixel(row3Ptr, rowIndex, pixel);
1899 put4Pixel(row4Ptr, rowIndex, pixel);
1902 put4Pixel(row1Ptr, rowIndex, pixel);
1903 put4Pixel(row2Ptr, rowIndex, pixel);
1904 put4Pixel(row3Ptr, rowIndex, pixel);
1905 put4Pixel(row4Ptr, rowIndex, pixel);
1911 if (currentFlags & e14n)
1913 pixel = get4Pixel(row1Ptr, rowIndex);
1915 put4Pixel(row2Ptr, rowIndex, pixel);
1916 put4Pixel(row3Ptr, rowIndex, pixel);
1917 put4Pixel(row4Ptr, rowIndex, pixel);
1923 if (currentFlags & e21nw)
1925 put4Pixel(rowA, rowIndex+1, get4Pixel(rowA, rowIndex));
1927 if (!(currentFlags & (e21sw|e41si))) // if no south groups
1934 if (currentFlags & e41ni)
1936 pixel = get4Pixel(rowA, rowIndex);
1938 put4Pixel(rowA, rowIndex+1, pixel);
1939 put4Pixel(rowA, rowIndex+2, pixel);
1940 put4Pixel(rowA, rowIndex+3, pixel);
1942 if (!(currentFlags & (e21sw|e41si))) // if no south groups.
1949 if (currentFlags & e21sw)
1951 put4Pixel(rowB, rowIndex+1, get4Pixel(rowB, rowIndex));
1957 if (currentFlags & e41si)
1959 pixel = get4Pixel(rowB, rowIndex);
1961 put4Pixel(rowB, rowIndex+1, pixel);
1962 put4Pixel(rowB, rowIndex+2, pixel);
1963 put4Pixel(rowB, rowIndex+3, pixel);
1974 #endif // kMemWritesOptimize
1976 bool ErnieFilter::Process (RASTERDATA* ImageData)
1978 if ( ImageData == NULL ||
1979 (ImageData->rasterdata[COLORTYPE_COLOR] == NULL && ImageData->rasterdata[COLORTYPE_BLACK] == NULL))
1983 if (ImageData->rasterdata[COLORTYPE_BLACK])
1985 memcpy(m_black_row_ptrs[m_row_index], ImageData->rasterdata[COLORTYPE_BLACK],
1986 (ImageData->rastersize[COLORTYPE_BLACK] + 7) / 8);
1988 m_black_raster_sizes[m_row_index++] = ImageData->rastersize[COLORTYPE_BLACK];
1990 if (m_row_index == 4)
1992 if (ImageData->rasterdata[COLORTYPE_COLOR])
1994 submitRowToFilter(ImageData->rasterdata[COLORTYPE_COLOR]);
1996 // something ready after 4th time only
1997 return (m_buffered_row_count == 0);
2003 bool ErnieFilter::NextOutputRaster(RASTERDATA& next_raster)
2005 if (iRastersReady == 0){
2009 next_raster.rastersize[COLORTYPE_COLOR] = m_row_width_in_pixels * m_input_bytes_per_pixel;
2010 next_raster.rasterdata[COLORTYPE_COLOR] = m_row_ptrs[iRastersDelivered];
2011 next_raster.rastersize[COLORTYPE_BLACK] = m_black_raster_sizes[iRastersDelivered];
2012 if ( m_black_raster_sizes[iRastersDelivered] > 0 ){
2013 next_raster.rasterdata[COLORTYPE_BLACK] = m_black_row_ptrs[iRastersDelivered];
2015 next_raster.rasterdata[COLORTYPE_BLACK] = NULL;
2018 iRastersDelivered++;
2019 if (iRastersDelivered == 4) iRastersDelivered = 0;
2021 } //NextOutputRaster
2023 unsigned int ErnieFilter::GetMaxOutputWidth()
2025 return m_row_width_in_pixels * m_input_bytes_per_pixel;
2026 } //GetMaxOutputWidth
2028 void ErnieFilter::Flush()
2030 writeBufferedRows();
2031 iRastersDelivered=0;
2032 m_pixel_offsets_index = 0;
2033 iRastersReady = m_buffered_row_count;
2034 m_buffered_row_count = 0;