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