~ubuntu-branches/ubuntu/saucy/hplip/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/kbsd.dpatch/prnt/hpcups/ErnieFilter.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2012-05-26 11:20:39 UTC
  • mfrom: (1.5.6) (31.1.3 precise)
  • Revision ID: package-import@ubuntu.com-20120526112039-bevxczegxnbyr5m7
Tags: 3.12.4-1
* New upstream release
* Switch to source/format 3.0 (quilt) - drop dpatch
* Refreshed debian/patches
* dh_autoreconf debian/autogen.sh & set local-options single-debian-patch
* Update to debian/compat -> 9
* Fix "hardened build flags" patch from Moritz - thanks (Closes: #667828)
* Fix "duplex descriptor uninitialized" patch from Matej (Closes: #583273)
* Fix "please migrate to kde-runtime" patch from Pino (Closes: #666544)

Show diffs side-by-side

added added

removed removed

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