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