1
/*****************************************************************************\
2
filterhpa.cpp : Implimentation for the TErnieFilter class
4
Copyright (c) 1996 - 2015, HP Co.
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions
10
1. Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
12
2. Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in the
14
documentation and/or other materials provided with the distribution.
15
3. Neither the name of HP nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24
TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
\*****************************************************************************/
32
#if defined(APDK_DJ9xxVIP) && defined(APDK_VIP_COLORFILTERING)
36
// copied from vob \di_research on 10/31/00
37
// MODIFICATIONS BY GE:
38
// 0. remove Windows header references
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
45
//#define assert ASSERT
47
#include "ernieplatform.h"
48
#include "filterhpa.h"
51
extern int blockStats[];
54
#if ((kMemWritesOptimize != 1) && (kMemWritesOptimize != 0))
55
#error "kMemWritesOptimize must be 0 or 1"
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)
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.
66
rFinal = (r0 + r1 + 1) / 2;
67
gFinal = (g0 + g1) / 2;
68
bFinal = (b0 + b1 + 1) / 2;
72
rFinal = (r0 + r1) / 2;
73
gFinal = (g0 + g1 + 1) / 2;
74
bFinal = (b0 + b1) / 2;
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)
85
ASSERT(rowWidthInPixels > 0);
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;
91
// int currPixel, lastPixel;
92
uint32_t currPixel, lastPixel;
93
bool lastPairAveraged = false;
94
bool last2by2Averaged = false;
97
for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
99
if ((pixelNum & 0x03) == 0x00) // 0,4,8...
101
last2by2Averaged = false; // Reinitialize every four columns;
104
currPixel = get4Pixel(currPtr);
106
flagsPtr[0] = (e11n|e11s); // Initialize in case nothing is found for this column
108
if (isWhite(currPixel))
111
#if kGatherStats == 1
112
blockStats[esWhiteFound]++;
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))
119
R1 = GetRed(currPixel);
120
G1 = GetGreen(currPixel);
121
B1 = GetBlue(currPixel);
123
// Can only horizontally average every other pixel, much like the 2x2 blocks.
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)))
137
int didNotBuild4by1 = true;
138
#if kGatherStats == 1
139
blockStats[es21nw]++;
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...
145
ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
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)))
157
#if kGatherStats == 1
158
blockStats[es41ni]++;
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...
164
currPixel = (lastR<<16) + (lastG<<8) + lastB;
166
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
168
#if kMemWritesOptimize == 0
169
put4Pixel(currPtr, -3, currPixel);
170
put4Pixel(currPtr, -2, currPixel);
171
put4Pixel(currPtr, -1, currPixel);
172
put4Pixel(currPtr, 0, currPixel);
174
put4Pixel(currPtr, -3, currPixel);
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;
183
if (didNotBuild4by1) // Not a 4x1 so output 2x1.
185
ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
188
currPixel = (lastR<<16) + (lastG<<8) + lastB;
190
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
192
#if kMemWritesOptimize == 0
193
put4Pixel(currPtr, -1, currPixel);
194
put4Pixel(currPtr, 0, currPixel);
196
put4Pixel(currPtr, -1, currPixel);
198
flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
199
flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
201
} // If DeltaE... Looking for two by one
204
else // no flag bits set.
206
lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
209
currPtr += eBufferedPixelWidthInBytes;
211
} // for each pixel...
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)
223
ASSERT(rowWidthInPixels > 0);
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;
229
// int currPixel, upPixel, lastPixel;
230
uint32_t currPixel, upPixel, lastPixel;
231
bool lastPairAveraged = false;
232
bool last2by2Averaged = false;
234
for (int pixelNum = 0; pixelNum < rowWidthInPixels; pixelNum++)
236
if ((pixelNum & 0x03) == 0x00) // 0,4,8...
238
last2by2Averaged = false; // Reinitialize every four columns;
241
upPixel = get4Pixel(upPtr);
242
currPixel = get4Pixel(currPtr);
244
flagsPtr[0] = (e11n|e11s); // Initialize in case nothing is found for this column
246
if (isWhite(upPixel) && isWhite(currPixel)) // both white?
249
#if kGatherStats == 1
250
blockStats[esWhiteFound]++;
254
// Do vertical average on the current 2 pixel high column
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))
259
R1 = GetRed(currPixel);
260
G1 = GetGreen(currPixel);
261
B1 = GetBlue(currPixel);
263
R0 = GetRed(upPixel);
264
G0 = GetGreen(upPixel);
265
B0 = GetBlue(upPixel);
267
if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R0, R1, G0, G1, B0, B1, fMaxErrorForTwoPixels)))
274
ASSERT(flagsPtr[0] == (e11n|e11s));
276
#if kGatherStats == 1
279
R1 = GetRed(currPixel);
280
G1 = GetGreen(currPixel);
281
B1 = GetBlue(currPixel);
283
R0 = GetRed(upPixel);
284
G0 = GetGreen(upPixel);
285
B0 = GetBlue(upPixel);
287
AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
289
// look for a 2x2 block average on every other column
291
{ // It looks like we are at the end of a 2x2 block
292
if (lastPairAveraged)
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)))
302
ASSERT(flagsPtr[-1] == e12);
303
int didNotBuild4by2 = true;
304
#if kGatherStats == 1
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
312
if ((pixelNum & 0x03) == 0x03) // 3,7,11,15... Looking for a 4x2 block to average
314
if (last2by2Averaged)
317
| | | | We have two 2x2s.
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)))
335
#if kGatherStats == 1
338
didNotBuild4by2 = false;
341
flagsPtr[-2] = flagsPtr[-1] = flagsPtr[0] = e42;
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
346
currPixel = (R1<<16) + (G1<<8) + B1;
348
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
360
put4Pixel(upPtr, -3, currPixel);
366
{ // The first 2x2 block of this pair of 2x2 blocks wasn't averaged.
368
|X X| | | not averaged block and averaged 2x2.
373
last2by2Averaged = true;
376
currPixel = (R1<<16) + (G1<<8) + B1;
378
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
380
#if kMemWritesOptimize == 0
381
put4Pixel(upPtr, -1, currPixel);
382
put4Pixel(upPtr, 0, currPixel);
383
put4Pixel(currPtr, -1, currPixel);
384
put4Pixel(currPtr, 0, currPixel);
386
put4Pixel(upPtr, -1, currPixel);
390
else // Not looking for a 4x2 block yet so just output this 2x2 block for now.
393
| | |? ?| 1st 2x2 and maybe another later.
398
last2by2Averaged = true;
401
currPixel = (R1<<16) + (G1<<8) + B1;
403
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
405
#if kMemWritesOptimize == 0
406
put4Pixel(upPtr, -1, currPixel);
407
put4Pixel(upPtr, 0, currPixel);
408
put4Pixel(currPtr, -1, currPixel);
409
put4Pixel(currPtr, 0, currPixel);
411
put4Pixel(upPtr, -1, currPixel);
415
else // The two averaged columns are not close enough in Delta E
423
last2by2Averaged = false;
426
currPixel = (R1<<16) + (G1<<8) + B1;
428
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
430
#if kMemWritesOptimize == 0
431
put4Pixel(upPtr, 0, currPixel);
432
put4Pixel(currPtr, 0, currPixel);
434
put4Pixel(upPtr,0, currPixel);
440
lastPairAveraged = true;
442
else // This is the right place for 2x2 averaging but the previous column wasn't averaged
445
X | | Two non averaged pixels and a 1x2.
449
last2by2Averaged = false;
450
lastPairAveraged = true;
456
currPixel = (R1<<16) + (G1<<8) + B1;
458
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
460
#if kMemWritesOptimize == 0
461
put4Pixel(upPtr, 0, currPixel);
462
put4Pixel(currPtr, 0, currPixel);
464
put4Pixel(upPtr, 0, currPixel);
468
else // Not on the boundary for a 2x2 block, so just output current averaged 1x2 column
476
lastPairAveraged = true;
482
currPixel = (R1<<16) + (G1<<8) + B1;
484
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
486
#if kMemWritesOptimize == 0
487
put4Pixel(upPtr, 0, currPixel);
488
put4Pixel(currPtr, 0, currPixel);
490
put4Pixel(upPtr, 0, currPixel);
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
499
| | X 1x2 averaged block and two non averaged pixels.
504
lastPairAveraged = false;
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.
511
// Can only horizontally average every other pixel, much like the 2x2 blocks.
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)))
525
#if kGatherStats == 1
526
blockStats[es21nw]++;
528
int didNotBuild4by1 = true;
530
AverageNRound(isOdd(pixelNum), lastR, lastR, R0, lastG, lastG, G0, lastB, lastB, B0);
532
if ((pixelNum >= 3) && (flagsPtr[-3] & e21nw)) // 4,5,6,7,12,13,14,15,20...
534
ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
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)))
547
#if kGatherStats == 1
548
blockStats[es41ni]++;
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...
554
currPixel = (lastR<<16) + (lastG<<8) + lastB;
556
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
558
#if kMemWritesOptimize == 0
559
put4Pixel(upPtr, -3, currPixel);
560
put4Pixel(upPtr, -2, currPixel);
561
put4Pixel(upPtr, -1, currPixel);
562
put4Pixel(upPtr, 0, currPixel);
564
put4Pixel(upPtr, -3, currPixel);
567
ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
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;
576
if (didNotBuild4by1) // Not an upper 4x1 so output upper 2x1.
579
currPixel = (lastR<<16) + (lastG<<8) + lastB;
581
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
583
#if kMemWritesOptimize == 0
584
put4Pixel(upPtr, -1, currPixel);
585
put4Pixel(upPtr, 0, currPixel);
587
put4Pixel(upPtr, -1, currPixel);
589
ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
590
flagsPtr[-1] = (flagsPtr[-1] & ~eNorths) | e21nw;
591
flagsPtr[0] = (flagsPtr[0] & ~eNorths) | e21ne;
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)))
606
int didNotBuild4by1 = true;
607
#if kGatherStats == 1
608
blockStats[es21sw]++;
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...
613
// Look for a lower 4x1
614
ASSERT(!((flagsPtr[-3] | flagsPtr[-2] | flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
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)))
626
#if kGatherStats == 1
627
blockStats[es41si]++;
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...
633
currPixel = (lastR<<16) + (lastG<<8) + lastB;
635
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
637
#if kMemWritesOptimize == 0
638
put4Pixel(currPtr, -3, currPixel);
639
put4Pixel(currPtr, -2, currPixel);
640
put4Pixel(currPtr, -1, currPixel);
641
put4Pixel(currPtr, 0, currPixel);
643
put4Pixel(currPtr, -3, currPixel);
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;
652
if (didNotBuild4by1) // Not a lower 4x1 so output lower 2x1.
654
ASSERT(!((flagsPtr[-1] | flagsPtr[0]) & eTheRest)); // no vertical blocks
657
currPixel = (lastR<<16) + (lastG<<8) + lastB;
659
currPixel = (lastR<<24) + (lastG<<16) + (lastB<<8);
661
#if kMemWritesOptimize == 0
662
put4Pixel(currPtr, -1, currPixel);
663
put4Pixel(currPtr, 0, currPixel);
665
put4Pixel(currPtr, -1, currPixel);
668
flagsPtr[-1] = (flagsPtr[-1] & ~eSouths) | e21sw;
669
flagsPtr[0] = (flagsPtr[0] & ~eSouths) | e21se;
671
} // If DeltaE... Looking for two by one
675
else // no flag bits set.
677
lastPairAveraged = false; // EGW Fixes bug on business graphics. 11/24/97
680
upPtr += eBufferedPixelWidthInBytes;
681
currPtr += eBufferedPixelWidthInBytes;
683
} // for each pixel...
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)
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;
701
for (int pixelNum = 0; pixelNum < (fRowWidthInPixels-3);) // Make sure we have four pixels to work with
703
int currPixel, upPixel;
704
int R0, G0, B0, R1, G1, B1;
706
if ((fPixelFilteredFlags[0][pixelNum] & e42i) && (fPixelFilteredFlags[1][pixelNum] & e42i))
711
- - - - We have two 4x2s.
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);
720
upPixel = get4Pixel(row1Ptr);
721
currPixel = get4Pixel(row3Ptr);
723
R1 = GetRed(currPixel);
724
G1 = GetGreen(currPixel);
725
B1 = GetBlue(currPixel);
727
R0 = GetRed(upPixel);
728
G0 = GetGreen(upPixel);
729
B0 = GetBlue(upPixel);
731
if((maxErrorForSixteenPixels >= 3) &&(NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForSixteenPixels)))
740
#if kGatherStats == 1
741
blockStats[es44ni]++;
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
746
currPixel = (R1<<16) + (G1<<8) + B1;
748
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
768
put4Pixel(row1Ptr, 0, currPixel);
770
row1Ptr += 4*eBufferedPixelWidthInBytes;
771
row2Ptr += 4*eBufferedPixelWidthInBytes;
772
row3Ptr += 4*eBufferedPixelWidthInBytes;
773
row4Ptr += 4*eBufferedPixelWidthInBytes;
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;
780
if ((pixelNum >= 4) && (fPixelFilteredFlags[1][pixelNum-4] & e44si)) // 4,5,6,7,12,13,14,15,20...
784
| | | | We have two 4x4s.
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);
792
upPixel = get4Pixel(row1Ptr, -8);
794
R0 = GetRed(upPixel);
795
G0 = GetGreen(upPixel);
796
B0 = GetBlue(upPixel);
798
if( (maxErrorForThirtyTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForThirtyTwoPixels)))
807
#if kGatherStats == 1
808
blockStats[es84ni]++;
810
AverageNRound((pixelNum & 0x08) == 0x08, R1, R1, R0, G1, G1, G0, B1, B1, B0);
812
currPixel = (R1<<16) + (G1<<8) + B1;
814
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
850
put4Pixel(row1Ptr, -8, currPixel);
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;
859
else // could not build 4x4 so move forward past the stacked 4x2s.
861
row1Ptr += 4*eBufferedPixelWidthInBytes;
862
row2Ptr += 4*eBufferedPixelWidthInBytes;
863
row3Ptr += 4*eBufferedPixelWidthInBytes;
864
row4Ptr += 4*eBufferedPixelWidthInBytes;
868
else if ((fPixelFilteredFlags[0][pixelNum] & e22w) && (fPixelFilteredFlags[1][pixelNum] & e22w))
879
ASSERT(fPixelFilteredFlags[0][pixelNum] == e22w && fPixelFilteredFlags[0][pixelNum+1] == e22e);
880
ASSERT(fPixelFilteredFlags[1][pixelNum] == e22w && fPixelFilteredFlags[1][pixelNum+1] == e22e);
882
upPixel = get4Pixel(row1Ptr);
883
currPixel = get4Pixel(row3Ptr);
885
R1 = GetRed(currPixel);
886
G1 = GetGreen(currPixel);
887
B1 = GetBlue(currPixel);
889
R0 = GetRed(upPixel);
890
G0 = GetGreen(upPixel);
891
B0 = GetBlue(upPixel);
893
if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
902
#if kGatherStats == 1
903
blockStats[es24nw]++;
905
AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
908
currPixel = (R1<<16) + (G1<<8) + B1;
910
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
922
put4Pixel(row1Ptr, 0, currPixel);
924
row1Ptr += 2*eBufferedPixelWidthInBytes;
925
row2Ptr += 2*eBufferedPixelWidthInBytes;
926
row3Ptr += 2*eBufferedPixelWidthInBytes;
927
row4Ptr += 2*eBufferedPixelWidthInBytes;
929
fPixelFilteredFlags[0][pixelNum] = e24nw;
930
fPixelFilteredFlags[0][pixelNum+1] = e24ne;
931
fPixelFilteredFlags[1][pixelNum] = e24sw;
932
fPixelFilteredFlags[1][pixelNum+1] = e24se;
936
row1Ptr += 2*eBufferedPixelWidthInBytes;
937
row2Ptr += 2*eBufferedPixelWidthInBytes;
938
row3Ptr += 2*eBufferedPixelWidthInBytes;
939
row4Ptr += 2*eBufferedPixelWidthInBytes;
943
else if ((fPixelFilteredFlags[0][pixelNum] & e12) && (fPixelFilteredFlags[1][pixelNum] & e12))
954
ASSERT(fPixelFilteredFlags[0][pixelNum] == e12);
955
ASSERT(fPixelFilteredFlags[1][pixelNum] == e12);
957
upPixel = get4Pixel(row1Ptr);
958
currPixel = get4Pixel(row3Ptr);
960
R1 = GetRed(currPixel);
961
G1 = GetGreen(currPixel);
962
B1 = GetBlue(currPixel);
964
R0 = GetRed(upPixel);
965
G0 = GetGreen(upPixel);
966
B0 = GetBlue(upPixel);
968
if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
977
#if kGatherStats == 1
980
AverageNRound((pixelNum & 0x01) == 0x01, R1, R1, R0, G1, G1, G0, B1, B1, B0);
983
currPixel = (R1<<16) + (G1<<8) + B1;
985
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
987
#if kMemWritesOptimize == 0
988
put4Pixel(row1Ptr, 0, currPixel);
989
put4Pixel(row2Ptr, 0, currPixel);
990
put4Pixel(row3Ptr, 0, currPixel);
991
put4Pixel(row4Ptr, 0, currPixel);
993
put4Pixel(row1Ptr, 0, currPixel);
995
fPixelFilteredFlags[0][pixelNum] = e14n;
996
fPixelFilteredFlags[1][pixelNum] = e14s;
999
row1Ptr += eBufferedPixelWidthInBytes;
1000
row2Ptr += eBufferedPixelWidthInBytes;
1001
row3Ptr += eBufferedPixelWidthInBytes;
1002
row4Ptr += eBufferedPixelWidthInBytes;
1006
else if ((fPixelFilteredFlags[0][pixelNum] & e41si)
1007
&& (fPixelFilteredFlags[1][pixelNum] & e41ni))
1011
- - - - We have two 4x1s.
1017
upPixel = get4Pixel(row2Ptr);
1018
currPixel = get4Pixel(row3Ptr);
1020
R1 = GetRed(currPixel);
1021
G1 = GetGreen(currPixel);
1022
B1 = GetBlue(currPixel);
1024
R0 = GetRed(upPixel);
1025
G0 = GetGreen(upPixel);
1026
B0 = GetBlue(upPixel);
1029
if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1037
#if kGatherStats == 1
1038
blockStats[es42w]++;
1040
AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1043
currPixel = (R1<<16) + (G1<<8) + B1;
1045
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
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;
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;
1069
row1Ptr += 4*eBufferedPixelWidthInBytes;
1070
row2Ptr += 4*eBufferedPixelWidthInBytes;
1071
row3Ptr += 4*eBufferedPixelWidthInBytes;
1072
row4Ptr += 4*eBufferedPixelWidthInBytes;
1074
else if ((fPixelFilteredFlags[0][pixelNum] & e21sw)
1075
&& (fPixelFilteredFlags[1][pixelNum] & e21nw))
1079
- - We have two 2x1s.
1084
ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1085
ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1087
upPixel = get4Pixel(row2Ptr);
1088
currPixel = get4Pixel(row3Ptr);
1090
R1 = GetRed(currPixel);
1091
G1 = GetGreen(currPixel);
1092
B1 = GetBlue(currPixel);
1094
R0 = GetRed(upPixel);
1095
G0 = GetGreen(upPixel);
1096
B0 = GetBlue(upPixel);
1098
if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1105
#if kGatherStats == 1
1106
blockStats[es22w]++;
1108
AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1111
currPixel = (R1<<16) + (G1<<8) + B1;
1113
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
1121
fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e21sw;
1122
fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e21se;
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;
1130
row1Ptr += 2*eBufferedPixelWidthInBytes;
1131
row2Ptr += 2*eBufferedPixelWidthInBytes;
1132
row3Ptr += 2*eBufferedPixelWidthInBytes;
1133
row4Ptr += 2*eBufferedPixelWidthInBytes;
1135
else if ((fPixelFilteredFlags[0][pixelNum] & e11s)
1136
&& (fPixelFilteredFlags[1][pixelNum] & e11n))
1146
upPixel = get4Pixel(row2Ptr);
1147
currPixel = get4Pixel(row3Ptr);
1149
R1 = GetRed(currPixel);
1150
G1 = GetGreen(currPixel);
1151
B1 = GetBlue(currPixel);
1153
R0 = GetRed(upPixel);
1154
G0 = GetGreen(upPixel);
1155
B0 = GetBlue(upPixel);
1157
if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, fMaxErrorForTwoPixels)))
1164
#if kGatherStats == 1
1165
blockStats[es12w]++;
1167
AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1170
currPixel = (R1<<16) + (G1<<8) + B1;
1172
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
1178
fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e11s;
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.
1185
row1Ptr += eBufferedPixelWidthInBytes;
1186
row2Ptr += eBufferedPixelWidthInBytes;
1187
row3Ptr += eBufferedPixelWidthInBytes;
1188
row4Ptr += eBufferedPixelWidthInBytes;
1190
else // Do no vertical filtering here.
1194
row1Ptr += eBufferedPixelWidthInBytes;
1195
row2Ptr += eBufferedPixelWidthInBytes;
1196
row3Ptr += eBufferedPixelWidthInBytes;
1197
row4Ptr += eBufferedPixelWidthInBytes;
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)
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;
1216
for (int pixelNum = 0; pixelNum < (fRowWidthInPixels-3);) // Make sure we have four pixels to work with
1218
// int currPixel, upPixel;
1219
uint32_t currPixel, upPixel;
1220
int R0, G0, B0, R1, G1, B1;
1222
if ((fPixelFilteredFlags[0][pixelNum] & e41si)
1223
&& (fPixelFilteredFlags[1][pixelNum] & e41ni))
1227
- - - - We have two 4x1s.
1232
ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1233
ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1235
upPixel = get4Pixel(row2Ptr);
1236
currPixel = get4Pixel(row3Ptr);
1238
R1 = GetRed(currPixel);
1239
G1 = GetGreen(currPixel);
1240
B1 = GetBlue(currPixel);
1242
R0 = GetRed(upPixel);
1243
G0 = GetGreen(upPixel);
1244
B0 = GetBlue(upPixel);
1247
if ((maxErrorForEightPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForEightPixels)))
1255
#if kGatherStats == 1
1256
blockStats[es42w]++;
1258
AverageNRound((pixelNum & 0x04) == 0x04, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1261
currPixel = (R1<<16) + (G1<<8) + B1;
1263
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
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;
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;
1287
row1Ptr += 4*eBufferedPixelWidthInBytes;
1288
row2Ptr += 4*eBufferedPixelWidthInBytes;
1289
row3Ptr += 4*eBufferedPixelWidthInBytes;
1291
else if ((fPixelFilteredFlags[0][pixelNum] & e21sw)
1292
&& (fPixelFilteredFlags[1][pixelNum] & e21nw))
1296
- - We have two 2x1s.
1301
ASSERT(!((fPixelFilteredFlags[0][pixelNum] & e11s) | (fPixelFilteredFlags[0][pixelNum+1] & e11s)));
1302
ASSERT(!((fPixelFilteredFlags[1][pixelNum] & e11n) | (fPixelFilteredFlags[1][pixelNum+1] & e11n)));
1304
upPixel = get4Pixel(row2Ptr);
1305
currPixel = get4Pixel(row3Ptr);
1307
R1 = GetRed(currPixel);
1308
G1 = GetGreen(currPixel);
1309
B1 = GetBlue(currPixel);
1311
R0 = GetRed(upPixel);
1312
G0 = GetGreen(upPixel);
1313
B0 = GetBlue(upPixel);
1315
if ((maxErrorForFourPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, maxErrorForFourPixels)))
1322
#if kGatherStats == 1
1323
blockStats[es22w]++;
1325
AverageNRound((pixelNum & 0x02) == 0x02, R1, R1, R0, G1, G1, G0, B1, B1, B0);
1328
currPixel = (R1<<16) + (G1<<8) + B1;
1330
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
1338
fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e21sw;
1339
fPixelFilteredFlags[0][pixelNum+1] = fPixelFilteredFlags[0][pixelNum+1] & ~e21se;
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;
1347
row1Ptr += 2*eBufferedPixelWidthInBytes;
1348
row2Ptr += 2*eBufferedPixelWidthInBytes;
1349
row3Ptr += 2*eBufferedPixelWidthInBytes;
1351
else if ((fPixelFilteredFlags[0][pixelNum] & e11s)
1352
&& (fPixelFilteredFlags[1][pixelNum] & e11n))
1362
upPixel = get4Pixel(row2Ptr);
1363
currPixel = get4Pixel(row3Ptr);
1365
R1 = GetRed(currPixel);
1366
G1 = GetGreen(currPixel);
1367
B1 = GetBlue(currPixel);
1369
R0 = GetRed(upPixel);
1370
G0 = GetGreen(upPixel);
1371
B0 = GetBlue(upPixel);
1373
if ((fMaxErrorForTwoPixels >= 3) && (NewDeltaE(R1, R0, G1, G0, B1, B0, fMaxErrorForTwoPixels)))
1380
#if kGatherStats == 1
1381
blockStats[es12w]++;
1383
AverageNRound(isOdd(pixelNum), R1, R1, R0, G1, G1, G0, B1, B1, B0);
1386
currPixel = (R1<<16) + (G1<<8) + B1;
1388
currPixel = (R1<<24) + (G1<<16) + (B1<<8);
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);
1394
fPixelFilteredFlags[0][pixelNum] = fPixelFilteredFlags[0][pixelNum] & ~e11s;
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.
1401
row1Ptr += eBufferedPixelWidthInBytes;
1402
row2Ptr += eBufferedPixelWidthInBytes;
1403
row3Ptr += eBufferedPixelWidthInBytes;
1405
else // Do no vertical filtering here.
1409
row1Ptr += eBufferedPixelWidthInBytes;
1410
row2Ptr += eBufferedPixelWidthInBytes;
1411
row3Ptr += eBufferedPixelWidthInBytes;
1416
#define NEWTEST true
1418
inline bool TErnieFilter::NewDeltaE(int dr0, int dr1, int dg0, int dg1, int db0, int db1, int tolerance)
1420
int Y0, Y1, dY, Cr0, Cr1, Cb0, Cb1, dCr, dCb;
1422
// new Delta E stuff from Jay
1424
Y0 = 5*dr0 + 9*dg0 + 2*db0;
1425
Y1 = 5*dr1 + 9*dg1 + 2*db1;
1427
dY = ABS(Y0 - Y1) >> 4;
1429
if(dY > tolerance) {
1434
Cr0 = (dr0 << 4) - Y0;
1435
Cr1 = (dr1 << 4) - Y1;
1436
dCr = ABS(Cr0 - Cr1) >> 5;
1443
Cb0 = (db0 << 4) - Y0;
1444
Cb1 = (db1 << 4) - Y1;
1445
dCb = ABS(Cb0 - Cb1) >> 6;
1455
TErnieFilter::TErnieFilter(int rowWidthInPixels, pixelTypes pixelType, unsigned int maxErrorForTwoPixels, int bytesPerPixel)
1456
: fOriginalPixelSize(bytesPerPixel)
1459
ASSERT((fOriginalPixelSize == 3) || (fOriginalPixelSize == 4));
1460
ASSERT(rowWidthInPixels > 0);
1461
ASSERT(pixelType == eBGRPixelData);
1463
fInternalBufferPixelSize = 4;
1465
fPixelOffsetIndex = 0;
1466
fRowWidthInPixels = rowWidthInPixels;
1467
fRowWidthInBytes = fRowWidthInPixels*fInternalBufferPixelSize;
1468
fMaxErrorForTwoPixels = maxErrorForTwoPixels;
1470
for (index = 0; index < 4; index++)
1472
fRowBuf[index] = new uint32_t[rowWidthInPixels];
1473
ASSERT(fRowBuf[index]);
1475
fRowPtr[index] = new unsigned char[rowWidthInPixels*fOriginalPixelSize];
1476
ASSERT(fRowPtr[index]);
1478
fBlackRowPtr[index] = new BYTE[rowWidthInPixels*fOriginalPixelSize];
1479
ASSERT(fBlackRowPtr[index]);
1481
BlackRasterSize[index] = 0;
1484
for (index = 0; index < 2; index++)
1486
fPixelFilteredFlags[index] = new unsigned int[rowWidthInPixels];
1487
ASSERT(fPixelFilteredFlags[index]);
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.
1493
int maxCompressionBufSize = fRowWidthInBytes + 1 + ((int)ceil((float)MAX((rowWidthInPixels-2)/255, 0)));
1495
fCompressionOutBuf = new unsigned char[maxCompressionBufSize];
1496
ASSERT(fCompressionOutBuf);
1498
fNumberOfBufferedRows = 0;
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;
1513
TErnieFilter::~TErnieFilter()
1515
// Deallocate memory next.
1518
for (index = 0; index < 4; index++)
1520
delete [] fRowBuf[index];
1521
delete [] fRowPtr[index];
1522
delete [] fBlackRowPtr[index];
1525
for (index = 0; index < 2; index++)
1527
delete [] fPixelFilteredFlags[index];
1530
delete [] fCompressionOutBuf;
1533
void TErnieFilter::writeBufferedRows()
1537
// We just have one lonely raster left. Nothing
1538
// we can do but filter it horizontally.
1539
if( 1 == fNumberOfBufferedRows)
1542
int offset2 = fPixelOffset[fPixelOffsetIndex];
1544
Filter1RawRow( (unsigned char*)(fRowBuf[0] + offset2),
1545
fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1546
fPixelFilteredFlags[0] + fPixelOffset[fPixelOffsetIndex]);
1549
unsigned char *rowPtr = fRowPtr[0];
1554
memcpy(rowPtr, &fRowBuf[0][pixelIndex], 3);
1556
} while (++pixelIndex < fRowWidthInPixels);
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)
1564
// Write the two rows back out.
1566
for (k = 0; k < 2; k++)
1568
unsigned char *rowPtr = fRowPtr[k];
1573
memcpy(rowPtr, &fRowBuf[k][pixelIndex], 3);
1575
} while (++pixelIndex < fRowWidthInPixels);
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)
1587
int offset2 = fPixelOffset[fPixelOffsetIndex];
1589
Filter1RawRow( (unsigned char*)(fRowBuf[2] + offset2),
1590
fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1591
fPixelFilteredFlags[1] + fPixelOffset[fPixelOffsetIndex]);
1594
Filter3FilteredRows( (unsigned char*)fRowBuf[0],
1595
(unsigned char*)fRowBuf[1],
1596
(unsigned char*)fRowBuf[2]);
1599
for (k = 0; k < 3; k++)
1601
unsigned char *rowPtr = fRowPtr[k];
1606
memcpy(rowPtr, &fRowBuf[k][pixelIndex], 3);
1608
} while (++pixelIndex < fRowWidthInPixels);
1613
void TErnieFilter::submitRowToFilter(unsigned char *rowPtr)
1615
memcpy(fRowPtr[fNumberOfBufferedRows], rowPtr, fRowWidthInPixels*3);
1617
// Now reformat the pixel data from 24 bit to 32 bit pixels
1619
uint32_t *RowPtrDest = fRowBuf[fNumberOfBufferedRows];
1629
RowPtrDest[pixelIndex] = ((byte3 << 16) | (byte2 << 8) | (byte1)) & 0x00FFFFFF;
1631
RowPtrDest[pixelIndex] = ((byte1 << 24) | (byte2 << 16) | (byte3 << 8)) & 0xFFFFFF00;
1632
} while (++pixelIndex < fRowWidthInPixels);
1634
fNumberOfBufferedRows++;
1637
iRastersDelivered=0;
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)
1644
int offset2 = fPixelOffset[fPixelOffsetIndex];
1646
Filter2RawRows( (unsigned char*)(fRowBuf[1] + offset2),
1647
(unsigned char*)(fRowBuf[0] + offset2),
1648
fRowWidthInPixels - fPixelOffset[fPixelOffsetIndex],
1649
fPixelFilteredFlags[0] + fPixelOffset[fPixelOffsetIndex]);
1652
if (4 == fNumberOfBufferedRows)
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]);
1660
Filter2PairsOfFilteredRows( (unsigned char*)fRowBuf[0],
1661
(unsigned char*)fRowBuf[1],
1662
(unsigned char*)fRowBuf[2],
1663
(unsigned char*)fRowBuf[3]);
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.
1671
fPixelOffsetIndex = (fPixelOffsetIndex + 1) % 8; // cycle the offset index.
1674
for (k = 0; k < fPixelOffset[fPixelOffsetIndex]; k++) // Clear out the flags that we're offsetting past for this next iteration.
1676
fPixelFilteredFlags[0][k] = eDone;
1677
fPixelFilteredFlags[1][k] = eDone;
1680
// Write the four rows back out.
1681
for (k = 0; k < 4; k++)
1683
unsigned char *rowPtr = fRowPtr[k];
1688
memcpy(rowPtr, &fRowBuf[k][pixelIndex], fOriginalPixelSize);
1689
rowPtr += fOriginalPixelSize;
1690
} while (++pixelIndex < fRowWidthInPixels);
1693
fNumberOfBufferedRows = 0;
1699
#if kMemWritesOptimize == 1
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
1707
void TErnieFilter::WriteBlockPixels(void)
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];
1714
for (int flagSet = 0; flagSet <= 1; flagSet++)
1716
unsigned int *flagsPtr = fPixelFilteredFlags[0];
1717
unsigned char *rowA = (unsigned char*)fRowBuf[0];
1718
unsigned char *rowB = (unsigned char*)fRowBuf[1];
1722
flagsPtr = fPixelFilteredFlags[1];
1723
rowA = (unsigned char*)fRowBuf[2];
1724
rowB = (unsigned char*)fRowBuf[3];
1727
for (int rowIndex = 0; rowIndex < fRowWidthInPixels;)
1729
unsigned int currentFlags = flagsPtr[rowIndex];
1731
#ifndef NDEBUG /* only done for debug builds */
1732
int numberOfBitsSet = 0;
1733
unsigned int currentFlagsCopy = currentFlags & eTopLeftOfBlocks;
1734
while (currentFlagsCopy)
1736
if (currentFlagsCopy & 1) numberOfBitsSet++;
1737
currentFlagsCopy >>= 1;
1739
ASSERT( (numberOfBitsSet <= 1) ||
1740
((numberOfBitsSet == 2) &&
1741
(((currentFlags & eTopLeftOfBlocks) & ~(e21nw|e21sw|e41ni|e41si))==0)));
1744
if (currentFlags & eTopLeftOfBlocks) // Avoids doing a lot of checks if nothing is set.
1746
// unsigned int 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.
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)
1756
pixel = get4Pixel(rowA, rowIndex);
1758
put4Pixel(rowB, rowIndex, pixel);
1760
put4Pixel(rowA, rowIndex, pixel);
1761
put4Pixel(rowB, rowIndex, pixel);
1767
if (currentFlags & e12)
1769
put4Pixel(rowB, rowIndex, get4Pixel(rowA, rowIndex));
1775
if (currentFlags & e42i)
1777
pixel = get4Pixel(rowA, rowIndex);
1779
put4Pixel(rowB, rowIndex, pixel);
1782
put4Pixel(rowA, rowIndex, pixel);
1783
put4Pixel(rowB, rowIndex, pixel);
1786
put4Pixel(rowB, rowIndex, pixel);
1787
put4Pixel(rowA, rowIndex, pixel);
1790
put4Pixel(rowA, rowIndex, pixel);
1791
put4Pixel(rowB, rowIndex, pixel);
1797
if (currentFlags & e84ni)
1799
pixel = get4Pixel(rowA, rowIndex);
1801
put4Pixel(row2Ptr, rowIndex, pixel);
1802
put4Pixel(row3Ptr, rowIndex, pixel);
1803
put4Pixel(row4Ptr, rowIndex, pixel);
1806
put4Pixel(row1Ptr, rowIndex, pixel);
1807
put4Pixel(row2Ptr, rowIndex, pixel);
1808
put4Pixel(row3Ptr, rowIndex, pixel);
1809
put4Pixel(row4Ptr, rowIndex, pixel);
1812
put4Pixel(row1Ptr, rowIndex, pixel);
1813
put4Pixel(row2Ptr, rowIndex, pixel);
1814
put4Pixel(row3Ptr, rowIndex, pixel);
1815
put4Pixel(row4Ptr, rowIndex, pixel);
1818
put4Pixel(row1Ptr, rowIndex, pixel);
1819
put4Pixel(row2Ptr, rowIndex, pixel);
1820
put4Pixel(row3Ptr, rowIndex, pixel);
1821
put4Pixel(row4Ptr, rowIndex, pixel);
1824
put4Pixel(row1Ptr, rowIndex, pixel);
1825
put4Pixel(row2Ptr, rowIndex, pixel);
1826
put4Pixel(row3Ptr, rowIndex, pixel);
1827
put4Pixel(row4Ptr, rowIndex, pixel);
1830
put4Pixel(row1Ptr, rowIndex, pixel);
1831
put4Pixel(row2Ptr, rowIndex, pixel);
1832
put4Pixel(row3Ptr, rowIndex, pixel);
1833
put4Pixel(row4Ptr, rowIndex, pixel);
1836
put4Pixel(row1Ptr, rowIndex, pixel);
1837
put4Pixel(row2Ptr, rowIndex, pixel);
1838
put4Pixel(row3Ptr, rowIndex, pixel);
1839
put4Pixel(row4Ptr, rowIndex, pixel);
1842
put4Pixel(row1Ptr, rowIndex, pixel);
1843
put4Pixel(row2Ptr, rowIndex, pixel);
1844
put4Pixel(row3Ptr, rowIndex, pixel);
1845
put4Pixel(row4Ptr, rowIndex, pixel);
1852
if (currentFlags & e24nw)
1854
pixel = get4Pixel(row1Ptr, rowIndex);
1856
put4Pixel(row2Ptr, rowIndex, pixel);
1857
put4Pixel(row3Ptr, rowIndex, pixel);
1858
put4Pixel(row4Ptr, rowIndex, pixel);
1861
put4Pixel(row1Ptr, rowIndex, pixel);
1862
put4Pixel(row2Ptr, rowIndex, pixel);
1863
put4Pixel(row3Ptr, rowIndex, pixel);
1864
put4Pixel(row4Ptr, rowIndex, pixel);
1870
if (currentFlags & e44ni)
1872
pixel = get4Pixel(row1Ptr, rowIndex);
1874
put4Pixel(row2Ptr, rowIndex, pixel);
1875
put4Pixel(row3Ptr, rowIndex, pixel);
1876
put4Pixel(row4Ptr, rowIndex, pixel);
1879
put4Pixel(row1Ptr, rowIndex, pixel);
1880
put4Pixel(row2Ptr, rowIndex, pixel);
1881
put4Pixel(row3Ptr, rowIndex, pixel);
1882
put4Pixel(row4Ptr, rowIndex, pixel);
1885
put4Pixel(row1Ptr, rowIndex, pixel);
1886
put4Pixel(row2Ptr, rowIndex, pixel);
1887
put4Pixel(row3Ptr, rowIndex, pixel);
1888
put4Pixel(row4Ptr, rowIndex, pixel);
1891
put4Pixel(row1Ptr, rowIndex, pixel);
1892
put4Pixel(row2Ptr, rowIndex, pixel);
1893
put4Pixel(row3Ptr, rowIndex, pixel);
1894
put4Pixel(row4Ptr, rowIndex, pixel);
1900
if (currentFlags & e14n)
1902
pixel = get4Pixel(row1Ptr, rowIndex);
1904
put4Pixel(row2Ptr, rowIndex, pixel);
1905
put4Pixel(row3Ptr, rowIndex, pixel);
1906
put4Pixel(row4Ptr, rowIndex, pixel);
1912
if (currentFlags & e21nw)
1914
put4Pixel(rowA, rowIndex+1, get4Pixel(rowA, rowIndex));
1916
if (!(currentFlags & (e21sw|e41si))) // if no south groups
1923
if (currentFlags & e41ni)
1925
pixel = get4Pixel(rowA, rowIndex);
1927
put4Pixel(rowA, rowIndex+1, pixel);
1928
put4Pixel(rowA, rowIndex+2, pixel);
1929
put4Pixel(rowA, rowIndex+3, pixel);
1931
if (!(currentFlags & (e21sw|e41si))) // if no south groups.
1938
if (currentFlags & e21sw)
1940
put4Pixel(rowB, rowIndex+1, get4Pixel(rowB, rowIndex));
1946
if (currentFlags & e41si)
1948
pixel = get4Pixel(rowB, rowIndex);
1950
put4Pixel(rowB, rowIndex+1, pixel);
1951
put4Pixel(rowB, rowIndex+2, pixel);
1952
put4Pixel(rowB, rowIndex+3, pixel);
1963
#endif // kMemWritesOptimize
1967
#endif // APDK_DJ9xxVIP && APDK_VIP_COLORFILTERING