xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision c28218850aee34164ef4a66cd6575ba1b72f7709)
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 #define MAP( cVal0, cVal1, nFrac )  ((sal_uInt8)((((long)(cVal0)<<7L)+nFrac*((long)(cVal1)-(cVal0)))>>7L))
44 
45 #define CALC_ERRORS                                                             \
46                         nTemp   = p1T[nX++] >> 12;                              \
47                         nBErr = MinMax( nTemp, 0, 255 );                        \
48                         nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
49                         nTemp   = p1T[nX++] >> 12;                              \
50                         nGErr = MinMax( nTemp, 0, 255 );                        \
51                         nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
52                         nTemp   = p1T[nX] >> 12;                                \
53                         nRErr = MinMax( nTemp, 0, 255 );                        \
54                         nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
55 
56 #define CALC_TABLES3                                        \
57                         p2T[nX++] += FloydError3[nBErr];    \
58                         p2T[nX++] += FloydError3[nGErr];    \
59                         p2T[nX++] += FloydError3[nRErr];
60 
61 #define CALC_TABLES5                                        \
62                         p2T[nX++] += FloydError5[nBErr];    \
63                         p2T[nX++] += FloydError5[nGErr];    \
64                         p2T[nX++] += FloydError5[nRErr];
65 
66 #define CALC_TABLES7                                        \
67                         p1T[++nX] += FloydError7[nBErr];    \
68                         p2T[nX++] += FloydError1[nBErr];    \
69                         p1T[nX] += FloydError7[nGErr];      \
70                         p2T[nX++] += FloydError1[nGErr];    \
71                         p1T[nX] += FloydError7[nRErr];      \
72                         p2T[nX] += FloydError1[nRErr];
73 
74 // -----------
75 // - Statics -
76 // -----------
77 
78 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
79 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
80 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
81 
82 // ------------------------------------------------------------------------
83 
84 sal_uLong nVCLDitherLut[ 256 ] =
85 {
86        0, 49152, 12288, 61440,  3072, 52224, 15360, 64512,   768, 49920, 13056,
87    62208,  3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
88    48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
89    57344,  4096, 53248, 11264, 60416,  7168, 56320,  8960, 58112,  4864, 54016,
90    12032, 61184,  7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
91    23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
92    14336, 63488,  1024, 50176, 13312, 62464,  2816, 51968, 15104, 64256,  1792,
93    50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
94    35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392,  6144,
95    55296,  9216, 58368,  5120, 54272, 11008, 60160,  6912, 56064,  9984, 59136,
96     5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
97    27392, 39680, 23296, 42752, 26368, 38656, 22272,   512, 49664, 12800, 61952,
98     3584, 52736, 15872, 65024,   256, 49408, 12544, 61696,  3328, 52480, 15616,
99    64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
100    45312, 28928, 36096, 19712, 48384, 32000,  8704, 57856,  4608, 53760, 11776,
101    60928,  7680, 56832,  8448, 57600,  4352, 53504, 11520, 60672,  7424, 56576,
102    41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
103    20736, 44288, 27904, 40192, 23808,  2560, 51712, 14848, 64000,  1536, 50688,
104    13824, 62976,  2304, 51456, 14592, 63744,  1280, 50432, 13568, 62720, 35328,
105    18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
106    34048, 17664, 46336, 29952, 10752, 59904,  6656, 55808,  9728, 58880,  5632,
107    54784, 10496, 59648,  6400, 55552,  9472, 58624,  5376, 54528, 43520, 27136,
108    39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
109    25856, 38144, 21760
110 };
111 
112 // ------------------------------------------------------------------------
113 
114 sal_uLong nVCLLut[ 256 ] =
115 {
116          0,  1286,  2572,  3858,  5144,  6430,  7716,  9002,
117      10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
118      20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
119      30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
120      41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
121      51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
122      61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
123      72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
124      82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
125      92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
126     102880,104166,105452,106738,108024,109310,110596,111882,
127     113168,114454,115740,117026,118312,119598,120884,122170,
128     123456,124742,126028,127314,128600,129886,131172,132458,
129     133744,135030,136316,137602,138888,140174,141460,142746,
130     144032,145318,146604,147890,149176,150462,151748,153034,
131     154320,155606,156892,158178,159464,160750,162036,163322,
132     164608,165894,167180,168466,169752,171038,172324,173610,
133     174896,176182,177468,178754,180040,181326,182612,183898,
134     185184,186470,187756,189042,190328,191614,192900,194186,
135     195472,196758,198044,199330,200616,201902,203188,204474,
136     205760,207046,208332,209618,210904,212190,213476,214762,
137     216048,217334,218620,219906,221192,222478,223764,225050,
138     226336,227622,228908,230194,231480,232766,234052,235338,
139     236624,237910,239196,240482,241768,243054,244340,245626,
140     246912,248198,249484,250770,252056,253342,254628,255914,
141     257200,258486,259772,261058,262344,263630,264916,266202,
142     267488,268774,270060,271346,272632,273918,275204,276490,
143     277776,279062,280348,281634,282920,284206,285492,286778,
144     288064,289350,290636,291922,293208,294494,295780,297066,
145     298352,299638,300924,302210,303496,304782,306068,307354,
146     308640,309926,311212,312498,313784,315070,316356,317642,
147     318928,320214,321500,322786,324072,325358,326644,327930
148 };
149 
150 // ------------------------------------------------------------------------
151 
152 long FloydMap[256] =
153 {
154     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1,
158     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
165     3, 3, 3, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
168     4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
169     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
170 };
171 
172 // ------------------------------------------------------------------------
173 
174 long FloydError1[61] =
175 {
176     -7680, -7424, -7168, -6912, -6656, -6400, -6144,
177     -5888, -5632, -5376, -5120, -4864, -4608, -4352,
178     -4096, -3840, -3584, -3328, -3072, -2816, -2560,
179     -2304, -2048, -1792, -1536, -1280, -1024, -768,
180     -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
181     1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
182     3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
183     5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
184 };
185 
186 // ------------------------------------------------------------------------
187 
188 long FloydError3[61] =
189 {
190     -23040, -22272, -21504, -20736, -19968, -19200,
191     -18432, -17664, -16896, -16128, -15360, -14592,
192     -13824, -13056, -12288, -11520, -10752, -9984,
193     -9216, -8448, -7680, -6912, -6144, -5376, -4608,
194     -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
195     2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
196     8448, 9216, 9984, 10752, 11520, 12288, 13056,
197     13824, 14592, 15360, 16128, 16896, 17664, 18432,
198     19200, 19968, 20736, 21504, 22272, 23040
199 };
200 
201 // ------------------------------------------------------------------------
202 
203 long FloydError5[61] =
204 {
205     -38400, -37120, -35840, -34560, -33280, -32000,
206     -30720, -29440, -28160, -26880, -25600, -24320,
207     -23040, -21760, -20480, -19200, -17920, -16640,
208     -15360, -14080, -12800, -11520, -10240, -8960,
209     -7680, -6400, -5120, -3840, -2560, -1280,   0,
210     1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
211     11520, 12800, 14080, 15360, 16640, 17920, 19200,
212     20480, 21760, 23040, 24320, 25600, 26880, 28160,
213     29440, 30720, 32000, 33280, 34560, 35840, 37120,
214     38400
215 };
216 
217 // ------------------------------------------------------------------------
218 
219 long FloydError7[61] =
220 {
221     -53760, -51968, -50176, -48384, -46592, -44800,
222     -43008, -41216, -39424, -37632, -35840, -34048,
223     -32256, -30464, -28672, -26880, -25088, -23296,
224     -21504, -19712, -17920, -16128, -14336, -12544,
225     -10752, -8960, -7168, -5376, -3584, -1792,  0,
226     1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
227     16128, 17920, 19712, 21504, 23296, 25088, 26880,
228     28672, 30464, 32256, 34048, 35840, 37632, 39424,
229     41216, 43008, 44800, 46592, 48384, 50176, 51968,
230     53760
231 };
232 
233 // ------------------------------------------------------------------------
234 
235 long FloydIndexMap[6] =
236 {
237     -30,  21, 72, 123, 174, 225
238 };
239 
240 // --------------------------
241 // - ImplCreateDitherMatrix -
242 // --------------------------
243 
244 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
245 {
246     double          fVal = 3.125;
247     const double    fVal16 = fVal / 16.;
248     long            i, j, k, l;
249     sal_uInt16          pMtx[ 16 ][ 16 ];
250     sal_uInt16          nMax = 0;
251     static sal_uInt8    pMagic[4][4] = { { 0, 14,  3, 13, },
252                                      {11,  5,  8,  6, },
253                                      {12,  2, 15,  1, },
254                                      {7,   9,  4, 10 } };
255 
256     // MagicSquare aufbauen
257     for ( i = 0; i < 4; i++ )
258        for ( j = 0; j < 4; j++ )
259            for ( k = 0; k < 4; k++ )
260                 for ( l = 0; l < 4; l++ )
261                     nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
262                     (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
263 
264     // auf Intervall [0;254] skalieren
265     for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
266         for( j = 0; j < 16; j++ )
267             (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] );
268 }
269 
270 // ----------
271 // - Bitmap -
272 // ----------
273 
274 sal_Bool Bitmap::Convert( BmpConversion eConversion )
275 {
276     const sal_uInt16    nBitCount = GetBitCount();
277     sal_Bool            bRet = sal_False;
278 
279     switch( eConversion )
280     {
281         case( BMP_CONVERSION_1BIT_THRESHOLD ):
282             bRet = ImplMakeMono( 128 );
283         break;
284 
285         case( BMP_CONVERSION_1BIT_MATRIX ):
286             bRet = ImplMakeMonoDither();
287         break;
288 
289         case( BMP_CONVERSION_4BIT_GREYS ):
290             bRet = ImplMakeGreyscales( 16 );
291         break;
292 
293         case( BMP_CONVERSION_4BIT_COLORS ):
294         {
295             if( nBitCount < 4 )
296                 bRet = ImplConvertUp( 4, NULL );
297             else if( nBitCount > 4 )
298                 bRet = ImplConvertDown( 4, NULL );
299             else
300                 bRet = sal_True;
301         }
302         break;
303 
304         case( BMP_CONVERSION_4BIT_TRANS ):
305         {
306             Color aTrans( BMP_COL_TRANS );
307 
308             if( nBitCount < 4 )
309                 bRet = ImplConvertUp( 4, &aTrans );
310             else
311                 bRet = ImplConvertDown( 4, &aTrans );
312         }
313         break;
314 
315         case( BMP_CONVERSION_8BIT_GREYS ):
316             bRet = ImplMakeGreyscales( 256 );
317         break;
318 
319         case( BMP_CONVERSION_8BIT_COLORS ):
320         {
321             if( nBitCount < 8 )
322                 bRet = ImplConvertUp( 8 );
323             else if( nBitCount > 8 )
324                 bRet = ImplConvertDown( 8 );
325             else
326                 bRet = sal_True;
327         }
328         break;
329 
330         case( BMP_CONVERSION_8BIT_TRANS ):
331         {
332             Color aTrans( BMP_COL_TRANS );
333 
334             if( nBitCount < 8 )
335                 bRet = ImplConvertUp( 8, &aTrans );
336             else
337                 bRet = ImplConvertDown( 8, &aTrans );
338         }
339         break;
340 
341         case( BMP_CONVERSION_24BIT ):
342         {
343             if( nBitCount < 24 )
344                 bRet = ImplConvertUp( 24, sal_False );
345             else
346                 bRet = sal_True;
347         }
348         break;
349 
350         case( BMP_CONVERSION_GHOSTED ):
351             bRet = ImplConvertGhosted();
352         break;
353 
354         default:
355             DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
356         break;
357     }
358 
359     return bRet;
360 }
361 
362 // ------------------------------------------------------------------------
363 
364 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
365 {
366     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
367     sal_Bool                bRet = sal_False;
368 
369     if( pReadAcc )
370     {
371         Bitmap              aNewBmp( GetSizePixel(), 1 );
372         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
373 
374         if( pWriteAcc )
375         {
376             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
377             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
378             const long          nWidth = pWriteAcc->Width();
379             const long          nHeight = pWriteAcc->Height();
380 
381             if( pReadAcc->HasPalette() )
382             {
383                 for( long nY = 0L; nY < nHeight; nY++ )
384                 {
385                     for( long nX = 0L; nX < nWidth; nX++ )
386                     {
387                         const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
388                         if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
389                             cThreshold )
390                         {
391                             pWriteAcc->SetPixel( nY, nX, aWhite );
392                         }
393                         else
394                             pWriteAcc->SetPixel( nY, nX, aBlack );
395                     }
396                 }
397             }
398             else
399             {
400                 for( long nY = 0L; nY < nHeight; nY++ )
401                 {
402                     for( long nX = 0L; nX < nWidth; nX++ )
403                     {
404                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
405                             cThreshold )
406                         {
407                             pWriteAcc->SetPixel( nY, nX, aWhite );
408                         }
409                         else
410                             pWriteAcc->SetPixel( nY, nX, aBlack );
411                     }
412                 }
413             }
414 
415             aNewBmp.ReleaseAccess( pWriteAcc );
416             bRet = sal_True;
417         }
418 
419         ReleaseAccess( pReadAcc );
420 
421         if( bRet )
422         {
423             const MapMode   aMap( maPrefMapMode );
424             const Size      aSize( maPrefSize );
425 
426             *this = aNewBmp;
427 
428             maPrefMapMode = aMap;
429             maPrefSize = aSize;
430         }
431     }
432 
433     return bRet;
434 }
435 
436 // ------------------------------------------------------------------------
437 
438 sal_Bool Bitmap::ImplMakeMonoDither()
439 {
440     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
441     sal_Bool                bRet = sal_False;
442 
443     if( pReadAcc )
444     {
445         Bitmap              aNewBmp( GetSizePixel(), 1 );
446         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
447 
448         if( pWriteAcc )
449         {
450             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
451             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
452             const long          nWidth = pWriteAcc->Width();
453             const long          nHeight = pWriteAcc->Height();
454             sal_uInt8               pDitherMatrix[ 16 ][ 16 ];
455 
456             ImplCreateDitherMatrix( &pDitherMatrix );
457 
458             if( pReadAcc->HasPalette() )
459             {
460                 for( long nY = 0L; nY < nHeight; nY++ )
461                 {
462                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
463                     {
464                         const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
465                         if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
466                             pDitherMatrix[ nModY ][ nX % 16 ] )
467                         {
468                             pWriteAcc->SetPixel( nY, nX, aWhite );
469                         }
470                         else
471                             pWriteAcc->SetPixel( nY, nX, aBlack );
472                     }
473                 }
474             }
475             else
476             {
477                 for( long nY = 0L; nY < nHeight; nY++ )
478                 {
479                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
480                     {
481                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
482                             pDitherMatrix[ nModY ][ nX % 16 ]  )
483                         {
484                             pWriteAcc->SetPixel( nY, nX, aWhite );
485                         }
486                         else
487                             pWriteAcc->SetPixel( nY, nX, aBlack );
488                     }
489                 }
490             }
491 
492             aNewBmp.ReleaseAccess( pWriteAcc );
493             bRet = sal_True;
494         }
495 
496         ReleaseAccess( pReadAcc );
497 
498         if( bRet )
499         {
500             const MapMode   aMap( maPrefMapMode );
501             const Size      aSize( maPrefSize );
502 
503             *this = aNewBmp;
504 
505             maPrefMapMode = aMap;
506             maPrefSize = aSize;
507         }
508     }
509 
510     return bRet;
511 }
512 
513 // ------------------------------------------------------------------------
514 
515 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
516 {
517     DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
518 
519     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
520     sal_Bool                bRet = sal_False;
521 
522     if( pReadAcc )
523     {
524         const BitmapPalette&    rPal = GetGreyPalette( nGreys );
525         sal_uLong                   nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
526         sal_Bool                    bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
527 
528         if( !bPalDiffers )
529             bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
530 
531         if( bPalDiffers )
532         {
533             Bitmap              aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
534             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
535 
536             if( pWriteAcc )
537             {
538                 const long  nWidth = pWriteAcc->Width();
539                 const long  nHeight = pWriteAcc->Height();
540 
541                 if( pReadAcc->HasPalette() )
542                 {
543                     for( long nY = 0L; nY < nHeight; nY++ )
544                     {
545                         for( long nX = 0L; nX < nWidth; nX++ )
546                         {
547                             const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
548                             pWriteAcc->SetPixelIndex( nY, nX,
549                                 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
550                         }
551                     }
552                 }
553                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
554                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
555                 {
556                     nShift += 8;
557 
558                     for( long nY = 0L; nY < nHeight; nY++ )
559                     {
560                         Scanline pReadScan = pReadAcc->GetScanline( nY );
561                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
562 
563                         for( long nX = 0L; nX < nWidth; nX++ )
564                         {
565                             const sal_uLong nB = *pReadScan++;
566                             const sal_uLong nG = *pReadScan++;
567                             const sal_uLong nR = *pReadScan++;
568 
569                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
570                         }
571                     }
572                 }
573                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
574                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
575                 {
576                     nShift += 8;
577 
578                     for( long nY = 0L; nY < nHeight; nY++ )
579                     {
580                         Scanline pReadScan = pReadAcc->GetScanline( nY );
581                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
582 
583                         for( long nX = 0L; nX < nWidth; nX++ )
584                         {
585                             const sal_uLong nR = *pReadScan++;
586                             const sal_uLong nG = *pReadScan++;
587                             const sal_uLong nB = *pReadScan++;
588 
589                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
590                         }
591                     }
592                 }
593                 else
594                 {
595                     for( long nY = 0L; nY < nHeight; nY++ )
596                         for( long nX = 0L; nX < nWidth; nX++ )
597                             pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
598                 }
599 
600                 aNewBmp.ReleaseAccess( pWriteAcc );
601                 bRet = sal_True;
602             }
603 
604             ReleaseAccess( pReadAcc );
605 
606             if( bRet )
607             {
608                 const MapMode   aMap( maPrefMapMode );
609                 const Size      aSize( maPrefSize );
610 
611                 *this = aNewBmp;
612 
613                 maPrefMapMode = aMap;
614                 maPrefSize = aSize;
615             }
616         }
617         else
618         {
619             ReleaseAccess( pReadAcc );
620             bRet = sal_True;
621         }
622     }
623 
624     return bRet;
625 }
626 
627 // ------------------------------------------------------------------------
628 
629 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
630 {
631     DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
632 
633     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
634     sal_Bool                bRet = sal_False;
635 
636     if( pReadAcc )
637     {
638         BitmapPalette       aPal;
639         Bitmap              aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
640         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
641 
642         if( pWriteAcc )
643         {
644             const long  nWidth = pWriteAcc->Width();
645             const long  nHeight = pWriteAcc->Height();
646 
647             if( pWriteAcc->HasPalette() )
648             {
649                 const sal_uInt16            nOldCount = 1 << GetBitCount();
650                 const BitmapPalette&    rOldPal = pReadAcc->GetPalette();
651 
652                 aPal.SetEntryCount( 1 << nBitCount );
653 
654                 for( sal_uInt16 i = 0; i < nOldCount; i++ )
655                     aPal[ i ] = rOldPal[ i ];
656 
657                 if( pExtColor )
658                     aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
659 
660                 pWriteAcc->SetPalette( aPal );
661 
662                 for( long nY = 0L; nY < nHeight; nY++ )
663                     for( long nX = 0L; nX < nWidth; nX++ )
664                         pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
665             }
666             else
667             {
668                 if( pReadAcc->HasPalette() )
669                 {
670                     for( long nY = 0L; nY < nHeight; nY++ )
671                         for( long nX = 0L; nX < nWidth; nX++ )
672                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
673                 }
674                 else
675                 {
676                     for( long nY = 0L; nY < nHeight; nY++ )
677                         for( long nX = 0L; nX < nWidth; nX++ )
678                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
679                 }
680             }
681 
682             aNewBmp.ReleaseAccess( pWriteAcc );
683             bRet = sal_True;
684         }
685 
686         ReleaseAccess( pReadAcc );
687 
688         if( bRet )
689         {
690             const MapMode   aMap( maPrefMapMode );
691             const Size      aSize( maPrefSize );
692 
693             *this = aNewBmp;
694 
695             maPrefMapMode = aMap;
696             maPrefSize = aSize;
697         }
698     }
699 
700     return bRet;
701 }
702 
703 // ------------------------------------------------------------------------
704 
705 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
706 {
707     DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
708 
709     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
710     sal_Bool                bRet = sal_False;
711 
712     if( pReadAcc )
713     {
714         BitmapPalette       aPal;
715         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aPal );
716         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
717 
718         if( pWriteAcc )
719         {
720             const sal_uInt16    nCount = 1 << nBitCount;
721             const long      nWidth = pWriteAcc->Width();
722             const long      nWidth1 = nWidth - 1L;
723             const long      nHeight = pWriteAcc->Height();
724             Octree          aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
725             InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
726             BitmapColor     aColor;
727             ImpErrorQuad    aErrQuad;
728             ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
729             ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
730             ImpErrorQuad*   pQLine1 = pErrQuad1;
731             ImpErrorQuad*   pQLine2 = 0;
732             long            nX, nY;
733             long            nYTmp = 0L;
734             sal_uInt8           cIndex;
735             sal_Bool            bQ1 = sal_True;
736 
737             if( pExtColor )
738             {
739                 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
740                 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
741             }
742 
743             // set Black/White always, if we have enough space
744             if( aPal.GetEntryCount() < ( nCount - 1 ) )
745             {
746                 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
747                 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
748                 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
749             }
750 
751             pWriteAcc->SetPalette( aPal );
752 
753             for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
754             {
755                 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
756                 {
757                     if( pReadAcc->HasPalette() )
758                         pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
759                     else
760                         pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
761                 }
762             }
763 
764             for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
765             {
766                 // first pixel in the line
767                 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
768                 pWriteAcc->SetPixelIndex( nY, 0, cIndex );
769 
770                 for( nX = 1L; nX < nWidth1; nX++ )
771                 {
772                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
773                     aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
774                     pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
775                     pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
776                     pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
777                     pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
778                     pWriteAcc->SetPixelIndex( nY, nX, cIndex );
779                 }
780 
781                 // letztes ZeilenPixel
782                 if( nX < nWidth )
783                 {
784                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
785                     pWriteAcc->SetPixelIndex( nY, nX, cIndex );
786                 }
787 
788                 // Zeilenpuffer neu fuellen/kopieren
789                 pQLine1 = pQLine2;
790                 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
791 
792                 if( nYTmp < nHeight )
793                 {
794                     for( nX = 0L; nX < nWidth; nX++ )
795                     {
796                         if( pReadAcc->HasPalette() )
797                             pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
798                         else
799                             pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
800                     }
801                 }
802             }
803 
804             // Zeilenpuffer zerstoeren
805             delete[] pErrQuad1;
806             delete[] pErrQuad2;
807 
808             aNewBmp.ReleaseAccess( pWriteAcc );
809             bRet = sal_True;
810         }
811 
812         ReleaseAccess( pReadAcc );
813 
814         if( bRet )
815         {
816             const MapMode   aMap( maPrefMapMode );
817             const Size      aSize( maPrefSize );
818 
819             *this = aNewBmp;
820 
821             maPrefMapMode = aMap;
822             maPrefSize = aSize;
823         }
824     }
825 
826     return bRet;
827 }
828 
829 // ------------------------------------------------------------------------
830 
831 sal_Bool Bitmap::ImplConvertGhosted()
832 {
833     Bitmap              aNewBmp;
834     BitmapReadAccess*   pR = AcquireReadAccess();
835     sal_Bool                bRet = sal_False;
836 
837     if( pR )
838     {
839         if( pR->HasPalette() )
840         {
841             BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
842 
843             for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
844             {
845                 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
846                 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
847                                                      ( rOld.GetGreen() >> 1 ) | 0x80,
848                                                      ( rOld.GetBlue() >> 1 ) | 0x80 );
849             }
850 
851             aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
852             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
853 
854             if( pW )
855             {
856                 pW->CopyBuffer( *pR );
857                 aNewBmp.ReleaseAccess( pW );
858                 bRet = sal_True;
859             }
860         }
861         else
862         {
863             aNewBmp = Bitmap( GetSizePixel(), 24 );
864 
865             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
866 
867             if( pW )
868             {
869                 const long nWidth = pR->Width(), nHeight = pR->Height();
870 
871                 for( long nY = 0; nY < nHeight; nY++ )
872                 {
873                     for( long nX = 0; nX < nWidth; nX++ )
874                     {
875                         const BitmapColor aOld( pR->GetPixel( nY, nX ) );
876                         pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
877                                                            ( aOld.GetGreen() >> 1 ) | 0x80,
878                                                            ( aOld.GetBlue() >> 1 ) | 0x80 ) );
879 
880                     }
881                 }
882 
883                 aNewBmp.ReleaseAccess( pW );
884                 bRet = sal_True;
885             }
886         }
887 
888         ReleaseAccess( pR );
889     }
890 
891     if( bRet )
892     {
893         const MapMode   aMap( maPrefMapMode );
894         const Size      aSize( maPrefSize );
895 
896         *this = aNewBmp;
897 
898         maPrefMapMode = aMap;
899         maPrefSize = aSize;
900     }
901 
902     return bRet;
903 }
904 
905 // ------------------------------------------------------------------------
906 
907 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
908 {
909 #ifdef DBG_UTIL
910     // #121233# allow to test the different scalers in debug build with source
911     // level debugger (change nNumber to desired action)
912     static sal_uInt16 nNumber(0);
913 
914     switch(nNumber)
915     {
916         case 0 : break;
917         case 1: nScaleFlag = BMP_SCALE_FAST; break;
918         case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break;
919         case 3: nScaleFlag = BMP_SCALE_SUPER; break;
920         case 4: nScaleFlag = BMP_SCALE_LANCZOS; break;
921         case 5: nScaleFlag = BMP_SCALE_BICUBIC; break;
922         case 6: nScaleFlag = BMP_SCALE_BILINEAR; break;
923         case 7: nScaleFlag = BMP_SCALE_BOX; break;
924         case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break;
925         case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break;
926     }
927 #endif // DBG_UTIL
928 
929     if(basegfx::fTools::equalZero(rScaleX) && basegfx::fTools::equalZero(rScaleY))
930     {
931         // no scale
932         return true;
933     }
934     else
935     {
936         if(BMP_SCALE_BESTQUALITY == nScaleFlag)
937         {
938             // Use LANCZOS when best quality is requested
939             nScaleFlag = BMP_SCALE_LANCZOS;
940         }
941         else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag)
942         {
943             // Use BMP_SCALE_SUPER when speed is requested, but not worst quality
944             nScaleFlag = BMP_SCALE_SUPER;
945         }
946 
947         switch(nScaleFlag)
948         {
949             default:
950             case BMP_SCALE_NONE :
951             {
952                 return false;
953                 break;
954             }
955             case BMP_SCALE_FAST :
956             {
957                 return ImplScaleFast( rScaleX, rScaleY );
958                 break;
959             }
960             case BMP_SCALE_INTERPOLATE :
961             {
962                 return ImplScaleInterpolate( rScaleX, rScaleY );
963                 break;
964             }
965             case BMP_SCALE_SUPER :
966             {
967                 if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
968                 {
969                     // fallback to ImplScaleFast
970                     return ImplScaleFast( rScaleX, rScaleY );
971                 }
972                 else
973                 {
974                     // #121233# use method from symphony
975                     return ImplScaleSuper( rScaleX, rScaleY );
976                 }
977                 break;
978             }
979             case BMP_SCALE_LANCZOS :
980             {
981                 const Lanczos3Kernel kernel;
982 
983                 return ImplScaleConvolution( rScaleX, rScaleY, kernel);
984                 break;
985             }
986             case BMP_SCALE_BICUBIC :
987             {
988                 const BicubicKernel kernel;
989 
990                 return ImplScaleConvolution( rScaleX, rScaleY, kernel );
991                 break;
992             }
993             case BMP_SCALE_BILINEAR :
994             {
995                 const BilinearKernel kernel;
996 
997                 return ImplScaleConvolution( rScaleX, rScaleY, kernel );
998                 break;
999             }
1000             case BMP_SCALE_BOX :
1001             {
1002                 const BoxKernel kernel;
1003 
1004                 return ImplScaleConvolution( rScaleX, rScaleY, kernel );
1005                 break;
1006             }
1007         }
1008     }
1009 
1010     // should not happen
1011     return false;
1012 }
1013 
1014 // ------------------------------------------------------------------------
1015 
1016 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
1017 {
1018     const Size  aSize( GetSizePixel() );
1019     sal_Bool        bRet;
1020 
1021     if( aSize.Width() && aSize.Height() )
1022     {
1023         bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
1024                       (double) rNewSize.Height() / aSize.Height(),
1025                       nScaleFlag );
1026     }
1027     else
1028         bRet = sal_True;
1029 
1030     return bRet;
1031 }
1032 
1033 // ------------------------------------------------------------------------
1034 
1035 void Bitmap::AdaptBitCount(Bitmap& rNew) const
1036 {
1037     ImplAdaptBitCount(rNew);
1038 }
1039 
1040 // ------------------------------------------------------------------------
1041 
1042 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const
1043 {
1044     // aNew is the result of some operation; adapt it's BitCount to the original (this)
1045     if(GetBitCount() != rNew.GetBitCount())
1046     {
1047         switch(GetBitCount())
1048         {
1049             case 1:
1050             {
1051                 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD);
1052                 break;
1053             }
1054             case 4:
1055             {
1056                 if(HasGreyPalette())
1057                 {
1058                     rNew.Convert(BMP_CONVERSION_4BIT_GREYS);
1059                 }
1060                 else
1061                 {
1062                     rNew.Convert(BMP_CONVERSION_4BIT_COLORS);
1063                 }
1064                 break;
1065             }
1066             case 8:
1067             {
1068                 if(HasGreyPalette())
1069                 {
1070                     rNew.Convert(BMP_CONVERSION_8BIT_GREYS);
1071                 }
1072                 else
1073                 {
1074                     rNew.Convert(BMP_CONVERSION_8BIT_COLORS);
1075                 }
1076                 break;
1077             }
1078             case 24:
1079             {
1080                 rNew.Convert(BMP_CONVERSION_24BIT);
1081                 break;
1082             }
1083             default:
1084             {
1085                 OSL_ENSURE(false, "BitDepth adaption failed (!)");
1086                 break;
1087             }
1088         }
1089     }
1090 }
1091 
1092 // ------------------------------------------------------------------------
1093 
1094 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
1095 {
1096     const Size  aSizePix( GetSizePixel() );
1097     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1098     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1099     sal_Bool        bRet = sal_False;
1100 
1101     if( nNewWidth && nNewHeight )
1102     {
1103         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1104         if ( !pReadAcc )
1105             return sal_False;
1106 
1107         Bitmap              aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
1108         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1109 
1110         if( pWriteAcc )
1111         {
1112             const long  nScanlineSize = pWriteAcc->GetScanlineSize();
1113             const long  nNewWidth1 = nNewWidth - 1L;
1114             const long  nNewHeight1 = nNewHeight - 1L;
1115             const long  nWidth = pReadAcc->Width();
1116             const long  nHeight = pReadAcc->Height();
1117             long*       pLutX = new long[ nNewWidth ];
1118             long*       pLutY = new long[ nNewHeight ];
1119             long        nX, nY, nMapY, nActY = 0L;
1120 
1121             if( nNewWidth1 && nNewHeight1 )
1122             {
1123                 for( nX = 0L; nX < nNewWidth; nX++ )
1124                     pLutX[ nX ] = nX * nWidth / nNewWidth;
1125 
1126                 for( nY = 0L; nY < nNewHeight; nY++ )
1127                     pLutY[ nY ] = nY * nHeight / nNewHeight;
1128 
1129                 while( nActY < nNewHeight )
1130                 {
1131                     nMapY = pLutY[ nActY ];
1132 
1133                     for( nX = 0L; nX < nNewWidth; nX++ )
1134                         pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
1135 
1136                     while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
1137                     {
1138                         memcpy( pWriteAcc->GetScanline( nActY + 1L ),
1139                                  pWriteAcc->GetScanline( nActY ), nScanlineSize );
1140                         nActY++;
1141                     }
1142 
1143                     nActY++;
1144                 }
1145 
1146                 bRet = sal_True;
1147             }
1148 
1149             delete[] pLutX;
1150             delete[] pLutY;
1151         }
1152 
1153         ReleaseAccess( pReadAcc );
1154         aNewBmp.ReleaseAccess( pWriteAcc );
1155 
1156         if( bRet )
1157             ImplAssignWithSize( aNewBmp );
1158     }
1159 
1160     return bRet;
1161 }
1162 
1163 // ------------------------------------------------------------------------
1164 
1165 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1166 {
1167     const Size  aSizePix( GetSizePixel() );
1168     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1169     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1170     sal_Bool        bRet = sal_False;
1171 
1172     if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1173     {
1174         BitmapColor         aCol0;
1175         BitmapColor         aCol1;
1176         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1177         long                nWidth = pReadAcc->Width();
1178         long                nHeight = pReadAcc->Height();
1179         Bitmap              aNewBmp( Size( nNewWidth, nHeight ), 24 );
1180         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1181         long*               pLutInt;
1182         long*               pLutFrac;
1183         long                nX, nY;
1184         long                lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1185         double              fTemp;
1186         long                nTemp;
1187 
1188         if( pReadAcc && pWriteAcc )
1189         {
1190             const long      nNewWidth1 = nNewWidth - 1L;
1191             const long      nWidth1 = pReadAcc->Width() - 1L;
1192             const double    fRevScaleX = (double) nWidth1 / nNewWidth1;
1193 
1194             pLutInt = new long[ nNewWidth ];
1195             pLutFrac = new long[ nNewWidth ];
1196 
1197             for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1198             {
1199                 fTemp = nX * fRevScaleX;
1200                 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1201                 fTemp -= pLutInt[ nX ];
1202                 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1203             }
1204 
1205             for( nY = 0L; nY < nHeight; nY++ )
1206             {
1207                 if( 1 == nWidth )
1208                 {
1209                     if( pReadAcc->HasPalette() )
1210                     {
1211                         aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1212                     }
1213                     else
1214                     {
1215                         aCol0 = pReadAcc->GetPixel( nY, 0 );
1216                     }
1217 
1218                     for( nX = 0L; nX < nNewWidth; nX++ )
1219                     {
1220                         pWriteAcc->SetPixel( nY, nX, aCol0 );
1221                     }
1222                 }
1223                 else
1224                 {
1225                     for( nX = 0L; nX < nNewWidth; nX++ )
1226                     {
1227                         nTemp = pLutInt[ nX ];
1228 
1229                         if( pReadAcc->HasPalette() )
1230                         {
1231                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1232                             aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1233                         }
1234                         else
1235                         {
1236                             aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1237                             aCol1 = pReadAcc->GetPixel( nY, nTemp );
1238                         }
1239 
1240                         nTemp = pLutFrac[ nX ];
1241 
1242                         lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1243                         lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1244                         lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1245 
1246                         aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1247                         aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1248                         aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1249 
1250                         pWriteAcc->SetPixel( nY, nX, aCol0 );
1251                     }
1252                 }
1253             }
1254 
1255             delete[] pLutInt;
1256             delete[] pLutFrac;
1257             bRet = sal_True;
1258         }
1259 
1260         ReleaseAccess( pReadAcc );
1261         aNewBmp.ReleaseAccess( pWriteAcc );
1262 
1263         if( bRet )
1264         {
1265             bRet = sal_False;
1266             *this = aNewBmp;
1267             aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1268             pReadAcc = AcquireReadAccess();
1269             pWriteAcc = aNewBmp.AcquireWriteAccess();
1270 
1271             if( pReadAcc && pWriteAcc )
1272             {
1273                 const long      nNewHeight1 = nNewHeight - 1L;
1274                 const long      nHeight1 = pReadAcc->Height() - 1L;
1275                 const double    fRevScaleY = (double) nHeight1 / nNewHeight1;
1276 
1277                 pLutInt = new long[ nNewHeight ];
1278                 pLutFrac = new long[ nNewHeight ];
1279 
1280                 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1281                 {
1282                     fTemp = nY * fRevScaleY;
1283                     pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1284                     fTemp -= pLutInt[ nY ];
1285                     pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1286                 }
1287 
1288                 // after 1st step, bitmap *is* 24bit format (see above)
1289                 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1290 
1291                 for( nX = 0L; nX < nNewWidth; nX++ )
1292                 {
1293                     if( 1 == nHeight )
1294                     {
1295                         aCol0 = pReadAcc->GetPixel( 0, nX );
1296 
1297                         for( nY = 0L; nY < nNewHeight; nY++ )
1298                         {
1299                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1300                         }
1301                     }
1302                     else
1303                     {
1304                         for( nY = 0L; nY < nNewHeight; nY++ )
1305                         {
1306                             nTemp = pLutInt[ nY ];
1307 
1308                             aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1309                             aCol1 = pReadAcc->GetPixel( nTemp, nX );
1310 
1311                             nTemp = pLutFrac[ nY ];
1312 
1313                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1314                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1315                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1316 
1317                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1318                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1319                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1320 
1321                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1322                         }
1323                     }
1324                 }
1325 
1326                 delete[] pLutInt;
1327                 delete[] pLutFrac;
1328                 bRet = sal_True;
1329             }
1330 
1331             ReleaseAccess( pReadAcc );
1332             aNewBmp.ReleaseAccess( pWriteAcc );
1333 
1334             if( bRet )
1335             {
1336                 ImplAdaptBitCount(aNewBmp);
1337                 *this = aNewBmp;
1338             }
1339         }
1340     }
1341 
1342     if( !bRet )
1343     {
1344         bRet = ImplScaleFast( rScaleX, rScaleY );
1345     }
1346 
1347     return bRet;
1348 }
1349 
1350 // ------------------------------------------------------------------------
1351 // #121233# Added BMP_SCALE_SUPER from symphony code
1352 
1353 sal_Bool Bitmap::ImplScaleSuper(
1354     const double& rScaleX,
1355     const double& rScaleY )
1356 {
1357     const Size  aSizePix( GetSizePixel() );
1358     bool   bHMirr = ( rScaleX < 0 );
1359     bool   bVMirr = ( rScaleY < 0 );
1360     double scaleX = bHMirr ? -rScaleX : rScaleX;
1361     double scaleY = bVMirr ? -rScaleY : rScaleY;
1362     const long  nDstW = FRound( aSizePix.Width() * scaleX );
1363     const long  nDstH = FRound( aSizePix.Height() * scaleY );
1364     const double fScaleThresh = 0.6;
1365     bool bRet = false;
1366 
1367     if( ( nDstW > 1L ) && ( nDstH > 1L ) )
1368     {
1369         BitmapColor         aCol0, aCol1, aColRes;
1370         BitmapReadAccess*   pAcc = AcquireReadAccess();
1371         long                nW = pAcc->Width() ;
1372         long                nH = pAcc->Height() ;
1373         Bitmap              aOutBmp( Size( nDstW, nDstH ), 24 );
1374         BitmapWriteAccess*  pWAcc = aOutBmp.AcquireWriteAccess();
1375         long*               pMapIX = new long[ nDstW ];
1376         long*               pMapIY = new long[ nDstH ];
1377         long*               pMapFX = new long[ nDstW ];
1378         long*               pMapFY = new long[ nDstH ];
1379         long                nX, nY, nXDst, nYDst;;
1380         double              fTemp;
1381         long                nTemp , nTempX, nTempY, nTempFX, nTempFY;
1382         sal_uInt8           cR0, cG0, cB0, cR1, cG1, cB1;
1383         long                nStartX = 0 , nStartY = 0;
1384         long                nEndX = nDstW - 1L;
1385         long                nEndY = nDstH - 1L;
1386         long                nMax = 1 << 7L;
1387 
1388         if( pAcc && pWAcc )
1389         {
1390             const double    fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0;
1391             const double    fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0;
1392 
1393             // create horizontal mapping table
1394             for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ )
1395             {
1396                 fTemp = nX * fRevScaleX;
1397 
1398                 if( bHMirr )
1399                     fTemp = nTempX - fTemp;
1400 
1401                 pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1402             }
1403 
1404             // create vertical mapping table
1405             for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ )
1406             {
1407                 fTemp = nY * fRevScaleY;
1408 
1409                 if( bVMirr )
1410                     fTemp = nTempY - fTemp;
1411 
1412                 pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1413             }
1414 
1415             if( pAcc->HasPalette() )
1416             {
1417                 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1418                 {
1419                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1420                     {
1421                         Scanline pLine0, pLine1;
1422 
1423                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1424                         {
1425                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1426                             pLine0 = pAcc->GetScanline( nTempY );
1427                             pLine1 = pAcc->GetScanline( ++nTempY );
1428 
1429                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1430                             {
1431                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1432 
1433                                 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] );
1434                                 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1435                                 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] );
1436                                 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1437 
1438                                 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
1439                                 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
1440                                 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
1441 
1442                                 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
1443                                 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
1444                                 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
1445 
1446                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1447                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1448                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1449                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1450                             }
1451                         }
1452                     }
1453                     else
1454                     {
1455                         Scanline    pTmpY;
1456                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1457                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1458                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1459 
1460                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1461                         {
1462                             nTop = bVMirr ? ( nY + 1 ) : nY;
1463                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1464 
1465                             if( nY ==nEndY )
1466                             {
1467                                 nLineStart = pMapIY[ nY ];
1468                                 nLineRange = 0;
1469                             }
1470                             else
1471                             {
1472                                 nLineStart = pMapIY[ nTop ] ;
1473                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1474                             }
1475 
1476                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1477                             {
1478                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1479                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1480 
1481                                 if( nX == nEndX )
1482                                 {
1483                                     nRowStart = pMapIX[ nX ];
1484                                     nRowRange = 0;
1485                                 }
1486                                 else
1487                                 {
1488                                     nRowStart = pMapIX[ nLeft ];
1489                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1490                                 }
1491 
1492                                 nSumR = nSumG = nSumB = 0;
1493                                 nTotalWeightY = 0;
1494 
1495                                 for(int i = 0; i<= nLineRange; i++)
1496                                 {
1497                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1498                                     nSumRowR = nSumRowG = nSumRowB = 0;
1499                                     nTotalWeightX = 0;
1500 
1501                                     for(int j = 0; j <= nRowRange; j++)
1502                                     {
1503                                         const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] );
1504 
1505                                         if(nX == nEndX )
1506                                         {
1507                                             nSumRowB += rCol.GetBlue() << 7L;
1508                                             nSumRowG += rCol.GetGreen() << 7L;
1509                                             nSumRowR += rCol.GetRed() << 7L;
1510                                             nTotalWeightX += 1 << 7L;
1511                                         }
1512                                         else if( j == 0 )
1513                                         {
1514                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1515                                             nSumRowB += ( nWeightX *rCol.GetBlue()) ;
1516                                             nSumRowG += ( nWeightX *rCol.GetGreen()) ;
1517                                             nSumRowR += ( nWeightX *rCol.GetRed()) ;
1518                                             nTotalWeightX += nWeightX;
1519                                         }
1520                                         else if ( nRowRange == j )
1521                                         {
1522                                             nWeightX = pMapFX[ nRight ] ;
1523                                             nSumRowB += ( nWeightX *rCol.GetBlue() );
1524                                             nSumRowG += ( nWeightX *rCol.GetGreen() );
1525                                             nSumRowR += ( nWeightX *rCol.GetRed() );
1526                                             nTotalWeightX += nWeightX;
1527                                         }
1528                                         else
1529                                         {
1530                                             nSumRowB += rCol.GetBlue() << 7L;
1531                                             nSumRowG += rCol.GetGreen() << 7L;
1532                                             nSumRowR += rCol.GetRed() << 7L;
1533                                             nTotalWeightX += 1 << 7L;
1534                                         }
1535                                     }
1536 
1537                                     if( nY == nEndY )
1538                                         nWeightY = nMax;
1539                                     else if( i == 0 )
1540                                         nWeightY = nMax - pMapFY[ nTop ];
1541                                     else if( nLineRange == 1 )
1542                                         nWeightY = pMapFY[ nTop ];
1543                                     else if ( nLineRange == i )
1544                                         nWeightY = pMapFY[ nBottom ];
1545                                     else
1546                                         nWeightY = nMax;
1547 
1548                                     nWeightY = nWeightY ;
1549                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1550                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1551                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1552                                     nTotalWeightY += nWeightY;
1553                                 }
1554 
1555                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1556                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1557                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1558                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1559 
1560                             }
1561                         }
1562                     }
1563 }
1564                 else
1565                 {
1566                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1567                     {
1568                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1569                         {
1570                             nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ];
1571 
1572                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1573                             {
1574                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1575 
1576                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) );
1577                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) );
1578                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1579                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1580                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1581 
1582                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) );
1583                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) );
1584                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1585                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1586                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1587 
1588                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1589                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1590                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1591                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1592                             }
1593                         }
1594 
1595                     }
1596                     else
1597                     {
1598                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1599                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1600                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1601 
1602                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1603                         {
1604                             nTop = bVMirr ? ( nY + 1 ) : nY;
1605                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1606 
1607                             if( nY ==nEndY )
1608                             {
1609                                 nLineStart = pMapIY[ nY ];
1610                                 nLineRange = 0;
1611                             }
1612                             else
1613                             {
1614                                 nLineStart = pMapIY[ nTop ] ;
1615                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1616                             }
1617 
1618                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1619                             {
1620                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1621                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1622 
1623                                 if( nX == nEndX )
1624                                 {
1625                                     nRowStart = pMapIX[ nX ];
1626                                     nRowRange = 0;
1627                                 }
1628                                 else
1629                                 {
1630                                     nRowStart = pMapIX[ nLeft ];
1631                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1632                                 }
1633 
1634                                 nSumR = nSumG = nSumB = 0;
1635                                 nTotalWeightY = 0;
1636 
1637                                 for(int i = 0; i<= nLineRange; i++)
1638                                 {
1639                                     nSumRowR = nSumRowG = nSumRowB = 0;
1640                                     nTotalWeightX = 0;
1641 
1642                                     for(int j = 0; j <= nRowRange; j++)
1643                                     {
1644                                         aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
1645 
1646                                         if(nX == nEndX )
1647                                         {
1648 
1649                                             nSumRowB += aCol0.GetBlue() << 7L;
1650                                             nSumRowG += aCol0.GetGreen() << 7L;
1651                                             nSumRowR += aCol0.GetRed() << 7L;
1652                                             nTotalWeightX += 1 << 7L;
1653                                         }
1654                                         else if( j == 0 )
1655                                         {
1656 
1657                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1658                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
1659                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
1660                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
1661                                             nTotalWeightX += nWeightX;
1662                                         }
1663                                         else if ( nRowRange == j )
1664                                         {
1665 
1666                                             nWeightX = pMapFX[ nRight ] ;
1667                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
1668                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
1669                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
1670                                             nTotalWeightX += nWeightX;
1671                                         }
1672                                         else
1673                                         {
1674 
1675                                             nSumRowB += aCol0.GetBlue() << 7L;
1676                                             nSumRowG += aCol0.GetGreen() << 7L;
1677                                             nSumRowR += aCol0.GetRed() << 7L;
1678                                             nTotalWeightX += 1 << 7L;
1679                                         }
1680                                     }
1681 
1682                                     if( nY == nEndY )
1683                                         nWeightY = nMax;
1684                                     else if( i == 0 )
1685                                         nWeightY = nMax - pMapFY[ nTop ];
1686                                     else if( nLineRange == 1 )
1687                                         nWeightY = pMapFY[ nTop ];
1688                                     else if ( nLineRange == i )
1689                                         nWeightY = pMapFY[ nBottom ];
1690                                     else
1691                                         nWeightY = nMax;
1692 
1693                                     nWeightY = nWeightY ;
1694                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1695                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1696                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1697                                     nTotalWeightY += nWeightY;
1698                                 }
1699 
1700                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1701                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1702                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1703                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1704                             }
1705                         }
1706                     }
1707                 }
1708             }
1709             else
1710             {
1711                 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1712                 {
1713                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1714                     {
1715                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1716                         long        nOff;
1717 
1718                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1719                         {
1720                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1721                             pLine0 = pAcc->GetScanline( nTempY );
1722                             pLine1 = pAcc->GetScanline( ++nTempY );
1723 
1724                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1725                             {
1726                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1727                                 nTempFX = pMapFX[ nX ];
1728 
1729                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1730                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1731                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1732                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
1733 
1734                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1735                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1736                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1737                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
1738 
1739                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1740                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1741                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1742                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1743                             }
1744                         }
1745                     }
1746                     else
1747                     {
1748                         Scanline    pTmpY, pTmpX;
1749                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1750                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1751                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1752 
1753                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1754                         {
1755                             nTop = bVMirr ? ( nY + 1 ) : nY;
1756                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1757 
1758                             if( nY ==nEndY )
1759                             {
1760                                 nLineStart = pMapIY[ nY ];
1761                                 nLineRange = 0;
1762                             }
1763                             else
1764                             {
1765                                 nLineStart = pMapIY[ nTop ] ;
1766                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1767                             }
1768 
1769                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1770                             {
1771                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1772                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1773 
1774                                 if( nX == nEndX  )
1775                                 {
1776                                     nRowStart = pMapIX[ nX ];
1777                                     nRowRange = 0;
1778                                 }
1779                                 else
1780                                 {
1781                                     nRowStart = pMapIX[ nLeft ];
1782                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1783                                 }
1784 
1785                                 nSumR = nSumG = nSumB = 0;
1786                                 nTotalWeightY = 0;
1787 
1788                                 for(int i = 0; i<= nLineRange; i++)
1789                                 {
1790                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1791                                     pTmpX = pTmpY + 3L * nRowStart;
1792                                     nSumRowR = nSumRowG = nSumRowB = 0;
1793                                     nTotalWeightX = 0;
1794 
1795                                     for(int j = 0; j <= nRowRange; j++)
1796                                     {
1797                                         if(nX == nEndX )
1798                                         {
1799                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1800                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1801                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1802                                             nTotalWeightX += 1 << 7L;
1803                                         }
1804                                         else if( j == 0 )
1805                                         {
1806                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1807                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1808                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1809                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1810                                             nTotalWeightX += nWeightX;
1811                                         }
1812                                         else if ( nRowRange == j )
1813                                         {
1814                                             nWeightX = pMapFX[ nRight ] ;
1815                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1816                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1817                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1818                                             nTotalWeightX += nWeightX;
1819                                         }
1820                                         else
1821                                         {
1822                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1823                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1824                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1825                                             nTotalWeightX += 1 << 7L;
1826                                         }
1827                                     }
1828 
1829                                     if( nY == nEndY )
1830                                         nWeightY = nMax;
1831                                     else if( i == 0 )
1832                                         nWeightY = nMax - pMapFY[ nTop ];
1833                                     else if( nLineRange == 1 )
1834                                         nWeightY = pMapFY[ nTop ];
1835                                     else if ( nLineRange == i )
1836                                         nWeightY = pMapFY[ nBottom ];
1837                                     else
1838                                         nWeightY = nMax;
1839 
1840                                     nWeightY = nWeightY ;
1841                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1842                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1843                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1844                                     nTotalWeightY += nWeightY;
1845                                 }
1846 
1847                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1848                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1849                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1850                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1851 
1852                             }
1853                         }
1854                     }
1855                 }
1856                 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1857                 {
1858                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1859                     {
1860                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1861                         long        nOff;
1862 
1863                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1864                         {
1865                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1866                             pLine0 = pAcc->GetScanline( nTempY );
1867                             pLine1 = pAcc->GetScanline( ++nTempY );
1868 
1869                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1870                             {
1871                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1872                                 nTempFX = pMapFX[ nX ];
1873 
1874                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1875                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1876                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1877                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
1878 
1879                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1880                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1881                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1882                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
1883 
1884                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1885                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1886                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1887                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1888                             }
1889                         }
1890                     }
1891                     else
1892                     {
1893                         Scanline    pTmpY, pTmpX;
1894                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1895                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1896                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1897 
1898                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1899                         {
1900                             nTop = bVMirr ? ( nY + 1 ) : nY;
1901                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1902 
1903                             if( nY ==nEndY )
1904                             {
1905                                 nLineStart = pMapIY[ nY ];
1906                                 nLineRange = 0;
1907                             }
1908                             else
1909                             {
1910                                 nLineStart = pMapIY[ nTop ] ;
1911                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1912                             }
1913 
1914                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1915                             {
1916                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1917                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1918 
1919                                 if( nX == nEndX )
1920                                 {
1921                                     nRowStart = pMapIX[ nX ];
1922                                     nRowRange = 0;
1923                                 }
1924                                 else
1925                                 {
1926                                     nRowStart = pMapIX[ nLeft ];
1927                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1928                                 }
1929 
1930                                 nSumR = nSumG = nSumB = 0;
1931                                 nTotalWeightY = 0;
1932 
1933                                 for(int i = 0; i<= nLineRange; i++)
1934                                 {
1935                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1936                                     pTmpX = pTmpY + 3L * nRowStart;
1937                                     nSumRowR = nSumRowG = nSumRowB = 0;
1938                                     nTotalWeightX = 0;
1939 
1940                                     for(int j = 0; j <= nRowRange; j++)
1941                                     {
1942                                         if(nX == nEndX )
1943                                         {
1944                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1945                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1946                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1947                                             nTotalWeightX += 1 << 7L;
1948                                         }
1949                                         else if( j == 0 )
1950                                         {
1951                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1952                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1953                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1954                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1955                                             nTotalWeightX += nWeightX;
1956                                         }
1957                                         else if ( nRowRange == j )
1958                                         {
1959                                             nWeightX = pMapFX[ nRight ] ;
1960                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1961                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1962                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1963                                             nTotalWeightX += nWeightX;
1964                                         }
1965                                         else
1966                                         {
1967                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1968                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1969                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1970                                             nTotalWeightX += 1 << 7L;
1971                                         }
1972                                     }
1973 
1974                                     if( nY == nEndY )
1975                                         nWeightY = nMax;
1976                                     else if( i == 0 )
1977                                         nWeightY = nMax - pMapFY[ nTop ];
1978                                     else if( nLineRange == 1 )
1979                                         nWeightY = pMapFY[ nTop ];
1980                                     else if ( nLineRange == i )
1981                                         nWeightY = pMapFY[ nBottom ];
1982                                     else
1983                                         nWeightY = nMax;
1984 
1985                                     nWeightY = nWeightY ;
1986                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1987                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1988                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1989                                     nTotalWeightY += nWeightY;
1990                                 }
1991 
1992                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1993                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1994                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1995                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1996 
1997                             }
1998                         }
1999                     }
2000                 }
2001                 else
2002                 {
2003                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
2004                     {
2005                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2006                         {
2007                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
2008 
2009                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
2010                             {
2011                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
2012 
2013                                 aCol0 = pAcc->GetPixel( nTempY, nTempX );
2014                                 aCol1 = pAcc->GetPixel( nTempY, ++nTempX );
2015                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2016                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2017                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2018 
2019                                 aCol1 = pAcc->GetPixel( ++nTempY, nTempX );
2020                                 aCol0 = pAcc->GetPixel( nTempY--, --nTempX );
2021                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2022                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2023                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2024 
2025                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
2026                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
2027                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
2028                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2029                             }
2030                         }
2031                     }
2032                     else
2033                     {
2034                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
2035                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
2036                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
2037 
2038                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2039                         {
2040                             nTop = bVMirr ? ( nY + 1 ) : nY;
2041                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
2042 
2043                             if( nY ==nEndY )
2044                             {
2045                                 nLineStart = pMapIY[ nY ];
2046                                 nLineRange = 0;
2047                             }
2048                             else
2049                             {
2050                                 nLineStart = pMapIY[ nTop ] ;
2051                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
2052                             }
2053 
2054                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
2055                             {
2056                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
2057                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
2058 
2059                                 if( nX == nEndX )
2060                                 {
2061                                     nRowStart = pMapIX[ nX ];
2062                                     nRowRange = 0;
2063                                 }
2064                                 else
2065                                 {
2066                                     nRowStart = pMapIX[ nLeft ];
2067                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
2068                                 }
2069 
2070                                 nSumR = nSumG = nSumB = 0;
2071                                 nTotalWeightY = 0;
2072 
2073                                 for(int i = 0; i<= nLineRange; i++)
2074                                 {
2075                                     nSumRowR = nSumRowG = nSumRowB = 0;
2076                                     nTotalWeightX = 0;
2077 
2078                                     for(int j = 0; j <= nRowRange; j++)
2079                                     {
2080                                         aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j );
2081 
2082                                         if(nX == nEndX )
2083                                         {
2084 
2085                                             nSumRowB += aCol0.GetBlue() << 7L;
2086                                             nSumRowG += aCol0.GetGreen() << 7L;
2087                                             nSumRowR += aCol0.GetRed() << 7L;
2088                                             nTotalWeightX += 1 << 7L;
2089                                         }
2090                                         else if( j == 0 )
2091                                         {
2092 
2093                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
2094                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
2095                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
2096                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
2097                                             nTotalWeightX += nWeightX;
2098                                         }
2099                                         else if ( nRowRange == j )
2100                                         {
2101 
2102                                             nWeightX = pMapFX[ nRight ] ;
2103                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
2104                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
2105                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
2106                                             nTotalWeightX += nWeightX;
2107                                         }
2108                                         else
2109                                         {
2110                                             nSumRowB += aCol0.GetBlue() << 7L;
2111                                             nSumRowG += aCol0.GetGreen() << 7L;
2112                                             nSumRowR += aCol0.GetRed() << 7L;
2113                                             nTotalWeightX += 1 << 7L;
2114                                         }
2115                                     }
2116 
2117                                     if( nY == nEndY )
2118                                         nWeightY = nMax;
2119                                     else if( i == 0 )
2120                                         nWeightY = nMax - pMapFY[ nTop ];
2121                                     else if( nLineRange == 1 )
2122                                         nWeightY = pMapFY[ nTop ];
2123                                     else if ( nLineRange == i )
2124                                         nWeightY = pMapFY[ nBottom ];
2125                                     else
2126                                         nWeightY = nMax;
2127 
2128                                     nWeightY = nWeightY ;
2129                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
2130                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
2131                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
2132                                     nTotalWeightY += nWeightY;
2133                                 }
2134 
2135                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2136                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2137                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2138                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2139 
2140                             }
2141                         }
2142                     }
2143                 }
2144             }
2145 
2146             bRet = true;
2147         }
2148 
2149         delete[] pMapIX;
2150         delete[] pMapIY;
2151         delete[] pMapFX;
2152         delete[] pMapFY;
2153 
2154         ReleaseAccess( pAcc );
2155         aOutBmp.ReleaseAccess( pWAcc );
2156 
2157         if( bRet )
2158         {
2159             ImplAdaptBitCount(aOutBmp);
2160             ImplAssignWithSize(aOutBmp);
2161         }
2162 
2163         if( !bRet )
2164             bRet = ImplScaleFast( scaleX, scaleY );
2165     }
2166 
2167     return bRet;
2168 }
2169 
2170 //-----------------------------------------------------------------------------------
2171 
2172 namespace
2173 {
2174     void ImplCalculateContributions(
2175         const sal_uInt32 aSourceSize,
2176         const sal_uInt32 aDestinationSize,
2177         sal_uInt32& aNumberOfContributions,
2178         double*& pWeights,
2179         sal_uInt32*& pPixels,
2180         sal_uInt32*& pCount,
2181         const Kernel& aKernel)
2182     {
2183         const double fSamplingRadius(aKernel.GetWidth());
2184         const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
2185         const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
2186         const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
2187 
2188         aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
2189         const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
2190         pWeights = new double[nAllocSize];
2191         pPixels = new sal_uInt32[nAllocSize];
2192         pCount = new sal_uInt32[aDestinationSize];
2193 
2194         for(sal_uInt32 i(0); i < aDestinationSize; i++)
2195         {
2196             const sal_uInt32 aIndex(i * aNumberOfContributions);
2197             const double aCenter(i / fScale);
2198             const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
2199             const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
2200             sal_uInt32 aCurrentCount(0);
2201 
2202             for(sal_Int32 j(aLeft); j <= aRight; j++)
2203             {
2204                 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
2205 
2206                 // Reduce calculations with ignoring weights of 0.0
2207                 if(fabs(aWeight) < 0.0001)
2208                 {
2209                     continue;
2210                 }
2211 
2212                 // Handling on edges
2213                 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
2214                 const sal_uInt32 nIndex(aIndex + aCurrentCount);
2215 
2216                 pWeights[nIndex] = aWeight;
2217                 pPixels[nIndex] = aPixelIndex;
2218 
2219                 aCurrentCount++;
2220             }
2221 
2222             pCount[i] = aCurrentCount;
2223         }
2224     }
2225 
2226     sal_Bool ImplScaleConvolutionHor(
2227         Bitmap& rSource,
2228         Bitmap& rTarget,
2229         const double& rScaleX,
2230         const Kernel& aKernel)
2231     {
2232         // Do horizontal filtering
2233         OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2234         const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2235         const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
2236 
2237         if(nWidth == nNewWidth)
2238         {
2239             return true;
2240         }
2241 
2242         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2243 
2244         if(pReadAcc)
2245         {
2246             double* pWeights = 0;
2247             sal_uInt32* pPixels = 0;
2248             sal_uInt32* pCount = 0;
2249             sal_uInt32 aNumberOfContributions(0);
2250 
2251             const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2252             ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2253             rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
2254             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2255             bool bResult(0 != pWriteAcc);
2256 
2257             if(bResult)
2258             {
2259                 for(sal_uInt32 y(0); y < nHeight; y++)
2260                 {
2261                     for(sal_uInt32 x(0); x < nNewWidth; x++)
2262                     {
2263                         const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
2264                         double aSum(0.0);
2265                         double aValueRed(0.0);
2266                         double aValueGreen(0.0);
2267                         double aValueBlue(0.0);
2268 
2269                         for(sal_uInt32 j(0); j < pCount[x]; j++)
2270                         {
2271                             const sal_uInt32 aIndex(aBaseIndex + j);
2272                             const double aWeight(pWeights[aIndex]);
2273                             BitmapColor aColor;
2274 
2275                             aSum += aWeight;
2276 
2277                             if(pReadAcc->HasPalette())
2278                             {
2279                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
2280                             }
2281                             else
2282                             {
2283                                 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
2284                             }
2285 
2286                             aValueRed += aWeight * aColor.GetRed();
2287                             aValueGreen += aWeight * aColor.GetGreen();
2288                             aValueBlue += aWeight * aColor.GetBlue();
2289                         }
2290 
2291                         const BitmapColor aResultColor(
2292                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2293                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2294                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2295 
2296                         pWriteAcc->SetPixel(y, x, aResultColor);
2297                     }
2298                 }
2299 
2300                 rTarget.ReleaseAccess(pWriteAcc);
2301             }
2302 
2303             rSource.ReleaseAccess(pReadAcc);
2304             delete[] pWeights;
2305             delete[] pCount;
2306             delete[] pPixels;
2307 
2308             if(bResult)
2309             {
2310                 return true;
2311             }
2312         }
2313 
2314         return false;
2315     }
2316 
2317     bool ImplScaleConvolutionVer(
2318         Bitmap& rSource,
2319         Bitmap& rTarget,
2320         const double& rScaleY,
2321         const Kernel& aKernel)
2322     {
2323         // Do vertical filtering
2324         OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2325         const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2326         const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
2327 
2328         if(nHeight == nNewHeight)
2329         {
2330             return true;
2331         }
2332 
2333         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2334 
2335         if(pReadAcc)
2336         {
2337             double* pWeights = 0;
2338             sal_uInt32* pPixels = 0;
2339             sal_uInt32* pCount = 0;
2340             sal_uInt32 aNumberOfContributions(0);
2341 
2342             const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2343             ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2344             rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
2345             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2346             bool bResult(0 != pWriteAcc);
2347 
2348             if(pWriteAcc)
2349             {
2350                 for(sal_uInt32 x(0); x < nWidth; x++)
2351                 {
2352                     for(sal_uInt32 y(0); y < nNewHeight; y++)
2353                     {
2354                         const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
2355                         double aSum(0.0);
2356                         double aValueRed(0.0);
2357                         double aValueGreen(0.0);
2358                         double aValueBlue(0.0);
2359 
2360                         for(sal_uInt32 j(0); j < pCount[y]; j++)
2361                         {
2362                             const sal_uInt32 aIndex(aBaseIndex + j);
2363                             const double aWeight(pWeights[aIndex]);
2364                             BitmapColor aColor;
2365 
2366                             aSum += aWeight;
2367 
2368                             if(pReadAcc->HasPalette())
2369                             {
2370                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
2371                             }
2372                             else
2373                             {
2374                                 aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
2375                             }
2376 
2377                             aValueRed += aWeight * aColor.GetRed();
2378                             aValueGreen += aWeight * aColor.GetGreen();
2379                             aValueBlue += aWeight * aColor.GetBlue();
2380                         }
2381 
2382                         const BitmapColor aResultColor(
2383                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2384                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2385                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2386 
2387                         if(pWriteAcc->HasPalette())
2388                         {
2389                             pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
2390                         }
2391                         else
2392                         {
2393                             pWriteAcc->SetPixel(y, x, aResultColor);
2394                         }
2395                     }
2396                 }
2397             }
2398 
2399             rTarget.ReleaseAccess(pWriteAcc);
2400             rSource.ReleaseAccess(pReadAcc);
2401 
2402             delete[] pWeights;
2403             delete[] pCount;
2404             delete[] pPixels;
2405 
2406             if(bResult)
2407             {
2408                 return true;
2409             }
2410         }
2411 
2412         return false;
2413     }
2414 }
2415 
2416 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and
2417 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see
2418 // bugzilla task for deitails) Thanks!
2419 sal_Bool Bitmap::ImplScaleConvolution(
2420     const double& rScaleX,
2421     const double& rScaleY,
2422     const Kernel& aKernel)
2423 {
2424     const bool bMirrorHor(rScaleX < 0.0);
2425     const bool bMirrorVer(rScaleY < 0.0);
2426     const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
2427     const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
2428     const sal_uInt32 nWidth(GetSizePixel().Width());
2429     const sal_uInt32 nHeight(GetSizePixel().Height());
2430     const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
2431     const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
2432     const bool bScaleHor(nWidth != nNewWidth);
2433     const bool bScaleVer(nHeight != nNewHeight);
2434     const bool bMirror(bMirrorHor || bMirrorVer);
2435 
2436     if(!bMirror && !bScaleHor && !bScaleVer)
2437     {
2438         return true;
2439     }
2440 
2441     bool bResult(true);
2442     sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
2443     bool bMirrorAfter(false);
2444 
2445     if(bMirror)
2446     {
2447         if(bMirrorHor)
2448         {
2449             nMirrorFlags |= BMP_MIRROR_HORZ;
2450         }
2451 
2452         if(bMirrorVer)
2453         {
2454             nMirrorFlags |= BMP_MIRROR_VERT;
2455         }
2456 
2457         const sal_uInt32 nStartSize(nWidth * nHeight);
2458         const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
2459 
2460         bMirrorAfter = nStartSize > nEndSize;
2461 
2462         if(!bMirrorAfter)
2463         {
2464             bResult = Mirror(nMirrorFlags);
2465         }
2466     }
2467 
2468     Bitmap aResult;
2469 
2470     if(bResult)
2471     {
2472         const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
2473         const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
2474 
2475         if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2476         {
2477             if(bScaleHor)
2478             {
2479                 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel);
2480             }
2481 
2482             if(bResult && bScaleVer)
2483             {
2484                 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel);
2485             }
2486         }
2487         else
2488         {
2489             if(bScaleVer)
2490             {
2491                 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel);
2492             }
2493 
2494             if(bResult && bScaleHor)
2495             {
2496                 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel);
2497             }
2498         }
2499     }
2500 
2501     if(bResult && bMirrorAfter)
2502     {
2503         bResult = aResult.Mirror(nMirrorFlags);
2504     }
2505 
2506     if(bResult)
2507     {
2508         ImplAdaptBitCount(aResult);
2509         *this = aResult;
2510     }
2511 
2512     return bResult;
2513 }
2514 
2515 // ------------------------------------------------------------------------
2516 
2517 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2518 {
2519     sal_Bool bRet = sal_False;
2520 
2521     const Size aSizePix( GetSizePixel() );
2522 
2523     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2524         bRet = sal_True;
2525     else if( nDitherFlags & BMP_DITHER_MATRIX )
2526         bRet = ImplDitherMatrix();
2527     else if( nDitherFlags & BMP_DITHER_FLOYD )
2528         bRet = ImplDitherFloyd();
2529     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2530         bRet = ImplDitherFloyd16();
2531 
2532     return bRet;
2533 }
2534 
2535 // ------------------------------------------------------------------------
2536 
2537 sal_Bool Bitmap::ImplDitherMatrix()
2538 {
2539     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2540     Bitmap              aNewBmp( GetSizePixel(), 8 );
2541     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2542     sal_Bool                bRet = sal_False;
2543 
2544     if( pReadAcc && pWriteAcc )
2545     {
2546         const sal_uLong nWidth = pReadAcc->Width();
2547         const sal_uLong nHeight = pReadAcc->Height();
2548         BitmapColor aIndex( (sal_uInt8) 0 );
2549 
2550         if( pReadAcc->HasPalette() )
2551         {
2552             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2553             {
2554                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2555                 {
2556                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2557                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2558                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2559                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2560                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2561 
2562                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2563                     pWriteAcc->SetPixel( nY, nX, aIndex );
2564                 }
2565             }
2566         }
2567         else
2568         {
2569             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2570             {
2571                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2572                 {
2573                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
2574                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2575                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2576                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2577                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2578 
2579                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2580                     pWriteAcc->SetPixel( nY, nX, aIndex );
2581                 }
2582             }
2583         }
2584 
2585         bRet = sal_True;
2586     }
2587 
2588     ReleaseAccess( pReadAcc );
2589     aNewBmp.ReleaseAccess( pWriteAcc );
2590 
2591     if( bRet )
2592     {
2593         const MapMode   aMap( maPrefMapMode );
2594         const Size      aSize( maPrefSize );
2595 
2596         *this = aNewBmp;
2597 
2598         maPrefMapMode = aMap;
2599         maPrefSize = aSize;
2600     }
2601 
2602     return bRet;
2603 }
2604 
2605 // ------------------------------------------------------------------------
2606 
2607 sal_Bool Bitmap::ImplDitherFloyd()
2608 {
2609     const Size  aSize( GetSizePixel() );
2610     sal_Bool        bRet = sal_False;
2611 
2612     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2613     {
2614         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2615         Bitmap              aNewBmp( GetSizePixel(), 8 );
2616         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2617 
2618         if( pReadAcc && pWriteAcc )
2619         {
2620             BitmapColor aColor;
2621             long        nWidth = pReadAcc->Width();
2622             long        nWidth1 = nWidth - 1L;
2623             long        nHeight = pReadAcc->Height();
2624             long        nX;
2625             long        nW = nWidth * 3L;
2626             long        nW2 = nW - 3L;
2627             long        nRErr, nGErr, nBErr;
2628             long        nRC, nGC, nBC;
2629             long        nTemp;
2630             long        nZ;
2631             long*       p1 = new long[ nW ];
2632             long*       p2 = new long[ nW ];
2633             long*       p1T = p1;
2634             long*       p2T = p2;
2635             long*       pTmp;
2636             sal_Bool        bPal = pReadAcc->HasPalette();
2637 
2638             pTmp = p2T;
2639 
2640             if( bPal )
2641             {
2642                 for( nZ = 0; nZ < nWidth; nZ++ )
2643                 {
2644                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2645 
2646                     *pTmp++ = (long) aColor.GetBlue() << 12;
2647                     *pTmp++ = (long) aColor.GetGreen() << 12;
2648                     *pTmp++ = (long) aColor.GetRed() << 12;
2649                 }
2650             }
2651             else
2652             {
2653                 for( nZ = 0; nZ < nWidth; nZ++ )
2654                 {
2655                     aColor = pReadAcc->GetPixel( 0, nZ );
2656 
2657                     *pTmp++ = (long) aColor.GetBlue() << 12;
2658                     *pTmp++ = (long) aColor.GetGreen() << 12;
2659                     *pTmp++ = (long) aColor.GetRed() << 12;
2660                 }
2661             }
2662 
2663             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2664             {
2665                 pTmp = p1T;
2666                 p1T = p2T;
2667                 p2T = pTmp;
2668 
2669                 if( nY < nHeight )
2670                 {
2671                     if( bPal )
2672                     {
2673                         for( nZ = 0; nZ < nWidth; nZ++ )
2674                         {
2675                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2676 
2677                             *pTmp++ = (long) aColor.GetBlue() << 12;
2678                             *pTmp++ = (long) aColor.GetGreen() << 12;
2679                             *pTmp++ = (long) aColor.GetRed() << 12;
2680                         }
2681                     }
2682                     else
2683                     {
2684                         for( nZ = 0; nZ < nWidth; nZ++ )
2685                         {
2686                             aColor = pReadAcc->GetPixel( nY, nZ );
2687 
2688                             *pTmp++ = (long) aColor.GetBlue() << 12;
2689                             *pTmp++ = (long) aColor.GetGreen() << 12;
2690                             *pTmp++ = (long) aColor.GetRed() << 12;
2691                         }
2692                     }
2693                 }
2694 
2695                 // erstes Pixel gesondert betrachten
2696                 nX = 0;
2697                 CALC_ERRORS;
2698                 CALC_TABLES7;
2699                 nX -= 5;
2700                 CALC_TABLES5;
2701                 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2702 
2703                 // mittlere Pixel ueber Schleife
2704                 long nXAcc;
2705                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2706                 {
2707                     CALC_ERRORS;
2708                     CALC_TABLES7;
2709                     nX -= 8;
2710                     CALC_TABLES3;
2711                     CALC_TABLES5;
2712                     pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2713                 }
2714 
2715                 // letztes Pixel gesondert betrachten
2716                 CALC_ERRORS;
2717                 nX -= 5;
2718                 CALC_TABLES3;
2719                 CALC_TABLES5;
2720                 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2721             }
2722 
2723             delete[] p1;
2724             delete[] p2;
2725             bRet = sal_True;
2726         }
2727 
2728         ReleaseAccess( pReadAcc );
2729         aNewBmp.ReleaseAccess( pWriteAcc );
2730 
2731         if( bRet )
2732         {
2733             const MapMode   aMap( maPrefMapMode );
2734             const Size      aPrefSize( maPrefSize );
2735 
2736             *this = aNewBmp;
2737 
2738             maPrefMapMode = aMap;
2739             maPrefSize = aPrefSize;
2740         }
2741     }
2742 
2743     return bRet;
2744 }
2745 
2746 // ------------------------------------------------------------------------
2747 
2748 sal_Bool Bitmap::ImplDitherFloyd16()
2749 {
2750     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2751     Bitmap              aNewBmp( GetSizePixel(), 24 );
2752     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2753     sal_Bool                bRet = sal_False;
2754 
2755     if( pReadAcc && pWriteAcc )
2756     {
2757         const long      nWidth = pWriteAcc->Width();
2758         const long      nWidth1 = nWidth - 1L;
2759         const long      nHeight = pWriteAcc->Height();
2760         BitmapColor     aColor;
2761         BitmapColor     aBestCol;
2762         ImpErrorQuad    aErrQuad;
2763         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
2764         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
2765         ImpErrorQuad*   pQLine1 = pErrQuad1;
2766         ImpErrorQuad*   pQLine2 = 0;
2767         long            nX, nY;
2768         long            nYTmp = 0L;
2769         sal_Bool            bQ1 = sal_True;
2770 
2771         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2772             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2773                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2774 
2775         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2776         {
2777             // erstes ZeilenPixel
2778             aBestCol = pQLine1[ 0 ].ImplGetColor();
2779             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2780             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2781             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2782             pWriteAcc->SetPixel( nY, 0, aBestCol );
2783 
2784             for( nX = 1L; nX < nWidth1; nX++ )
2785             {
2786                 aColor = pQLine1[ nX ].ImplGetColor();
2787                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2788                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2789                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2790                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2791                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2792                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2793                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2794                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2795                 pWriteAcc->SetPixel( nY, nX, aBestCol );
2796             }
2797 
2798             // letztes ZeilenPixel
2799             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2800             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2801             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2802             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2803             pWriteAcc->SetPixel( nY, nX, aBestCol );
2804 
2805             // Zeilenpuffer neu fuellen/kopieren
2806             pQLine1 = pQLine2;
2807             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2808 
2809             if( nYTmp < nHeight )
2810                 for( nX = 0L; nX < nWidth; nX++ )
2811                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2812         }
2813 
2814         // Zeilenpuffer zerstoeren
2815         delete[] pErrQuad1;
2816         delete[] pErrQuad2;
2817         bRet = sal_True;
2818     }
2819 
2820     ReleaseAccess( pReadAcc );
2821     aNewBmp.ReleaseAccess( pWriteAcc );
2822 
2823     if( bRet )
2824     {
2825         const MapMode   aMap( maPrefMapMode );
2826         const Size      aSize( maPrefSize );
2827 
2828         *this = aNewBmp;
2829 
2830         maPrefMapMode = aMap;
2831         maPrefSize = aSize;
2832     }
2833 
2834     return bRet;
2835 }
2836 
2837 // ------------------------------------------------------------------------
2838 
2839 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2840 {
2841     sal_Bool bRet;
2842 
2843     if( GetColorCount() <= (sal_uLong) nColorCount )
2844         bRet = sal_True;
2845     else if( nColorCount )
2846     {
2847         if( BMP_REDUCE_SIMPLE == eReduce )
2848             bRet = ImplReduceSimple( nColorCount );
2849         else if( BMP_REDUCE_POPULAR == eReduce )
2850             bRet = ImplReducePopular( nColorCount );
2851         else
2852             bRet = ImplReduceMedian( nColorCount );
2853     }
2854     else
2855         bRet = sal_False;
2856 
2857     return bRet;
2858 }
2859 
2860 // ------------------------------------------------------------------------
2861 
2862 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2863 {
2864     Bitmap              aNewBmp;
2865     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2866     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
2867     sal_uInt16              nBitCount;
2868     sal_Bool                bRet = sal_False;
2869 
2870     if( nColCount <= 2 )
2871         nBitCount = 1;
2872     else if( nColCount <= 16 )
2873         nBitCount = 4;
2874     else
2875         nBitCount = 8;
2876 
2877     if( pRAcc )
2878     {
2879         Octree                  aOct( *pRAcc, nColCount );
2880         const BitmapPalette&    rPal = aOct.GetPalette();
2881         BitmapWriteAccess*      pWAcc;
2882 
2883         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2884         pWAcc = aNewBmp.AcquireWriteAccess();
2885 
2886         if( pWAcc )
2887         {
2888             const long nWidth = pRAcc->Width();
2889             const long nHeight = pRAcc->Height();
2890 
2891             if( pRAcc->HasPalette() )
2892             {
2893                 for( long nY = 0L; nY < nHeight; nY++ )
2894                     for( long nX =0L; nX < nWidth; nX++ )
2895                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2896             }
2897             else
2898             {
2899                 for( long nY = 0L; nY < nHeight; nY++ )
2900                     for( long nX =0L; nX < nWidth; nX++ )
2901                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2902             }
2903 
2904             aNewBmp.ReleaseAccess( pWAcc );
2905             bRet = sal_True;
2906         }
2907 
2908         ReleaseAccess( pRAcc );
2909     }
2910 
2911     if( bRet )
2912     {
2913         const MapMode   aMap( maPrefMapMode );
2914         const Size      aSize( maPrefSize );
2915 
2916         *this = aNewBmp;
2917         maPrefMapMode = aMap;
2918         maPrefSize = aSize;
2919     }
2920 
2921     return bRet;
2922 }
2923 
2924 // ------------------------------------------------------------------------
2925 
2926 struct PopularColorCount
2927 {
2928     sal_uInt32  mnIndex;
2929     sal_uInt32  mnCount;
2930 };
2931 
2932 // ------------------------------------------------------------------------
2933 
2934 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2935 {
2936     int nRet;
2937 
2938     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2939         nRet = 1;
2940     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2941         nRet = 0;
2942     else
2943         nRet = -1;
2944 
2945     return nRet;
2946 }
2947 
2948 // ------------------------------------------------------------------------
2949 
2950 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2951 {
2952     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2953     sal_uInt16              nBitCount;
2954     sal_Bool                bRet = sal_False;
2955 
2956     if( nColCount > 256 )
2957         nColCount = 256;
2958 
2959     if( nColCount < 17 )
2960         nBitCount = 4;
2961     else
2962         nBitCount = 8;
2963 
2964     if( pRAcc )
2965     {
2966         const sal_uInt32    nValidBits = 4;
2967         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
2968         const sal_uInt32    nLeftShiftBits1 = nValidBits;
2969         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
2970         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
2971         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
2972         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2973         const long          nWidth = pRAcc->Width();
2974         const long          nHeight = pRAcc->Height();
2975         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
2976         long                nX, nY, nR, nG, nB, nIndex;
2977 
2978         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
2979 
2980         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2981         {
2982             for( nG = 0; nG < 256; nG += nColorOffset )
2983             {
2984                 for( nB = 0; nB < 256; nB += nColorOffset )
2985                 {
2986                     pCountTable[ nIndex ].mnIndex = nIndex;
2987                     nIndex++;
2988                 }
2989             }
2990         }
2991 
2992         if( pRAcc->HasPalette() )
2993         {
2994             for( nY = 0L; nY < nHeight; nY++ )
2995             {
2996                 for( nX = 0L; nX < nWidth; nX++ )
2997                 {
2998                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2999                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3000                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3001                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3002                 }
3003             }
3004         }
3005         else
3006         {
3007             for( nY = 0L; nY < nHeight; nY++ )
3008             {
3009                 for( nX = 0L; nX < nWidth; nX++ )
3010                 {
3011                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3012                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3013                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3014                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3015                 }
3016             }
3017         }
3018 
3019         BitmapPalette aNewPal( nColCount );
3020 
3021         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3022 
3023         for( sal_uInt16 n = 0; n < nColCount; n++ )
3024         {
3025             const PopularColorCount& rPop = pCountTable[ n ];
3026             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3027                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3028                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3029         }
3030 
3031         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3032         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3033 
3034         if( pWAcc )
3035         {
3036             BitmapColor aDstCol( (sal_uInt8) 0 );
3037             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
3038 
3039             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3040                 for( nG = 0; nG < 256; nG += nColorOffset )
3041                     for( nB = 0; nB < 256; nB += nColorOffset )
3042                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3043 
3044             if( pRAcc->HasPalette() )
3045             {
3046                 for( nY = 0L; nY < nHeight; nY++ )
3047                 {
3048                     for( nX = 0L; nX < nWidth; nX++ )
3049                     {
3050                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3051                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3052                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3053                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3054                         pWAcc->SetPixel( nY, nX, aDstCol );
3055                     }
3056                 }
3057             }
3058             else
3059             {
3060                 for( nY = 0L; nY < nHeight; nY++ )
3061                 {
3062                     for( nX = 0L; nX < nWidth; nX++ )
3063                     {
3064                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3065                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3066                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3067                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3068                         pWAcc->SetPixel( nY, nX, aDstCol );
3069                     }
3070                 }
3071             }
3072 
3073             delete[] pIndexMap;
3074             aNewBmp.ReleaseAccess( pWAcc );
3075             bRet = sal_True;
3076         }
3077 
3078         delete[] pCountTable;
3079         ReleaseAccess( pRAcc );
3080 
3081         if( bRet )
3082         {
3083             const MapMode   aMap( maPrefMapMode );
3084             const Size      aSize( maPrefSize );
3085 
3086             *this = aNewBmp;
3087             maPrefMapMode = aMap;
3088             maPrefSize = aSize;
3089         }
3090     }
3091 
3092     return bRet;
3093 }
3094 
3095 // ------------------------------------------------------------------------
3096 
3097 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3098 {
3099     BitmapReadAccess*   pRAcc = AcquireReadAccess();
3100     sal_uInt16              nBitCount;
3101     sal_Bool                bRet = sal_False;
3102 
3103     if( nColCount < 17 )
3104         nBitCount = 4;
3105     else if( nColCount < 257 )
3106         nBitCount = 8;
3107     else
3108     {
3109         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3110         nBitCount = 8;
3111         nColCount = 256;
3112     }
3113 
3114     if( pRAcc )
3115     {
3116         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
3117         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3118 
3119         if( pWAcc )
3120         {
3121             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
3122             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3123             const long  nWidth = pWAcc->Width();
3124             const long  nHeight = pWAcc->Height();
3125             long        nIndex = 0L;
3126 
3127             memset( (HPBYTE) pColBuf, 0, nSize );
3128 
3129             // create Buffer
3130             if( pRAcc->HasPalette() )
3131             {
3132                 for( long nY = 0L; nY < nHeight; nY++ )
3133                 {
3134                     for( long nX = 0L; nX < nWidth; nX++ )
3135                     {
3136                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3137                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3138                     }
3139                 }
3140             }
3141             else
3142             {
3143                 for( long nY = 0L; nY < nHeight; nY++ )
3144                 {
3145                     for( long nX = 0L; nX < nWidth; nX++ )
3146                     {
3147                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3148                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3149                     }
3150                 }
3151             }
3152 
3153             // create palette via median cut
3154             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3155             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3156                            nColCount, nWidth * nHeight, nIndex );
3157 
3158             // do mapping of colors to palette
3159             InverseColorMap aMap( aPal );
3160             pWAcc->SetPalette( aPal );
3161             for( long nY = 0L; nY < nHeight; nY++ )
3162                 for( long nX = 0L; nX < nWidth; nX++ )
3163                     pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3164 
3165             rtl_freeMemory( pColBuf );
3166             aNewBmp.ReleaseAccess( pWAcc );
3167             bRet = sal_True;
3168         }
3169 
3170         ReleaseAccess( pRAcc );
3171 
3172         if( bRet )
3173         {
3174             const MapMode   aMap( maPrefMapMode );
3175             const Size      aSize( maPrefSize );
3176 
3177             *this = aNewBmp;
3178             maPrefMapMode = aMap;
3179             maPrefSize = aSize;
3180         }
3181     }
3182 
3183     return bRet;
3184 }
3185 
3186 // ------------------------------------------------------------------------
3187 
3188 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3189                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3190                             long nColors, long nPixels, long& rIndex )
3191 {
3192     if( !nPixels )
3193         return;
3194 
3195     BitmapColor aCol;
3196     const long  nRLen = nR2 - nR1;
3197     const long  nGLen = nG2 - nG1;
3198     const long  nBLen = nB2 - nB1;
3199     long        nR, nG, nB;
3200     sal_uLong*      pBuf = pColBuf;
3201 
3202     if( !nRLen && !nGLen && !nBLen )
3203     {
3204         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3205         {
3206             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3207             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3208             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3209             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3210         }
3211     }
3212     else
3213     {
3214         if( 1 == nColors || 1 == nPixels )
3215         {
3216             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3217 
3218             for( nR = nR1; nR <= nR2; nR++ )
3219             {
3220                 for( nG = nG1; nG <= nG2; nG++ )
3221                 {
3222                     for( nB = nB1; nB <= nB2; nB++ )
3223                     {
3224                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3225 
3226                         if( nPixSum )
3227                         {
3228                             nRSum += nR * nPixSum;
3229                             nGSum += nG * nPixSum;
3230                             nBSum += nB * nPixSum;
3231                         }
3232                     }
3233                 }
3234             }
3235 
3236             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3237             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3238             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3239             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3240         }
3241         else
3242         {
3243             const long  nTest = ( nPixels >> 1 );
3244             long        nPixOld = 0;
3245             long        nPixNew = 0;
3246 
3247             if( nBLen > nGLen && nBLen > nRLen )
3248             {
3249                 nB = nB1 - 1;
3250 
3251                 while( nPixNew < nTest )
3252                 {
3253                     nB++, nPixOld = nPixNew;
3254                     for( nR = nR1; nR <= nR2; nR++ )
3255                         for( nG = nG1; nG <= nG2; nG++ )
3256                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3257                 }
3258 
3259                 if( nB < nB2 )
3260                 {
3261                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3262                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3263                 }
3264                 else
3265                 {
3266                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3267                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3268                 }
3269             }
3270             else if( nGLen > nRLen )
3271             {
3272                 nG = nG1 - 1;
3273 
3274                 while( nPixNew < nTest )
3275                 {
3276                     nG++, nPixOld = nPixNew;
3277                     for( nR = nR1; nR <= nR2; nR++ )
3278                         for( nB = nB1; nB <= nB2; nB++ )
3279                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3280                 }
3281 
3282                 if( nG < nG2 )
3283                 {
3284                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3285                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3286                 }
3287                 else
3288                 {
3289                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3290                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3291                 }
3292             }
3293             else
3294             {
3295                 nR = nR1 - 1;
3296 
3297                 while( nPixNew < nTest )
3298                 {
3299                     nR++, nPixOld = nPixNew;
3300                     for( nG = nG1; nG <= nG2; nG++ )
3301                         for( nB = nB1; nB <= nB2; nB++ )
3302                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3303                 }
3304 
3305                 if( nR < nR2 )
3306                 {
3307                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3308                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3309                 }
3310                 else
3311                 {
3312                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3313                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3314                 }
3315             }
3316         }
3317     }
3318 }
3319 
3320 // ------------------------------------------------------------------------
3321 
3322 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3323 {
3324     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3325 }
3326 
3327 // ------------------------------------------------------------------------
3328 
3329 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3330 {
3331     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3332 }
3333 
3334 // ------------------------------------------------------------------------
3335 
3336 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3337                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3338                      double fGamma, sal_Bool bInvert )
3339 {
3340     sal_Bool bRet = sal_False;
3341 
3342     // nothing to do => return quickly
3343     if( !nLuminancePercent && !nContrastPercent &&
3344         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3345         ( fGamma == 1.0 ) && !bInvert )
3346     {
3347         bRet = sal_True;
3348     }
3349     else
3350     {
3351         BitmapWriteAccess* pAcc = AcquireWriteAccess();
3352 
3353         if( pAcc )
3354         {
3355             BitmapColor     aCol;
3356             const long      nW = pAcc->Width();
3357             const long      nH = pAcc->Height();
3358             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
3359             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
3360             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
3361             long            nX, nY;
3362             double          fM, fROff, fGOff, fBOff, fOff;
3363 
3364             // calculate slope
3365             if( nContrastPercent >= 0 )
3366                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3367             else
3368                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3369 
3370             // total offset = luminance offset + contrast offset
3371             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3372 
3373             // channel offset = channel offset  + total offset
3374             fROff = nChannelRPercent * 2.55 + fOff;
3375             fGOff = nChannelGPercent * 2.55 + fOff;
3376             fBOff = nChannelBPercent * 2.55 + fOff;
3377 
3378             // calculate gamma value
3379             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3380             const sal_Bool bGamma = ( fGamma != 1.0 );
3381 
3382             // create mapping table
3383             for( nX = 0L; nX < 256L; nX++ )
3384             {
3385                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3386                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3387                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3388 
3389                 if( bGamma )
3390                 {
3391                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3392                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3393                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3394                 }
3395 
3396                 if( bInvert )
3397                 {
3398                     cMapR[ nX ] = ~cMapR[ nX ];
3399                     cMapG[ nX ] = ~cMapG[ nX ];
3400                     cMapB[ nX ] = ~cMapB[ nX ];
3401                 }
3402             }
3403 
3404             // do modifying
3405             if( pAcc->HasPalette() )
3406             {
3407                 BitmapColor aNewCol;
3408 
3409                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3410                 {
3411                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3412                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3413                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3414                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3415                     pAcc->SetPaletteColor( i, aNewCol );
3416                 }
3417             }
3418             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3419             {
3420                 for( nY = 0L; nY < nH; nY++ )
3421                 {
3422                     Scanline pScan = pAcc->GetScanline( nY );
3423 
3424                     for( nX = 0L; nX < nW; nX++ )
3425                     {
3426                         *pScan = cMapB[ *pScan ]; pScan++;
3427                         *pScan = cMapG[ *pScan ]; pScan++;
3428                         *pScan = cMapR[ *pScan ]; pScan++;
3429                     }
3430                 }
3431             }
3432             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3433             {
3434                 for( nY = 0L; nY < nH; nY++ )
3435                 {
3436                     Scanline pScan = pAcc->GetScanline( nY );
3437 
3438                     for( nX = 0L; nX < nW; nX++ )
3439                     {
3440                         *pScan = cMapR[ *pScan ]; pScan++;
3441                         *pScan = cMapG[ *pScan ]; pScan++;
3442                         *pScan = cMapB[ *pScan ]; pScan++;
3443                     }
3444                 }
3445             }
3446             else
3447             {
3448                 for( nY = 0L; nY < nH; nY++ )
3449                 {
3450                     for( nX = 0L; nX < nW; nX++ )
3451                     {
3452                         aCol = pAcc->GetPixel( nY, nX );
3453                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
3454                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3455                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3456                         pAcc->SetPixel( nY, nX, aCol );
3457                     }
3458                 }
3459             }
3460 
3461             delete[] cMapR;
3462             delete[] cMapG;
3463             delete[] cMapB;
3464             ReleaseAccess( pAcc );
3465             bRet = sal_True;
3466         }
3467     }
3468 
3469     return bRet;
3470 }
3471