xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <stdlib.h>
32 
33 #include <vcl/bmpacc.hxx>
34 #include <vcl/octree.hxx>
35 #include <vcl/bitmapex.hxx>
36 #include <vcl/bitmap.hxx>
37 
38 #include <impoct.hxx>
39 #include <impvect.hxx>
40 
41 // -----------
42 // - Defines -
43 // -----------
44 
45 #define RGB15( _def_cR, _def_cG, _def_cB )  (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
46 #define GAMMA( _def_cVal, _def_InvGamma )   ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
47 
48 #define CALC_ERRORS                                                             \
49                         nTemp   = p1T[nX++] >> 12;                              \
50                         nBErr = MinMax( nTemp, 0, 255 );                        \
51                         nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
52                         nTemp   = p1T[nX++] >> 12;                              \
53                         nGErr = MinMax( nTemp, 0, 255 );                        \
54                         nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
55                         nTemp   = p1T[nX] >> 12;                                \
56                         nRErr = MinMax( nTemp, 0, 255 );                        \
57                         nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
58 
59 #define CALC_TABLES3                                        \
60                         p2T[nX++] += FloydError3[nBErr];    \
61                         p2T[nX++] += FloydError3[nGErr];    \
62                         p2T[nX++] += FloydError3[nRErr];
63 
64 #define CALC_TABLES5                                        \
65                         p2T[nX++] += FloydError5[nBErr];    \
66                         p2T[nX++] += FloydError5[nGErr];    \
67                         p2T[nX++] += FloydError5[nRErr];
68 
69 #define CALC_TABLES7                                        \
70                         p1T[++nX] += FloydError7[nBErr];    \
71                         p2T[nX++] += FloydError1[nBErr];    \
72                         p1T[nX] += FloydError7[nGErr];      \
73                         p2T[nX++] += FloydError1[nGErr];    \
74                         p1T[nX] += FloydError7[nRErr];      \
75                         p2T[nX] += FloydError1[nRErr];
76 
77 // -----------
78 // - Statics -
79 // -----------
80 
81 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
82 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
83 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
84 
85 // ------------------------------------------------------------------------
86 
87 sal_uLong nVCLDitherLut[ 256 ] =
88 {
89        0, 49152, 12288, 61440,  3072, 52224, 15360, 64512,   768, 49920, 13056,
90    62208,  3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
91    48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
92    57344,  4096, 53248, 11264, 60416,  7168, 56320,  8960, 58112,  4864, 54016,
93    12032, 61184,  7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
94    23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
95    14336, 63488,  1024, 50176, 13312, 62464,  2816, 51968, 15104, 64256,  1792,
96    50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
97    35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392,  6144,
98    55296,  9216, 58368,  5120, 54272, 11008, 60160,  6912, 56064,  9984, 59136,
99     5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
100    27392, 39680, 23296, 42752, 26368, 38656, 22272,   512, 49664, 12800, 61952,
101     3584, 52736, 15872, 65024,   256, 49408, 12544, 61696,  3328, 52480, 15616,
102    64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
103    45312, 28928, 36096, 19712, 48384, 32000,  8704, 57856,  4608, 53760, 11776,
104    60928,  7680, 56832,  8448, 57600,  4352, 53504, 11520, 60672,  7424, 56576,
105    41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
106    20736, 44288, 27904, 40192, 23808,  2560, 51712, 14848, 64000,  1536, 50688,
107    13824, 62976,  2304, 51456, 14592, 63744,  1280, 50432, 13568, 62720, 35328,
108    18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
109    34048, 17664, 46336, 29952, 10752, 59904,  6656, 55808,  9728, 58880,  5632,
110    54784, 10496, 59648,  6400, 55552,  9472, 58624,  5376, 54528, 43520, 27136,
111    39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
112    25856, 38144, 21760
113 };
114 
115 // ------------------------------------------------------------------------
116 
117 sal_uLong nVCLLut[ 256 ] =
118 {
119          0,  1286,  2572,  3858,  5144,  6430,  7716,  9002,
120      10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
121      20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
122      30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
123      41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
124      51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
125      61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
126      72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
127      82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
128      92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
129     102880,104166,105452,106738,108024,109310,110596,111882,
130     113168,114454,115740,117026,118312,119598,120884,122170,
131     123456,124742,126028,127314,128600,129886,131172,132458,
132     133744,135030,136316,137602,138888,140174,141460,142746,
133     144032,145318,146604,147890,149176,150462,151748,153034,
134     154320,155606,156892,158178,159464,160750,162036,163322,
135     164608,165894,167180,168466,169752,171038,172324,173610,
136     174896,176182,177468,178754,180040,181326,182612,183898,
137     185184,186470,187756,189042,190328,191614,192900,194186,
138     195472,196758,198044,199330,200616,201902,203188,204474,
139     205760,207046,208332,209618,210904,212190,213476,214762,
140     216048,217334,218620,219906,221192,222478,223764,225050,
141     226336,227622,228908,230194,231480,232766,234052,235338,
142     236624,237910,239196,240482,241768,243054,244340,245626,
143     246912,248198,249484,250770,252056,253342,254628,255914,
144     257200,258486,259772,261058,262344,263630,264916,266202,
145     267488,268774,270060,271346,272632,273918,275204,276490,
146     277776,279062,280348,281634,282920,284206,285492,286778,
147     288064,289350,290636,291922,293208,294494,295780,297066,
148     298352,299638,300924,302210,303496,304782,306068,307354,
149     308640,309926,311212,312498,313784,315070,316356,317642,
150     318928,320214,321500,322786,324072,325358,326644,327930
151 };
152 
153 // ------------------------------------------------------------------------
154 
155 long FloydMap[256] =
156 {
157     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
158     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
159     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
160     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
161     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
162     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
163     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
164     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
165     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
166     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
167     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
168     3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
169     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
170     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
171     4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
172     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
173 };
174 
175 // ------------------------------------------------------------------------
176 
177 long FloydError1[61] =
178 {
179     -7680, -7424, -7168, -6912, -6656, -6400, -6144,
180     -5888, -5632, -5376, -5120, -4864, -4608, -4352,
181     -4096, -3840, -3584, -3328, -3072, -2816, -2560,
182     -2304, -2048, -1792, -1536, -1280, -1024, -768,
183     -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
184     1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
185     3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
186     5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
187 };
188 
189 // ------------------------------------------------------------------------
190 
191 long FloydError3[61] =
192 {
193     -23040, -22272, -21504, -20736, -19968, -19200,
194     -18432, -17664, -16896, -16128, -15360, -14592,
195     -13824, -13056, -12288, -11520, -10752, -9984,
196     -9216, -8448, -7680, -6912, -6144, -5376, -4608,
197     -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
198     2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
199     8448, 9216, 9984, 10752, 11520, 12288, 13056,
200     13824, 14592, 15360, 16128, 16896, 17664, 18432,
201     19200, 19968, 20736, 21504, 22272, 23040
202 };
203 
204 // ------------------------------------------------------------------------
205 
206 long FloydError5[61] =
207 {
208     -38400, -37120, -35840, -34560, -33280, -32000,
209     -30720, -29440, -28160, -26880, -25600, -24320,
210     -23040, -21760, -20480, -19200, -17920, -16640,
211     -15360, -14080, -12800, -11520, -10240, -8960,
212     -7680, -6400, -5120, -3840, -2560, -1280,   0,
213     1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
214     11520, 12800, 14080, 15360, 16640, 17920, 19200,
215     20480, 21760, 23040, 24320, 25600, 26880, 28160,
216     29440, 30720, 32000, 33280, 34560, 35840, 37120,
217     38400
218 };
219 
220 // ------------------------------------------------------------------------
221 
222 long FloydError7[61] =
223 {
224     -53760, -51968, -50176, -48384, -46592, -44800,
225     -43008, -41216, -39424, -37632, -35840, -34048,
226     -32256, -30464, -28672, -26880, -25088, -23296,
227     -21504, -19712, -17920, -16128, -14336, -12544,
228     -10752, -8960, -7168, -5376, -3584, -1792,  0,
229     1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
230     16128, 17920, 19712, 21504, 23296, 25088, 26880,
231     28672, 30464, 32256, 34048, 35840, 37632, 39424,
232     41216, 43008, 44800, 46592, 48384, 50176, 51968,
233     53760
234 };
235 
236 // ------------------------------------------------------------------------
237 
238 long FloydIndexMap[6] =
239 {
240     -30,  21, 72, 123, 174, 225
241 };
242 
243 // --------------------------
244 // - ImplCreateDitherMatrix -
245 // --------------------------
246 
247 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
248 {
249     double          fVal = 3.125;
250     const double    fVal16 = fVal / 16.;
251     long            i, j, k, l;
252     sal_uInt16          pMtx[ 16 ][ 16 ];
253     sal_uInt16          nMax = 0;
254     static sal_uInt8    pMagic[4][4] = { { 0, 14,  3, 13, },
255                                      {11,  5,  8,  6, },
256                                      {12,  2, 15,  1, },
257                                      {7,   9,  4, 10 } };
258 
259     // MagicSquare aufbauen
260     for ( i = 0; i < 4; i++ )
261        for ( j = 0; j < 4; j++ )
262            for ( k = 0; k < 4; k++ )
263                 for ( l = 0; l < 4; l++ )
264                     nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
265                     (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
266 
267     // auf Intervall [0;254] skalieren
268     for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
269         for( j = 0; j < 16; j++ )
270             (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] );
271 }
272 
273 // ----------
274 // - Bitmap -
275 // ----------
276 
277 sal_Bool Bitmap::Convert( BmpConversion eConversion )
278 {
279     const sal_uInt16    nBitCount = GetBitCount();
280     sal_Bool            bRet = sal_False;
281 
282     switch( eConversion )
283     {
284         case( BMP_CONVERSION_1BIT_THRESHOLD ):
285             bRet = ImplMakeMono( 128 );
286         break;
287 
288         case( BMP_CONVERSION_1BIT_MATRIX ):
289             bRet = ImplMakeMonoDither();
290         break;
291 
292         case( BMP_CONVERSION_4BIT_GREYS ):
293             bRet = ImplMakeGreyscales( 16 );
294         break;
295 
296         case( BMP_CONVERSION_4BIT_COLORS ):
297         {
298             if( nBitCount < 4 )
299                 bRet = ImplConvertUp( 4, NULL );
300             else if( nBitCount > 4 )
301                 bRet = ImplConvertDown( 4, NULL );
302             else
303                 bRet = sal_True;
304         }
305         break;
306 
307         case( BMP_CONVERSION_4BIT_TRANS ):
308         {
309             Color aTrans( BMP_COL_TRANS );
310 
311             if( nBitCount < 4 )
312                 bRet = ImplConvertUp( 4, &aTrans );
313             else
314                 bRet = ImplConvertDown( 4, &aTrans );
315         }
316         break;
317 
318         case( BMP_CONVERSION_8BIT_GREYS ):
319             bRet = ImplMakeGreyscales( 256 );
320         break;
321 
322         case( BMP_CONVERSION_8BIT_COLORS ):
323         {
324             if( nBitCount < 8 )
325                 bRet = ImplConvertUp( 8 );
326             else if( nBitCount > 8 )
327                 bRet = ImplConvertDown( 8 );
328             else
329                 bRet = sal_True;
330         }
331         break;
332 
333         case( BMP_CONVERSION_8BIT_TRANS ):
334         {
335             Color aTrans( BMP_COL_TRANS );
336 
337             if( nBitCount < 8 )
338                 bRet = ImplConvertUp( 8, &aTrans );
339             else
340                 bRet = ImplConvertDown( 8, &aTrans );
341         }
342         break;
343 
344         case( BMP_CONVERSION_24BIT ):
345         {
346             if( nBitCount < 24 )
347                 bRet = ImplConvertUp( 24, sal_False );
348             else
349                 bRet = sal_True;
350         }
351         break;
352 
353         case( BMP_CONVERSION_GHOSTED ):
354             bRet = ImplConvertGhosted();
355         break;
356 
357         default:
358             DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
359         break;
360     }
361 
362     return bRet;
363 }
364 
365 // ------------------------------------------------------------------------
366 
367 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
368 {
369     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
370     sal_Bool                bRet = sal_False;
371 
372     if( pReadAcc )
373     {
374         Bitmap              aNewBmp( GetSizePixel(), 1 );
375         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
376 
377         if( pWriteAcc )
378         {
379             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
380             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
381             const long          nWidth = pWriteAcc->Width();
382             const long          nHeight = pWriteAcc->Height();
383 
384             if( pReadAcc->HasPalette() )
385             {
386                 for( long nY = 0L; nY < nHeight; nY++ )
387                 {
388                     for( long nX = 0L; nX < nWidth; nX++ )
389                     {
390                         if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >=
391                             cThreshold )
392                         {
393                             pWriteAcc->SetPixel( nY, nX, aWhite );
394                         }
395                         else
396                             pWriteAcc->SetPixel( nY, nX, aBlack );
397                     }
398                 }
399             }
400             else
401             {
402                 for( long nY = 0L; nY < nHeight; nY++ )
403                 {
404                     for( long nX = 0L; nX < nWidth; nX++ )
405                     {
406                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
407                             cThreshold )
408                         {
409                             pWriteAcc->SetPixel( nY, nX, aWhite );
410                         }
411                         else
412                             pWriteAcc->SetPixel( nY, nX, aBlack );
413                     }
414                 }
415             }
416 
417             aNewBmp.ReleaseAccess( pWriteAcc );
418             bRet = sal_True;
419         }
420 
421         ReleaseAccess( pReadAcc );
422 
423         if( bRet )
424         {
425             const MapMode   aMap( maPrefMapMode );
426             const Size      aSize( maPrefSize );
427 
428             *this = aNewBmp;
429 
430             maPrefMapMode = aMap;
431             maPrefSize = aSize;
432         }
433     }
434 
435     return bRet;
436 }
437 
438 // ------------------------------------------------------------------------
439 
440 sal_Bool Bitmap::ImplMakeMonoDither()
441 {
442     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
443     sal_Bool                bRet = sal_False;
444 
445     if( pReadAcc )
446     {
447         Bitmap              aNewBmp( GetSizePixel(), 1 );
448         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
449 
450         if( pWriteAcc )
451         {
452             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
453             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
454             const long          nWidth = pWriteAcc->Width();
455             const long          nHeight = pWriteAcc->Height();
456             sal_uInt8               pDitherMatrix[ 16 ][ 16 ];
457 
458             ImplCreateDitherMatrix( &pDitherMatrix );
459 
460             if( pReadAcc->HasPalette() )
461             {
462                 for( long nY = 0L; nY < nHeight; nY++ )
463                 {
464                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
465                     {
466                         if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >
467                             pDitherMatrix[ nModY ][ nX % 16 ] )
468                         {
469                             pWriteAcc->SetPixel( nY, nX, aWhite );
470                         }
471                         else
472                             pWriteAcc->SetPixel( nY, nX, aBlack );
473                     }
474                 }
475             }
476             else
477             {
478                 for( long nY = 0L; nY < nHeight; nY++ )
479                 {
480                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
481                     {
482                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
483                             pDitherMatrix[ nModY ][ nX % 16 ]  )
484                         {
485                             pWriteAcc->SetPixel( nY, nX, aWhite );
486                         }
487                         else
488                             pWriteAcc->SetPixel( nY, nX, aBlack );
489                     }
490                 }
491             }
492 
493             aNewBmp.ReleaseAccess( pWriteAcc );
494             bRet = sal_True;
495         }
496 
497         ReleaseAccess( pReadAcc );
498 
499         if( bRet )
500         {
501             const MapMode   aMap( maPrefMapMode );
502             const Size      aSize( maPrefSize );
503 
504             *this = aNewBmp;
505 
506             maPrefMapMode = aMap;
507             maPrefSize = aSize;
508         }
509     }
510 
511     return bRet;
512 }
513 
514 // ------------------------------------------------------------------------
515 
516 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
517 {
518     DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
519 
520     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
521     sal_Bool                bRet = sal_False;
522 
523     if( pReadAcc )
524     {
525         const BitmapPalette&    rPal = GetGreyPalette( nGreys );
526         sal_uLong                   nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
527         sal_Bool                    bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
528 
529         if( !bPalDiffers )
530             bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
531 
532         if( bPalDiffers )
533         {
534             Bitmap              aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
535             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
536 
537             if( pWriteAcc )
538             {
539                 const long  nWidth = pWriteAcc->Width();
540                 const long  nHeight = pWriteAcc->Height();
541 
542                 if( pReadAcc->HasPalette() )
543                 {
544                     for( long nY = 0L; nY < nHeight; nY++ )
545                     {
546                         for( long nX = 0L; nX < nWidth; nX++ )
547                         {
548                             pWriteAcc->SetPixel( nY, nX,
549                                 (sal_uInt8) ( pReadAcc->GetPaletteColor(
550                                     pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) );
551                         }
552                     }
553                 }
554                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
555                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
556                 {
557                     nShift += 8;
558 
559                     for( long nY = 0L; nY < nHeight; nY++ )
560                     {
561                         Scanline pReadScan = pReadAcc->GetScanline( nY );
562                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
563 
564                         for( long nX = 0L; nX < nWidth; nX++ )
565                         {
566                             const sal_uLong nB = *pReadScan++;
567                             const sal_uLong nG = *pReadScan++;
568                             const sal_uLong nR = *pReadScan++;
569 
570                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
571                         }
572                     }
573                 }
574                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
575                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
576                 {
577                     nShift += 8;
578 
579                     for( long nY = 0L; nY < nHeight; nY++ )
580                     {
581                         Scanline pReadScan = pReadAcc->GetScanline( nY );
582                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
583 
584                         for( long nX = 0L; nX < nWidth; nX++ )
585                         {
586                             const sal_uLong nR = *pReadScan++;
587                             const sal_uLong nG = *pReadScan++;
588                             const sal_uLong nB = *pReadScan++;
589 
590                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
591                         }
592                     }
593                 }
594                 else
595                 {
596                     for( long nY = 0L; nY < nHeight; nY++ )
597                         for( long nX = 0L; nX < nWidth; nX++ )
598                             pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) );
599                 }
600 
601                 aNewBmp.ReleaseAccess( pWriteAcc );
602                 bRet = sal_True;
603             }
604 
605             ReleaseAccess( pReadAcc );
606 
607             if( bRet )
608             {
609                 const MapMode   aMap( maPrefMapMode );
610                 const Size      aSize( maPrefSize );
611 
612                 *this = aNewBmp;
613 
614                 maPrefMapMode = aMap;
615                 maPrefSize = aSize;
616             }
617         }
618         else
619         {
620             ReleaseAccess( pReadAcc );
621             bRet = sal_True;
622         }
623     }
624 
625     return bRet;
626 }
627 
628 // ------------------------------------------------------------------------
629 
630 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
631 {
632     DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
633 
634     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
635     sal_Bool                bRet = sal_False;
636 
637     if( pReadAcc )
638     {
639         BitmapPalette       aPal;
640         Bitmap              aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
641         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
642 
643         if( pWriteAcc )
644         {
645             const long  nWidth = pWriteAcc->Width();
646             const long  nHeight = pWriteAcc->Height();
647 
648             if( pWriteAcc->HasPalette() )
649             {
650                 const sal_uInt16            nOldCount = 1 << GetBitCount();
651                 const BitmapPalette&    rOldPal = pReadAcc->GetPalette();
652 
653                 aPal.SetEntryCount( 1 << nBitCount );
654 
655                 for( sal_uInt16 i = 0; i < nOldCount; i++ )
656                     aPal[ i ] = rOldPal[ i ];
657 
658                 if( pExtColor )
659                     aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
660 
661                 pWriteAcc->SetPalette( aPal );
662 
663                 for( long nY = 0L; nY < nHeight; nY++ )
664                     for( long nX = 0L; nX < nWidth; nX++ )
665                         pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
666             }
667             else
668             {
669                 if( pReadAcc->HasPalette() )
670                 {
671                     for( long nY = 0L; nY < nHeight; nY++ )
672                         for( long nX = 0L; nX < nWidth; nX++ )
673                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
674                 }
675                 else
676                 {
677                     for( long nY = 0L; nY < nHeight; nY++ )
678                         for( long nX = 0L; nX < nWidth; nX++ )
679                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
680                 }
681             }
682 
683             aNewBmp.ReleaseAccess( pWriteAcc );
684             bRet = sal_True;
685         }
686 
687         ReleaseAccess( pReadAcc );
688 
689         if( bRet )
690         {
691             const MapMode   aMap( maPrefMapMode );
692             const Size      aSize( maPrefSize );
693 
694             *this = aNewBmp;
695 
696             maPrefMapMode = aMap;
697             maPrefSize = aSize;
698         }
699     }
700 
701     return bRet;
702 }
703 
704 // ------------------------------------------------------------------------
705 
706 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
707 {
708     DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
709 
710     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
711     sal_Bool                bRet = sal_False;
712 
713     if( pReadAcc )
714     {
715         BitmapPalette       aPal;
716         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aPal );
717         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
718 
719         if( pWriteAcc )
720         {
721             const sal_uInt16    nCount = 1 << nBitCount;
722             const long      nWidth = pWriteAcc->Width();
723             const long      nWidth1 = nWidth - 1L;
724             const long      nHeight = pWriteAcc->Height();
725             Octree          aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
726             InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
727             BitmapColor     aColor;
728             ImpErrorQuad    aErrQuad;
729             ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
730             ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
731             ImpErrorQuad*   pQLine1 = pErrQuad1;
732             ImpErrorQuad*   pQLine2 = 0;
733             long            nX, nY;
734             long            nYTmp = 0L;
735             sal_uInt8           cIndex;
736             sal_Bool            bQ1 = sal_True;
737 
738             if( pExtColor )
739             {
740                 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
741                 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
742             }
743 
744             // set Black/White always, if we have enough space
745             if( aPal.GetEntryCount() < ( nCount - 1 ) )
746             {
747                 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
748                 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
749                 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
750             }
751 
752             pWriteAcc->SetPalette( aPal );
753 
754             for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
755             {
756                 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
757                 {
758                     if( pReadAcc->HasPalette() )
759                         pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
760                     else
761                         pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
762                 }
763             }
764 
765             for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
766             {
767                 // erstes ZeilenPixel
768                 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
769                 pWriteAcc->SetPixel( nY, 0, cIndex );
770 
771                 for( nX = 1L; nX < nWidth1; nX++ )
772                 {
773                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
774                     aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
775                     pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
776                     pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
777                     pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
778                     pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
779                     pWriteAcc->SetPixel( nY, nX, cIndex );
780                 }
781 
782                 // letztes ZeilenPixel
783                 if( nX < nWidth )
784                 {
785                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
786                     pWriteAcc->SetPixel( nY, nX, cIndex );
787                 }
788 
789                 // Zeilenpuffer neu fuellen/kopieren
790                 pQLine1 = pQLine2;
791                 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
792 
793                 if( nYTmp < nHeight )
794                 {
795                     for( nX = 0L; nX < nWidth; nX++ )
796                     {
797                         if( pReadAcc->HasPalette() )
798                                 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
799                         else
800                             pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
801                     }
802                 }
803             }
804 
805             // Zeilenpuffer zerstoeren
806             delete[] pErrQuad1;
807             delete[] pErrQuad2;
808 
809             aNewBmp.ReleaseAccess( pWriteAcc );
810             bRet = sal_True;
811         }
812 
813         ReleaseAccess( pReadAcc );
814 
815         if( bRet )
816         {
817             const MapMode   aMap( maPrefMapMode );
818             const Size      aSize( maPrefSize );
819 
820             *this = aNewBmp;
821 
822             maPrefMapMode = aMap;
823             maPrefSize = aSize;
824         }
825     }
826 
827     return bRet;
828 }
829 
830 // ------------------------------------------------------------------------
831 
832 sal_Bool Bitmap::ImplConvertGhosted()
833 {
834     Bitmap              aNewBmp;
835     BitmapReadAccess*   pR = AcquireReadAccess();
836     sal_Bool                bRet = sal_False;
837 
838     if( pR )
839     {
840         if( pR->HasPalette() )
841         {
842             BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
843 
844             for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
845             {
846                 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
847                 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
848                                                      ( rOld.GetGreen() >> 1 ) | 0x80,
849                                                      ( rOld.GetBlue() >> 1 ) | 0x80 );
850             }
851 
852             aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
853             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
854 
855             if( pW )
856             {
857                 pW->CopyBuffer( *pR );
858                 aNewBmp.ReleaseAccess( pW );
859                 bRet = sal_True;
860             }
861         }
862         else
863         {
864             aNewBmp = Bitmap( GetSizePixel(), 24 );
865 
866             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
867 
868             if( pW )
869             {
870                 const long nWidth = pR->Width(), nHeight = pR->Height();
871 
872                 for( long nY = 0; nY < nHeight; nY++ )
873                 {
874                     for( long nX = 0; nX < nWidth; nX++ )
875                     {
876                         const BitmapColor aOld( pR->GetPixel( nY, nX ) );
877                         pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
878                                                            ( aOld.GetGreen() >> 1 ) | 0x80,
879                                                            ( aOld.GetBlue() >> 1 ) | 0x80 ) );
880 
881                     }
882                 }
883 
884                 aNewBmp.ReleaseAccess( pW );
885                 bRet = sal_True;
886             }
887         }
888 
889         ReleaseAccess( pR );
890     }
891 
892     if( bRet )
893     {
894         const MapMode   aMap( maPrefMapMode );
895         const Size      aSize( maPrefSize );
896 
897         *this = aNewBmp;
898 
899         maPrefMapMode = aMap;
900         maPrefSize = aSize;
901     }
902 
903     return bRet;
904 }
905 
906 // ------------------------------------------------------------------------
907 
908 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
909 {
910     sal_Bool bRet;
911 
912     if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
913     {
914         if( BMP_SCALE_FAST == nScaleFlag )
915             bRet = ImplScaleFast( rScaleX, rScaleY );
916         else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
917             bRet = ImplScaleInterpolate( rScaleX, rScaleY );
918         else
919             bRet = sal_False;
920     }
921     else
922         bRet = sal_True;
923 
924     return bRet;
925 }
926 
927 // ------------------------------------------------------------------------
928 
929 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
930 {
931     const Size  aSize( GetSizePixel() );
932     sal_Bool        bRet;
933 
934     if( aSize.Width() && aSize.Height() )
935     {
936         bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
937                       (double) rNewSize.Height() / aSize.Height(),
938                       nScaleFlag );
939     }
940     else
941         bRet = sal_True;
942 
943     return bRet;
944 }
945 
946 // ------------------------------------------------------------------------
947 
948 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
949 {
950     const Size  aSizePix( GetSizePixel() );
951     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
952     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
953     sal_Bool        bRet = sal_False;
954 
955     if( nNewWidth && nNewHeight )
956     {
957         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
958         Bitmap              aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
959         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
960 
961         if( pReadAcc && pWriteAcc )
962         {
963             const long  nScanlineSize = pWriteAcc->GetScanlineSize();
964             const long  nNewWidth1 = nNewWidth - 1L;
965             const long  nNewHeight1 = nNewHeight - 1L;
966             const long  nWidth = pReadAcc->Width();
967             const long  nHeight = pReadAcc->Height();
968             long*       pLutX = new long[ nNewWidth ];
969             long*       pLutY = new long[ nNewHeight ];
970             long        nX, nY, nMapY, nActY = 0L;
971 
972             if( nNewWidth1 && nNewHeight1 )
973             {
974                 for( nX = 0L; nX < nNewWidth; nX++ )
975                     pLutX[ nX ] = nX * nWidth / nNewWidth;
976 
977                 for( nY = 0L; nY < nNewHeight; nY++ )
978                     pLutY[ nY ] = nY * nHeight / nNewHeight;
979 
980                 while( nActY < nNewHeight )
981                 {
982                     nMapY = pLutY[ nActY ];
983 
984                     for( nX = 0L; nX < nNewWidth; nX++ )
985                         pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
986 
987                     while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
988                     {
989                         memcpy( pWriteAcc->GetScanline( nActY + 1L ),
990                                  pWriteAcc->GetScanline( nActY ), nScanlineSize );
991                         nActY++;
992                     }
993 
994                     nActY++;
995                 }
996 
997                 bRet = sal_True;
998             }
999 
1000             delete[] pLutX;
1001             delete[] pLutY;
1002         }
1003 
1004         ReleaseAccess( pReadAcc );
1005         aNewBmp.ReleaseAccess( pWriteAcc );
1006 
1007         if( bRet )
1008             ImplAssignWithSize( aNewBmp );
1009     }
1010 
1011     return bRet;
1012 }
1013 
1014 // ------------------------------------------------------------------------
1015 
1016 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1017 {
1018     const Size  aSizePix( GetSizePixel() );
1019     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1020     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1021     sal_Bool        bRet = sal_False;
1022 
1023     if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1024     {
1025         BitmapColor         aCol0;
1026         BitmapColor         aCol1;
1027         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1028         long                nWidth = pReadAcc->Width();
1029         long                nHeight = pReadAcc->Height();
1030         Bitmap              aNewBmp( Size( nNewWidth, nHeight ), 24 );
1031         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1032         long*               pLutInt;
1033         long*               pLutFrac;
1034         long                nX, nY;
1035         long                lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1036         double              fTemp;
1037         long                nTemp;
1038 
1039         if( pReadAcc && pWriteAcc )
1040         {
1041             const long      nNewWidth1 = nNewWidth - 1L;
1042             const long      nWidth1 = pReadAcc->Width() - 1L;
1043             const double    fRevScaleX = (double) nWidth1 / nNewWidth1;
1044 
1045             pLutInt = new long[ nNewWidth ];
1046             pLutFrac = new long[ nNewWidth ];
1047 
1048             for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1049             {
1050                 fTemp = nX * fRevScaleX;
1051                 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1052                 fTemp -= pLutInt[ nX ];
1053                 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1054             }
1055 
1056             if( pReadAcc->HasPalette() )
1057             {
1058                 for( nY = 0L; nY < nHeight; nY++ )
1059                 {
1060                     if( 1 == nWidth )
1061                     {
1062                         aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
1063 
1064                         for( nX = 0L; nX < nNewWidth; nX++ )
1065                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1066                     }
1067                     else
1068                     {
1069                         for( nX = 0L; nX < nNewWidth; nX++ )
1070                         {
1071                             nTemp = pLutInt[ nX ];
1072 
1073                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
1074                             aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
1075 
1076                             nTemp = pLutFrac[ nX ];
1077 
1078                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1079                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1080                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1081 
1082                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1083                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1084                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1085 
1086                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1087                         }
1088                     }
1089                 }
1090             }
1091             else
1092             {
1093                 for( nY = 0L; nY < nHeight; nY++ )
1094                 {
1095                     if( 1 == nWidth )
1096                     {
1097                         aCol0 = pReadAcc->GetPixel( nY, 0 );
1098 
1099                         for( nX = 0L; nX < nNewWidth; nX++ )
1100                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1101                     }
1102                     else
1103                     {
1104                         for( nX = 0L; nX < nNewWidth; nX++ )
1105                         {
1106                             nTemp = pLutInt[ nX ];
1107 
1108                             aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1109                             aCol1 = pReadAcc->GetPixel( nY, nTemp );
1110 
1111                             nTemp = pLutFrac[ nX ];
1112 
1113                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1114                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1115                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1116 
1117                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1118                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1119                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1120 
1121                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1122                         }
1123                     }
1124                 }
1125             }
1126 
1127             delete[] pLutInt;
1128             delete[] pLutFrac;
1129             bRet = sal_True;
1130         }
1131 
1132         ReleaseAccess( pReadAcc );
1133         aNewBmp.ReleaseAccess( pWriteAcc );
1134 
1135         if( bRet )
1136         {
1137             bRet = sal_False;
1138             ImplAssignWithSize( aNewBmp );
1139             pReadAcc = AcquireReadAccess();
1140             aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1141             pWriteAcc = aNewBmp.AcquireWriteAccess();
1142 
1143             if( pReadAcc && pWriteAcc )
1144             {
1145                 const long      nNewHeight1 = nNewHeight - 1L;
1146                 const long      nHeight1 = pReadAcc->Height() - 1L;
1147                 const double    fRevScaleY = (double) nHeight1 / nNewHeight1;
1148 
1149                 pLutInt = new long[ nNewHeight ];
1150                 pLutFrac = new long[ nNewHeight ];
1151 
1152                 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1153                 {
1154                     fTemp = nY * fRevScaleY;
1155                     pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1156                     fTemp -= pLutInt[ nY ];
1157                     pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1158                 }
1159 
1160                 if( pReadAcc->HasPalette() )
1161                 {
1162                     for( nX = 0L; nX < nNewWidth; nX++ )
1163                     {
1164                         if( 1 == nHeight )
1165                         {
1166                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
1167 
1168                             for( nY = 0L; nY < nNewHeight; nY++ )
1169                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1170                         }
1171                         else
1172                         {
1173                             for( nY = 0L; nY < nNewHeight; nY++ )
1174                             {
1175                                 nTemp = pLutInt[ nY ];
1176 
1177                                 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
1178                                 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
1179 
1180                                 nTemp = pLutFrac[ nY ];
1181 
1182                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1183                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1184                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1185 
1186                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1187                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1188                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1189 
1190                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1191                             }
1192                         }
1193                     }
1194                 }
1195                 else
1196                 {
1197                     for( nX = 0L; nX < nNewWidth; nX++ )
1198                     {
1199                         if( 1 == nHeight )
1200                         {
1201                             aCol0 = pReadAcc->GetPixel( 0, nX );
1202 
1203                             for( nY = 0L; nY < nNewHeight; nY++ )
1204                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1205                         }
1206                         else
1207                         {
1208                             for( nY = 0L; nY < nNewHeight; nY++ )
1209                             {
1210                                 nTemp = pLutInt[ nY ];
1211 
1212                                 aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1213                                 aCol1 = pReadAcc->GetPixel( nTemp, nX );
1214 
1215                                 nTemp = pLutFrac[ nY ];
1216 
1217                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1218                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1219                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1220 
1221                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1222                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1223                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1224 
1225                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1226                             }
1227                         }
1228                     }
1229                 }
1230 
1231                 delete[] pLutInt;
1232                 delete[] pLutFrac;
1233                 bRet = sal_True;
1234             }
1235 
1236             ReleaseAccess( pReadAcc );
1237             aNewBmp.ReleaseAccess( pWriteAcc );
1238 
1239             if( bRet )
1240                 ImplAssignWithSize( aNewBmp );
1241         }
1242     }
1243 
1244     if( !bRet )
1245         bRet = ImplScaleFast( rScaleX, rScaleY );
1246 
1247     return bRet;
1248 }
1249 
1250 // ------------------------------------------------------------------------
1251 
1252 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1253 {
1254     sal_Bool bRet = sal_False;
1255 
1256     const Size aSizePix( GetSizePixel() );
1257 
1258     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1259         bRet = sal_True;
1260     else if( nDitherFlags & BMP_DITHER_MATRIX )
1261         bRet = ImplDitherMatrix();
1262     else if( nDitherFlags & BMP_DITHER_FLOYD )
1263         bRet = ImplDitherFloyd();
1264     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1265         bRet = ImplDitherFloyd16();
1266 
1267     return bRet;
1268 }
1269 
1270 // ------------------------------------------------------------------------
1271 
1272 sal_Bool Bitmap::ImplDitherMatrix()
1273 {
1274     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1275     Bitmap              aNewBmp( GetSizePixel(), 8 );
1276     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1277     sal_Bool                bRet = sal_False;
1278 
1279     if( pReadAcc && pWriteAcc )
1280     {
1281         const sal_uLong nWidth = pReadAcc->Width();
1282         const sal_uLong nHeight = pReadAcc->Height();
1283         BitmapColor aIndex( (sal_uInt8) 0 );
1284 
1285         if( pReadAcc->HasPalette() )
1286         {
1287             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1288             {
1289                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1290                 {
1291                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
1292                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1293                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1294                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1295                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1296 
1297                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1298                     pWriteAcc->SetPixel( nY, nX, aIndex );
1299                 }
1300             }
1301         }
1302         else
1303         {
1304             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1305             {
1306                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1307                 {
1308                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
1309                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1310                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1311                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1312                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1313 
1314                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1315                     pWriteAcc->SetPixel( nY, nX, aIndex );
1316                 }
1317             }
1318         }
1319 
1320         bRet = sal_True;
1321     }
1322 
1323     ReleaseAccess( pReadAcc );
1324     aNewBmp.ReleaseAccess( pWriteAcc );
1325 
1326     if( bRet )
1327     {
1328         const MapMode   aMap( maPrefMapMode );
1329         const Size      aSize( maPrefSize );
1330 
1331         *this = aNewBmp;
1332 
1333         maPrefMapMode = aMap;
1334         maPrefSize = aSize;
1335     }
1336 
1337     return bRet;
1338 }
1339 
1340 // ------------------------------------------------------------------------
1341 
1342 sal_Bool Bitmap::ImplDitherFloyd()
1343 {
1344     const Size  aSize( GetSizePixel() );
1345     sal_Bool        bRet = sal_False;
1346 
1347     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1348     {
1349         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1350         Bitmap              aNewBmp( GetSizePixel(), 8 );
1351         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1352 
1353         if( pReadAcc && pWriteAcc )
1354         {
1355             BitmapColor aColor;
1356             long        nWidth = pReadAcc->Width();
1357             long        nWidth1 = nWidth - 1L;
1358             long        nHeight = pReadAcc->Height();
1359             long        nX;
1360             long        nW = nWidth * 3L;
1361             long        nW2 = nW - 3L;
1362             long        nRErr, nGErr, nBErr;
1363             long        nRC, nGC, nBC;
1364             long        nTemp;
1365             long        nZ;
1366             long*       p1 = new long[ nW ];
1367             long*       p2 = new long[ nW ];
1368             long*       p1T = p1;
1369             long*       p2T = p2;
1370             long*       pTmp;
1371             sal_Bool        bPal = pReadAcc->HasPalette();
1372 
1373             pTmp = p2T;
1374 
1375             if( bPal )
1376             {
1377                 for( nZ = 0; nZ < nWidth; nZ++ )
1378                 {
1379                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
1380 
1381                     *pTmp++ = (long) aColor.GetBlue() << 12;
1382                     *pTmp++ = (long) aColor.GetGreen() << 12;
1383                     *pTmp++ = (long) aColor.GetRed() << 12;
1384                 }
1385             }
1386             else
1387             {
1388                 for( nZ = 0; nZ < nWidth; nZ++ )
1389                 {
1390                     aColor = pReadAcc->GetPixel( 0, nZ );
1391 
1392                     *pTmp++ = (long) aColor.GetBlue() << 12;
1393                     *pTmp++ = (long) aColor.GetGreen() << 12;
1394                     *pTmp++ = (long) aColor.GetRed() << 12;
1395                 }
1396             }
1397 
1398             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1399             {
1400                 pTmp = p1T;
1401                 p1T = p2T;
1402                 p2T = pTmp;
1403 
1404                 if( nY < nHeight )
1405                 {
1406                     if( bPal )
1407                     {
1408                         for( nZ = 0; nZ < nWidth; nZ++ )
1409                         {
1410                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
1411 
1412                             *pTmp++ = (long) aColor.GetBlue() << 12;
1413                             *pTmp++ = (long) aColor.GetGreen() << 12;
1414                             *pTmp++ = (long) aColor.GetRed() << 12;
1415                         }
1416                     }
1417                     else
1418                     {
1419                         for( nZ = 0; nZ < nWidth; nZ++ )
1420                         {
1421                             aColor = pReadAcc->GetPixel( nY, nZ );
1422 
1423                             *pTmp++ = (long) aColor.GetBlue() << 12;
1424                             *pTmp++ = (long) aColor.GetGreen() << 12;
1425                             *pTmp++ = (long) aColor.GetRed() << 12;
1426                         }
1427                     }
1428                 }
1429 
1430                 // erstes Pixel gesondert betrachten
1431                 nX = 0;
1432                 CALC_ERRORS;
1433                 CALC_TABLES7;
1434                 nX -= 5;
1435                 CALC_TABLES5;
1436                 pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1437 
1438                 // mittlere Pixel ueber Schleife
1439                 long nXAcc;
1440                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1441                 {
1442                     CALC_ERRORS;
1443                     CALC_TABLES7;
1444                     nX -= 8;
1445                     CALC_TABLES3;
1446                     CALC_TABLES5;
1447                     pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1448                 }
1449 
1450                 // letztes Pixel gesondert betrachten
1451                 CALC_ERRORS;
1452                 nX -= 5;
1453                 CALC_TABLES3;
1454                 CALC_TABLES5;
1455                 pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1456             }
1457 
1458             delete[] p1;
1459             delete[] p2;
1460             bRet = sal_True;
1461         }
1462 
1463         ReleaseAccess( pReadAcc );
1464         aNewBmp.ReleaseAccess( pWriteAcc );
1465 
1466         if( bRet )
1467         {
1468             const MapMode   aMap( maPrefMapMode );
1469             const Size      aPrefSize( maPrefSize );
1470 
1471             *this = aNewBmp;
1472 
1473             maPrefMapMode = aMap;
1474             maPrefSize = aPrefSize;
1475         }
1476     }
1477 
1478     return bRet;
1479 }
1480 
1481 // ------------------------------------------------------------------------
1482 
1483 sal_Bool Bitmap::ImplDitherFloyd16()
1484 {
1485     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1486     Bitmap              aNewBmp( GetSizePixel(), 24 );
1487     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1488     sal_Bool                bRet = sal_False;
1489 
1490     if( pReadAcc && pWriteAcc )
1491     {
1492         const long      nWidth = pWriteAcc->Width();
1493         const long      nWidth1 = nWidth - 1L;
1494         const long      nHeight = pWriteAcc->Height();
1495         BitmapColor     aColor;
1496         BitmapColor     aBestCol;
1497         ImpErrorQuad    aErrQuad;
1498         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
1499         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
1500         ImpErrorQuad*   pQLine1 = pErrQuad1;
1501         ImpErrorQuad*   pQLine2 = 0;
1502         long            nX, nY;
1503         long            nYTmp = 0L;
1504         sal_Bool            bQ1 = sal_True;
1505 
1506         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1507             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1508                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1509 
1510         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1511         {
1512             // erstes ZeilenPixel
1513             aBestCol = pQLine1[ 0 ].ImplGetColor();
1514             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1515             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1516             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1517             pWriteAcc->SetPixel( nY, 0, aBestCol );
1518 
1519             for( nX = 1L; nX < nWidth1; nX++ )
1520             {
1521                 aColor = pQLine1[ nX ].ImplGetColor();
1522                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1523                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1524                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1525                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1526                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1527                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1528                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1529                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1530                 pWriteAcc->SetPixel( nY, nX, aBestCol );
1531             }
1532 
1533             // letztes ZeilenPixel
1534             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1535             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1536             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1537             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1538             pWriteAcc->SetPixel( nY, nX, aBestCol );
1539 
1540             // Zeilenpuffer neu fuellen/kopieren
1541             pQLine1 = pQLine2;
1542             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1543 
1544             if( nYTmp < nHeight )
1545                 for( nX = 0L; nX < nWidth; nX++ )
1546                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1547         }
1548 
1549         // Zeilenpuffer zerstoeren
1550         delete[] pErrQuad1;
1551         delete[] pErrQuad2;
1552         bRet = sal_True;
1553     }
1554 
1555     ReleaseAccess( pReadAcc );
1556     aNewBmp.ReleaseAccess( pWriteAcc );
1557 
1558     if( bRet )
1559     {
1560         const MapMode   aMap( maPrefMapMode );
1561         const Size      aSize( maPrefSize );
1562 
1563         *this = aNewBmp;
1564 
1565         maPrefMapMode = aMap;
1566         maPrefSize = aSize;
1567     }
1568 
1569     return bRet;
1570 }
1571 
1572 // ------------------------------------------------------------------------
1573 
1574 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1575 {
1576     sal_Bool bRet;
1577 
1578     if( GetColorCount() <= (sal_uLong) nColorCount )
1579         bRet = sal_True;
1580     else if( nColorCount )
1581     {
1582         if( BMP_REDUCE_SIMPLE == eReduce )
1583             bRet = ImplReduceSimple( nColorCount );
1584         else if( BMP_REDUCE_POPULAR == eReduce )
1585             bRet = ImplReducePopular( nColorCount );
1586         else
1587             bRet = ImplReduceMedian( nColorCount );
1588     }
1589     else
1590         bRet = sal_False;
1591 
1592     return bRet;
1593 }
1594 
1595 // ------------------------------------------------------------------------
1596 
1597 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1598 {
1599     Bitmap              aNewBmp;
1600     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1601     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
1602     sal_uInt16              nBitCount;
1603     sal_Bool                bRet = sal_False;
1604 
1605     if( nColCount <= 2 )
1606         nBitCount = 1;
1607     else if( nColCount <= 16 )
1608         nBitCount = 4;
1609     else
1610         nBitCount = 8;
1611 
1612     if( pRAcc )
1613     {
1614         Octree                  aOct( *pRAcc, nColCount );
1615         const BitmapPalette&    rPal = aOct.GetPalette();
1616         BitmapWriteAccess*      pWAcc;
1617 
1618         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1619         pWAcc = aNewBmp.AcquireWriteAccess();
1620 
1621         if( pWAcc )
1622         {
1623             const long nWidth = pRAcc->Width();
1624             const long nHeight = pRAcc->Height();
1625 
1626             if( pRAcc->HasPalette() )
1627             {
1628                 for( long nY = 0L; nY < nHeight; nY++ )
1629                     for( long nX =0L; nX < nWidth; nX++ )
1630                         pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
1631             }
1632             else
1633             {
1634                 for( long nY = 0L; nY < nHeight; nY++ )
1635                     for( long nX =0L; nX < nWidth; nX++ )
1636                         pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
1637             }
1638 
1639             aNewBmp.ReleaseAccess( pWAcc );
1640             bRet = sal_True;
1641         }
1642 
1643         ReleaseAccess( pRAcc );
1644     }
1645 
1646     if( bRet )
1647     {
1648         const MapMode   aMap( maPrefMapMode );
1649         const Size      aSize( maPrefSize );
1650 
1651         *this = aNewBmp;
1652         maPrefMapMode = aMap;
1653         maPrefSize = aSize;
1654     }
1655 
1656     return bRet;
1657 }
1658 
1659 // ------------------------------------------------------------------------
1660 
1661 struct PopularColorCount
1662 {
1663     sal_uInt32  mnIndex;
1664     sal_uInt32  mnCount;
1665 };
1666 
1667 // ------------------------------------------------------------------------
1668 
1669 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1670 {
1671     int nRet;
1672 
1673     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1674         nRet = 1;
1675     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1676         nRet = 0;
1677     else
1678         nRet = -1;
1679 
1680     return nRet;
1681 }
1682 
1683 // ------------------------------------------------------------------------
1684 
1685 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1686 {
1687     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1688     sal_uInt16              nBitCount;
1689     sal_Bool                bRet = sal_False;
1690 
1691     if( nColCount > 256 )
1692         nColCount = 256;
1693 
1694     if( nColCount < 17 )
1695         nBitCount = 4;
1696     else
1697         nBitCount = 8;
1698 
1699     if( pRAcc )
1700     {
1701         const sal_uInt32    nValidBits = 4;
1702         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
1703         const sal_uInt32    nLeftShiftBits1 = nValidBits;
1704         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
1705         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
1706         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
1707         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1708         const long          nWidth = pRAcc->Width();
1709         const long          nHeight = pRAcc->Height();
1710         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
1711         long                nX, nY, nR, nG, nB, nIndex;
1712 
1713         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1714 
1715         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1716         {
1717             for( nG = 0; nG < 256; nG += nColorOffset )
1718             {
1719                 for( nB = 0; nB < 256; nB += nColorOffset )
1720                 {
1721                     pCountTable[ nIndex ].mnIndex = nIndex;
1722                     nIndex++;
1723                 }
1724             }
1725         }
1726 
1727         if( pRAcc->HasPalette() )
1728         {
1729             for( nY = 0L; nY < nHeight; nY++ )
1730             {
1731                 for( nX = 0L; nX < nWidth; nX++ )
1732                 {
1733                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1734                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1735                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1736                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1737                 }
1738             }
1739         }
1740         else
1741         {
1742             for( nY = 0L; nY < nHeight; nY++ )
1743             {
1744                 for( nX = 0L; nX < nWidth; nX++ )
1745                 {
1746                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1747                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1748                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1749                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1750                 }
1751             }
1752         }
1753 
1754         BitmapPalette aNewPal( nColCount );
1755 
1756         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1757 
1758         for( sal_uInt16 n = 0; n < nColCount; n++ )
1759         {
1760             const PopularColorCount& rPop = pCountTable[ n ];
1761             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1762                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1763                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1764         }
1765 
1766         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1767         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1768 
1769         if( pWAcc )
1770         {
1771             BitmapColor aDstCol( (sal_uInt8) 0 );
1772             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
1773 
1774             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1775                 for( nG = 0; nG < 256; nG += nColorOffset )
1776                     for( nB = 0; nB < 256; nB += nColorOffset )
1777                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1778 
1779             if( pRAcc->HasPalette() )
1780             {
1781                 for( nY = 0L; nY < nHeight; nY++ )
1782                 {
1783                     for( nX = 0L; nX < nWidth; nX++ )
1784                     {
1785                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1786                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1787                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1788                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1789                         pWAcc->SetPixel( nY, nX, aDstCol );
1790                     }
1791                 }
1792             }
1793             else
1794             {
1795                 for( nY = 0L; nY < nHeight; nY++ )
1796                 {
1797                     for( nX = 0L; nX < nWidth; nX++ )
1798                     {
1799                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1800                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1801                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1802                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1803                         pWAcc->SetPixel( nY, nX, aDstCol );
1804                     }
1805                 }
1806             }
1807 
1808             delete[] pIndexMap;
1809             aNewBmp.ReleaseAccess( pWAcc );
1810             bRet = sal_True;
1811         }
1812 
1813         delete[] pCountTable;
1814         ReleaseAccess( pRAcc );
1815 
1816         if( bRet )
1817         {
1818             const MapMode   aMap( maPrefMapMode );
1819             const Size      aSize( maPrefSize );
1820 
1821             *this = aNewBmp;
1822             maPrefMapMode = aMap;
1823             maPrefSize = aSize;
1824         }
1825     }
1826 
1827     return bRet;
1828 }
1829 
1830 // ------------------------------------------------------------------------
1831 
1832 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1833 {
1834     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1835     sal_uInt16              nBitCount;
1836     sal_Bool                bRet = sal_False;
1837 
1838     if( nColCount < 17 )
1839         nBitCount = 4;
1840     else if( nColCount < 257 )
1841         nBitCount = 8;
1842     else
1843     {
1844         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1845         nBitCount = 8;
1846         nColCount = 256;
1847     }
1848 
1849     if( pRAcc )
1850     {
1851         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
1852         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1853 
1854         if( pWAcc )
1855         {
1856             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
1857             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1858             const long  nWidth = pWAcc->Width();
1859             const long  nHeight = pWAcc->Height();
1860             long        nIndex = 0L;
1861 
1862             memset( (HPBYTE) pColBuf, 0, nSize );
1863 
1864             // create Buffer
1865             if( pRAcc->HasPalette() )
1866             {
1867                 for( long nY = 0L; nY < nHeight; nY++ )
1868                 {
1869                     for( long nX = 0L; nX < nWidth; nX++ )
1870                     {
1871                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1872                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1873                     }
1874                 }
1875             }
1876             else
1877             {
1878                 for( long nY = 0L; nY < nHeight; nY++ )
1879                 {
1880                     for( long nX = 0L; nX < nWidth; nX++ )
1881                     {
1882                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1883                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1884                     }
1885                 }
1886             }
1887 
1888             // create palette via median cut
1889             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1890             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1891                            nColCount, nWidth * nHeight, nIndex );
1892 
1893             // do mapping of colors to palette
1894             InverseColorMap aMap( aPal );
1895             pWAcc->SetPalette( aPal );
1896             for( long nY = 0L; nY < nHeight; nY++ )
1897                 for( long nX = 0L; nX < nWidth; nX++ )
1898                     pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
1899 
1900             rtl_freeMemory( pColBuf );
1901             aNewBmp.ReleaseAccess( pWAcc );
1902             bRet = sal_True;
1903         }
1904 
1905         ReleaseAccess( pRAcc );
1906 
1907         if( bRet )
1908         {
1909             const MapMode   aMap( maPrefMapMode );
1910             const Size      aSize( maPrefSize );
1911 
1912             *this = aNewBmp;
1913             maPrefMapMode = aMap;
1914             maPrefSize = aSize;
1915         }
1916     }
1917 
1918     return bRet;
1919 }
1920 
1921 // ------------------------------------------------------------------------
1922 
1923 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1924                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1925                             long nColors, long nPixels, long& rIndex )
1926 {
1927     if( !nPixels )
1928         return;
1929 
1930     BitmapColor aCol;
1931     const long  nRLen = nR2 - nR1;
1932     const long  nGLen = nG2 - nG1;
1933     const long  nBLen = nB2 - nB1;
1934     long        nR, nG, nB;
1935     sal_uLong*      pBuf = pColBuf;
1936 
1937     if( !nRLen && !nGLen && !nBLen )
1938     {
1939         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1940         {
1941             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1942             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1943             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1944             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1945         }
1946     }
1947     else
1948     {
1949         if( 1 == nColors || 1 == nPixels )
1950         {
1951             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1952 
1953             for( nR = nR1; nR <= nR2; nR++ )
1954             {
1955                 for( nG = nG1; nG <= nG2; nG++ )
1956                 {
1957                     for( nB = nB1; nB <= nB2; nB++ )
1958                     {
1959                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1960 
1961                         if( nPixSum )
1962                         {
1963                             nRSum += nR * nPixSum;
1964                             nGSum += nG * nPixSum;
1965                             nBSum += nB * nPixSum;
1966                         }
1967                     }
1968                 }
1969             }
1970 
1971             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1972             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1973             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1974             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1975         }
1976         else
1977         {
1978             const long  nTest = ( nPixels >> 1 );
1979             long        nPixOld = 0;
1980             long        nPixNew = 0;
1981 
1982             if( nBLen > nGLen && nBLen > nRLen )
1983             {
1984                 nB = nB1 - 1;
1985 
1986                 while( nPixNew < nTest )
1987                 {
1988                     nB++, nPixOld = nPixNew;
1989                     for( nR = nR1; nR <= nR2; nR++ )
1990                         for( nG = nG1; nG <= nG2; nG++ )
1991                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1992                 }
1993 
1994                 if( nB < nB2 )
1995                 {
1996                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1997                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1998                 }
1999                 else
2000                 {
2001                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2002                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2003                 }
2004             }
2005             else if( nGLen > nRLen )
2006             {
2007                 nG = nG1 - 1;
2008 
2009                 while( nPixNew < nTest )
2010                 {
2011                     nG++, nPixOld = nPixNew;
2012                     for( nR = nR1; nR <= nR2; nR++ )
2013                         for( nB = nB1; nB <= nB2; nB++ )
2014                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2015                 }
2016 
2017                 if( nG < nG2 )
2018                 {
2019                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2020                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2021                 }
2022                 else
2023                 {
2024                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2025                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2026                 }
2027             }
2028             else
2029             {
2030                 nR = nR1 - 1;
2031 
2032                 while( nPixNew < nTest )
2033                 {
2034                     nR++, nPixOld = nPixNew;
2035                     for( nG = nG1; nG <= nG2; nG++ )
2036                         for( nB = nB1; nB <= nB2; nB++ )
2037                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2038                 }
2039 
2040                 if( nR < nR2 )
2041                 {
2042                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2043                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2044                 }
2045                 else
2046                 {
2047                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2048                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2049                 }
2050             }
2051         }
2052     }
2053 }
2054 
2055 // ------------------------------------------------------------------------
2056 
2057 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2058 {
2059     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2060 }
2061 
2062 // ------------------------------------------------------------------------
2063 
2064 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2065 {
2066     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2067 }
2068 
2069 // ------------------------------------------------------------------------
2070 
2071 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2072                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2073                      double fGamma, sal_Bool bInvert )
2074 {
2075     sal_Bool bRet = sal_False;
2076 
2077     // nothing to do => return quickly
2078     if( !nLuminancePercent && !nContrastPercent &&
2079         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2080         ( fGamma == 1.0 ) && !bInvert )
2081     {
2082         bRet = sal_True;
2083     }
2084     else
2085     {
2086         BitmapWriteAccess* pAcc = AcquireWriteAccess();
2087 
2088         if( pAcc )
2089         {
2090             BitmapColor     aCol;
2091             const long      nW = pAcc->Width();
2092             const long      nH = pAcc->Height();
2093             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
2094             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
2095             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
2096             long            nX, nY;
2097             double          fM, fROff, fGOff, fBOff, fOff;
2098 
2099             // calculate slope
2100             if( nContrastPercent >= 0 )
2101                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2102             else
2103                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2104 
2105             // total offset = luminance offset + contrast offset
2106             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2107 
2108             // channel offset = channel offset  + total offset
2109             fROff = nChannelRPercent * 2.55 + fOff;
2110             fGOff = nChannelGPercent * 2.55 + fOff;
2111             fBOff = nChannelBPercent * 2.55 + fOff;
2112 
2113             // calculate gamma value
2114             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2115             const sal_Bool bGamma = ( fGamma != 1.0 );
2116 
2117             // create mapping table
2118             for( nX = 0L; nX < 256L; nX++ )
2119             {
2120                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2121                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2122                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2123 
2124                 if( bGamma )
2125                 {
2126                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2127                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2128                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2129                 }
2130 
2131                 if( bInvert )
2132                 {
2133                     cMapR[ nX ] = ~cMapR[ nX ];
2134                     cMapG[ nX ] = ~cMapG[ nX ];
2135                     cMapB[ nX ] = ~cMapB[ nX ];
2136                 }
2137             }
2138 
2139             // do modifying
2140             if( pAcc->HasPalette() )
2141             {
2142                 BitmapColor aNewCol;
2143 
2144                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2145                 {
2146                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2147                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2148                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2149                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2150                     pAcc->SetPaletteColor( i, aNewCol );
2151                 }
2152             }
2153             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2154             {
2155                 for( nY = 0L; nY < nH; nY++ )
2156                 {
2157                     Scanline pScan = pAcc->GetScanline( nY );
2158 
2159                     for( nX = 0L; nX < nW; nX++ )
2160                     {
2161                         *pScan = cMapB[ *pScan ]; pScan++;
2162                         *pScan = cMapG[ *pScan ]; pScan++;
2163                         *pScan = cMapR[ *pScan ]; pScan++;
2164                     }
2165                 }
2166             }
2167             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2168             {
2169                 for( nY = 0L; nY < nH; nY++ )
2170                 {
2171                     Scanline pScan = pAcc->GetScanline( nY );
2172 
2173                     for( nX = 0L; nX < nW; nX++ )
2174                     {
2175                         *pScan = cMapR[ *pScan ]; pScan++;
2176                         *pScan = cMapG[ *pScan ]; pScan++;
2177                         *pScan = cMapB[ *pScan ]; pScan++;
2178                     }
2179                 }
2180             }
2181             else
2182             {
2183                 for( nY = 0L; nY < nH; nY++ )
2184                 {
2185                     for( nX = 0L; nX < nW; nX++ )
2186                     {
2187                         aCol = pAcc->GetPixel( nY, nX );
2188                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
2189                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2190                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2191                         pAcc->SetPixel( nY, nX, aCol );
2192                     }
2193                 }
2194             }
2195 
2196             delete[] cMapR;
2197             delete[] cMapG;
2198             delete[] cMapB;
2199             ReleaseAccess( pAcc );
2200             bRet = sal_True;
2201         }
2202     }
2203 
2204     return bRet;
2205 }
2206