~mimose/+junk/hplip-3.16.11

« back to all changes in this revision

Viewing changes to prnt/hpijs/filterhpa.cpp

  • Committer: guoyalong
  • Date: 2017-09-20 10:13:05 UTC
  • Revision ID: guoyalong@kylinos.cn-20170920101305-82zaolzpv1qghz29
Modified debian/control & debian/rules.

Show diffs side-by-side

added added

removed removed

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