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