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