xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision 1a517a076699a7a90fb3d3a8688b4d40f1f973e9)
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         Bitmap aSource(*this);
2485 
2486         if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2487         {
2488             if(bScaleHor)
2489             {
2490                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2491             }
2492 
2493             if(bResult && bScaleVer)
2494             {
2495                 if(bScaleHor)
2496                 {
2497                     // copy partial result, independent of color depth
2498                     aSource = aResult;
2499                 }
2500 
2501                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2502             }
2503         }
2504         else
2505         {
2506             if(bScaleVer)
2507             {
2508                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2509             }
2510 
2511             if(bResult && bScaleHor)
2512             {
2513                 if(bScaleVer)
2514                 {
2515                     // copy partial result, independent of color depth
2516                     aSource = aResult;
2517                 }
2518 
2519                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2520             }
2521         }
2522     }
2523 
2524     if(bResult && bMirrorAfter)
2525     {
2526         bResult = aResult.Mirror(nMirrorFlags);
2527     }
2528 
2529     if(bResult)
2530     {
2531         ImplAdaptBitCount(aResult);
2532         *this = aResult;
2533     }
2534 
2535     return bResult;
2536 }
2537 
2538 // ------------------------------------------------------------------------
2539 
2540 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2541 {
2542     sal_Bool bRet = sal_False;
2543 
2544     const Size aSizePix( GetSizePixel() );
2545 
2546     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2547         bRet = sal_True;
2548     else if( nDitherFlags & BMP_DITHER_MATRIX )
2549         bRet = ImplDitherMatrix();
2550     else if( nDitherFlags & BMP_DITHER_FLOYD )
2551         bRet = ImplDitherFloyd();
2552     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2553         bRet = ImplDitherFloyd16();
2554 
2555     return bRet;
2556 }
2557 
2558 // ------------------------------------------------------------------------
2559 
2560 sal_Bool Bitmap::ImplDitherMatrix()
2561 {
2562     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2563     Bitmap              aNewBmp( GetSizePixel(), 8 );
2564     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2565     sal_Bool                bRet = sal_False;
2566 
2567     if( pReadAcc && pWriteAcc )
2568     {
2569         const sal_uLong nWidth = pReadAcc->Width();
2570         const sal_uLong nHeight = pReadAcc->Height();
2571         BitmapColor aIndex( (sal_uInt8) 0 );
2572 
2573         if( pReadAcc->HasPalette() )
2574         {
2575             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2576             {
2577                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2578                 {
2579                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2580                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2581                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2582                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2583                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2584 
2585                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2586                     pWriteAcc->SetPixel( nY, nX, aIndex );
2587                 }
2588             }
2589         }
2590         else
2591         {
2592             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2593             {
2594                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2595                 {
2596                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
2597                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2598                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2599                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2600                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2601 
2602                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2603                     pWriteAcc->SetPixel( nY, nX, aIndex );
2604                 }
2605             }
2606         }
2607 
2608         bRet = sal_True;
2609     }
2610 
2611     ReleaseAccess( pReadAcc );
2612     aNewBmp.ReleaseAccess( pWriteAcc );
2613 
2614     if( bRet )
2615     {
2616         const MapMode   aMap( maPrefMapMode );
2617         const Size      aSize( maPrefSize );
2618 
2619         *this = aNewBmp;
2620 
2621         maPrefMapMode = aMap;
2622         maPrefSize = aSize;
2623     }
2624 
2625     return bRet;
2626 }
2627 
2628 // ------------------------------------------------------------------------
2629 
2630 sal_Bool Bitmap::ImplDitherFloyd()
2631 {
2632     const Size  aSize( GetSizePixel() );
2633     sal_Bool        bRet = sal_False;
2634 
2635     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2636     {
2637         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2638         Bitmap              aNewBmp( GetSizePixel(), 8 );
2639         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2640 
2641         if( pReadAcc && pWriteAcc )
2642         {
2643             BitmapColor aColor;
2644             long        nWidth = pReadAcc->Width();
2645             long        nWidth1 = nWidth - 1L;
2646             long        nHeight = pReadAcc->Height();
2647             long        nX;
2648             long        nW = nWidth * 3L;
2649             long        nW2 = nW - 3L;
2650             long        nRErr, nGErr, nBErr;
2651             long        nRC, nGC, nBC;
2652             long        nTemp;
2653             long        nZ;
2654             long*       p1 = new long[ nW ];
2655             long*       p2 = new long[ nW ];
2656             long*       p1T = p1;
2657             long*       p2T = p2;
2658             long*       pTmp;
2659             sal_Bool        bPal = pReadAcc->HasPalette();
2660 
2661             pTmp = p2T;
2662 
2663             if( bPal )
2664             {
2665                 for( nZ = 0; nZ < nWidth; nZ++ )
2666                 {
2667                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2668 
2669                     *pTmp++ = (long) aColor.GetBlue() << 12;
2670                     *pTmp++ = (long) aColor.GetGreen() << 12;
2671                     *pTmp++ = (long) aColor.GetRed() << 12;
2672                 }
2673             }
2674             else
2675             {
2676                 for( nZ = 0; nZ < nWidth; nZ++ )
2677                 {
2678                     aColor = pReadAcc->GetPixel( 0, nZ );
2679 
2680                     *pTmp++ = (long) aColor.GetBlue() << 12;
2681                     *pTmp++ = (long) aColor.GetGreen() << 12;
2682                     *pTmp++ = (long) aColor.GetRed() << 12;
2683                 }
2684             }
2685 
2686             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2687             {
2688                 pTmp = p1T;
2689                 p1T = p2T;
2690                 p2T = pTmp;
2691 
2692                 if( nY < nHeight )
2693                 {
2694                     if( bPal )
2695                     {
2696                         for( nZ = 0; nZ < nWidth; nZ++ )
2697                         {
2698                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2699 
2700                             *pTmp++ = (long) aColor.GetBlue() << 12;
2701                             *pTmp++ = (long) aColor.GetGreen() << 12;
2702                             *pTmp++ = (long) aColor.GetRed() << 12;
2703                         }
2704                     }
2705                     else
2706                     {
2707                         for( nZ = 0; nZ < nWidth; nZ++ )
2708                         {
2709                             aColor = pReadAcc->GetPixel( nY, nZ );
2710 
2711                             *pTmp++ = (long) aColor.GetBlue() << 12;
2712                             *pTmp++ = (long) aColor.GetGreen() << 12;
2713                             *pTmp++ = (long) aColor.GetRed() << 12;
2714                         }
2715                     }
2716                 }
2717 
2718                 // erstes Pixel gesondert betrachten
2719                 nX = 0;
2720                 CALC_ERRORS;
2721                 CALC_TABLES7;
2722                 nX -= 5;
2723                 CALC_TABLES5;
2724                 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2725 
2726                 // mittlere Pixel ueber Schleife
2727                 long nXAcc;
2728                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2729                 {
2730                     CALC_ERRORS;
2731                     CALC_TABLES7;
2732                     nX -= 8;
2733                     CALC_TABLES3;
2734                     CALC_TABLES5;
2735                     pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2736                 }
2737 
2738                 // letztes Pixel gesondert betrachten
2739                 CALC_ERRORS;
2740                 nX -= 5;
2741                 CALC_TABLES3;
2742                 CALC_TABLES5;
2743                 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2744             }
2745 
2746             delete[] p1;
2747             delete[] p2;
2748             bRet = sal_True;
2749         }
2750 
2751         ReleaseAccess( pReadAcc );
2752         aNewBmp.ReleaseAccess( pWriteAcc );
2753 
2754         if( bRet )
2755         {
2756             const MapMode   aMap( maPrefMapMode );
2757             const Size      aPrefSize( maPrefSize );
2758 
2759             *this = aNewBmp;
2760 
2761             maPrefMapMode = aMap;
2762             maPrefSize = aPrefSize;
2763         }
2764     }
2765 
2766     return bRet;
2767 }
2768 
2769 // ------------------------------------------------------------------------
2770 
2771 sal_Bool Bitmap::ImplDitherFloyd16()
2772 {
2773     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2774     Bitmap              aNewBmp( GetSizePixel(), 24 );
2775     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2776     sal_Bool                bRet = sal_False;
2777 
2778     if( pReadAcc && pWriteAcc )
2779     {
2780         const long      nWidth = pWriteAcc->Width();
2781         const long      nWidth1 = nWidth - 1L;
2782         const long      nHeight = pWriteAcc->Height();
2783         BitmapColor     aColor;
2784         BitmapColor     aBestCol;
2785         ImpErrorQuad    aErrQuad;
2786         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
2787         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
2788         ImpErrorQuad*   pQLine1 = pErrQuad1;
2789         ImpErrorQuad*   pQLine2 = 0;
2790         long            nX, nY;
2791         long            nYTmp = 0L;
2792         sal_Bool            bQ1 = sal_True;
2793 
2794         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2795             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2796                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2797 
2798         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2799         {
2800             // erstes ZeilenPixel
2801             aBestCol = pQLine1[ 0 ].ImplGetColor();
2802             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2803             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2804             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2805             pWriteAcc->SetPixel( nY, 0, aBestCol );
2806 
2807             for( nX = 1L; nX < nWidth1; nX++ )
2808             {
2809                 aColor = pQLine1[ nX ].ImplGetColor();
2810                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2811                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2812                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2813                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2814                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2815                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2816                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2817                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2818                 pWriteAcc->SetPixel( nY, nX, aBestCol );
2819             }
2820 
2821             // letztes ZeilenPixel
2822             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2823             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2824             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2825             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2826             pWriteAcc->SetPixel( nY, nX, aBestCol );
2827 
2828             // Zeilenpuffer neu fuellen/kopieren
2829             pQLine1 = pQLine2;
2830             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2831 
2832             if( nYTmp < nHeight )
2833                 for( nX = 0L; nX < nWidth; nX++ )
2834                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2835         }
2836 
2837         // Zeilenpuffer zerstoeren
2838         delete[] pErrQuad1;
2839         delete[] pErrQuad2;
2840         bRet = sal_True;
2841     }
2842 
2843     ReleaseAccess( pReadAcc );
2844     aNewBmp.ReleaseAccess( pWriteAcc );
2845 
2846     if( bRet )
2847     {
2848         const MapMode   aMap( maPrefMapMode );
2849         const Size      aSize( maPrefSize );
2850 
2851         *this = aNewBmp;
2852 
2853         maPrefMapMode = aMap;
2854         maPrefSize = aSize;
2855     }
2856 
2857     return bRet;
2858 }
2859 
2860 // ------------------------------------------------------------------------
2861 
2862 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2863 {
2864     sal_Bool bRet;
2865 
2866     if( GetColorCount() <= (sal_uLong) nColorCount )
2867         bRet = sal_True;
2868     else if( nColorCount )
2869     {
2870         if( BMP_REDUCE_SIMPLE == eReduce )
2871             bRet = ImplReduceSimple( nColorCount );
2872         else if( BMP_REDUCE_POPULAR == eReduce )
2873             bRet = ImplReducePopular( nColorCount );
2874         else
2875             bRet = ImplReduceMedian( nColorCount );
2876     }
2877     else
2878         bRet = sal_False;
2879 
2880     return bRet;
2881 }
2882 
2883 // ------------------------------------------------------------------------
2884 
2885 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2886 {
2887     Bitmap              aNewBmp;
2888     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2889     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
2890     sal_uInt16              nBitCount;
2891     sal_Bool                bRet = sal_False;
2892 
2893     if( nColCount <= 2 )
2894         nBitCount = 1;
2895     else if( nColCount <= 16 )
2896         nBitCount = 4;
2897     else
2898         nBitCount = 8;
2899 
2900     if( pRAcc )
2901     {
2902         Octree                  aOct( *pRAcc, nColCount );
2903         const BitmapPalette&    rPal = aOct.GetPalette();
2904         BitmapWriteAccess*      pWAcc;
2905 
2906         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2907         pWAcc = aNewBmp.AcquireWriteAccess();
2908 
2909         if( pWAcc )
2910         {
2911             const long nWidth = pRAcc->Width();
2912             const long nHeight = pRAcc->Height();
2913 
2914             if( pRAcc->HasPalette() )
2915             {
2916                 for( long nY = 0L; nY < nHeight; nY++ )
2917                     for( long nX =0L; nX < nWidth; nX++ )
2918                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2919             }
2920             else
2921             {
2922                 for( long nY = 0L; nY < nHeight; nY++ )
2923                     for( long nX =0L; nX < nWidth; nX++ )
2924                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2925             }
2926 
2927             aNewBmp.ReleaseAccess( pWAcc );
2928             bRet = sal_True;
2929         }
2930 
2931         ReleaseAccess( pRAcc );
2932     }
2933 
2934     if( bRet )
2935     {
2936         const MapMode   aMap( maPrefMapMode );
2937         const Size      aSize( maPrefSize );
2938 
2939         *this = aNewBmp;
2940         maPrefMapMode = aMap;
2941         maPrefSize = aSize;
2942     }
2943 
2944     return bRet;
2945 }
2946 
2947 // ------------------------------------------------------------------------
2948 
2949 struct PopularColorCount
2950 {
2951     sal_uInt32  mnIndex;
2952     sal_uInt32  mnCount;
2953 };
2954 
2955 // ------------------------------------------------------------------------
2956 
2957 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2958 {
2959     int nRet;
2960 
2961     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2962         nRet = 1;
2963     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2964         nRet = 0;
2965     else
2966         nRet = -1;
2967 
2968     return nRet;
2969 }
2970 
2971 // ------------------------------------------------------------------------
2972 
2973 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2974 {
2975     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2976     sal_uInt16              nBitCount;
2977     sal_Bool                bRet = sal_False;
2978 
2979     if( nColCount > 256 )
2980         nColCount = 256;
2981 
2982     if( nColCount < 17 )
2983         nBitCount = 4;
2984     else
2985         nBitCount = 8;
2986 
2987     if( pRAcc )
2988     {
2989         const sal_uInt32    nValidBits = 4;
2990         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
2991         const sal_uInt32    nLeftShiftBits1 = nValidBits;
2992         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
2993         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
2994         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
2995         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2996         const long          nWidth = pRAcc->Width();
2997         const long          nHeight = pRAcc->Height();
2998         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
2999         long                nX, nY, nR, nG, nB, nIndex;
3000 
3001         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
3002 
3003         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3004         {
3005             for( nG = 0; nG < 256; nG += nColorOffset )
3006             {
3007                 for( nB = 0; nB < 256; nB += nColorOffset )
3008                 {
3009                     pCountTable[ nIndex ].mnIndex = nIndex;
3010                     nIndex++;
3011                 }
3012             }
3013         }
3014 
3015         if( pRAcc->HasPalette() )
3016         {
3017             for( nY = 0L; nY < nHeight; nY++ )
3018             {
3019                 for( nX = 0L; nX < nWidth; nX++ )
3020                 {
3021                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3022                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3023                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3024                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3025                 }
3026             }
3027         }
3028         else
3029         {
3030             for( nY = 0L; nY < nHeight; nY++ )
3031             {
3032                 for( nX = 0L; nX < nWidth; nX++ )
3033                 {
3034                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3035                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3036                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3037                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3038                 }
3039             }
3040         }
3041 
3042         BitmapPalette aNewPal( nColCount );
3043 
3044         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3045 
3046         for( sal_uInt16 n = 0; n < nColCount; n++ )
3047         {
3048             const PopularColorCount& rPop = pCountTable[ n ];
3049             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3050                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3051                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3052         }
3053 
3054         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3055         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3056 
3057         if( pWAcc )
3058         {
3059             BitmapColor aDstCol( (sal_uInt8) 0 );
3060             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
3061 
3062             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3063                 for( nG = 0; nG < 256; nG += nColorOffset )
3064                     for( nB = 0; nB < 256; nB += nColorOffset )
3065                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3066 
3067             if( pRAcc->HasPalette() )
3068             {
3069                 for( nY = 0L; nY < nHeight; nY++ )
3070                 {
3071                     for( nX = 0L; nX < nWidth; nX++ )
3072                     {
3073                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3074                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3075                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3076                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3077                         pWAcc->SetPixel( nY, nX, aDstCol );
3078                     }
3079                 }
3080             }
3081             else
3082             {
3083                 for( nY = 0L; nY < nHeight; nY++ )
3084                 {
3085                     for( nX = 0L; nX < nWidth; nX++ )
3086                     {
3087                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3088                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3089                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3090                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3091                         pWAcc->SetPixel( nY, nX, aDstCol );
3092                     }
3093                 }
3094             }
3095 
3096             delete[] pIndexMap;
3097             aNewBmp.ReleaseAccess( pWAcc );
3098             bRet = sal_True;
3099         }
3100 
3101         delete[] pCountTable;
3102         ReleaseAccess( pRAcc );
3103 
3104         if( bRet )
3105         {
3106             const MapMode   aMap( maPrefMapMode );
3107             const Size      aSize( maPrefSize );
3108 
3109             *this = aNewBmp;
3110             maPrefMapMode = aMap;
3111             maPrefSize = aSize;
3112         }
3113     }
3114 
3115     return bRet;
3116 }
3117 
3118 // ------------------------------------------------------------------------
3119 
3120 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3121 {
3122     BitmapReadAccess*   pRAcc = AcquireReadAccess();
3123     sal_uInt16              nBitCount;
3124     sal_Bool                bRet = sal_False;
3125 
3126     if( nColCount < 17 )
3127         nBitCount = 4;
3128     else if( nColCount < 257 )
3129         nBitCount = 8;
3130     else
3131     {
3132         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3133         nBitCount = 8;
3134         nColCount = 256;
3135     }
3136 
3137     if( pRAcc )
3138     {
3139         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
3140         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3141 
3142         if( pWAcc )
3143         {
3144             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
3145             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3146             const long  nWidth = pWAcc->Width();
3147             const long  nHeight = pWAcc->Height();
3148             long        nIndex = 0L;
3149 
3150             memset( (HPBYTE) pColBuf, 0, nSize );
3151 
3152             // create Buffer
3153             if( pRAcc->HasPalette() )
3154             {
3155                 for( long nY = 0L; nY < nHeight; nY++ )
3156                 {
3157                     for( long nX = 0L; nX < nWidth; nX++ )
3158                     {
3159                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3160                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3161                     }
3162                 }
3163             }
3164             else
3165             {
3166                 for( long nY = 0L; nY < nHeight; nY++ )
3167                 {
3168                     for( long nX = 0L; nX < nWidth; nX++ )
3169                     {
3170                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3171                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3172                     }
3173                 }
3174             }
3175 
3176             // create palette via median cut
3177             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3178             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3179                            nColCount, nWidth * nHeight, nIndex );
3180 
3181             // do mapping of colors to palette
3182             InverseColorMap aMap( aPal );
3183             pWAcc->SetPalette( aPal );
3184             for( long nY = 0L; nY < nHeight; nY++ )
3185                 for( long nX = 0L; nX < nWidth; nX++ )
3186                     pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3187 
3188             rtl_freeMemory( pColBuf );
3189             aNewBmp.ReleaseAccess( pWAcc );
3190             bRet = sal_True;
3191         }
3192 
3193         ReleaseAccess( pRAcc );
3194 
3195         if( bRet )
3196         {
3197             const MapMode   aMap( maPrefMapMode );
3198             const Size      aSize( maPrefSize );
3199 
3200             *this = aNewBmp;
3201             maPrefMapMode = aMap;
3202             maPrefSize = aSize;
3203         }
3204     }
3205 
3206     return bRet;
3207 }
3208 
3209 // ------------------------------------------------------------------------
3210 
3211 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3212                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3213                             long nColors, long nPixels, long& rIndex )
3214 {
3215     if( !nPixels )
3216         return;
3217 
3218     BitmapColor aCol;
3219     const long  nRLen = nR2 - nR1;
3220     const long  nGLen = nG2 - nG1;
3221     const long  nBLen = nB2 - nB1;
3222     long        nR, nG, nB;
3223     sal_uLong*      pBuf = pColBuf;
3224 
3225     if( !nRLen && !nGLen && !nBLen )
3226     {
3227         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3228         {
3229             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3230             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3231             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3232             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3233         }
3234     }
3235     else
3236     {
3237         if( 1 == nColors || 1 == nPixels )
3238         {
3239             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3240 
3241             for( nR = nR1; nR <= nR2; nR++ )
3242             {
3243                 for( nG = nG1; nG <= nG2; nG++ )
3244                 {
3245                     for( nB = nB1; nB <= nB2; nB++ )
3246                     {
3247                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3248 
3249                         if( nPixSum )
3250                         {
3251                             nRSum += nR * nPixSum;
3252                             nGSum += nG * nPixSum;
3253                             nBSum += nB * nPixSum;
3254                         }
3255                     }
3256                 }
3257             }
3258 
3259             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3260             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3261             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3262             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3263         }
3264         else
3265         {
3266             const long  nTest = ( nPixels >> 1 );
3267             long        nPixOld = 0;
3268             long        nPixNew = 0;
3269 
3270             if( nBLen > nGLen && nBLen > nRLen )
3271             {
3272                 nB = nB1 - 1;
3273 
3274                 while( nPixNew < nTest )
3275                 {
3276                     nB++, nPixOld = nPixNew;
3277                     for( nR = nR1; nR <= nR2; nR++ )
3278                         for( nG = nG1; nG <= nG2; nG++ )
3279                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3280                 }
3281 
3282                 if( nB < nB2 )
3283                 {
3284                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3285                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3286                 }
3287                 else
3288                 {
3289                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3290                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3291                 }
3292             }
3293             else if( nGLen > nRLen )
3294             {
3295                 nG = nG1 - 1;
3296 
3297                 while( nPixNew < nTest )
3298                 {
3299                     nG++, nPixOld = nPixNew;
3300                     for( nR = nR1; nR <= nR2; nR++ )
3301                         for( nB = nB1; nB <= nB2; nB++ )
3302                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3303                 }
3304 
3305                 if( nG < nG2 )
3306                 {
3307                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3308                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3309                 }
3310                 else
3311                 {
3312                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3313                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3314                 }
3315             }
3316             else
3317             {
3318                 nR = nR1 - 1;
3319 
3320                 while( nPixNew < nTest )
3321                 {
3322                     nR++, nPixOld = nPixNew;
3323                     for( nG = nG1; nG <= nG2; nG++ )
3324                         for( nB = nB1; nB <= nB2; nB++ )
3325                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3326                 }
3327 
3328                 if( nR < nR2 )
3329                 {
3330                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3331                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3332                 }
3333                 else
3334                 {
3335                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3336                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3337                 }
3338             }
3339         }
3340     }
3341 }
3342 
3343 // ------------------------------------------------------------------------
3344 
3345 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3346 {
3347     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3348 }
3349 
3350 // ------------------------------------------------------------------------
3351 
3352 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3353 {
3354     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3355 }
3356 
3357 // ------------------------------------------------------------------------
3358 
3359 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3360                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3361                      double fGamma, sal_Bool bInvert )
3362 {
3363     sal_Bool bRet = sal_False;
3364 
3365     // nothing to do => return quickly
3366     if( !nLuminancePercent && !nContrastPercent &&
3367         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3368         ( fGamma == 1.0 ) && !bInvert )
3369     {
3370         bRet = sal_True;
3371     }
3372     else
3373     {
3374         BitmapWriteAccess* pAcc = AcquireWriteAccess();
3375 
3376         if( pAcc )
3377         {
3378             BitmapColor     aCol;
3379             const long      nW = pAcc->Width();
3380             const long      nH = pAcc->Height();
3381             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
3382             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
3383             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
3384             long            nX, nY;
3385             double          fM, fROff, fGOff, fBOff, fOff;
3386 
3387             // calculate slope
3388             if( nContrastPercent >= 0 )
3389                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3390             else
3391                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3392 
3393             // total offset = luminance offset + contrast offset
3394             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3395 
3396             // channel offset = channel offset  + total offset
3397             fROff = nChannelRPercent * 2.55 + fOff;
3398             fGOff = nChannelGPercent * 2.55 + fOff;
3399             fBOff = nChannelBPercent * 2.55 + fOff;
3400 
3401             // calculate gamma value
3402             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3403             const sal_Bool bGamma = ( fGamma != 1.0 );
3404 
3405             // create mapping table
3406             for( nX = 0L; nX < 256L; nX++ )
3407             {
3408                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3409                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3410                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3411 
3412                 if( bGamma )
3413                 {
3414                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3415                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3416                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3417                 }
3418 
3419                 if( bInvert )
3420                 {
3421                     cMapR[ nX ] = ~cMapR[ nX ];
3422                     cMapG[ nX ] = ~cMapG[ nX ];
3423                     cMapB[ nX ] = ~cMapB[ nX ];
3424                 }
3425             }
3426 
3427             // do modifying
3428             if( pAcc->HasPalette() )
3429             {
3430                 BitmapColor aNewCol;
3431 
3432                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3433                 {
3434                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3435                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3436                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3437                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3438                     pAcc->SetPaletteColor( i, aNewCol );
3439                 }
3440             }
3441             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3442             {
3443                 for( nY = 0L; nY < nH; nY++ )
3444                 {
3445                     Scanline pScan = pAcc->GetScanline( nY );
3446 
3447                     for( nX = 0L; nX < nW; nX++ )
3448                     {
3449                         *pScan = cMapB[ *pScan ]; pScan++;
3450                         *pScan = cMapG[ *pScan ]; pScan++;
3451                         *pScan = cMapR[ *pScan ]; pScan++;
3452                     }
3453                 }
3454             }
3455             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3456             {
3457                 for( nY = 0L; nY < nH; nY++ )
3458                 {
3459                     Scanline pScan = pAcc->GetScanline( nY );
3460 
3461                     for( nX = 0L; nX < nW; nX++ )
3462                     {
3463                         *pScan = cMapR[ *pScan ]; pScan++;
3464                         *pScan = cMapG[ *pScan ]; pScan++;
3465                         *pScan = cMapB[ *pScan ]; pScan++;
3466                     }
3467                 }
3468             }
3469             else
3470             {
3471                 for( nY = 0L; nY < nH; nY++ )
3472                 {
3473                     for( nX = 0L; nX < nW; nX++ )
3474                     {
3475                         aCol = pAcc->GetPixel( nY, nX );
3476                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
3477                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3478                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3479                         pAcc->SetPixel( nY, nX, aCol );
3480                     }
3481                 }
3482             }
3483 
3484             delete[] cMapR;
3485             delete[] cMapG;
3486             delete[] cMapB;
3487             ReleaseAccess( pAcc );
3488             bRet = sal_True;
3489         }
3490     }
3491 
3492     return bRet;
3493 }
3494