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