Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / filterhpa.cpp
1 /*****************************************************************************\
2   filterhpa.cpp : Implimentation for the TErnieFilter class
3
4   Copyright (c) 1996 - 2001, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
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.
18
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 \*****************************************************************************/
30
31
32 #if defined(APDK_DJ9xxVIP) && defined(APDK_VIP_COLORFILTERING)
33
34 #include "header.h"
35
36 // copied from vob \di_research on 10/31/00
37 // MODIFICATIONS BY GE:
38 // 0. remove Windows header references
39 // 1. define assert
40 // 2. set iRastersReady, iRastersDelivered in submitrowtofilter
41 // 3. (constructor) allocate (and delete in destructor) buffers for fRowPtr
42 //      (instead of setting it to input buffers, since we reuse input buffers)
43 // 4. copy data into fRowPtr in submitrowtofilter
44
45 //#define assert ASSERT
46
47 #include "ernieplatform.h"
48 #include "filterhpa.h"
49
50 #if kGatherStats == 1
51 extern int blockStats[];
52 #endif
53
54 #if ((kMemWritesOptimize != 1) && (kMemWritesOptimize != 0))
55 #error "kMemWritesOptimize must be 0 or 1"
56 #endif
57
58 APDK_BEGIN_NAMESPACE
59
60 inline void AverageNRound(bool roundGreenDown, int &rFinal, int &r0, int &r1, int &gFinal, int &g0, int &g1, int &bFinal, int &b0, int &b1);
61 inline void AverageNRound(bool roundGreenDown, int &rFinal, int &r0, int &r1, int &gFinal, int &g0, int &g1, int &bFinal, int &b0, int &b1)
62 {
63     // 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.
64     if (roundGreenDown)
65     {
66         rFinal = (r0 + r1 + 1) / 2;
67         gFinal = (g0 + g1) / 2;
68         bFinal = (b0 + b1 + 1) / 2;
69     }
70     else
71     {
72         rFinal = (r0 + r1) / 2;
73         gFinal = (g0 + g1 + 1) / 2;
74         bFinal = (b0 + b1) / 2;
75     }
76 }
77
78
79 // Filter1RawRow.  To be used to filter an odd row for which we don't have a pair,
80 // found at the bottom of bands that aren't divisable by 2.  This routine
81 // filters its row horizontally forming 4x1 and 2x1 blocks.
82 void TErnieFilter::Filter1RawRow(unsigned char *currPtr, int rowWidthInPixels, unsigned int *flagsPtr)
83 {
84     ASSERT(currPtr);
85     ASSERT(rowWidthInPixels > 0);
86
87     int R0, G0, B0, R1, G1, B1, lastR, lastG, lastB;
88     const unsigned int maxErrorForFourPixels = fMaxErrorForTwoPixels / 2;
89 //    const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
90
91 //    int currPixel, lastPixel;
92     uint32_t currPixel, lastPixel;
93     bool lastPairAveraged = false;
94     bool last2by2Averaged = false;
95
96
97     for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
98     {
99         if ((pixelNum & 0x03) == 0x00) // 0,4,8...
100         {
101             last2by2Averaged = false; // Reinitialize every four columns;
102         }
103
104         currPixel = get4Pixel(currPtr);
105
106         flagsPtr[0] = (e11n|e11s);  // Initialize in case nothing is found for this column
107
108         if (isWhite(currPixel))
109         {
110             flagsPtr[0] = eDone;
111 #if kGatherStats == 1
112             blockStats[esWhiteFound]++;
113 #endif
114         }
115
116         // Currently we bail entirely if there is white. Later we may still do RLE on the non white pixel if one is present.
117         if (flagsPtr[0] == (e11n|e11s))
118         {
119             R1 = GetRed(currPixel);
120             G1 = GetGreen(currPixel);
121             B1 = GetBlue(currPixel);
122
123             // Can only horizontally average every other pixel, much like the 2x2 blocks.
124             if (isOdd(pixelNum))
125             {
126                 // do horizontal on current raster
127                 lastPixel = get4Pixel(currPtr,-1);
128                 lastR = GetRed(lastPixel);
129                 lastG = GetGreen(lastPixel);
130                 lastB = GetBlue(lastPixel);
131                 if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1, lastB, B1, fMaxErrorForTwoPixels)))
132                 {
133                     /*   - -
134                         |   | build 2x1
135                          - -
136                     */
137                     int didNotBuild4by1 = true;
138 #if kGatherStats == 1
139                     blockStats[es21nw]++;
140 #endif
141                     AverageNRound(isOdd(pixelNum), lastR, lastR, R1, lastG, lastG, G1, lastB, lastB, B1);
142                     if ((pixelNum >= 3) && (flagsPtr[-3] & e21nw)) // 4,5,6,7,12,13,14,15,20...
143                     {
144                         // Look for a 4x1
145                         ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
146
147                         lastPixel = get4Pixel(currPtr,-3);
148                         R0 = GetRed(lastPixel);
149                         G0 = GetGreen(lastPixel);
150                         B0 = GetBlue(lastPixel);
151                         if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0, lastB, B0, maxErrorForFourPixels)))
152                         {
153                             /*   - - - -
154                                 |       | build 4x1
155                                  - - - -
156                             */
157 #if kGatherStats == 1
158                             blockStats[es41ni]++;
159 #endif
160                             didNotBuild4by1 = false;
161                             AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
162
163                             if(littleEndian)
164                                 currPixel = (lastR<<16) + (lastG<<8) + lastB;
165                             else if(bigEndian)
166                                 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
167
168 #if kMemWritesOptimize == 0
169                             put4Pixel(currPtr, -3, currPixel);
170                             put4Pixel(currPtr, -2, currPixel);
171                             put4Pixel(currPtr, -1, currPixel);
172                             put4Pixel(currPtr, 0, currPixel);
173 #else
174                             put4Pixel(currPtr, -3, currPixel);
175 #endif
176                             flagsPtr[-3] = (flagsPtr[-3] & ~eNorths) | e41ni;
177                             flagsPtr[-2] = (flagsPtr[-2] & ~eNorths) | e41n;
178                             flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e41n;
179                             flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e41n;
180                         }
181                     }
182
183                     if (didNotBuild4by1) // Not a 4x1 so output 2x1.
184                     {
185                         ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
186
187                         if(littleEndian)
188                             currPixel = (lastR<<16) + (lastG<<8) + lastB;
189                         else if(bigEndian)
190                             currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
191
192 #if kMemWritesOptimize == 0
193                         put4Pixel(currPtr, -1, currPixel);
194                         put4Pixel(currPtr, 0, currPixel);
195 #else
196                         put4Pixel(currPtr, -1, currPixel);
197 #endif
198                         flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
199                         flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
200                     }
201                 }  // If DeltaE... Looking for two by one
202             }  // IsOdd(pixelNum)
203         }
204         else // no flag bits set.
205         {
206             lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
207         }
208
209         currPtr += eBufferedPixelWidthInBytes;
210         flagsPtr++;
211     }      // for each pixel...
212 }
213
214 // Filter2RawRows:  Looks filter two raw rows together to form blocks.  Vertical
215 // blocks are prefered over horizontal ones.  The routine will create 1x2 blocks
216 // before it will create 4x1's.  In total this routine will create 1x2, 2x2, 4x2,
217 // 4x1, and 2x1 blocks sizes, with the potential for two seperate 4x1's or 2x1's
218 // in the upper and lower rasters.
219 void TErnieFilter::Filter2RawRows(unsigned char *currPtr, unsigned char *upPtr, int rowWidthInPixels, unsigned int *flagsPtr)
220 {
221     ASSERT(currPtr);
222     ASSERT(upPtr);
223     ASSERT(rowWidthInPixels > 0);
224
225     int R0, G0, B0, R1, G1, B1, lastR, lastG, lastB;
226     const unsigned int maxErrorForFourPixels = fMaxErrorForTwoPixels / 2;
227     const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
228
229 //    int currPixel, upPixel, lastPixel;
230     uint32_t currPixel, upPixel, lastPixel;
231     bool lastPairAveraged = false;
232     bool last2by2Averaged = false;
233
234     for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
235     {
236         if ((pixelNum & 0x03) == 0x00) // 0,4,8...
237         {
238             last2by2Averaged = false; // Reinitialize every four columns;
239         }
240
241         upPixel = get4Pixel(upPtr);
242         currPixel = get4Pixel(currPtr);
243
244         flagsPtr[0] = (e11n|e11s);  // Initialize in case nothing is found for this column
245
246         if (isWhite(upPixel) && isWhite(currPixel)) // both white?
247         {
248             flagsPtr[0] = eDone;
249 #if kGatherStats == 1
250             blockStats[esWhiteFound]++;
251 #endif
252         }
253
254         // Do vertical average on the current 2 pixel high column
255
256         // Currently we bail entirely if there is white. Later we may still do RLE on the non white pixel if one is present.
257         if (flagsPtr[0] == (e11n|e11s))
258         {
259             R1 = GetRed(currPixel);
260             G1 = GetGreen(currPixel);
261             B1 = GetBlue(currPixel);
262
263             R0 = GetRed(upPixel);
264             G0 = GetGreen(upPixel);
265             B0 = GetBlue(upPixel);
266
267             if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R0, R1, G0, G1, B0, B1, fMaxErrorForTwoPixels)))
268             {
269                 /*   _
270                     | | build 1x2
271                     | |
272                      -
273                 */
274                 ASSERT(flagsPtr[0] == (e11n|e11s));
275                 flagsPtr[0] = e12;
276 #if kGatherStats == 1
277                 blockStats[es12]++;
278 #endif
279                 R1 = GetRed(currPixel);
280                 G1 = GetGreen(currPixel);
281                 B1 = GetBlue(currPixel);
282
283                 R0 = GetRed(upPixel);
284                 G0 = GetGreen(upPixel);
285                 B0 = GetBlue(upPixel);
286
287                 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
288
289                 // look for a 2x2 block average on every other column
290                 if (isOdd(pixelNum))
291                 {   // It looks like we are at the end of a 2x2 block
292                     if (lastPairAveraged)
293                     {
294                         // Last pair was averaged so it's ok to try to make a 2x2 block
295                         if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1,lastB, B1, maxErrorForFourPixels)))
296                         {
297                             /* - -
298                               |   | build 2x2
299                               |   |
300                                - -
301                             */
302                             ASSERT(flagsPtr[-1] == e12);
303                             int didNotBuild4by2 = true;
304 #if kGatherStats == 1
305                             blockStats[es22w]++;
306 #endif
307                             flagsPtr[-1] = e22w;
308                             flagsPtr[0] = e22e;
309
310                             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
311
312                             if ((pixelNum & 0x03) == 0x03)  // 3,7,11,15... Looking for a 4x2 block to average
313                             {
314                                 if (last2by2Averaged)
315                                 {
316                                     /*   - -   - -
317                                         |   | |   | We have two 2x2s.
318                                         |   | |   |
319                                          - -   - -
320                                     */
321
322                                     lastPixel = get4Pixel(upPtr, -3); // Go back to previous 2x2 block and get the pixel
323                                     lastR = GetRed(lastPixel);
324                                     lastG = GetGreen(lastPixel);
325                                     lastB = GetBlue(lastPixel);
326                                     if ((maxErrorForEightPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1,lastB, B1, maxErrorForEightPixels)))
327                                     {
328
329
330                                         /* - - - -
331                                           |       | build 4x2.
332                                           |       |
333                                            - - - -
334                                         */
335 #if kGatherStats == 1
336                                         blockStats[es42i]++;
337 #endif
338                                         didNotBuild4by2 = false;
339
340                                         flagsPtr[-3] = e42i;
341                                         flagsPtr[-2] = flagsPtr[-1] = flagsPtr[0] = e42;
342
343                                         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
344
345                                         if(littleEndian)
346                                             currPixel = (R1<<16) + (G1<<8) + B1;
347                                         else if(bigEndian)
348                                             currPixel = (R1<<24) + (G1<<16) + (B1<<8);
349
350 #if kMemWritesOptimize == 0
351                                         put4Pixel(upPtr, -3, currPixel);
352                                         put4Pixel(upPtr, -2, currPixel);
353                                         put4Pixel(upPtr, -1, currPixel);
354                                         put4Pixel(upPtr,  0, currPixel);
355                                         put4Pixel(currPtr, -3, currPixel);
356                                         put4Pixel(currPtr, -2, currPixel);
357                                         put4Pixel(currPtr, -1, currPixel);
358                                         put4Pixel(currPtr, 0, currPixel);
359 #else
360                                         put4Pixel(upPtr, -3, currPixel);
361 #endif
362                                     }
363                                 }
364
365                                 if (didNotBuild4by2)
366                                 {   // The first 2x2 block of this pair of 2x2 blocks wasn't averaged.
367                                     /*    - -    - -
368                                          |X X|  |   | not averaged block and averaged 2x2.
369                                          |X X|  |   |
370                                           - -    - -
371                                     */
372
373                                     last2by2Averaged = true;
374
375                                     if(littleEndian)
376                                         currPixel = (R1<<16) + (G1<<8) + B1;
377                                     else if(bigEndian)
378                                         currPixel = (R1<<24) + (G1<<16) + (B1<<8);
379
380 #if kMemWritesOptimize == 0
381                                     put4Pixel(upPtr, -1, currPixel);
382                                     put4Pixel(upPtr, 0, currPixel);
383                                     put4Pixel(currPtr, -1, currPixel);
384                                     put4Pixel(currPtr, 0, currPixel);
385 #else
386                                     put4Pixel(upPtr, -1, currPixel);
387 #endif
388                                 }
389                             }
390                             else  // Not looking for a 4x2 block yet so just output this 2x2 block for now.
391                             {
392                                 /*    - -    - -
393                                      |   |  |? ?| 1st 2x2 and maybe another later.
394                                      |   |  |? ?|
395                                       - -    - -
396                                 */
397
398                                 last2by2Averaged = true;
399
400                                 if(littleEndian)
401                                     currPixel = (R1<<16) + (G1<<8) + B1;
402                                 else if(bigEndian)
403                                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
404
405 #if kMemWritesOptimize == 0
406                                 put4Pixel(upPtr, -1, currPixel);
407                                 put4Pixel(upPtr, 0, currPixel);
408                                 put4Pixel(currPtr, -1, currPixel);
409                                 put4Pixel(currPtr, 0, currPixel);
410 #else
411                                 put4Pixel(upPtr, -1, currPixel);
412 #endif
413                             }
414                         }
415                         else  // The two averaged columns are not close enough in Delta E
416                         {
417                             /*  -    _
418                                | |  | | 2 1x2 blocks
419                                | |  | |
420                                 -    -
421                             */
422
423                             last2by2Averaged = false;
424
425                             if(littleEndian)
426                                 currPixel = (R1<<16) + (G1<<8) + B1;
427                             else if(bigEndian)
428                                 currPixel = (R1<<24) + (G1<<16) + (B1<<8);
429
430 #if kMemWritesOptimize == 0
431                             put4Pixel(upPtr, 0, currPixel);
432                             put4Pixel(currPtr, 0, currPixel);
433 #else
434                             put4Pixel(upPtr,0, currPixel);
435 #endif
436                         }
437                         lastR = R1;
438                         lastG = G1;
439                         lastB = B1;
440                         lastPairAveraged = true;
441                     }
442                     else  // This is the right place for 2x2 averaging but the previous column wasn't averaged
443                     {
444                         /*     -
445                             X | | Two non averaged pixels and a 1x2.
446                             X | |
447                                -
448                         */
449                         last2by2Averaged = false;
450                         lastPairAveraged = true;
451                         lastR = R1;
452                         lastG = G1;
453                         lastB = B1;
454
455                         if(littleEndian)
456                             currPixel = (R1<<16) + (G1<<8) + B1;
457                         else if(bigEndian)
458                             currPixel = (R1<<24) + (G1<<16) + (B1<<8);
459
460 #if kMemWritesOptimize == 0
461                         put4Pixel(upPtr, 0, currPixel);
462                         put4Pixel(currPtr, 0, currPixel);
463 #else
464                         put4Pixel(upPtr, 0, currPixel);
465 #endif
466                     }
467                 }
468                 else  // Not on the boundary for a 2x2 block, so just output current averaged 1x2 column
469                 {
470                     /*    -
471                          | | ?  1x2
472                          | | ?
473                           -
474                     */
475
476                     lastPairAveraged = true;
477                     lastR = R1;
478                     lastG = G1;
479                     lastB = B1;
480
481                     if(littleEndian)
482                         currPixel = (R1<<16) + (G1<<8) + B1;
483                     else if(bigEndian)
484                         currPixel = (R1<<24) + (G1<<16) + (B1<<8);
485
486 #if kMemWritesOptimize == 0
487                     put4Pixel(upPtr, 0, currPixel);
488                     put4Pixel(currPtr, 0, currPixel);
489 #else
490                     put4Pixel(upPtr, 0, currPixel);
491 #endif
492                 }
493             }
494             else if (lastPairAveraged)
495             {   // This is the case where we can't average current column and the last column was averaged.
496                 // Don't do anything if last pair was averaged and this one can't be
497
498                 /*    -
499                      | | X 1x2 averaged block and two non averaged pixels.
500                      | | X
501                       -
502                 */
503
504                 lastPairAveraged = false;
505             }
506             else
507              // can't vertically average current column so look for some horizontal averaging as a fallback
508              // Only do it if the last pair wasn't averaged either because we don't want to mess up a vertical averaging
509              // just to create a possible horizontal averaging.
510             {
511                 // Can only horizontally average every other pixel, much like the 2x2 blocks.
512                 if (isOdd(pixelNum))
513                 {
514                     // do horizontal averaging on previous raster
515                     lastPixel = get4Pixel(upPtr,-1);
516                     lastR = GetRed(lastPixel);
517                     lastG = GetGreen(lastPixel);
518                     lastB = GetBlue(lastPixel);
519                     if (((fMaxErrorForTwoPixels >= 3)) && (NewDeltaE(lastR, R0, lastG, G0,lastB, B0, fMaxErrorForTwoPixels)))
520                     {
521                         /*   - -
522                             |   | build upper 2x1
523                              - -
524                         */
525 #if kGatherStats == 1
526                         blockStats[es21nw]++;
527 #endif
528                         int didNotBuild4by1 = true;
529
530                         AverageNRound(isOdd(pixelNum), lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0);
531
532                         if ((pixelNum >= 3) && (flagsPtr[-3] & e21nw)) // 4,5,6,7,12,13,14,15,20...
533                         {
534                             ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
535
536                             // Attempt an upper 4x1
537                             lastPixel = get4Pixel(upPtr,-3);
538                             R0 = GetRed(lastPixel);
539                             G0 = GetGreen(lastPixel);
540                             B0 = GetBlue(lastPixel);
541                             if ( (maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0,lastB, B0, maxErrorForFourPixels)))
542                             {
543                                 /*   - - - -
544                                     |       | build upper 4x1
545                                      - - - -
546                                 */
547 #if kGatherStats == 1
548                                 blockStats[es41ni]++;
549 #endif
550                                 didNotBuild4by1 = false;
551                                 AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
552
553                                 if(littleEndian)
554                                     currPixel = (lastR<<16) + (lastG<<8) + lastB;
555                                 else if(bigEndian)
556                                     currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
557
558 #if kMemWritesOptimize == 0
559                                 put4Pixel(upPtr, -3, currPixel);
560                                 put4Pixel(upPtr, -2, currPixel);
561                                 put4Pixel(upPtr, -1, currPixel);
562                                 put4Pixel(upPtr, 0, currPixel);
563 #else
564                                 put4Pixel(upPtr, -3, currPixel);
565 #endif
566
567                                 ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
568
569                                 flagsPtr[-3] = (flagsPtr[-3] & ~eNorths) | e41ni;
570                                 flagsPtr[-2] = (flagsPtr[-2] & ~eNorths) | e41n;
571                                 flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e41n;
572                                 flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e41n;
573                             }
574                         }
575
576                         if (didNotBuild4by1) // Not an upper 4x1 so output upper 2x1.
577                         {
578                             if(littleEndian)
579                                 currPixel = (lastR<<16) + (lastG<<8) + lastB;
580                             else if(bigEndian)
581                                 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
582
583 #if kMemWritesOptimize == 0
584                             put4Pixel(upPtr, -1, currPixel);
585                             put4Pixel(upPtr, 0, currPixel);
586 #else
587                             put4Pixel(upPtr, -1, currPixel);
588 #endif
589                             ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
590                             flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
591                             flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
592                         }
593                     }
594
595                     // do horizontal on current raster
596                     lastPixel = get4Pixel(currPtr,-1);
597                     lastR = GetRed(lastPixel);
598                     lastG = GetGreen(lastPixel);
599                     lastB = GetBlue(lastPixel);
600                     if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(lastR, R1, lastG, G1, lastB, B1, fMaxErrorForTwoPixels)))
601                     {
602                         /*   - -
603                             |   | build lower 2x1
604                              - -
605                         */
606                         int didNotBuild4by1 = true;
607 #if kGatherStats == 1
608                         blockStats[es21sw]++;
609 #endif
610                         AverageNRound(isOdd(pixelNum), lastR, lastR, R1, lastG, lastG, G1, lastB, lastB, B1);
611                         if ((pixelNum >= 3) && (flagsPtr[-3] & e21sw)) // 4,5,6,7,12,13,14,15,20...
612                         {
613                             // Look for a lower 4x1
614                             ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
615
616                             lastPixel = get4Pixel(currPtr,-3);
617                             R0 = GetRed(lastPixel);
618                             G0 = GetGreen(lastPixel);
619                             B0 = GetBlue(lastPixel);
620                             if ((maxErrorForFourPixels >= 3) && (NewDeltaE(lastR, R0, lastG, G0, lastB, B0, maxErrorForFourPixels)))
621                             {
622                                 /*   - - - -
623                                     |       | build lower 4x1
624                                      - - - -
625                                 */
626 #if kGatherStats == 1
627                                 blockStats[es41si]++;
628 #endif
629                                 didNotBuild4by1 = false;
630                                 AverageNRound((pixelNum & 0x04)== 0x04, lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0); // 4,5,6,7,12,13,14,15,20...
631
632                                 if(littleEndian)
633                                     currPixel = (lastR<<16) + (lastG<<8) + lastB;
634                                 else if(bigEndian)
635                                     currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
636
637 #if kMemWritesOptimize == 0
638                                 put4Pixel(currPtr, -3, currPixel);
639                                 put4Pixel(currPtr, -2, currPixel);
640                                 put4Pixel(currPtr, -1, currPixel);
641                                 put4Pixel(currPtr, 0, currPixel);
642 #else
643                                 put4Pixel(currPtr, -3, currPixel);
644 #endif
645                                 flagsPtr[-3] = (flagsPtr[-3] & ~eSouths) | e41si;
646                                 flagsPtr[-2] = (flagsPtr[-2] & ~eSouths) | e41s;
647                                 flagsPtr[-1] = (flagsPtr[-1] & ~eSouths) | e41s;
648                                 flagsPtr[0] = (flagsPtr[0] & ~eSouths) | e41s;
649                             }
650                         }
651
652                         if (didNotBuild4by1) // Not a lower 4x1 so output lower 2x1.
653                         {
654                             ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
655
656                             if(littleEndian)
657                                 currPixel = (lastR<<16) + (lastG<<8) + lastB;
658                             else if(bigEndian)
659                                 currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
660
661 #if kMemWritesOptimize == 0
662                             put4Pixel(currPtr, -1, currPixel);
663                             put4Pixel(currPtr, 0, currPixel);
664 #else
665                             put4Pixel(currPtr, -1, currPixel);
666 #endif
667
668                             flagsPtr[-1] = (flagsPtr[-1] & ~eSouths) | e21sw;
669                             flagsPtr[0] = (flagsPtr[0] & ~eSouths) | e21se;
670                         }
671                     }  // If DeltaE... Looking for two by one
672                 }  // IsOdd(pixelNum)
673             }
674         }
675         else // no flag bits set.
676         {
677             lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
678         }
679
680         upPtr += eBufferedPixelWidthInBytes;
681         currPtr += eBufferedPixelWidthInBytes;
682         flagsPtr++;
683     }  // for each pixel...
684 }
685
686 // Filter2PairsOfFilteredRows.  This routine takes 2 pairs of rows that
687 // have been through the Filter2RawRows routine and puts blocks together
688 // to make bigger blocks.  It prefers taking 2 high blocks and putting
689 // them together to make four high blocks, but as a last resort it will
690 // take try to take a 1 high blocks from the second and third rasters and
691 // create 2 high blocks.  The possible block sizes this routine could
692 // create are 8x4, 4x4, 2x4, and 1x4, and then with the second and third rasters
693 // 4x2, 2x2, and 1x2.
694 void TErnieFilter::Filter2PairsOfFilteredRows(unsigned char *row1Ptr, unsigned char *row2Ptr, unsigned char *row3Ptr, unsigned char *row4Ptr)
695 {
696     const unsigned int maxErrorForFourPixels = fMaxErrorForTwoPixels / 2;
697     const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
698     const unsigned int maxErrorForSixteenPixels = maxErrorForEightPixels / 2;
699     const unsigned int maxErrorForThirtyTwoPixels = maxErrorForSixteenPixels / 2;
700
701     for (int pixelNum = 0; pixelNum < (fRowWidthInPixels-3);)  // Make sure we have four pixels to work with
702     {
703         int currPixel, upPixel;
704         int R0, G0, B0, R1, G1, B1;
705
706         if ((fPixelFilteredFlags[0][pixelNum] & e42i) && (fPixelFilteredFlags[1][pixelNum] & e42i))
707         {
708             /*  - - - -
709                |       |
710                |       |
711                 - - - -     We have two 4x2s.
712                 - - - -
713                |       |
714                |       |
715                 - - - -
716             */
717             ASSERT(fPixelFilteredFlags[0][pixelNum] == e42i && fPixelFilteredFlags[0][pixelNum+1] == e42 && fPixelFilteredFlags[0][pixelNum+2] == e42 && fPixelFilteredFlags[0][pixelNum+3] == e42);
718             ASSERT(fPixelFilteredFlags[1][pixelNum] == e42i && fPixelFilteredFlags[1][pixelNum+1] == e42 && fPixelFilteredFlags[1][pixelNum+2] == e42 && fPixelFilteredFlags[1][pixelNum+3] == e42);
719
720             upPixel = get4Pixel(row1Ptr);
721             currPixel = get4Pixel(row3Ptr);
722
723             R1 = GetRed(currPixel);
724             G1 = GetGreen(currPixel);
725             B1 = GetBlue(currPixel);
726
727             R0 = GetRed(upPixel);
728             G0 = GetGreen(upPixel);
729             B0 = GetBlue(upPixel);
730
731             if((maxErrorForSixteenPixels >= 3) &&(NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForSixteenPixels)))
732             {
733                 /*   - - - -
734                     |       |
735                     |       | build 4x4
736                     |       |
737                     |       |
738                      - - - -
739                 */
740 #if kGatherStats == 1
741                 blockStats[es44ni]++;
742 #endif
743                 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
744
745                 if(littleEndian)
746                     currPixel = (R1<<16) + (G1<<8) + B1;
747                 else if(bigEndian)
748                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
749
750 #if kMemWritesOptimize == 0
751                 put4Pixel(row1Ptr, 0, currPixel);
752                 put4Pixel(row1Ptr, 1, currPixel);
753                 put4Pixel(row1Ptr, 2, currPixel);
754                 put4Pixel(row1Ptr, 3, currPixel);
755                 put4Pixel(row2Ptr, 0, currPixel);
756                 put4Pixel(row2Ptr, 1, currPixel);
757                 put4Pixel(row2Ptr, 2, currPixel);
758                 put4Pixel(row2Ptr, 3, currPixel);
759                 put4Pixel(row3Ptr, 0, currPixel);
760                 put4Pixel(row3Ptr, 1, currPixel);
761                 put4Pixel(row3Ptr, 2, currPixel);
762                 put4Pixel(row3Ptr, 3, currPixel);
763                 put4Pixel(row4Ptr, 0, currPixel);
764                 put4Pixel(row4Ptr, 1, currPixel);
765                 put4Pixel(row4Ptr, 2, currPixel);
766                 put4Pixel(row4Ptr, 3, currPixel);
767 #else
768                 put4Pixel(row1Ptr, 0, currPixel);
769 #endif
770                 row1Ptr += 4*eBufferedPixelWidthInBytes;
771                 row2Ptr += 4*eBufferedPixelWidthInBytes;
772                 row3Ptr += 4*eBufferedPixelWidthInBytes;
773                 row4Ptr += 4*eBufferedPixelWidthInBytes;
774
775                 fPixelFilteredFlags[0][pixelNum] = e44ni;
776                 fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+2] = fPixelFilteredFlags[0][pixelNum+3] = e44n;
777                 fPixelFilteredFlags[1][pixelNum] = e44si;
778                 fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+2] = fPixelFilteredFlags[1][pixelNum+3] = e44s;
779
780                 if ((pixelNum >= 4) && (fPixelFilteredFlags[1][pixelNum-4] & e44si)) // 4,5,6,7,12,13,14,15,20...
781                 {
782                     /*   - - - -     - - - -
783                         |       |   |       |
784                         |       |   |       | We have two 4x4s.
785                         |       |   |       |
786                         |       |   |       |
787                          - - - -     - - - -
788                     */
789                     ASSERT(fPixelFilteredFlags[0][pixelNum-4] == e44ni && fPixelFilteredFlags[0][pixelNum-3] == e44n && fPixelFilteredFlags[0][pixelNum-2] == e44n && fPixelFilteredFlags[0][pixelNum-1] == e44n);
790                     ASSERT(fPixelFilteredFlags[1][pixelNum-4] == e44si && fPixelFilteredFlags[1][pixelNum-3] == e44s && fPixelFilteredFlags[1][pixelNum-2] == e44s && fPixelFilteredFlags[1][pixelNum-1] == e44s);
791
792                     upPixel = get4Pixel(row1Ptr, -8);
793
794                     R0 = GetRed(upPixel);
795                     G0 = GetGreen(upPixel);
796                     B0 = GetBlue(upPixel);
797
798                     if( (maxErrorForThirtyTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForThirtyTwoPixels)))
799                     {
800                         /*   - - - - - - - -
801                             |               |
802                             |               | build 8x4
803                             |               |
804                             |               |
805                              - - - - - - - -
806                         */
807 #if kGatherStats == 1
808                         blockStats[es84ni]++;
809 #endif
810                         AverageNRound((pixelNum & 0x08) == 0x08, R1, R1, R0, G1, G1, G0, B1, B1, B0);
811                         if(littleEndian)
812                             currPixel = (R1<<16) + (G1<<8) + B1;
813                         else if(bigEndian)
814                             currPixel = (R1<<24) + (G1<<16) + (B1<<8);
815
816 #if kMemWritesOptimize == 0
817                         put4Pixel(row1Ptr, -8, currPixel);
818                         put4Pixel(row1Ptr, -7, currPixel);
819                         put4Pixel(row1Ptr, -6, currPixel);
820                         put4Pixel(row1Ptr, -5, currPixel);
821                         put4Pixel(row1Ptr, -4, currPixel);
822                         put4Pixel(row1Ptr, -3, currPixel);
823                         put4Pixel(row1Ptr, -2, currPixel);
824                         put4Pixel(row1Ptr, -1, currPixel);
825                         put4Pixel(row2Ptr, -8, currPixel);
826                         put4Pixel(row2Ptr, -7, currPixel);
827                         put4Pixel(row2Ptr, -6, currPixel);
828                         put4Pixel(row2Ptr, -5, currPixel);
829                         put4Pixel(row2Ptr, -4, currPixel);
830                         put4Pixel(row2Ptr, -3, currPixel);
831                         put4Pixel(row2Ptr, -2, currPixel);
832                         put4Pixel(row2Ptr, -1, currPixel);
833                         put4Pixel(row3Ptr, -8, currPixel);
834                         put4Pixel(row3Ptr, -7, currPixel);
835                         put4Pixel(row3Ptr, -6, currPixel);
836                         put4Pixel(row3Ptr, -5, currPixel);
837                         put4Pixel(row3Ptr, -4, currPixel);
838                         put4Pixel(row3Ptr, -3, currPixel);
839                         put4Pixel(row3Ptr, -2, currPixel);
840                         put4Pixel(row3Ptr, -1, currPixel);
841                         put4Pixel(row4Ptr, -8, currPixel);
842                         put4Pixel(row4Ptr, -7, currPixel);
843                         put4Pixel(row4Ptr, -6, currPixel);
844                         put4Pixel(row4Ptr, -5, currPixel);
845                         put4Pixel(row4Ptr, -4, currPixel);
846                         put4Pixel(row4Ptr, -3, currPixel);
847                         put4Pixel(row4Ptr, -2, currPixel);
848                         put4Pixel(row4Ptr, -1, currPixel);
849 #else
850                         put4Pixel(row1Ptr, -8, currPixel);
851 #endif
852                         fPixelFilteredFlags[0][pixelNum-4] = e84ni;
853                         fPixelFilteredFlags[0][pixelNum-3] = fPixelFilteredFlags[0][pixelNum-2] = fPixelFilteredFlags[0][pixelNum-1] = fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+2] = fPixelFilteredFlags[0][pixelNum+3] = e84n;
854                         fPixelFilteredFlags[1][pixelNum-4] = e84si;
855                         fPixelFilteredFlags[1][pixelNum-3] = fPixelFilteredFlags[1][pixelNum-2] = fPixelFilteredFlags[1][pixelNum-1] = fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+2] = fPixelFilteredFlags[1][pixelNum+3] = e84s;
856                     }
857                 }
858             }
859             else // could not build 4x4 so move forward past the stacked 4x2s.
860             {
861                 row1Ptr += 4*eBufferedPixelWidthInBytes;
862                 row2Ptr += 4*eBufferedPixelWidthInBytes;
863                 row3Ptr += 4*eBufferedPixelWidthInBytes;
864                 row4Ptr += 4*eBufferedPixelWidthInBytes;
865             }
866             pixelNum += 4;
867         }
868         else if ((fPixelFilteredFlags[0][pixelNum] & e22w) && (fPixelFilteredFlags[1][pixelNum] & e22w))
869         {
870             /*   - -
871                 |   |
872                 |   |
873                  - -   we have 2 2x2s.
874                  - -
875                 |   |
876                 |   |
877                  - -
878             */
879             ASSERT(fPixelFilteredFlags[0][pixelNum] == e22w && fPixelFilteredFlags[0][pixelNum+1] == e22e);
880             ASSERT(fPixelFilteredFlags[1][pixelNum] == e22w && fPixelFilteredFlags[1][pixelNum+1] == e22e);
881
882             upPixel = get4Pixel(row1Ptr);
883             currPixel = get4Pixel(row3Ptr);
884
885             R1 = GetRed(currPixel);
886             G1 = GetGreen(currPixel);
887             B1 = GetBlue(currPixel);
888
889             R0 = GetRed(upPixel);
890             G0 = GetGreen(upPixel);
891             B0 = GetBlue(upPixel);
892
893             if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
894             {
895                 /*   - -
896                     |   |
897                     |   | build 2x4
898                     |   |
899                     |   |
900                      - -
901                 */
902 #if kGatherStats == 1
903                 blockStats[es24nw]++;
904 #endif
905                 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
906
907                 if(littleEndian)
908                     currPixel = (R1<<16) + (G1<<8) + B1;
909                 else if(bigEndian)
910                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
911
912 #if kMemWritesOptimize == 0
913                 put4Pixel(row1Ptr, 0, currPixel);
914                 put4Pixel(row1Ptr, 1, currPixel);
915                 put4Pixel(row2Ptr, 0, currPixel);
916                 put4Pixel(row2Ptr, 1, currPixel);
917                 put4Pixel(row3Ptr, 0, currPixel);
918                 put4Pixel(row3Ptr, 1, currPixel);
919                 put4Pixel(row4Ptr, 0, currPixel);
920                 put4Pixel(row4Ptr, 1, currPixel);
921 #else
922                 put4Pixel(row1Ptr, 0, currPixel);
923 #endif
924                 row1Ptr += 2*eBufferedPixelWidthInBytes;
925                 row2Ptr += 2*eBufferedPixelWidthInBytes;
926                 row3Ptr += 2*eBufferedPixelWidthInBytes;
927                 row4Ptr += 2*eBufferedPixelWidthInBytes;
928
929                 fPixelFilteredFlags[0][pixelNum] = e24nw;
930                 fPixelFilteredFlags[0][pixelNum+1] = e24ne;
931                 fPixelFilteredFlags[1][pixelNum] = e24sw;
932                 fPixelFilteredFlags[1][pixelNum+1] = e24se;
933             }
934             else
935             {
936                 row1Ptr += 2*eBufferedPixelWidthInBytes;
937                 row2Ptr += 2*eBufferedPixelWidthInBytes;
938                 row3Ptr += 2*eBufferedPixelWidthInBytes;
939                 row4Ptr += 2*eBufferedPixelWidthInBytes;
940             }
941             pixelNum += 2;
942         }
943         else if ((fPixelFilteredFlags[0][pixelNum] & e12) && (fPixelFilteredFlags[1][pixelNum] & e12))
944         {
945             /*   -
946                 | |
947                 | |
948                  -  we have two 1x2s.
949                  -
950                 | |
951                 | |
952                  -
953             */
954             ASSERT(fPixelFilteredFlags[0][pixelNum] == e12);
955             ASSERT(fPixelFilteredFlags[1][pixelNum] == e12);
956
957             upPixel = get4Pixel(row1Ptr);
958             currPixel = get4Pixel(row3Ptr);
959
960             R1 = GetRed(currPixel);
961             G1 = GetGreen(currPixel);
962             B1 = GetBlue(currPixel);
963
964             R0 = GetRed(upPixel);
965             G0 = GetGreen(upPixel);
966             B0 = GetBlue(upPixel);
967
968             if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
969             {
970                 /*   -
971                     | |
972                     | | build 1x4
973                     | |
974                     | |
975                      -
976                 */
977 #if kGatherStats == 1
978                 blockStats[es14n]++;
979 #endif
980                 AverageNRound((pixelNum & 0x01) == 0x01, R1, R1, R0, G1, G1, G0, B1, B1, B0);
981
982                 if(littleEndian)
983                     currPixel = (R1<<16) + (G1<<8) + B1;
984                 else if(bigEndian)
985                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
986
987 #if kMemWritesOptimize == 0
988                 put4Pixel(row1Ptr, 0, currPixel);
989                 put4Pixel(row2Ptr, 0, currPixel);
990                 put4Pixel(row3Ptr, 0, currPixel);
991                 put4Pixel(row4Ptr, 0, currPixel);
992 #else
993                 put4Pixel(row1Ptr, 0, currPixel);
994 #endif
995                 fPixelFilteredFlags[0][pixelNum] = e14n;
996                 fPixelFilteredFlags[1][pixelNum] = e14s;
997             }
998
999             row1Ptr += eBufferedPixelWidthInBytes;
1000             row2Ptr += eBufferedPixelWidthInBytes;
1001             row3Ptr += eBufferedPixelWidthInBytes;
1002             row4Ptr += eBufferedPixelWidthInBytes;
1003
1004             pixelNum++;
1005         }
1006         else if ((fPixelFilteredFlags[0][pixelNum] & e41si)
1007             && (fPixelFilteredFlags[1][pixelNum] & e41ni))
1008         {
1009             /*    - - - -
1010                  |       |
1011                   - - - -   We have two 4x1s.
1012                   - - - -
1013                  |       |
1014                   - - - -
1015             */
1016
1017             upPixel = get4Pixel(row2Ptr);
1018             currPixel = get4Pixel(row3Ptr);
1019
1020             R1 = GetRed(currPixel);
1021             G1 = GetGreen(currPixel);
1022             B1 = GetBlue(currPixel);
1023
1024             R0 = GetRed(upPixel);
1025             G0 = GetGreen(upPixel);
1026             B0 = GetBlue(upPixel);
1027
1028
1029             if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1030             {
1031
1032                 /*    - - - -
1033                      |       |  build 4x2.
1034                      |       |
1035                       - - - -
1036                 */
1037 #if kGatherStats == 1
1038                 blockStats[es42w]++;
1039 #endif
1040                 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1041
1042                 if(littleEndian)
1043                     currPixel = (R1<<16) + (G1<<8) + B1;
1044                 else if(bigEndian)
1045                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1046
1047                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1048                 put4Pixel(row2Ptr, 0, currPixel);
1049                 put4Pixel(row2Ptr, 1, currPixel);
1050                 put4Pixel(row2Ptr, 2, currPixel);
1051                 put4Pixel(row2Ptr, 3, currPixel);
1052                 put4Pixel(row3Ptr, 0, currPixel);
1053                 put4Pixel(row3Ptr, 1, currPixel);
1054                 put4Pixel(row3Ptr, 2, currPixel);
1055                 put4Pixel(row3Ptr, 3, currPixel);
1056
1057                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e41si;
1058                 fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1059                 fPixelFilteredFlags[0][pixelNum+2] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1060                 fPixelFilteredFlags[0][pixelNum+3] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1061
1062                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1063                 fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1064                 fPixelFilteredFlags[1][pixelNum+2] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1065                 fPixelFilteredFlags[1][pixelNum+3] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1066             }
1067             pixelNum += 4;
1068
1069             row1Ptr += 4*eBufferedPixelWidthInBytes;
1070             row2Ptr += 4*eBufferedPixelWidthInBytes;
1071             row3Ptr += 4*eBufferedPixelWidthInBytes;
1072             row4Ptr += 4*eBufferedPixelWidthInBytes;
1073         }
1074         else if ((fPixelFilteredFlags[0][pixelNum] & e21sw)
1075                 && (fPixelFilteredFlags[1][pixelNum] & e21nw))
1076         {
1077             /*    - -
1078                  |   |
1079                   - -  We have two 2x1s.
1080                   - -
1081                  |   |
1082                   - -
1083             */
1084             ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1085             ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1086
1087             upPixel = get4Pixel(row2Ptr);
1088             currPixel = get4Pixel(row3Ptr);
1089
1090             R1 = GetRed(currPixel);
1091             G1 = GetGreen(currPixel);
1092             B1 = GetBlue(currPixel);
1093
1094             R0 = GetRed(upPixel);
1095             G0 = GetGreen(upPixel);
1096             B0 = GetBlue(upPixel);
1097
1098             if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1099             {
1100                 /*    - -
1101                      |   |  build 2x2.
1102                      |   |
1103                       - -
1104                 */
1105 #if kGatherStats == 1
1106                 blockStats[es22w]++;
1107 #endif
1108                 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1109
1110                 if(littleEndian)
1111                     currPixel = (R1<<16) + (G1<<8) + B1;
1112                 else if(bigEndian)
1113                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1114
1115                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1116                 put4Pixel(row2Ptr, 0, currPixel);
1117                 put4Pixel(row2Ptr, 1, currPixel);
1118                 put4Pixel(row3Ptr, 0, currPixel);
1119                 put4Pixel(row3Ptr, 1, currPixel);
1120
1121                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e21sw;
1122                 fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e21se;
1123
1124                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1125                 fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+1] & ~e21ne;
1126             }
1127
1128             pixelNum += 2;
1129
1130             row1Ptr += 2*eBufferedPixelWidthInBytes;
1131             row2Ptr += 2*eBufferedPixelWidthInBytes;
1132             row3Ptr += 2*eBufferedPixelWidthInBytes;
1133             row4Ptr += 2*eBufferedPixelWidthInBytes;
1134         }
1135         else if ((fPixelFilteredFlags[0][pixelNum] & e11s)
1136                 && (fPixelFilteredFlags[1][pixelNum] & e11n))
1137         {
1138             /*    -
1139                  | |
1140                   -   We have two 1x1s.
1141                   -
1142                  | |
1143                   -
1144             */
1145
1146             upPixel = get4Pixel(row2Ptr);
1147             currPixel = get4Pixel(row3Ptr);
1148
1149             R1 = GetRed(currPixel);
1150             G1 = GetGreen(currPixel);
1151             B1 = GetBlue(currPixel);
1152
1153             R0 = GetRed(upPixel);
1154             G0 = GetGreen(upPixel);
1155             B0 = GetBlue(upPixel);
1156
1157             if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, fMaxErrorForTwoPixels)))
1158             {
1159                 /*    -
1160                      | |  build 1x2.
1161                      | |
1162                       -
1163                 */
1164 #if kGatherStats == 1
1165                 blockStats[es12w]++;
1166 #endif
1167                 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1168
1169                 if(littleEndian)
1170                     currPixel = (R1<<16) + (G1<<8) + B1;
1171                 else if(bigEndian)
1172                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1173
1174                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1175                 put4Pixel(row2Ptr, 0, currPixel);
1176                 put4Pixel(row3Ptr, 0, currPixel);
1177
1178                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e11s;
1179
1180                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1181             }
1182
1183             pixelNum += 1;
1184
1185             row1Ptr += eBufferedPixelWidthInBytes;
1186             row2Ptr += eBufferedPixelWidthInBytes;
1187             row3Ptr += eBufferedPixelWidthInBytes;
1188             row4Ptr += eBufferedPixelWidthInBytes;
1189         }
1190         else // Do no vertical filtering here.
1191         {
1192             pixelNum += 1;
1193
1194             row1Ptr += eBufferedPixelWidthInBytes;
1195             row2Ptr += eBufferedPixelWidthInBytes;
1196             row3Ptr += eBufferedPixelWidthInBytes;
1197             row4Ptr += eBufferedPixelWidthInBytes;
1198         }
1199     }
1200 }
1201
1202 // Filter3FilteredRows.  This routine only exists for the case of the odd size band
1203 // with three rasters left over.  I'm not sure how much extra benifit we really
1204 // get from running this, but for now I'm leaving it in.  Since Ernie deals with
1205 // block sizes that are powers of two its rather difficult to filter 3 rows together,
1206 // about all I've been able to do is look for 1 high blocks in the second and third
1207 // rasters to put together into 2 high blocks.  This routine will create 4x2, 2x2, and
1208 // 1x2 blocks from those second and third rasters.
1209 void TErnieFilter::Filter3FilteredRows(unsigned char *row1Ptr, unsigned char *row2Ptr, unsigned char *row3Ptr)
1210 {
1211     const unsigned int maxErrorForFourPixels = fMaxErrorForTwoPixels / 2;
1212     const unsigned int maxErrorForEightPixels = maxErrorForFourPixels / 2;
1213 //    const unsigned int maxErrorForSixteenPixels = maxErrorForEightPixels / 2;
1214 //    const unsigned int maxErrorForThirtyTwoPixels = maxErrorForSixteenPixels / 2;
1215
1216     for (int pixelNum = 0; pixelNum < (fRowWidthInPixels-3);)  // Make sure we have four pixels to work with
1217     {
1218 //        int currPixel, upPixel;
1219         uint32_t currPixel, upPixel;
1220         int R0, G0, B0, R1, G1, B1;
1221
1222         if ((fPixelFilteredFlags[0][pixelNum] & e41si)
1223                 && (fPixelFilteredFlags[1][pixelNum] & e41ni))
1224         {
1225             /*    - - - -
1226                  |       |
1227                   - - - -   We have two 4x1s.
1228                   - - - -
1229                  |       |
1230                   - - - -
1231             */
1232             ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1233             ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1234
1235             upPixel = get4Pixel(row2Ptr);
1236             currPixel = get4Pixel(row3Ptr);
1237
1238             R1 = GetRed(currPixel);
1239             G1 = GetGreen(currPixel);
1240             B1 = GetBlue(currPixel);
1241
1242             R0 = GetRed(upPixel);
1243             G0 = GetGreen(upPixel);
1244             B0 = GetBlue(upPixel);
1245
1246
1247             if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1248             {
1249
1250                 /*    - - - -
1251                      |       |  build 4x2.
1252                      |       |
1253                       - - - -
1254                 */
1255 #if kGatherStats == 1
1256                 blockStats[es42w]++;
1257 #endif
1258                 AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1259
1260                 if(littleEndian)
1261                     currPixel = (R1<<16) + (G1<<8) + B1;
1262                 else if(bigEndian)
1263                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1264
1265                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1266                 put4Pixel(row2Ptr, 0, currPixel);
1267                 put4Pixel(row2Ptr, 1, currPixel);
1268                 put4Pixel(row2Ptr, 2, currPixel);
1269                 put4Pixel(row2Ptr, 3, currPixel);
1270                 put4Pixel(row3Ptr, 0, currPixel);
1271                 put4Pixel(row3Ptr, 1, currPixel);
1272                 put4Pixel(row3Ptr, 2, currPixel);
1273                 put4Pixel(row3Ptr, 3, currPixel);
1274
1275                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e41si;
1276                 fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1277                 fPixelFilteredFlags[0][pixelNum+2] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1278                 fPixelFilteredFlags[0][pixelNum+3] = fPixelFilteredFlags[0][pixelNum+1] & ~e41s;
1279
1280                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1281                 fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1282                 fPixelFilteredFlags[1][pixelNum+2] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1283                 fPixelFilteredFlags[1][pixelNum+3] = fPixelFilteredFlags[1][pixelNum+1] & ~e41n;
1284             }
1285             pixelNum += 4;
1286
1287             row1Ptr += 4*eBufferedPixelWidthInBytes;
1288             row2Ptr += 4*eBufferedPixelWidthInBytes;
1289             row3Ptr += 4*eBufferedPixelWidthInBytes;
1290         }
1291         else if ((fPixelFilteredFlags[0][pixelNum] & e21sw)
1292                 && (fPixelFilteredFlags[1][pixelNum] & e21nw))
1293         {
1294             /*    - -
1295                  |   |
1296                   - -  We have two 2x1s.
1297                   - -
1298                  |   |
1299                   - -
1300             */
1301             ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1302             ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1303
1304             upPixel = get4Pixel(row2Ptr);
1305             currPixel = get4Pixel(row3Ptr);
1306
1307             R1 = GetRed(currPixel);
1308             G1 = GetGreen(currPixel);
1309             B1 = GetBlue(currPixel);
1310
1311             R0 = GetRed(upPixel);
1312             G0 = GetGreen(upPixel);
1313             B0 = GetBlue(upPixel);
1314
1315             if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1316             {
1317                 /*    - -
1318                      |   |  build 2x2.
1319                      |   |
1320                       - -
1321                 */
1322 #if kGatherStats == 1
1323                 blockStats[es22w]++;
1324 #endif
1325                 AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1326
1327                 if(littleEndian)
1328                     currPixel = (R1<<16) + (G1<<8) + B1;
1329                 else if(bigEndian)
1330                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1331
1332                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1333                 put4Pixel(row2Ptr, 0, currPixel);
1334                 put4Pixel(row2Ptr, 1, currPixel);
1335                 put4Pixel(row3Ptr, 0, currPixel);
1336                 put4Pixel(row3Ptr, 1, currPixel);
1337
1338                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e21sw;
1339                 fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e21se;
1340
1341                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1342                 fPixelFilteredFlags[1][pixelNum+1] = fPixelFilteredFlags[1][pixelNum+1] & ~e21ne;
1343             }
1344
1345             pixelNum += 2;
1346
1347             row1Ptr += 2*eBufferedPixelWidthInBytes;
1348             row2Ptr += 2*eBufferedPixelWidthInBytes;
1349             row3Ptr += 2*eBufferedPixelWidthInBytes;
1350         }
1351         else if ((fPixelFilteredFlags[0][pixelNum] & e11s)
1352                 && (fPixelFilteredFlags[1][pixelNum] & e11n))
1353         {
1354             /*    -
1355                  | |
1356                   -   We have two 1x1s.
1357                   -
1358                  | |
1359                   -
1360             */
1361
1362             upPixel = get4Pixel(row2Ptr);
1363             currPixel = get4Pixel(row3Ptr);
1364
1365             R1 = GetRed(currPixel);
1366             G1 = GetGreen(currPixel);
1367             B1 = GetBlue(currPixel);
1368
1369             R0 = GetRed(upPixel);
1370             G0 = GetGreen(upPixel);
1371             B0 = GetBlue(upPixel);
1372
1373             if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, fMaxErrorForTwoPixels)))
1374             {
1375                 /*    -
1376                      | |  build 1x2.
1377                      | |
1378                       -
1379                 */
1380 #if kGatherStats == 1
1381                 blockStats[es12w]++;
1382 #endif
1383                 AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1384
1385                 if(littleEndian)
1386                     currPixel = (R1<<16) + (G1<<8) + B1;
1387                 else if(bigEndian)
1388                     currPixel = (R1<<24) + (G1<<16) + (B1<<8);
1389
1390                 // Note we write this block out now and do not delay the writes for the postprocessing step since we do not track this block.
1391                 put4Pixel(row2Ptr, 0, currPixel);
1392                 put4Pixel(row3Ptr, 0, currPixel);
1393
1394                 fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e11s;
1395
1396                 fPixelFilteredFlags[1][pixelNum] = fPixelFilteredFlags[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.
1397             }
1398
1399             pixelNum += 1;
1400
1401             row1Ptr += eBufferedPixelWidthInBytes;
1402             row2Ptr += eBufferedPixelWidthInBytes;
1403             row3Ptr += eBufferedPixelWidthInBytes;
1404         }
1405         else // Do no vertical filtering here.
1406         {
1407             pixelNum += 1;
1408
1409             row1Ptr += eBufferedPixelWidthInBytes;
1410             row2Ptr += eBufferedPixelWidthInBytes;
1411             row3Ptr += eBufferedPixelWidthInBytes;
1412         }
1413     }
1414 }
1415
1416 #define NEWTEST true
1417
1418 inline bool TErnieFilter::NewDeltaE(int dr0, int dr1, int dg0, int dg1, int db0, int db1, int tolerance)
1419 {
1420     int Y0, Y1, dY, Cr0, Cr1, Cb0, Cb1, dCr, dCb;
1421
1422     // new Delta E stuff from Jay
1423
1424     Y0 = 5*dr0 + 9*dg0 + 2*db0;
1425     Y1 = 5*dr1 + 9*dg1 + 2*db1;
1426
1427     dY = ABS(Y0 - Y1) >> 4;
1428
1429     if(dY > tolerance) {
1430         return false;
1431     }
1432     else
1433     {
1434         Cr0 = (dr0 << 4) - Y0;
1435         Cr1 = (dr1 << 4) - Y1;
1436         dCr = ABS(Cr0 - Cr1) >> 5;
1437         if(dCr > tolerance)
1438         {
1439             return false;
1440         }
1441         else
1442         {
1443             Cb0 = (db0 << 4) - Y0;
1444             Cb1 = (db1 << 4) - Y1;
1445             dCb = ABS(Cb0 - Cb1) >> 6;
1446             if(dCb > tolerance)
1447             {
1448                 return false;
1449             }
1450         }
1451     }
1452     return true;
1453 }
1454
1455 TErnieFilter::TErnieFilter(int rowWidthInPixels, pixelTypes pixelType, unsigned int maxErrorForTwoPixels, int bytesPerPixel)
1456 : fOriginalPixelSize(bytesPerPixel)
1457 {
1458     int index;
1459     ASSERT((fOriginalPixelSize == 3) || (fOriginalPixelSize == 4));
1460     ASSERT(rowWidthInPixels > 0);
1461     ASSERT(pixelType == eBGRPixelData);
1462
1463     fInternalBufferPixelSize = 4;
1464
1465     fPixelOffsetIndex = 0;
1466     fRowWidthInPixels = rowWidthInPixels;
1467     fRowWidthInBytes = fRowWidthInPixels*fInternalBufferPixelSize;
1468     fMaxErrorForTwoPixels = maxErrorForTwoPixels;
1469
1470     for (index = 0; index < 4; index++)
1471     {
1472         fRowBuf[index] = new uint32_t[rowWidthInPixels];
1473         ASSERT(fRowBuf[index]);
1474
1475         fRowPtr[index] = new unsigned char[rowWidthInPixels*fOriginalPixelSize];
1476                 ASSERT(fRowPtr[index]);
1477
1478                 fBlackRowPtr[index] = new BYTE[rowWidthInPixels*fOriginalPixelSize];
1479                 ASSERT(fBlackRowPtr[index]);
1480
1481                 BlackRasterSize[index] = 0;
1482     }
1483
1484     for (index = 0; index < 2; index++)
1485     {
1486         fPixelFilteredFlags[index] = new unsigned int[rowWidthInPixels];
1487         ASSERT(fPixelFilteredFlags[index]);
1488     }
1489
1490     // The least compressible image will be all raw pixels. Maximum compressed size is:
1491     // full size + a bloat of Cmd byte + 1 VLI byte per 255 pixels rounded up to nearest integer.
1492
1493     int maxCompressionBufSize = fRowWidthInBytes + 1 + ((int)ceil((float)MAX((rowWidthInPixels-2)/255, 0)));
1494
1495     fCompressionOutBuf = new unsigned char[maxCompressionBufSize];
1496     ASSERT(fCompressionOutBuf);
1497
1498     fNumberOfBufferedRows = 0;
1499
1500     fPixelOffset[0] = 0;
1501     fPixelOffset[1] = 5;
1502     fPixelOffset[2] = 2;
1503     fPixelOffset[3] = 7;
1504     fPixelOffset[4] = 1;
1505     fPixelOffset[5] = 4;
1506     fPixelOffset[6] = 6;
1507     fPixelOffset[7] = 3;
1508
1509         RowIndex = 0;
1510 }
1511
1512
1513 TErnieFilter::~TErnieFilter()
1514 {
1515     // Deallocate memory next.
1516     int index;
1517
1518     for (index = 0; index < 4; index++)
1519     {
1520         delete [] fRowBuf[index];
1521         delete [] fRowPtr[index];
1522                 delete [] fBlackRowPtr[index];
1523     }
1524
1525     for (index = 0; index < 2; index++)
1526     {
1527         delete [] fPixelFilteredFlags[index];
1528     }
1529
1530     delete [] fCompressionOutBuf;
1531 }
1532
1533 void TErnieFilter::writeBufferedRows()
1534 {
1535     int pixelIndex = 0;
1536
1537     // We just have one lonely raster left.  Nothing
1538     // we can do but filter it horizontally.
1539     if( 1 == fNumberOfBufferedRows)
1540     {
1541
1542         int offset2 = fPixelOffset[fPixelOffsetIndex];
1543
1544         Filter1RawRow( (unsigned char*)(fRowBuf[0] + offset2),
1545                        fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1546                        fPixelFilteredFlags[0] + fPixelOffset[fPixelOffsetIndex]);
1547
1548
1549         unsigned char *rowPtr = fRowPtr[0];
1550         ASSERT(rowPtr);
1551         pixelIndex = 0;
1552         do
1553         {
1554             memcpy(rowPtr, &fRowBuf[0][pixelIndex], 3);
1555             rowPtr += 3;
1556         } while (++pixelIndex < fRowWidthInPixels);
1557
1558     }
1559     // If we've got a pair of rasters in the buffer, that pair
1560     // has already been filtered somewhat.  So lets just write them
1561     // out, some filtering is better than none.
1562     else if (2 == fNumberOfBufferedRows)
1563     {
1564         // Write the two rows back out.
1565         int k;
1566         for (k = 0; k < 2; k++)
1567         {
1568             unsigned char *rowPtr = fRowPtr[k];
1569             ASSERT(rowPtr);
1570             pixelIndex = 0;
1571             do
1572             {
1573                 memcpy(rowPtr, &fRowBuf[k][pixelIndex], 3);
1574                 rowPtr += 3;
1575             } while (++pixelIndex < fRowWidthInPixels);
1576         }
1577     }
1578     // Okay, if we had three rasters in the buffer, the pair
1579     // should have already been written out above, so lets
1580     // just run the odd raster through Ernie with to
1581     // get the horizontal filtering.  [Need to look to see
1582     // if there's something more we can do with filtering
1583     // all three together.]
1584     else if (3 == fNumberOfBufferedRows)
1585     {
1586
1587         int offset2 = fPixelOffset[fPixelOffsetIndex];
1588
1589         Filter1RawRow( (unsigned char*)(fRowBuf[2] + offset2),
1590                        fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1591                        fPixelFilteredFlags[1] + fPixelOffset[fPixelOffsetIndex]);
1592
1593
1594         Filter3FilteredRows( (unsigned char*)fRowBuf[0],
1595                              (unsigned char*)fRowBuf[1],
1596                              (unsigned char*)fRowBuf[2]);
1597
1598         int k;
1599         for (k = 0; k < 3; k++)
1600         {
1601             unsigned char *rowPtr = fRowPtr[k];
1602             ASSERT(rowPtr);
1603             pixelIndex = 0;
1604             do
1605             {
1606                 memcpy(rowPtr, &fRowBuf[k][pixelIndex], 3);
1607                 rowPtr += 3;
1608             } while (++pixelIndex < fRowWidthInPixels);
1609         }
1610     }
1611 }
1612
1613 void TErnieFilter::submitRowToFilter(unsigned char *rowPtr)
1614 {
1615     memcpy(fRowPtr[fNumberOfBufferedRows], rowPtr, fRowWidthInPixels*3);
1616
1617     // Now reformat the pixel data from 24 bit to 32 bit pixels
1618     int pixelIndex = 0;
1619     uint32_t *RowPtrDest = fRowBuf[fNumberOfBufferedRows];
1620     BYTE byte1 = 0;
1621     BYTE byte2 = 0;
1622     BYTE byte3 = 0;
1623     do
1624     {
1625         byte1 = *rowPtr++;
1626         byte2 = *rowPtr++;
1627         byte3 = *rowPtr++;
1628         if(littleEndian)
1629             RowPtrDest[pixelIndex] = ((byte3 << 16) | (byte2 << 8) | (byte1)) & 0x00FFFFFF;
1630         else if(bigEndian)
1631             RowPtrDest[pixelIndex] = ((byte1 << 24) | (byte2 << 16) | (byte3 << 8)) & 0xFFFFFF00;
1632     } while (++pixelIndex < fRowWidthInPixels);
1633
1634     fNumberOfBufferedRows++;
1635
1636     iRastersReady=0;
1637     iRastersDelivered=0;
1638
1639     // Next see about filtering & compression.
1640     // NOTE 1: as an optimization only do subsections of the raster at a time to stay in cache.
1641     // NOTE 2: Could filter the pixels left of the offset.
1642     if (2 == fNumberOfBufferedRows)
1643     {
1644         int offset2 = fPixelOffset[fPixelOffsetIndex];
1645
1646         Filter2RawRows( (unsigned char*)(fRowBuf[1] + offset2),
1647                         (unsigned char*)(fRowBuf[0] + offset2),
1648                         fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1649                         fPixelFilteredFlags[0] + fPixelOffset[fPixelOffsetIndex]);
1650     }
1651
1652     if (4 == fNumberOfBufferedRows)
1653     {
1654         int offset4 = fPixelOffset[fPixelOffsetIndex];
1655         Filter2RawRows( (unsigned char*)(fRowBuf[3] + offset4),
1656                         (unsigned char*)(fRowBuf[2] + offset4),
1657                         fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1658                         fPixelFilteredFlags[1] + fPixelOffset[fPixelOffsetIndex]);
1659
1660         Filter2PairsOfFilteredRows( (unsigned char*)fRowBuf[0],
1661                                     (unsigned char*)fRowBuf[1],
1662                                     (unsigned char*)fRowBuf[2],
1663                                     (unsigned char*)fRowBuf[3]);
1664
1665 #if kMemWritesOptimize == 1
1666         // Writing the blocks out on a post processing step in this manner could leave the last 3 rows
1667         // unfiltered. This is a trade off we make for simplicity. The resulting loss in compression is small.
1668         WriteBlockPixels();
1669 #endif
1670
1671         fPixelOffsetIndex = (fPixelOffsetIndex + 1) % 8; // cycle the offset index.
1672
1673         int k;
1674         for (k = 0; k < fPixelOffset[fPixelOffsetIndex]; k++) // Clear out the flags that we're offsetting past for this next iteration.
1675         {
1676             fPixelFilteredFlags[0][k] = eDone;
1677             fPixelFilteredFlags[1][k] = eDone;
1678         }
1679
1680         // Write the four rows back out.
1681         for (k = 0; k < 4; k++)
1682         {
1683             unsigned char *rowPtr = fRowPtr[k];
1684             ASSERT(rowPtr);
1685             pixelIndex = 0;
1686             do
1687             {
1688                 memcpy(rowPtr, &fRowBuf[k][pixelIndex], fOriginalPixelSize);
1689                 rowPtr += fOriginalPixelSize;
1690             } while (++pixelIndex < fRowWidthInPixels);
1691         }
1692
1693         fNumberOfBufferedRows = 0;
1694         iRastersReady = 4;
1695     }
1696 }
1697
1698
1699 #if kMemWritesOptimize == 1
1700
1701
1702 /*
1703 At this point the color for the entire block is stored in the top left
1704 corner of the block. This routine takes that pixel and smears it into the
1705 rest of the block.
1706 */
1707 void TErnieFilter::WriteBlockPixels(void)
1708 {
1709     unsigned char *row1Ptr = (unsigned char*)fRowBuf[0];
1710     unsigned char *row2Ptr = (unsigned char*)fRowBuf[1];
1711     unsigned char *row3Ptr = (unsigned char*)fRowBuf[2];
1712     unsigned char *row4Ptr = (unsigned char*)fRowBuf[3];
1713
1714     for (int flagSet = 0; flagSet <= 1; flagSet++)
1715     {
1716         unsigned int *flagsPtr = fPixelFilteredFlags[0];
1717         unsigned char *rowA = (unsigned char*)fRowBuf[0];
1718         unsigned char *rowB = (unsigned char*)fRowBuf[1];
1719
1720         if (flagSet == 1)
1721         {
1722             flagsPtr = fPixelFilteredFlags[1];
1723             rowA = (unsigned char*)fRowBuf[2];
1724             rowB = (unsigned char*)fRowBuf[3];
1725         }
1726
1727         for (int rowIndex = 0; rowIndex < fRowWidthInPixels;)
1728         {
1729             unsigned int currentFlags = flagsPtr[rowIndex];
1730
1731 #ifndef NDEBUG /* only done for debug builds */
1732             int numberOfBitsSet = 0;
1733             unsigned int currentFlagsCopy = currentFlags & eTopLeftOfBlocks;
1734             while (currentFlagsCopy)
1735             {
1736                 if (currentFlagsCopy & 1) numberOfBitsSet++;
1737                 currentFlagsCopy >>= 1;
1738             }
1739             ASSERT( (numberOfBitsSet <= 1) ||
1740                     ((numberOfBitsSet == 2) &&
1741                     (((currentFlags & eTopLeftOfBlocks) & ~(e21nw|e21sw|e41ni|e41si))==0)));
1742 #endif
1743
1744             if (currentFlags & eTopLeftOfBlocks) // Avoids doing a lot of checks if nothing is set.
1745             {
1746 //                unsigned int pixel;
1747                 uint32_t pixel;
1748                 //  The three possible scenerios are:
1749                 //  1: No top left of block bits are set.
1750                 //  2: 1 top left block bit is set.
1751                 //  3: 2 top left block bits are set. They are 21nw and 21sw.
1752
1753                 // Note: Due to possibly having two groups tracked by this flag we require the north checks to occur before the south checks.
1754                 if (currentFlags & e22w)
1755                 {
1756                     pixel = get4Pixel(rowA, rowIndex);
1757
1758                     put4Pixel(rowB, rowIndex, pixel);
1759                     rowIndex += 1;
1760                     put4Pixel(rowA, rowIndex, pixel);
1761                     put4Pixel(rowB, rowIndex, pixel);
1762
1763                     rowIndex += 1;
1764                     continue;
1765                 }
1766
1767                 if (currentFlags & e12)
1768                 {
1769                     put4Pixel(rowB, rowIndex, get4Pixel(rowA, rowIndex));
1770
1771                     rowIndex += 1;
1772                     continue;
1773                 }
1774
1775                 if (currentFlags & e42i)
1776                 {
1777                     pixel = get4Pixel(rowA, rowIndex);
1778
1779                     put4Pixel(rowB, rowIndex, pixel);
1780
1781                     rowIndex += 1;
1782                     put4Pixel(rowA, rowIndex, pixel);
1783                     put4Pixel(rowB, rowIndex, pixel);
1784
1785                     rowIndex += 1;
1786                     put4Pixel(rowB, rowIndex, pixel);
1787                     put4Pixel(rowA, rowIndex, pixel);
1788
1789                     rowIndex += 1;
1790                     put4Pixel(rowA, rowIndex, pixel);
1791                     put4Pixel(rowB, rowIndex, pixel);
1792
1793                     rowIndex += 1;
1794                     continue;
1795                 }
1796
1797                 if (currentFlags & e84ni)
1798                 {
1799                     pixel = get4Pixel(rowA, rowIndex);
1800
1801                     put4Pixel(row2Ptr, rowIndex, pixel);
1802                     put4Pixel(row3Ptr, rowIndex, pixel);
1803                     put4Pixel(row4Ptr, rowIndex, pixel);
1804
1805                     rowIndex += 1;
1806                     put4Pixel(row1Ptr, rowIndex, pixel);
1807                     put4Pixel(row2Ptr, rowIndex, pixel);
1808                     put4Pixel(row3Ptr, rowIndex, pixel);
1809                     put4Pixel(row4Ptr, rowIndex, pixel);
1810
1811                     rowIndex += 1;
1812                     put4Pixel(row1Ptr, rowIndex, pixel);
1813                     put4Pixel(row2Ptr, rowIndex, pixel);
1814                     put4Pixel(row3Ptr, rowIndex, pixel);
1815                     put4Pixel(row4Ptr, rowIndex, pixel);
1816
1817                     rowIndex += 1;
1818                     put4Pixel(row1Ptr, rowIndex, pixel);
1819                     put4Pixel(row2Ptr, rowIndex, pixel);
1820                     put4Pixel(row3Ptr, rowIndex, pixel);
1821                     put4Pixel(row4Ptr, rowIndex, pixel);
1822
1823                     rowIndex += 1;
1824                     put4Pixel(row1Ptr, rowIndex, pixel);
1825                     put4Pixel(row2Ptr, rowIndex, pixel);
1826                     put4Pixel(row3Ptr, rowIndex, pixel);
1827                     put4Pixel(row4Ptr, rowIndex, pixel);
1828
1829                     rowIndex += 1;
1830                     put4Pixel(row1Ptr, rowIndex, pixel);
1831                     put4Pixel(row2Ptr, rowIndex, pixel);
1832                     put4Pixel(row3Ptr, rowIndex, pixel);
1833                     put4Pixel(row4Ptr, rowIndex, pixel);
1834
1835                     rowIndex += 1;
1836                     put4Pixel(row1Ptr, rowIndex, pixel);
1837                     put4Pixel(row2Ptr, rowIndex, pixel);
1838                     put4Pixel(row3Ptr, rowIndex, pixel);
1839                     put4Pixel(row4Ptr, rowIndex, pixel);
1840
1841                     rowIndex += 1;
1842                     put4Pixel(row1Ptr, rowIndex, pixel);
1843                     put4Pixel(row2Ptr, rowIndex, pixel);
1844                     put4Pixel(row3Ptr, rowIndex, pixel);
1845                     put4Pixel(row4Ptr, rowIndex, pixel);
1846
1847                     rowIndex += 1;
1848
1849                     continue;
1850                 }
1851
1852                 if (currentFlags & e24nw)
1853                 {
1854                     pixel = get4Pixel(row1Ptr, rowIndex);
1855
1856                     put4Pixel(row2Ptr, rowIndex, pixel);
1857                     put4Pixel(row3Ptr, rowIndex, pixel);
1858                     put4Pixel(row4Ptr, rowIndex, pixel);
1859
1860                     rowIndex += 1;
1861                     put4Pixel(row1Ptr, rowIndex, pixel);
1862                     put4Pixel(row2Ptr, rowIndex, pixel);
1863                     put4Pixel(row3Ptr, rowIndex, pixel);
1864                     put4Pixel(row4Ptr, rowIndex, pixel);
1865
1866                     rowIndex += 1;
1867                     continue;
1868                 }
1869
1870                 if (currentFlags & e44ni)
1871                 {
1872                     pixel = get4Pixel(row1Ptr, rowIndex);
1873
1874                     put4Pixel(row2Ptr, rowIndex, pixel);
1875                     put4Pixel(row3Ptr, rowIndex, pixel);
1876                     put4Pixel(row4Ptr, rowIndex, pixel);
1877
1878                     rowIndex += 1;
1879                     put4Pixel(row1Ptr, rowIndex, pixel);
1880                     put4Pixel(row2Ptr, rowIndex, pixel);
1881                     put4Pixel(row3Ptr, rowIndex, pixel);
1882                     put4Pixel(row4Ptr, rowIndex, pixel);
1883
1884                     rowIndex += 1;
1885                     put4Pixel(row1Ptr, rowIndex, pixel);
1886                     put4Pixel(row2Ptr, rowIndex, pixel);
1887                     put4Pixel(row3Ptr, rowIndex, pixel);
1888                     put4Pixel(row4Ptr, rowIndex, pixel);
1889
1890                     rowIndex += 1;
1891                     put4Pixel(row1Ptr, rowIndex, pixel);
1892                     put4Pixel(row2Ptr, rowIndex, pixel);
1893                     put4Pixel(row3Ptr, rowIndex, pixel);
1894                     put4Pixel(row4Ptr, rowIndex, pixel);
1895
1896                     rowIndex += 1;
1897                     continue;
1898                 }
1899
1900                 if (currentFlags & e14n)
1901                 {
1902                     pixel = get4Pixel(row1Ptr, rowIndex);
1903
1904                     put4Pixel(row2Ptr, rowIndex, pixel);
1905                     put4Pixel(row3Ptr, rowIndex, pixel);
1906                     put4Pixel(row4Ptr, rowIndex, pixel);
1907
1908                     rowIndex += 1;
1909                     continue;
1910                 }
1911
1912                 if (currentFlags & e21nw)
1913                 {
1914                     put4Pixel(rowA, rowIndex+1, get4Pixel(rowA, rowIndex));
1915
1916                     if (!(currentFlags & (e21sw|e41si))) // if no south groups
1917                     {
1918                         rowIndex += 2;
1919                         continue;
1920                     }
1921                 }
1922
1923                 if (currentFlags & e41ni)
1924                 {
1925                     pixel = get4Pixel(rowA, rowIndex);
1926
1927                     put4Pixel(rowA, rowIndex+1, pixel);
1928                     put4Pixel(rowA, rowIndex+2, pixel);
1929                     put4Pixel(rowA, rowIndex+3, pixel);
1930
1931                     if (!(currentFlags & (e21sw|e41si))) // if no south groups.
1932                     {
1933                         rowIndex += 2;
1934                         continue;
1935                     }
1936                 }
1937
1938                 if (currentFlags & e21sw)
1939                 {
1940                     put4Pixel(rowB, rowIndex+1, get4Pixel(rowB, rowIndex));
1941
1942                     rowIndex += 2;
1943                     continue;
1944                 }
1945
1946                 if (currentFlags & e41si)
1947                 {
1948                     pixel = get4Pixel(rowB, rowIndex);
1949
1950                     put4Pixel(rowB, rowIndex+1, pixel);
1951                     put4Pixel(rowB, rowIndex+2, pixel);
1952                     put4Pixel(rowB, rowIndex+3, pixel);
1953
1954                     rowIndex += 2;
1955                     continue;
1956                 }
1957             }
1958             rowIndex += 1;
1959         }
1960     }
1961 }
1962
1963 #endif // kMemWritesOptimize
1964
1965 APDK_END_NAMESPACE
1966
1967 #endif  // APDK_DJ9xxVIP && APDK_VIP_COLORFILTERING