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