xref: /AOO41X/main/vcl/source/gdi/bitmap3.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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     bool bRetval(false);
910 
911 #ifdef DBG_UTIL
912     // #121233# allow to test the different scalers in debug build with source
913     // level debugger (change nNumber to desired action)
914     static sal_uInt16 nNumber(0);
915     const sal_uInt16 nStartCount(GetBitCount());
916 
917     switch(nNumber)
918     {
919         case 0 : break;
920         case 1: nScaleFlag = BMP_SCALE_FAST; break;
921         case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break;
922         case 3: nScaleFlag = BMP_SCALE_SUPER; break;
923         case 4: nScaleFlag = BMP_SCALE_LANCZOS; break;
924         case 5: nScaleFlag = BMP_SCALE_BICUBIC; break;
925         case 6: nScaleFlag = BMP_SCALE_BILINEAR; break;
926         case 7: nScaleFlag = BMP_SCALE_BOX; break;
927         case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break;
928         case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break;
929     }
930 #endif // DBG_UTIL
931 
932     if(basegfx::fTools::equalZero(rScaleX) && basegfx::fTools::equalZero(rScaleY))
933     {
934         // no scale
935         bRetval = true;
936     }
937     else
938     {
939         if(BMP_SCALE_BESTQUALITY == nScaleFlag)
940         {
941             // Use LANCZOS when best quality is requested
942             nScaleFlag = BMP_SCALE_LANCZOS;
943         }
944         else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag)
945         {
946             // Use BMP_SCALE_SUPER when speed is requested, but not worst quality
947             nScaleFlag = BMP_SCALE_SUPER;
948         }
949 
950         switch(nScaleFlag)
951         {
952             default:
953             case BMP_SCALE_NONE :
954             {
955                 bRetval = false;
956                 break;
957             }
958             case BMP_SCALE_FAST :
959             {
960                 bRetval = ImplScaleFast( rScaleX, rScaleY );
961                 break;
962             }
963             case BMP_SCALE_INTERPOLATE :
964             {
965                 bRetval = ImplScaleInterpolate( rScaleX, rScaleY );
966                 break;
967             }
968             case BMP_SCALE_SUPER :
969             {
970                 if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
971                 {
972                     // fallback to ImplScaleFast
973                     bRetval = ImplScaleFast( rScaleX, rScaleY );
974                 }
975                 else
976                 {
977                     // #121233# use method from symphony
978                     bRetval = ImplScaleSuper( rScaleX, rScaleY );
979                 }
980                 break;
981             }
982             case BMP_SCALE_LANCZOS :
983             {
984                 const Lanczos3Kernel kernel;
985 
986                 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel);
987                 break;
988             }
989             case BMP_SCALE_BICUBIC :
990             {
991                 const BicubicKernel kernel;
992 
993                 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
994                 break;
995             }
996             case BMP_SCALE_BILINEAR :
997             {
998                 const BilinearKernel kernel;
999 
1000                 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
1001                 break;
1002             }
1003             case BMP_SCALE_BOX :
1004             {
1005                 const BoxKernel kernel;
1006 
1007                 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
1008                 break;
1009             }
1010         }
1011     }
1012 
1013 #ifdef DBG_UTIL
1014     if(bRetval && nStartCount != GetBitCount())
1015     {
1016         OSL_ENSURE(false, "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
1017     }
1018 #endif
1019 
1020     return bRetval;
1021 }
1022 
1023 // ------------------------------------------------------------------------
1024 
1025 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
1026 {
1027     const Size  aSize( GetSizePixel() );
1028     sal_Bool        bRet;
1029 
1030     if( aSize.Width() && aSize.Height() )
1031     {
1032         bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
1033                       (double) rNewSize.Height() / aSize.Height(),
1034                       nScaleFlag );
1035     }
1036     else
1037         bRet = sal_True;
1038 
1039     return bRet;
1040 }
1041 
1042 // ------------------------------------------------------------------------
1043 
1044 void Bitmap::AdaptBitCount(Bitmap& rNew) const
1045 {
1046     ImplAdaptBitCount(rNew);
1047 }
1048 
1049 // ------------------------------------------------------------------------
1050 
1051 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const
1052 {
1053     // aNew is the result of some operation; adapt it's BitCount to the original (this)
1054     if(GetBitCount() != rNew.GetBitCount())
1055     {
1056         switch(GetBitCount())
1057         {
1058             case 1:
1059             {
1060                 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD);
1061                 break;
1062             }
1063             case 4:
1064             {
1065                 if(HasGreyPalette())
1066                 {
1067                     rNew.Convert(BMP_CONVERSION_4BIT_GREYS);
1068                 }
1069                 else
1070                 {
1071                     rNew.Convert(BMP_CONVERSION_4BIT_COLORS);
1072                 }
1073                 break;
1074             }
1075             case 8:
1076             {
1077                 if(HasGreyPalette())
1078                 {
1079                     rNew.Convert(BMP_CONVERSION_8BIT_GREYS);
1080                 }
1081                 else
1082                 {
1083                     rNew.Convert(BMP_CONVERSION_8BIT_COLORS);
1084                 }
1085                 break;
1086             }
1087             case 24:
1088             {
1089                 rNew.Convert(BMP_CONVERSION_24BIT);
1090                 break;
1091             }
1092             default:
1093             {
1094                 OSL_ENSURE(false, "BitDepth adaption failed (!)");
1095                 break;
1096             }
1097         }
1098     }
1099 }
1100 
1101 // ------------------------------------------------------------------------
1102 
1103 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
1104 {
1105     const Size  aSizePix( GetSizePixel() );
1106     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1107     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1108     sal_Bool        bRet = sal_False;
1109 
1110     if( nNewWidth && nNewHeight )
1111     {
1112         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1113         if ( !pReadAcc )
1114             return sal_False;
1115 
1116         Bitmap              aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
1117         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1118 
1119         if( pWriteAcc )
1120         {
1121             const long  nScanlineSize = pWriteAcc->GetScanlineSize();
1122             const long  nNewWidth1 = nNewWidth - 1L;
1123             const long  nNewHeight1 = nNewHeight - 1L;
1124             const long  nWidth = pReadAcc->Width();
1125             const long  nHeight = pReadAcc->Height();
1126             long*       pLutX = new long[ nNewWidth ];
1127             long*       pLutY = new long[ nNewHeight ];
1128             long        nX, nY, nMapY, nActY = 0L;
1129 
1130             if( nNewWidth1 && nNewHeight1 )
1131             {
1132                 for( nX = 0L; nX < nNewWidth; nX++ )
1133                     pLutX[ nX ] = nX * nWidth / nNewWidth;
1134 
1135                 for( nY = 0L; nY < nNewHeight; nY++ )
1136                     pLutY[ nY ] = nY * nHeight / nNewHeight;
1137 
1138                 while( nActY < nNewHeight )
1139                 {
1140                     nMapY = pLutY[ nActY ];
1141 
1142                     for( nX = 0L; nX < nNewWidth; nX++ )
1143                         pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
1144 
1145                     while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
1146                     {
1147                         memcpy( pWriteAcc->GetScanline( nActY + 1L ),
1148                                  pWriteAcc->GetScanline( nActY ), nScanlineSize );
1149                         nActY++;
1150                     }
1151 
1152                     nActY++;
1153                 }
1154 
1155                 bRet = sal_True;
1156             }
1157 
1158             delete[] pLutX;
1159             delete[] pLutY;
1160         }
1161 
1162         ReleaseAccess( pReadAcc );
1163         aNewBmp.ReleaseAccess( pWriteAcc );
1164 
1165         if( bRet )
1166             ImplAssignWithSize( aNewBmp );
1167     }
1168 
1169     return bRet;
1170 }
1171 
1172 // ------------------------------------------------------------------------
1173 
1174 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1175 {
1176     const Size  aSizePix( GetSizePixel() );
1177     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1178     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1179     sal_Bool        bRet = sal_False;
1180 
1181     if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1182     {
1183         BitmapColor         aCol0;
1184         BitmapColor         aCol1;
1185         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1186         long                nWidth = pReadAcc->Width();
1187         long                nHeight = pReadAcc->Height();
1188         Bitmap              aNewBmp( Size( nNewWidth, nHeight ), 24 );
1189         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1190         long*               pLutInt;
1191         long*               pLutFrac;
1192         long                nX, nY;
1193         long                lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1194         double              fTemp;
1195         long                nTemp;
1196 
1197         if( pReadAcc && pWriteAcc )
1198         {
1199             const long      nNewWidth1 = nNewWidth - 1L;
1200             const long      nWidth1 = pReadAcc->Width() - 1L;
1201             const double    fRevScaleX = (double) nWidth1 / nNewWidth1;
1202 
1203             pLutInt = new long[ nNewWidth ];
1204             pLutFrac = new long[ nNewWidth ];
1205 
1206             for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1207             {
1208                 fTemp = nX * fRevScaleX;
1209                 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1210                 fTemp -= pLutInt[ nX ];
1211                 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1212             }
1213 
1214             for( nY = 0L; nY < nHeight; nY++ )
1215             {
1216                 if( 1 == nWidth )
1217                 {
1218                     if( pReadAcc->HasPalette() )
1219                     {
1220                         aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1221                     }
1222                     else
1223                     {
1224                         aCol0 = pReadAcc->GetPixel( nY, 0 );
1225                     }
1226 
1227                     for( nX = 0L; nX < nNewWidth; nX++ )
1228                     {
1229                         pWriteAcc->SetPixel( nY, nX, aCol0 );
1230                     }
1231                 }
1232                 else
1233                 {
1234                     for( nX = 0L; nX < nNewWidth; nX++ )
1235                     {
1236                         nTemp = pLutInt[ nX ];
1237 
1238                         if( pReadAcc->HasPalette() )
1239                         {
1240                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1241                             aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1242                         }
1243                         else
1244                         {
1245                             aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1246                             aCol1 = pReadAcc->GetPixel( nY, nTemp );
1247                         }
1248 
1249                         nTemp = pLutFrac[ nX ];
1250 
1251                         lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1252                         lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1253                         lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1254 
1255                         aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1256                         aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1257                         aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1258 
1259                         pWriteAcc->SetPixel( nY, nX, aCol0 );
1260                     }
1261                 }
1262             }
1263 
1264             delete[] pLutInt;
1265             delete[] pLutFrac;
1266             bRet = sal_True;
1267         }
1268 
1269         ReleaseAccess( pReadAcc );
1270         aNewBmp.ReleaseAccess( pWriteAcc );
1271 
1272         if( bRet )
1273         {
1274             bRet = sal_False;
1275             const Bitmap aOriginal(*this);
1276             *this = aNewBmp;
1277             aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1278             pReadAcc = AcquireReadAccess();
1279             pWriteAcc = aNewBmp.AcquireWriteAccess();
1280 
1281             if( pReadAcc && pWriteAcc )
1282             {
1283                 const long      nNewHeight1 = nNewHeight - 1L;
1284                 const long      nHeight1 = pReadAcc->Height() - 1L;
1285                 const double    fRevScaleY = (double) nHeight1 / nNewHeight1;
1286 
1287                 pLutInt = new long[ nNewHeight ];
1288                 pLutFrac = new long[ nNewHeight ];
1289 
1290                 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1291                 {
1292                     fTemp = nY * fRevScaleY;
1293                     pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1294                     fTemp -= pLutInt[ nY ];
1295                     pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1296                 }
1297 
1298                 // after 1st step, bitmap *is* 24bit format (see above)
1299                 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1300 
1301                 for( nX = 0L; nX < nNewWidth; nX++ )
1302                 {
1303                     if( 1 == nHeight )
1304                     {
1305                         aCol0 = pReadAcc->GetPixel( 0, nX );
1306 
1307                         for( nY = 0L; nY < nNewHeight; nY++ )
1308                         {
1309                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1310                         }
1311                     }
1312                     else
1313                     {
1314                         for( nY = 0L; nY < nNewHeight; nY++ )
1315                         {
1316                             nTemp = pLutInt[ nY ];
1317 
1318                             aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1319                             aCol1 = pReadAcc->GetPixel( nTemp, nX );
1320 
1321                             nTemp = pLutFrac[ nY ];
1322 
1323                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1324                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1325                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1326 
1327                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1328                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1329                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1330 
1331                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1332                         }
1333                     }
1334                 }
1335 
1336                 delete[] pLutInt;
1337                 delete[] pLutFrac;
1338                 bRet = sal_True;
1339             }
1340 
1341             ReleaseAccess( pReadAcc );
1342             aNewBmp.ReleaseAccess( pWriteAcc );
1343 
1344             if( bRet )
1345             {
1346                 aOriginal.ImplAdaptBitCount(aNewBmp);
1347                 *this = aNewBmp;
1348             }
1349         }
1350     }
1351 
1352     if( !bRet )
1353     {
1354         bRet = ImplScaleFast( rScaleX, rScaleY );
1355     }
1356 
1357     return bRet;
1358 }
1359 
1360 // ------------------------------------------------------------------------
1361 // #121233# Added BMP_SCALE_SUPER from symphony code
1362 
1363 sal_Bool Bitmap::ImplScaleSuper(
1364     const double& rScaleX,
1365     const double& rScaleY )
1366 {
1367     const Size  aSizePix( GetSizePixel() );
1368     bool   bHMirr = ( rScaleX < 0 );
1369     bool   bVMirr = ( rScaleY < 0 );
1370     double scaleX = bHMirr ? -rScaleX : rScaleX;
1371     double scaleY = bVMirr ? -rScaleY : rScaleY;
1372     const long  nDstW = FRound( aSizePix.Width() * scaleX );
1373     const long  nDstH = FRound( aSizePix.Height() * scaleY );
1374     const double fScaleThresh = 0.6;
1375     bool bRet = false;
1376 
1377     if( ( nDstW > 1L ) && ( nDstH > 1L ) )
1378     {
1379         BitmapColor         aCol0, aCol1, aColRes;
1380         BitmapReadAccess*   pAcc = AcquireReadAccess();
1381         long                nW = pAcc->Width() ;
1382         long                nH = pAcc->Height() ;
1383         Bitmap              aOutBmp( Size( nDstW, nDstH ), 24 );
1384         BitmapWriteAccess*  pWAcc = aOutBmp.AcquireWriteAccess();
1385         long*               pMapIX = new long[ nDstW ];
1386         long*               pMapIY = new long[ nDstH ];
1387         long*               pMapFX = new long[ nDstW ];
1388         long*               pMapFY = new long[ nDstH ];
1389         long                nX, nY, nXDst, nYDst;;
1390         double              fTemp;
1391         long                nTemp , nTempX, nTempY, nTempFX, nTempFY;
1392         sal_uInt8           cR0, cG0, cB0, cR1, cG1, cB1;
1393         long                nStartX = 0 , nStartY = 0;
1394         long                nEndX = nDstW - 1L;
1395         long                nEndY = nDstH - 1L;
1396         long                nMax = 1 << 7L;
1397 
1398         if( pAcc && pWAcc )
1399         {
1400             const double    fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0;
1401             const double    fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0;
1402 
1403             // create horizontal mapping table
1404             for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ )
1405             {
1406                 fTemp = nX * fRevScaleX;
1407 
1408                 if( bHMirr )
1409                     fTemp = nTempX - fTemp;
1410 
1411                 pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1412             }
1413 
1414             // create vertical mapping table
1415             for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ )
1416             {
1417                 fTemp = nY * fRevScaleY;
1418 
1419                 if( bVMirr )
1420                     fTemp = nTempY - fTemp;
1421 
1422                 pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1423             }
1424 
1425             if( pAcc->HasPalette() )
1426             {
1427                 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1428                 {
1429                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1430                     {
1431                         Scanline pLine0, pLine1;
1432 
1433                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1434                         {
1435                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1436                             pLine0 = pAcc->GetScanline( nTempY );
1437                             pLine1 = pAcc->GetScanline( ++nTempY );
1438 
1439                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1440                             {
1441                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1442 
1443                                 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] );
1444                                 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1445                                 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] );
1446                                 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1447 
1448                                 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
1449                                 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
1450                                 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
1451 
1452                                 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
1453                                 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
1454                                 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
1455 
1456                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1457                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1458                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1459                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1460                             }
1461                         }
1462                     }
1463                     else
1464                     {
1465                         Scanline    pTmpY;
1466                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1467                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1468                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1469 
1470                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1471                         {
1472                             nTop = bVMirr ? ( nY + 1 ) : nY;
1473                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1474 
1475                             if( nY ==nEndY )
1476                             {
1477                                 nLineStart = pMapIY[ nY ];
1478                                 nLineRange = 0;
1479                             }
1480                             else
1481                             {
1482                                 nLineStart = pMapIY[ nTop ] ;
1483                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1484                             }
1485 
1486                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1487                             {
1488                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1489                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1490 
1491                                 if( nX == nEndX )
1492                                 {
1493                                     nRowStart = pMapIX[ nX ];
1494                                     nRowRange = 0;
1495                                 }
1496                                 else
1497                                 {
1498                                     nRowStart = pMapIX[ nLeft ];
1499                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1500                                 }
1501 
1502                                 nSumR = nSumG = nSumB = 0;
1503                                 nTotalWeightY = 0;
1504 
1505                                 for(int i = 0; i<= nLineRange; i++)
1506                                 {
1507                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1508                                     nSumRowR = nSumRowG = nSumRowB = 0;
1509                                     nTotalWeightX = 0;
1510 
1511                                     for(int j = 0; j <= nRowRange; j++)
1512                                     {
1513                                         const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] );
1514 
1515                                         if(nX == nEndX )
1516                                         {
1517                                             nSumRowB += rCol.GetBlue() << 7L;
1518                                             nSumRowG += rCol.GetGreen() << 7L;
1519                                             nSumRowR += rCol.GetRed() << 7L;
1520                                             nTotalWeightX += 1 << 7L;
1521                                         }
1522                                         else if( j == 0 )
1523                                         {
1524                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1525                                             nSumRowB += ( nWeightX *rCol.GetBlue()) ;
1526                                             nSumRowG += ( nWeightX *rCol.GetGreen()) ;
1527                                             nSumRowR += ( nWeightX *rCol.GetRed()) ;
1528                                             nTotalWeightX += nWeightX;
1529                                         }
1530                                         else if ( nRowRange == j )
1531                                         {
1532                                             nWeightX = pMapFX[ nRight ] ;
1533                                             nSumRowB += ( nWeightX *rCol.GetBlue() );
1534                                             nSumRowG += ( nWeightX *rCol.GetGreen() );
1535                                             nSumRowR += ( nWeightX *rCol.GetRed() );
1536                                             nTotalWeightX += nWeightX;
1537                                         }
1538                                         else
1539                                         {
1540                                             nSumRowB += rCol.GetBlue() << 7L;
1541                                             nSumRowG += rCol.GetGreen() << 7L;
1542                                             nSumRowR += rCol.GetRed() << 7L;
1543                                             nTotalWeightX += 1 << 7L;
1544                                         }
1545                                     }
1546 
1547                                     if( nY == nEndY )
1548                                         nWeightY = nMax;
1549                                     else if( i == 0 )
1550                                         nWeightY = nMax - pMapFY[ nTop ];
1551                                     else if( nLineRange == 1 )
1552                                         nWeightY = pMapFY[ nTop ];
1553                                     else if ( nLineRange == i )
1554                                         nWeightY = pMapFY[ nBottom ];
1555                                     else
1556                                         nWeightY = nMax;
1557 
1558                                     nWeightY = nWeightY ;
1559                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1560                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1561                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1562                                     nTotalWeightY += nWeightY;
1563                                 }
1564 
1565                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1566                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1567                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1568                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1569 
1570                             }
1571                         }
1572                     }
1573 }
1574                 else
1575                 {
1576                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1577                     {
1578                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1579                         {
1580                             nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ];
1581 
1582                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1583                             {
1584                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1585 
1586                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) );
1587                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) );
1588                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1589                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1590                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1591 
1592                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) );
1593                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) );
1594                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1595                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1596                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1597 
1598                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1599                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1600                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1601                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1602                             }
1603                         }
1604 
1605                     }
1606                     else
1607                     {
1608                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1609                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1610                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1611 
1612                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1613                         {
1614                             nTop = bVMirr ? ( nY + 1 ) : nY;
1615                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1616 
1617                             if( nY ==nEndY )
1618                             {
1619                                 nLineStart = pMapIY[ nY ];
1620                                 nLineRange = 0;
1621                             }
1622                             else
1623                             {
1624                                 nLineStart = pMapIY[ nTop ] ;
1625                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1626                             }
1627 
1628                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1629                             {
1630                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1631                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1632 
1633                                 if( nX == nEndX )
1634                                 {
1635                                     nRowStart = pMapIX[ nX ];
1636                                     nRowRange = 0;
1637                                 }
1638                                 else
1639                                 {
1640                                     nRowStart = pMapIX[ nLeft ];
1641                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1642                                 }
1643 
1644                                 nSumR = nSumG = nSumB = 0;
1645                                 nTotalWeightY = 0;
1646 
1647                                 for(int i = 0; i<= nLineRange; i++)
1648                                 {
1649                                     nSumRowR = nSumRowG = nSumRowB = 0;
1650                                     nTotalWeightX = 0;
1651 
1652                                     for(int j = 0; j <= nRowRange; j++)
1653                                     {
1654                                         aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
1655 
1656                                         if(nX == nEndX )
1657                                         {
1658 
1659                                             nSumRowB += aCol0.GetBlue() << 7L;
1660                                             nSumRowG += aCol0.GetGreen() << 7L;
1661                                             nSumRowR += aCol0.GetRed() << 7L;
1662                                             nTotalWeightX += 1 << 7L;
1663                                         }
1664                                         else if( j == 0 )
1665                                         {
1666 
1667                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1668                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
1669                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
1670                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
1671                                             nTotalWeightX += nWeightX;
1672                                         }
1673                                         else if ( nRowRange == j )
1674                                         {
1675 
1676                                             nWeightX = pMapFX[ nRight ] ;
1677                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
1678                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
1679                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
1680                                             nTotalWeightX += nWeightX;
1681                                         }
1682                                         else
1683                                         {
1684 
1685                                             nSumRowB += aCol0.GetBlue() << 7L;
1686                                             nSumRowG += aCol0.GetGreen() << 7L;
1687                                             nSumRowR += aCol0.GetRed() << 7L;
1688                                             nTotalWeightX += 1 << 7L;
1689                                         }
1690                                     }
1691 
1692                                     if( nY == nEndY )
1693                                         nWeightY = nMax;
1694                                     else if( i == 0 )
1695                                         nWeightY = nMax - pMapFY[ nTop ];
1696                                     else if( nLineRange == 1 )
1697                                         nWeightY = pMapFY[ nTop ];
1698                                     else if ( nLineRange == i )
1699                                         nWeightY = pMapFY[ nBottom ];
1700                                     else
1701                                         nWeightY = nMax;
1702 
1703                                     nWeightY = nWeightY ;
1704                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1705                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1706                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1707                                     nTotalWeightY += nWeightY;
1708                                 }
1709 
1710                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1711                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1712                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1713                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1714                             }
1715                         }
1716                     }
1717                 }
1718             }
1719             else
1720             {
1721                 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1722                 {
1723                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1724                     {
1725                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1726                         long        nOff;
1727 
1728                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1729                         {
1730                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1731                             pLine0 = pAcc->GetScanline( nTempY );
1732                             pLine1 = pAcc->GetScanline( ++nTempY );
1733 
1734                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1735                             {
1736                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1737                                 nTempFX = pMapFX[ nX ];
1738 
1739                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1740                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1741                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1742                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
1743 
1744                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1745                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1746                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1747                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
1748 
1749                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1750                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1751                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1752                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1753                             }
1754                         }
1755                     }
1756                     else
1757                     {
1758                         Scanline    pTmpY, pTmpX;
1759                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1760                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1761                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1762 
1763                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1764                         {
1765                             nTop = bVMirr ? ( nY + 1 ) : nY;
1766                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1767 
1768                             if( nY ==nEndY )
1769                             {
1770                                 nLineStart = pMapIY[ nY ];
1771                                 nLineRange = 0;
1772                             }
1773                             else
1774                             {
1775                                 nLineStart = pMapIY[ nTop ] ;
1776                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1777                             }
1778 
1779                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1780                             {
1781                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1782                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1783 
1784                                 if( nX == nEndX  )
1785                                 {
1786                                     nRowStart = pMapIX[ nX ];
1787                                     nRowRange = 0;
1788                                 }
1789                                 else
1790                                 {
1791                                     nRowStart = pMapIX[ nLeft ];
1792                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1793                                 }
1794 
1795                                 nSumR = nSumG = nSumB = 0;
1796                                 nTotalWeightY = 0;
1797 
1798                                 for(int i = 0; i<= nLineRange; i++)
1799                                 {
1800                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1801                                     pTmpX = pTmpY + 3L * nRowStart;
1802                                     nSumRowR = nSumRowG = nSumRowB = 0;
1803                                     nTotalWeightX = 0;
1804 
1805                                     for(int j = 0; j <= nRowRange; j++)
1806                                     {
1807                                         if(nX == nEndX )
1808                                         {
1809                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1810                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1811                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1812                                             nTotalWeightX += 1 << 7L;
1813                                         }
1814                                         else if( j == 0 )
1815                                         {
1816                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1817                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1818                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1819                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1820                                             nTotalWeightX += nWeightX;
1821                                         }
1822                                         else if ( nRowRange == j )
1823                                         {
1824                                             nWeightX = pMapFX[ nRight ] ;
1825                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1826                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1827                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1828                                             nTotalWeightX += nWeightX;
1829                                         }
1830                                         else
1831                                         {
1832                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1833                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1834                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1835                                             nTotalWeightX += 1 << 7L;
1836                                         }
1837                                     }
1838 
1839                                     if( nY == nEndY )
1840                                         nWeightY = nMax;
1841                                     else if( i == 0 )
1842                                         nWeightY = nMax - pMapFY[ nTop ];
1843                                     else if( nLineRange == 1 )
1844                                         nWeightY = pMapFY[ nTop ];
1845                                     else if ( nLineRange == i )
1846                                         nWeightY = pMapFY[ nBottom ];
1847                                     else
1848                                         nWeightY = nMax;
1849 
1850                                     nWeightY = nWeightY ;
1851                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1852                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1853                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1854                                     nTotalWeightY += nWeightY;
1855                                 }
1856 
1857                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1858                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1859                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1860                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1861 
1862                             }
1863                         }
1864                     }
1865                 }
1866                 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1867                 {
1868                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1869                     {
1870                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1871                         long        nOff;
1872 
1873                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1874                         {
1875                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1876                             pLine0 = pAcc->GetScanline( nTempY );
1877                             pLine1 = pAcc->GetScanline( ++nTempY );
1878 
1879                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1880                             {
1881                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1882                                 nTempFX = pMapFX[ nX ];
1883 
1884                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1885                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1886                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1887                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
1888 
1889                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1890                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1891                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1892                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
1893 
1894                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1895                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1896                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1897                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1898                             }
1899                         }
1900                     }
1901                     else
1902                     {
1903                         Scanline    pTmpY, pTmpX;
1904                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1905                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1906                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1907 
1908                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1909                         {
1910                             nTop = bVMirr ? ( nY + 1 ) : nY;
1911                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1912 
1913                             if( nY ==nEndY )
1914                             {
1915                                 nLineStart = pMapIY[ nY ];
1916                                 nLineRange = 0;
1917                             }
1918                             else
1919                             {
1920                                 nLineStart = pMapIY[ nTop ] ;
1921                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1922                             }
1923 
1924                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1925                             {
1926                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1927                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1928 
1929                                 if( nX == nEndX )
1930                                 {
1931                                     nRowStart = pMapIX[ nX ];
1932                                     nRowRange = 0;
1933                                 }
1934                                 else
1935                                 {
1936                                     nRowStart = pMapIX[ nLeft ];
1937                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1938                                 }
1939 
1940                                 nSumR = nSumG = nSumB = 0;
1941                                 nTotalWeightY = 0;
1942 
1943                                 for(int i = 0; i<= nLineRange; i++)
1944                                 {
1945                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1946                                     pTmpX = pTmpY + 3L * nRowStart;
1947                                     nSumRowR = nSumRowG = nSumRowB = 0;
1948                                     nTotalWeightX = 0;
1949 
1950                                     for(int j = 0; j <= nRowRange; j++)
1951                                     {
1952                                         if(nX == nEndX )
1953                                         {
1954                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1955                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1956                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1957                                             nTotalWeightX += 1 << 7L;
1958                                         }
1959                                         else if( j == 0 )
1960                                         {
1961                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1962                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1963                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1964                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1965                                             nTotalWeightX += nWeightX;
1966                                         }
1967                                         else if ( nRowRange == j )
1968                                         {
1969                                             nWeightX = pMapFX[ nRight ] ;
1970                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1971                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1972                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1973                                             nTotalWeightX += nWeightX;
1974                                         }
1975                                         else
1976                                         {
1977                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1978                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1979                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1980                                             nTotalWeightX += 1 << 7L;
1981                                         }
1982                                     }
1983 
1984                                     if( nY == nEndY )
1985                                         nWeightY = nMax;
1986                                     else if( i == 0 )
1987                                         nWeightY = nMax - pMapFY[ nTop ];
1988                                     else if( nLineRange == 1 )
1989                                         nWeightY = pMapFY[ nTop ];
1990                                     else if ( nLineRange == i )
1991                                         nWeightY = pMapFY[ nBottom ];
1992                                     else
1993                                         nWeightY = nMax;
1994 
1995                                     nWeightY = nWeightY ;
1996                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1997                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1998                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1999                                     nTotalWeightY += nWeightY;
2000                                 }
2001 
2002                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2003                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2004                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2005                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2006 
2007                             }
2008                         }
2009                     }
2010                 }
2011                 else
2012                 {
2013                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
2014                     {
2015                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2016                         {
2017                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
2018 
2019                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
2020                             {
2021                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
2022 
2023                                 aCol0 = pAcc->GetPixel( nTempY, nTempX );
2024                                 aCol1 = pAcc->GetPixel( nTempY, ++nTempX );
2025                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2026                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2027                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2028 
2029                                 aCol1 = pAcc->GetPixel( ++nTempY, nTempX );
2030                                 aCol0 = pAcc->GetPixel( nTempY--, --nTempX );
2031                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2032                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2033                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2034 
2035                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
2036                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
2037                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
2038                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2039                             }
2040                         }
2041                     }
2042                     else
2043                     {
2044                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
2045                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
2046                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
2047 
2048                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2049                         {
2050                             nTop = bVMirr ? ( nY + 1 ) : nY;
2051                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
2052 
2053                             if( nY ==nEndY )
2054                             {
2055                                 nLineStart = pMapIY[ nY ];
2056                                 nLineRange = 0;
2057                             }
2058                             else
2059                             {
2060                                 nLineStart = pMapIY[ nTop ] ;
2061                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
2062                             }
2063 
2064                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
2065                             {
2066                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
2067                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
2068 
2069                                 if( nX == nEndX )
2070                                 {
2071                                     nRowStart = pMapIX[ nX ];
2072                                     nRowRange = 0;
2073                                 }
2074                                 else
2075                                 {
2076                                     nRowStart = pMapIX[ nLeft ];
2077                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
2078                                 }
2079 
2080                                 nSumR = nSumG = nSumB = 0;
2081                                 nTotalWeightY = 0;
2082 
2083                                 for(int i = 0; i<= nLineRange; i++)
2084                                 {
2085                                     nSumRowR = nSumRowG = nSumRowB = 0;
2086                                     nTotalWeightX = 0;
2087 
2088                                     for(int j = 0; j <= nRowRange; j++)
2089                                     {
2090                                         aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j );
2091 
2092                                         if(nX == nEndX )
2093                                         {
2094 
2095                                             nSumRowB += aCol0.GetBlue() << 7L;
2096                                             nSumRowG += aCol0.GetGreen() << 7L;
2097                                             nSumRowR += aCol0.GetRed() << 7L;
2098                                             nTotalWeightX += 1 << 7L;
2099                                         }
2100                                         else if( j == 0 )
2101                                         {
2102 
2103                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
2104                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
2105                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
2106                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
2107                                             nTotalWeightX += nWeightX;
2108                                         }
2109                                         else if ( nRowRange == j )
2110                                         {
2111 
2112                                             nWeightX = pMapFX[ nRight ] ;
2113                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
2114                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
2115                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
2116                                             nTotalWeightX += nWeightX;
2117                                         }
2118                                         else
2119                                         {
2120                                             nSumRowB += aCol0.GetBlue() << 7L;
2121                                             nSumRowG += aCol0.GetGreen() << 7L;
2122                                             nSumRowR += aCol0.GetRed() << 7L;
2123                                             nTotalWeightX += 1 << 7L;
2124                                         }
2125                                     }
2126 
2127                                     if( nY == nEndY )
2128                                         nWeightY = nMax;
2129                                     else if( i == 0 )
2130                                         nWeightY = nMax - pMapFY[ nTop ];
2131                                     else if( nLineRange == 1 )
2132                                         nWeightY = pMapFY[ nTop ];
2133                                     else if ( nLineRange == i )
2134                                         nWeightY = pMapFY[ nBottom ];
2135                                     else
2136                                         nWeightY = nMax;
2137 
2138                                     nWeightY = nWeightY ;
2139                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
2140                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
2141                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
2142                                     nTotalWeightY += nWeightY;
2143                                 }
2144 
2145                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2146                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2147                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2148                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2149 
2150                             }
2151                         }
2152                     }
2153                 }
2154             }
2155 
2156             bRet = true;
2157         }
2158 
2159         delete[] pMapIX;
2160         delete[] pMapIY;
2161         delete[] pMapFX;
2162         delete[] pMapFY;
2163 
2164         ReleaseAccess( pAcc );
2165         aOutBmp.ReleaseAccess( pWAcc );
2166 
2167         if( bRet )
2168         {
2169             ImplAdaptBitCount(aOutBmp);
2170             ImplAssignWithSize(aOutBmp);
2171         }
2172 
2173         if( !bRet )
2174             bRet = ImplScaleFast( scaleX, scaleY );
2175     }
2176 
2177     return bRet;
2178 }
2179 
2180 //-----------------------------------------------------------------------------------
2181 
2182 namespace
2183 {
2184     void ImplCalculateContributions(
2185         const sal_uInt32 aSourceSize,
2186         const sal_uInt32 aDestinationSize,
2187         sal_uInt32& aNumberOfContributions,
2188         double*& pWeights,
2189         sal_uInt32*& pPixels,
2190         sal_uInt32*& pCount,
2191         const Kernel& aKernel)
2192     {
2193         const double fSamplingRadius(aKernel.GetWidth());
2194         const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
2195         const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
2196         const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
2197 
2198         aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
2199         const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
2200         pWeights = new double[nAllocSize];
2201         pPixels = new sal_uInt32[nAllocSize];
2202         pCount = new sal_uInt32[aDestinationSize];
2203 
2204         for(sal_uInt32 i(0); i < aDestinationSize; i++)
2205         {
2206             const sal_uInt32 aIndex(i * aNumberOfContributions);
2207             const double aCenter(i / fScale);
2208             const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
2209             const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
2210             sal_uInt32 aCurrentCount(0);
2211 
2212             for(sal_Int32 j(aLeft); j <= aRight; j++)
2213             {
2214                 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
2215 
2216                 // Reduce calculations with ignoring weights of 0.0
2217                 if(fabs(aWeight) < 0.0001)
2218                 {
2219                     continue;
2220                 }
2221 
2222                 // Handling on edges
2223                 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
2224                 const sal_uInt32 nIndex(aIndex + aCurrentCount);
2225 
2226                 pWeights[nIndex] = aWeight;
2227                 pPixels[nIndex] = aPixelIndex;
2228 
2229                 aCurrentCount++;
2230             }
2231 
2232             pCount[i] = aCurrentCount;
2233         }
2234     }
2235 
2236     sal_Bool ImplScaleConvolutionHor(
2237         Bitmap& rSource,
2238         Bitmap& rTarget,
2239         const double& rScaleX,
2240         const Kernel& aKernel)
2241     {
2242         // Do horizontal filtering
2243         OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2244         const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2245         const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
2246 
2247         if(nWidth == nNewWidth)
2248         {
2249             return true;
2250         }
2251 
2252         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2253 
2254         if(pReadAcc)
2255         {
2256             double* pWeights = 0;
2257             sal_uInt32* pPixels = 0;
2258             sal_uInt32* pCount = 0;
2259             sal_uInt32 aNumberOfContributions(0);
2260 
2261             const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2262             ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2263             rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
2264             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2265             bool bResult(0 != pWriteAcc);
2266 
2267             if(bResult)
2268             {
2269                 for(sal_uInt32 y(0); y < nHeight; y++)
2270                 {
2271                     for(sal_uInt32 x(0); x < nNewWidth; x++)
2272                     {
2273                         const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
2274                         double aSum(0.0);
2275                         double aValueRed(0.0);
2276                         double aValueGreen(0.0);
2277                         double aValueBlue(0.0);
2278 
2279                         for(sal_uInt32 j(0); j < pCount[x]; j++)
2280                         {
2281                             const sal_uInt32 aIndex(aBaseIndex + j);
2282                             const double aWeight(pWeights[aIndex]);
2283                             BitmapColor aColor;
2284 
2285                             aSum += aWeight;
2286 
2287                             if(pReadAcc->HasPalette())
2288                             {
2289                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
2290                             }
2291                             else
2292                             {
2293                                 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
2294                             }
2295 
2296                             aValueRed += aWeight * aColor.GetRed();
2297                             aValueGreen += aWeight * aColor.GetGreen();
2298                             aValueBlue += aWeight * aColor.GetBlue();
2299                         }
2300 
2301                         const BitmapColor aResultColor(
2302                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2303                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2304                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2305 
2306                         pWriteAcc->SetPixel(y, x, aResultColor);
2307                     }
2308                 }
2309 
2310                 rTarget.ReleaseAccess(pWriteAcc);
2311             }
2312 
2313             rSource.ReleaseAccess(pReadAcc);
2314             delete[] pWeights;
2315             delete[] pCount;
2316             delete[] pPixels;
2317 
2318             if(bResult)
2319             {
2320                 return true;
2321             }
2322         }
2323 
2324         return false;
2325     }
2326 
2327     bool ImplScaleConvolutionVer(
2328         Bitmap& rSource,
2329         Bitmap& rTarget,
2330         const double& rScaleY,
2331         const Kernel& aKernel)
2332     {
2333         // Do vertical filtering
2334         OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2335         const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2336         const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
2337 
2338         if(nHeight == nNewHeight)
2339         {
2340             return true;
2341         }
2342 
2343         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2344 
2345         if(pReadAcc)
2346         {
2347             double* pWeights = 0;
2348             sal_uInt32* pPixels = 0;
2349             sal_uInt32* pCount = 0;
2350             sal_uInt32 aNumberOfContributions(0);
2351 
2352             const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2353             ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2354             rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
2355             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2356             bool bResult(0 != pWriteAcc);
2357 
2358             if(pWriteAcc)
2359             {
2360                 for(sal_uInt32 x(0); x < nWidth; x++)
2361                 {
2362                     for(sal_uInt32 y(0); y < nNewHeight; y++)
2363                     {
2364                         const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
2365                         double aSum(0.0);
2366                         double aValueRed(0.0);
2367                         double aValueGreen(0.0);
2368                         double aValueBlue(0.0);
2369 
2370                         for(sal_uInt32 j(0); j < pCount[y]; j++)
2371                         {
2372                             const sal_uInt32 aIndex(aBaseIndex + j);
2373                             const double aWeight(pWeights[aIndex]);
2374                             BitmapColor aColor;
2375 
2376                             aSum += aWeight;
2377 
2378                             if(pReadAcc->HasPalette())
2379                             {
2380                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
2381                             }
2382                             else
2383                             {
2384                                 aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
2385                             }
2386 
2387                             aValueRed += aWeight * aColor.GetRed();
2388                             aValueGreen += aWeight * aColor.GetGreen();
2389                             aValueBlue += aWeight * aColor.GetBlue();
2390                         }
2391 
2392                         const BitmapColor aResultColor(
2393                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2394                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2395                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2396 
2397                         if(pWriteAcc->HasPalette())
2398                         {
2399                             pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
2400                         }
2401                         else
2402                         {
2403                             pWriteAcc->SetPixel(y, x, aResultColor);
2404                         }
2405                     }
2406                 }
2407             }
2408 
2409             rTarget.ReleaseAccess(pWriteAcc);
2410             rSource.ReleaseAccess(pReadAcc);
2411 
2412             delete[] pWeights;
2413             delete[] pCount;
2414             delete[] pPixels;
2415 
2416             if(bResult)
2417             {
2418                 return true;
2419             }
2420         }
2421 
2422         return false;
2423     }
2424 }
2425 
2426 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and
2427 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see
2428 // bugzilla task for deitails) Thanks!
2429 sal_Bool Bitmap::ImplScaleConvolution(
2430     const double& rScaleX,
2431     const double& rScaleY,
2432     const Kernel& aKernel)
2433 {
2434     const bool bMirrorHor(rScaleX < 0.0);
2435     const bool bMirrorVer(rScaleY < 0.0);
2436     const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
2437     const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
2438     const sal_uInt32 nWidth(GetSizePixel().Width());
2439     const sal_uInt32 nHeight(GetSizePixel().Height());
2440     const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
2441     const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
2442     const bool bScaleHor(nWidth != nNewWidth);
2443     const bool bScaleVer(nHeight != nNewHeight);
2444     const bool bMirror(bMirrorHor || bMirrorVer);
2445 
2446     if(!bMirror && !bScaleHor && !bScaleVer)
2447     {
2448         return true;
2449     }
2450 
2451     bool bResult(true);
2452     sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
2453     bool bMirrorAfter(false);
2454 
2455     if(bMirror)
2456     {
2457         if(bMirrorHor)
2458         {
2459             nMirrorFlags |= BMP_MIRROR_HORZ;
2460         }
2461 
2462         if(bMirrorVer)
2463         {
2464             nMirrorFlags |= BMP_MIRROR_VERT;
2465         }
2466 
2467         const sal_uInt32 nStartSize(nWidth * nHeight);
2468         const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
2469 
2470         bMirrorAfter = nStartSize > nEndSize;
2471 
2472         if(!bMirrorAfter)
2473         {
2474             bResult = Mirror(nMirrorFlags);
2475         }
2476     }
2477 
2478     Bitmap aResult;
2479 
2480     if(bResult)
2481     {
2482         const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
2483         const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
2484 
2485         if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2486         {
2487             if(bScaleHor)
2488             {
2489                 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel);
2490             }
2491 
2492             if(bResult && bScaleVer)
2493             {
2494                 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel);
2495             }
2496         }
2497         else
2498         {
2499             if(bScaleVer)
2500             {
2501                 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel);
2502             }
2503 
2504             if(bResult && bScaleHor)
2505             {
2506                 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel);
2507             }
2508         }
2509     }
2510 
2511     if(bResult && bMirrorAfter)
2512     {
2513         bResult = aResult.Mirror(nMirrorFlags);
2514     }
2515 
2516     if(bResult)
2517     {
2518         ImplAdaptBitCount(aResult);
2519         *this = aResult;
2520     }
2521 
2522     return bResult;
2523 }
2524 
2525 // ------------------------------------------------------------------------
2526 
2527 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2528 {
2529     sal_Bool bRet = sal_False;
2530 
2531     const Size aSizePix( GetSizePixel() );
2532 
2533     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2534         bRet = sal_True;
2535     else if( nDitherFlags & BMP_DITHER_MATRIX )
2536         bRet = ImplDitherMatrix();
2537     else if( nDitherFlags & BMP_DITHER_FLOYD )
2538         bRet = ImplDitherFloyd();
2539     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2540         bRet = ImplDitherFloyd16();
2541 
2542     return bRet;
2543 }
2544 
2545 // ------------------------------------------------------------------------
2546 
2547 sal_Bool Bitmap::ImplDitherMatrix()
2548 {
2549     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2550     Bitmap              aNewBmp( GetSizePixel(), 8 );
2551     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2552     sal_Bool                bRet = sal_False;
2553 
2554     if( pReadAcc && pWriteAcc )
2555     {
2556         const sal_uLong nWidth = pReadAcc->Width();
2557         const sal_uLong nHeight = pReadAcc->Height();
2558         BitmapColor aIndex( (sal_uInt8) 0 );
2559 
2560         if( pReadAcc->HasPalette() )
2561         {
2562             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2563             {
2564                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2565                 {
2566                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2567                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2568                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2569                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2570                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2571 
2572                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2573                     pWriteAcc->SetPixel( nY, nX, aIndex );
2574                 }
2575             }
2576         }
2577         else
2578         {
2579             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2580             {
2581                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2582                 {
2583                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
2584                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2585                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2586                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2587                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2588 
2589                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2590                     pWriteAcc->SetPixel( nY, nX, aIndex );
2591                 }
2592             }
2593         }
2594 
2595         bRet = sal_True;
2596     }
2597 
2598     ReleaseAccess( pReadAcc );
2599     aNewBmp.ReleaseAccess( pWriteAcc );
2600 
2601     if( bRet )
2602     {
2603         const MapMode   aMap( maPrefMapMode );
2604         const Size      aSize( maPrefSize );
2605 
2606         *this = aNewBmp;
2607 
2608         maPrefMapMode = aMap;
2609         maPrefSize = aSize;
2610     }
2611 
2612     return bRet;
2613 }
2614 
2615 // ------------------------------------------------------------------------
2616 
2617 sal_Bool Bitmap::ImplDitherFloyd()
2618 {
2619     const Size  aSize( GetSizePixel() );
2620     sal_Bool        bRet = sal_False;
2621 
2622     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2623     {
2624         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2625         Bitmap              aNewBmp( GetSizePixel(), 8 );
2626         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2627 
2628         if( pReadAcc && pWriteAcc )
2629         {
2630             BitmapColor aColor;
2631             long        nWidth = pReadAcc->Width();
2632             long        nWidth1 = nWidth - 1L;
2633             long        nHeight = pReadAcc->Height();
2634             long        nX;
2635             long        nW = nWidth * 3L;
2636             long        nW2 = nW - 3L;
2637             long        nRErr, nGErr, nBErr;
2638             long        nRC, nGC, nBC;
2639             long        nTemp;
2640             long        nZ;
2641             long*       p1 = new long[ nW ];
2642             long*       p2 = new long[ nW ];
2643             long*       p1T = p1;
2644             long*       p2T = p2;
2645             long*       pTmp;
2646             sal_Bool        bPal = pReadAcc->HasPalette();
2647 
2648             pTmp = p2T;
2649 
2650             if( bPal )
2651             {
2652                 for( nZ = 0; nZ < nWidth; nZ++ )
2653                 {
2654                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2655 
2656                     *pTmp++ = (long) aColor.GetBlue() << 12;
2657                     *pTmp++ = (long) aColor.GetGreen() << 12;
2658                     *pTmp++ = (long) aColor.GetRed() << 12;
2659                 }
2660             }
2661             else
2662             {
2663                 for( nZ = 0; nZ < nWidth; nZ++ )
2664                 {
2665                     aColor = pReadAcc->GetPixel( 0, nZ );
2666 
2667                     *pTmp++ = (long) aColor.GetBlue() << 12;
2668                     *pTmp++ = (long) aColor.GetGreen() << 12;
2669                     *pTmp++ = (long) aColor.GetRed() << 12;
2670                 }
2671             }
2672 
2673             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2674             {
2675                 pTmp = p1T;
2676                 p1T = p2T;
2677                 p2T = pTmp;
2678 
2679                 if( nY < nHeight )
2680                 {
2681                     if( bPal )
2682                     {
2683                         for( nZ = 0; nZ < nWidth; nZ++ )
2684                         {
2685                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2686 
2687                             *pTmp++ = (long) aColor.GetBlue() << 12;
2688                             *pTmp++ = (long) aColor.GetGreen() << 12;
2689                             *pTmp++ = (long) aColor.GetRed() << 12;
2690                         }
2691                     }
2692                     else
2693                     {
2694                         for( nZ = 0; nZ < nWidth; nZ++ )
2695                         {
2696                             aColor = pReadAcc->GetPixel( nY, nZ );
2697 
2698                             *pTmp++ = (long) aColor.GetBlue() << 12;
2699                             *pTmp++ = (long) aColor.GetGreen() << 12;
2700                             *pTmp++ = (long) aColor.GetRed() << 12;
2701                         }
2702                     }
2703                 }
2704 
2705                 // erstes Pixel gesondert betrachten
2706                 nX = 0;
2707                 CALC_ERRORS;
2708                 CALC_TABLES7;
2709                 nX -= 5;
2710                 CALC_TABLES5;
2711                 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2712 
2713                 // mittlere Pixel ueber Schleife
2714                 long nXAcc;
2715                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2716                 {
2717                     CALC_ERRORS;
2718                     CALC_TABLES7;
2719                     nX -= 8;
2720                     CALC_TABLES3;
2721                     CALC_TABLES5;
2722                     pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2723                 }
2724 
2725                 // letztes Pixel gesondert betrachten
2726                 CALC_ERRORS;
2727                 nX -= 5;
2728                 CALC_TABLES3;
2729                 CALC_TABLES5;
2730                 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2731             }
2732 
2733             delete[] p1;
2734             delete[] p2;
2735             bRet = sal_True;
2736         }
2737 
2738         ReleaseAccess( pReadAcc );
2739         aNewBmp.ReleaseAccess( pWriteAcc );
2740 
2741         if( bRet )
2742         {
2743             const MapMode   aMap( maPrefMapMode );
2744             const Size      aPrefSize( maPrefSize );
2745 
2746             *this = aNewBmp;
2747 
2748             maPrefMapMode = aMap;
2749             maPrefSize = aPrefSize;
2750         }
2751     }
2752 
2753     return bRet;
2754 }
2755 
2756 // ------------------------------------------------------------------------
2757 
2758 sal_Bool Bitmap::ImplDitherFloyd16()
2759 {
2760     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2761     Bitmap              aNewBmp( GetSizePixel(), 24 );
2762     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2763     sal_Bool                bRet = sal_False;
2764 
2765     if( pReadAcc && pWriteAcc )
2766     {
2767         const long      nWidth = pWriteAcc->Width();
2768         const long      nWidth1 = nWidth - 1L;
2769         const long      nHeight = pWriteAcc->Height();
2770         BitmapColor     aColor;
2771         BitmapColor     aBestCol;
2772         ImpErrorQuad    aErrQuad;
2773         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
2774         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
2775         ImpErrorQuad*   pQLine1 = pErrQuad1;
2776         ImpErrorQuad*   pQLine2 = 0;
2777         long            nX, nY;
2778         long            nYTmp = 0L;
2779         sal_Bool            bQ1 = sal_True;
2780 
2781         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2782             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2783                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2784 
2785         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2786         {
2787             // erstes ZeilenPixel
2788             aBestCol = pQLine1[ 0 ].ImplGetColor();
2789             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2790             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2791             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2792             pWriteAcc->SetPixel( nY, 0, aBestCol );
2793 
2794             for( nX = 1L; nX < nWidth1; nX++ )
2795             {
2796                 aColor = pQLine1[ nX ].ImplGetColor();
2797                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2798                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2799                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2800                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2801                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2802                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2803                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2804                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2805                 pWriteAcc->SetPixel( nY, nX, aBestCol );
2806             }
2807 
2808             // letztes ZeilenPixel
2809             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2810             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2811             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2812             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2813             pWriteAcc->SetPixel( nY, nX, aBestCol );
2814 
2815             // Zeilenpuffer neu fuellen/kopieren
2816             pQLine1 = pQLine2;
2817             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2818 
2819             if( nYTmp < nHeight )
2820                 for( nX = 0L; nX < nWidth; nX++ )
2821                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2822         }
2823 
2824         // Zeilenpuffer zerstoeren
2825         delete[] pErrQuad1;
2826         delete[] pErrQuad2;
2827         bRet = sal_True;
2828     }
2829 
2830     ReleaseAccess( pReadAcc );
2831     aNewBmp.ReleaseAccess( pWriteAcc );
2832 
2833     if( bRet )
2834     {
2835         const MapMode   aMap( maPrefMapMode );
2836         const Size      aSize( maPrefSize );
2837 
2838         *this = aNewBmp;
2839 
2840         maPrefMapMode = aMap;
2841         maPrefSize = aSize;
2842     }
2843 
2844     return bRet;
2845 }
2846 
2847 // ------------------------------------------------------------------------
2848 
2849 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2850 {
2851     sal_Bool bRet;
2852 
2853     if( GetColorCount() <= (sal_uLong) nColorCount )
2854         bRet = sal_True;
2855     else if( nColorCount )
2856     {
2857         if( BMP_REDUCE_SIMPLE == eReduce )
2858             bRet = ImplReduceSimple( nColorCount );
2859         else if( BMP_REDUCE_POPULAR == eReduce )
2860             bRet = ImplReducePopular( nColorCount );
2861         else
2862             bRet = ImplReduceMedian( nColorCount );
2863     }
2864     else
2865         bRet = sal_False;
2866 
2867     return bRet;
2868 }
2869 
2870 // ------------------------------------------------------------------------
2871 
2872 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2873 {
2874     Bitmap              aNewBmp;
2875     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2876     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
2877     sal_uInt16              nBitCount;
2878     sal_Bool                bRet = sal_False;
2879 
2880     if( nColCount <= 2 )
2881         nBitCount = 1;
2882     else if( nColCount <= 16 )
2883         nBitCount = 4;
2884     else
2885         nBitCount = 8;
2886 
2887     if( pRAcc )
2888     {
2889         Octree                  aOct( *pRAcc, nColCount );
2890         const BitmapPalette&    rPal = aOct.GetPalette();
2891         BitmapWriteAccess*      pWAcc;
2892 
2893         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2894         pWAcc = aNewBmp.AcquireWriteAccess();
2895 
2896         if( pWAcc )
2897         {
2898             const long nWidth = pRAcc->Width();
2899             const long nHeight = pRAcc->Height();
2900 
2901             if( pRAcc->HasPalette() )
2902             {
2903                 for( long nY = 0L; nY < nHeight; nY++ )
2904                     for( long nX =0L; nX < nWidth; nX++ )
2905                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2906             }
2907             else
2908             {
2909                 for( long nY = 0L; nY < nHeight; nY++ )
2910                     for( long nX =0L; nX < nWidth; nX++ )
2911                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2912             }
2913 
2914             aNewBmp.ReleaseAccess( pWAcc );
2915             bRet = sal_True;
2916         }
2917 
2918         ReleaseAccess( pRAcc );
2919     }
2920 
2921     if( bRet )
2922     {
2923         const MapMode   aMap( maPrefMapMode );
2924         const Size      aSize( maPrefSize );
2925 
2926         *this = aNewBmp;
2927         maPrefMapMode = aMap;
2928         maPrefSize = aSize;
2929     }
2930 
2931     return bRet;
2932 }
2933 
2934 // ------------------------------------------------------------------------
2935 
2936 struct PopularColorCount
2937 {
2938     sal_uInt32  mnIndex;
2939     sal_uInt32  mnCount;
2940 };
2941 
2942 // ------------------------------------------------------------------------
2943 
2944 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2945 {
2946     int nRet;
2947 
2948     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2949         nRet = 1;
2950     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2951         nRet = 0;
2952     else
2953         nRet = -1;
2954 
2955     return nRet;
2956 }
2957 
2958 // ------------------------------------------------------------------------
2959 
2960 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2961 {
2962     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2963     sal_uInt16              nBitCount;
2964     sal_Bool                bRet = sal_False;
2965 
2966     if( nColCount > 256 )
2967         nColCount = 256;
2968 
2969     if( nColCount < 17 )
2970         nBitCount = 4;
2971     else
2972         nBitCount = 8;
2973 
2974     if( pRAcc )
2975     {
2976         const sal_uInt32    nValidBits = 4;
2977         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
2978         const sal_uInt32    nLeftShiftBits1 = nValidBits;
2979         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
2980         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
2981         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
2982         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2983         const long          nWidth = pRAcc->Width();
2984         const long          nHeight = pRAcc->Height();
2985         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
2986         long                nX, nY, nR, nG, nB, nIndex;
2987 
2988         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
2989 
2990         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2991         {
2992             for( nG = 0; nG < 256; nG += nColorOffset )
2993             {
2994                 for( nB = 0; nB < 256; nB += nColorOffset )
2995                 {
2996                     pCountTable[ nIndex ].mnIndex = nIndex;
2997                     nIndex++;
2998                 }
2999             }
3000         }
3001 
3002         if( pRAcc->HasPalette() )
3003         {
3004             for( nY = 0L; nY < nHeight; nY++ )
3005             {
3006                 for( nX = 0L; nX < nWidth; nX++ )
3007                 {
3008                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3009                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3010                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3011                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3012                 }
3013             }
3014         }
3015         else
3016         {
3017             for( nY = 0L; nY < nHeight; nY++ )
3018             {
3019                 for( nX = 0L; nX < nWidth; nX++ )
3020                 {
3021                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3022                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3023                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3024                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3025                 }
3026             }
3027         }
3028 
3029         BitmapPalette aNewPal( nColCount );
3030 
3031         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3032 
3033         for( sal_uInt16 n = 0; n < nColCount; n++ )
3034         {
3035             const PopularColorCount& rPop = pCountTable[ n ];
3036             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3037                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3038                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3039         }
3040 
3041         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3042         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3043 
3044         if( pWAcc )
3045         {
3046             BitmapColor aDstCol( (sal_uInt8) 0 );
3047             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
3048 
3049             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3050                 for( nG = 0; nG < 256; nG += nColorOffset )
3051                     for( nB = 0; nB < 256; nB += nColorOffset )
3052                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3053 
3054             if( pRAcc->HasPalette() )
3055             {
3056                 for( nY = 0L; nY < nHeight; nY++ )
3057                 {
3058                     for( nX = 0L; nX < nWidth; nX++ )
3059                     {
3060                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3061                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3062                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3063                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3064                         pWAcc->SetPixel( nY, nX, aDstCol );
3065                     }
3066                 }
3067             }
3068             else
3069             {
3070                 for( nY = 0L; nY < nHeight; nY++ )
3071                 {
3072                     for( nX = 0L; nX < nWidth; nX++ )
3073                     {
3074                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3075                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3076                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3077                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3078                         pWAcc->SetPixel( nY, nX, aDstCol );
3079                     }
3080                 }
3081             }
3082 
3083             delete[] pIndexMap;
3084             aNewBmp.ReleaseAccess( pWAcc );
3085             bRet = sal_True;
3086         }
3087 
3088         delete[] pCountTable;
3089         ReleaseAccess( pRAcc );
3090 
3091         if( bRet )
3092         {
3093             const MapMode   aMap( maPrefMapMode );
3094             const Size      aSize( maPrefSize );
3095 
3096             *this = aNewBmp;
3097             maPrefMapMode = aMap;
3098             maPrefSize = aSize;
3099         }
3100     }
3101 
3102     return bRet;
3103 }
3104 
3105 // ------------------------------------------------------------------------
3106 
3107 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3108 {
3109     BitmapReadAccess*   pRAcc = AcquireReadAccess();
3110     sal_uInt16              nBitCount;
3111     sal_Bool                bRet = sal_False;
3112 
3113     if( nColCount < 17 )
3114         nBitCount = 4;
3115     else if( nColCount < 257 )
3116         nBitCount = 8;
3117     else
3118     {
3119         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3120         nBitCount = 8;
3121         nColCount = 256;
3122     }
3123 
3124     if( pRAcc )
3125     {
3126         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
3127         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3128 
3129         if( pWAcc )
3130         {
3131             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
3132             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3133             const long  nWidth = pWAcc->Width();
3134             const long  nHeight = pWAcc->Height();
3135             long        nIndex = 0L;
3136 
3137             memset( (HPBYTE) pColBuf, 0, nSize );
3138 
3139             // create Buffer
3140             if( pRAcc->HasPalette() )
3141             {
3142                 for( long nY = 0L; nY < nHeight; nY++ )
3143                 {
3144                     for( long nX = 0L; nX < nWidth; nX++ )
3145                     {
3146                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3147                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3148                     }
3149                 }
3150             }
3151             else
3152             {
3153                 for( long nY = 0L; nY < nHeight; nY++ )
3154                 {
3155                     for( long nX = 0L; nX < nWidth; nX++ )
3156                     {
3157                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3158                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3159                     }
3160                 }
3161             }
3162 
3163             // create palette via median cut
3164             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3165             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3166                            nColCount, nWidth * nHeight, nIndex );
3167 
3168             // do mapping of colors to palette
3169             InverseColorMap aMap( aPal );
3170             pWAcc->SetPalette( aPal );
3171             for( long nY = 0L; nY < nHeight; nY++ )
3172                 for( long nX = 0L; nX < nWidth; nX++ )
3173                     pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3174 
3175             rtl_freeMemory( pColBuf );
3176             aNewBmp.ReleaseAccess( pWAcc );
3177             bRet = sal_True;
3178         }
3179 
3180         ReleaseAccess( pRAcc );
3181 
3182         if( bRet )
3183         {
3184             const MapMode   aMap( maPrefMapMode );
3185             const Size      aSize( maPrefSize );
3186 
3187             *this = aNewBmp;
3188             maPrefMapMode = aMap;
3189             maPrefSize = aSize;
3190         }
3191     }
3192 
3193     return bRet;
3194 }
3195 
3196 // ------------------------------------------------------------------------
3197 
3198 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3199                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3200                             long nColors, long nPixels, long& rIndex )
3201 {
3202     if( !nPixels )
3203         return;
3204 
3205     BitmapColor aCol;
3206     const long  nRLen = nR2 - nR1;
3207     const long  nGLen = nG2 - nG1;
3208     const long  nBLen = nB2 - nB1;
3209     long        nR, nG, nB;
3210     sal_uLong*      pBuf = pColBuf;
3211 
3212     if( !nRLen && !nGLen && !nBLen )
3213     {
3214         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3215         {
3216             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3217             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3218             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3219             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3220         }
3221     }
3222     else
3223     {
3224         if( 1 == nColors || 1 == nPixels )
3225         {
3226             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3227 
3228             for( nR = nR1; nR <= nR2; nR++ )
3229             {
3230                 for( nG = nG1; nG <= nG2; nG++ )
3231                 {
3232                     for( nB = nB1; nB <= nB2; nB++ )
3233                     {
3234                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3235 
3236                         if( nPixSum )
3237                         {
3238                             nRSum += nR * nPixSum;
3239                             nGSum += nG * nPixSum;
3240                             nBSum += nB * nPixSum;
3241                         }
3242                     }
3243                 }
3244             }
3245 
3246             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3247             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3248             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3249             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3250         }
3251         else
3252         {
3253             const long  nTest = ( nPixels >> 1 );
3254             long        nPixOld = 0;
3255             long        nPixNew = 0;
3256 
3257             if( nBLen > nGLen && nBLen > nRLen )
3258             {
3259                 nB = nB1 - 1;
3260 
3261                 while( nPixNew < nTest )
3262                 {
3263                     nB++, nPixOld = nPixNew;
3264                     for( nR = nR1; nR <= nR2; nR++ )
3265                         for( nG = nG1; nG <= nG2; nG++ )
3266                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3267                 }
3268 
3269                 if( nB < nB2 )
3270                 {
3271                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3272                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3273                 }
3274                 else
3275                 {
3276                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3277                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3278                 }
3279             }
3280             else if( nGLen > nRLen )
3281             {
3282                 nG = nG1 - 1;
3283 
3284                 while( nPixNew < nTest )
3285                 {
3286                     nG++, nPixOld = nPixNew;
3287                     for( nR = nR1; nR <= nR2; nR++ )
3288                         for( nB = nB1; nB <= nB2; nB++ )
3289                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3290                 }
3291 
3292                 if( nG < nG2 )
3293                 {
3294                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3295                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3296                 }
3297                 else
3298                 {
3299                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3300                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3301                 }
3302             }
3303             else
3304             {
3305                 nR = nR1 - 1;
3306 
3307                 while( nPixNew < nTest )
3308                 {
3309                     nR++, nPixOld = nPixNew;
3310                     for( nG = nG1; nG <= nG2; nG++ )
3311                         for( nB = nB1; nB <= nB2; nB++ )
3312                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3313                 }
3314 
3315                 if( nR < nR2 )
3316                 {
3317                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3318                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3319                 }
3320                 else
3321                 {
3322                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3323                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3324                 }
3325             }
3326         }
3327     }
3328 }
3329 
3330 // ------------------------------------------------------------------------
3331 
3332 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3333 {
3334     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3335 }
3336 
3337 // ------------------------------------------------------------------------
3338 
3339 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3340 {
3341     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3342 }
3343 
3344 // ------------------------------------------------------------------------
3345 
3346 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3347                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3348                      double fGamma, sal_Bool bInvert )
3349 {
3350     sal_Bool bRet = sal_False;
3351 
3352     // nothing to do => return quickly
3353     if( !nLuminancePercent && !nContrastPercent &&
3354         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3355         ( fGamma == 1.0 ) && !bInvert )
3356     {
3357         bRet = sal_True;
3358     }
3359     else
3360     {
3361         BitmapWriteAccess* pAcc = AcquireWriteAccess();
3362 
3363         if( pAcc )
3364         {
3365             BitmapColor     aCol;
3366             const long      nW = pAcc->Width();
3367             const long      nH = pAcc->Height();
3368             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
3369             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
3370             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
3371             long            nX, nY;
3372             double          fM, fROff, fGOff, fBOff, fOff;
3373 
3374             // calculate slope
3375             if( nContrastPercent >= 0 )
3376                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3377             else
3378                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3379 
3380             // total offset = luminance offset + contrast offset
3381             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3382 
3383             // channel offset = channel offset  + total offset
3384             fROff = nChannelRPercent * 2.55 + fOff;
3385             fGOff = nChannelGPercent * 2.55 + fOff;
3386             fBOff = nChannelBPercent * 2.55 + fOff;
3387 
3388             // calculate gamma value
3389             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3390             const sal_Bool bGamma = ( fGamma != 1.0 );
3391 
3392             // create mapping table
3393             for( nX = 0L; nX < 256L; nX++ )
3394             {
3395                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3396                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3397                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3398 
3399                 if( bGamma )
3400                 {
3401                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3402                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3403                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3404                 }
3405 
3406                 if( bInvert )
3407                 {
3408                     cMapR[ nX ] = ~cMapR[ nX ];
3409                     cMapG[ nX ] = ~cMapG[ nX ];
3410                     cMapB[ nX ] = ~cMapB[ nX ];
3411                 }
3412             }
3413 
3414             // do modifying
3415             if( pAcc->HasPalette() )
3416             {
3417                 BitmapColor aNewCol;
3418 
3419                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3420                 {
3421                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3422                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3423                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3424                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3425                     pAcc->SetPaletteColor( i, aNewCol );
3426                 }
3427             }
3428             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3429             {
3430                 for( nY = 0L; nY < nH; nY++ )
3431                 {
3432                     Scanline pScan = pAcc->GetScanline( nY );
3433 
3434                     for( nX = 0L; nX < nW; nX++ )
3435                     {
3436                         *pScan = cMapB[ *pScan ]; pScan++;
3437                         *pScan = cMapG[ *pScan ]; pScan++;
3438                         *pScan = cMapR[ *pScan ]; pScan++;
3439                     }
3440                 }
3441             }
3442             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3443             {
3444                 for( nY = 0L; nY < nH; nY++ )
3445                 {
3446                     Scanline pScan = pAcc->GetScanline( nY );
3447 
3448                     for( nX = 0L; nX < nW; nX++ )
3449                     {
3450                         *pScan = cMapR[ *pScan ]; pScan++;
3451                         *pScan = cMapG[ *pScan ]; pScan++;
3452                         *pScan = cMapB[ *pScan ]; pScan++;
3453                     }
3454                 }
3455             }
3456             else
3457             {
3458                 for( nY = 0L; nY < nH; nY++ )
3459                 {
3460                     for( nX = 0L; nX < nW; nX++ )
3461                     {
3462                         aCol = pAcc->GetPixel( nY, nX );
3463                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
3464                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3465                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3466                         pAcc->SetPixel( nY, nX, aCol );
3467                     }
3468                 }
3469             }
3470 
3471             delete[] cMapR;
3472             delete[] cMapG;
3473             delete[] cMapB;
3474             ReleaseAccess( pAcc );
3475             bRet = sal_True;
3476         }
3477     }
3478 
3479     return bRet;
3480 }
3481