xref: /AOO41X/main/vcl/source/gdi/bitmap3.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
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 
ImplCreateDitherMatrix(sal_uInt8 (* pDitherMatrix)[16][16])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 
Convert(BmpConversion eConversion)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, NULL );
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 
ImplMakeMono(sal_uInt8 cThreshold)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 
ImplMakeMonoDither()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 
ImplMakeGreyscales(sal_uInt16 nGreys)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 
ImplConvertUp(sal_uInt16 nBitCount,Color * pExtColor)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 
ImplConvertDown(sal_uInt16 nBitCount,Color * pExtColor)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 
ImplConvertGhosted()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 
Scale(const double & rScaleX,const double & rScaleY,sal_uInt32 nScaleFlag)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 
Scale(const Size & rNewSize,sal_uInt32 nScaleFlag)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 
AdaptBitCount(Bitmap & rNew) const1048 void Bitmap::AdaptBitCount(Bitmap& rNew) const
1049 {
1050     ImplAdaptBitCount(rNew);
1051 }
1052 
1053 // ------------------------------------------------------------------------
1054 
ImplAdaptBitCount(Bitmap & rNew) const1055 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 
ImplScaleFast(const double & rScaleX,const double & rScaleY)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 
ImplScaleInterpolate(const double & rScaleX,const double & rScaleY)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 
ImplScaleSuper(const double & rScaleX,const double & rScaleY)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                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1563                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1564                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1565                                     nTotalWeightY += nWeightY;
1566                                 }
1567 
1568                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1569                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1570                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1571                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1572 
1573                             }
1574                         }
1575                     }
1576 }
1577                 else
1578                 {
1579                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1580                     {
1581                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1582                         {
1583                             nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ];
1584 
1585                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1586                             {
1587                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1588 
1589                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) );
1590                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) );
1591                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1592                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1593                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1594 
1595                                 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) );
1596                                 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) );
1597                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1598                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1599                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1600 
1601                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1602                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1603                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1604                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1605                             }
1606                         }
1607 
1608                     }
1609                     else
1610                     {
1611                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1612                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1613                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1614 
1615                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1616                         {
1617                             nTop = bVMirr ? ( nY + 1 ) : nY;
1618                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1619 
1620                             if( nY ==nEndY )
1621                             {
1622                                 nLineStart = pMapIY[ nY ];
1623                                 nLineRange = 0;
1624                             }
1625                             else
1626                             {
1627                                 nLineStart = pMapIY[ nTop ] ;
1628                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1629                             }
1630 
1631                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1632                             {
1633                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1634                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1635 
1636                                 if( nX == nEndX )
1637                                 {
1638                                     nRowStart = pMapIX[ nX ];
1639                                     nRowRange = 0;
1640                                 }
1641                                 else
1642                                 {
1643                                     nRowStart = pMapIX[ nLeft ];
1644                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1645                                 }
1646 
1647                                 nSumR = nSumG = nSumB = 0;
1648                                 nTotalWeightY = 0;
1649 
1650                                 for(int i = 0; i<= nLineRange; i++)
1651                                 {
1652                                     nSumRowR = nSumRowG = nSumRowB = 0;
1653                                     nTotalWeightX = 0;
1654 
1655                                     for(int j = 0; j <= nRowRange; j++)
1656                                     {
1657                                         aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
1658 
1659                                         if(nX == nEndX )
1660                                         {
1661 
1662                                             nSumRowB += aCol0.GetBlue() << 7L;
1663                                             nSumRowG += aCol0.GetGreen() << 7L;
1664                                             nSumRowR += aCol0.GetRed() << 7L;
1665                                             nTotalWeightX += 1 << 7L;
1666                                         }
1667                                         else if( j == 0 )
1668                                         {
1669 
1670                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1671                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
1672                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
1673                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
1674                                             nTotalWeightX += nWeightX;
1675                                         }
1676                                         else if ( nRowRange == j )
1677                                         {
1678 
1679                                             nWeightX = pMapFX[ nRight ] ;
1680                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
1681                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
1682                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
1683                                             nTotalWeightX += nWeightX;
1684                                         }
1685                                         else
1686                                         {
1687 
1688                                             nSumRowB += aCol0.GetBlue() << 7L;
1689                                             nSumRowG += aCol0.GetGreen() << 7L;
1690                                             nSumRowR += aCol0.GetRed() << 7L;
1691                                             nTotalWeightX += 1 << 7L;
1692                                         }
1693                                     }
1694 
1695                                     if( nY == nEndY )
1696                                         nWeightY = nMax;
1697                                     else if( i == 0 )
1698                                         nWeightY = nMax - pMapFY[ nTop ];
1699                                     else if( nLineRange == 1 )
1700                                         nWeightY = pMapFY[ nTop ];
1701                                     else if ( nLineRange == i )
1702                                         nWeightY = pMapFY[ nBottom ];
1703                                     else
1704                                         nWeightY = nMax;
1705 
1706                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1707                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1708                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1709                                     nTotalWeightY += nWeightY;
1710                                 }
1711 
1712                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1713                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1714                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1715                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1716                             }
1717                         }
1718                     }
1719                 }
1720             }
1721             else
1722             {
1723                 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1724                 {
1725                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1726                     {
1727                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1728                         long        nOff;
1729 
1730                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1731                         {
1732                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1733                             pLine0 = pAcc->GetScanline( nTempY );
1734                             pLine1 = pAcc->GetScanline( ++nTempY );
1735 
1736                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1737                             {
1738                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1739                                 nTempFX = pMapFX[ nX ];
1740 
1741                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1742                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1743                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1744                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
1745 
1746                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1747                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1748                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1749                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
1750 
1751                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1752                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1753                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1754                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1755                             }
1756                         }
1757                     }
1758                     else
1759                     {
1760                         Scanline    pTmpY, pTmpX;
1761                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1762                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1763                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1764 
1765                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1766                         {
1767                             nTop = bVMirr ? ( nY + 1 ) : nY;
1768                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1769 
1770                             if( nY ==nEndY )
1771                             {
1772                                 nLineStart = pMapIY[ nY ];
1773                                 nLineRange = 0;
1774                             }
1775                             else
1776                             {
1777                                 nLineStart = pMapIY[ nTop ] ;
1778                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1779                             }
1780 
1781                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1782                             {
1783                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1784                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1785 
1786                                 if( nX == nEndX  )
1787                                 {
1788                                     nRowStart = pMapIX[ nX ];
1789                                     nRowRange = 0;
1790                                 }
1791                                 else
1792                                 {
1793                                     nRowStart = pMapIX[ nLeft ];
1794                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1795                                 }
1796 
1797                                 nSumR = nSumG = nSumB = 0;
1798                                 nTotalWeightY = 0;
1799 
1800                                 for(int i = 0; i<= nLineRange; i++)
1801                                 {
1802                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1803                                     pTmpX = pTmpY + 3L * nRowStart;
1804                                     nSumRowR = nSumRowG = nSumRowB = 0;
1805                                     nTotalWeightX = 0;
1806 
1807                                     for(int j = 0; j <= nRowRange; j++)
1808                                     {
1809                                         if(nX == nEndX )
1810                                         {
1811                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1812                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1813                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1814                                             nTotalWeightX += 1 << 7L;
1815                                         }
1816                                         else if( j == 0 )
1817                                         {
1818                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1819                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1820                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1821                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1822                                             nTotalWeightX += nWeightX;
1823                                         }
1824                                         else if ( nRowRange == j )
1825                                         {
1826                                             nWeightX = pMapFX[ nRight ] ;
1827                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1828                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1829                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1830                                             nTotalWeightX += nWeightX;
1831                                         }
1832                                         else
1833                                         {
1834                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1835                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1836                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1837                                             nTotalWeightX += 1 << 7L;
1838                                         }
1839                                     }
1840 
1841                                     if( nY == nEndY )
1842                                         nWeightY = nMax;
1843                                     else if( i == 0 )
1844                                         nWeightY = nMax - pMapFY[ nTop ];
1845                                     else if( nLineRange == 1 )
1846                                         nWeightY = pMapFY[ nTop ];
1847                                     else if ( nLineRange == i )
1848                                         nWeightY = pMapFY[ nBottom ];
1849                                     else
1850                                         nWeightY = nMax;
1851 
1852                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1853                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1854                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1855                                     nTotalWeightY += nWeightY;
1856                                 }
1857 
1858                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1859                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1860                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1861                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1862 
1863                             }
1864                         }
1865                     }
1866                 }
1867                 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1868                 {
1869                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1870                     {
1871                         Scanline    pLine0, pLine1, pTmp0, pTmp1;
1872                         long        nOff;
1873 
1874                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1875                         {
1876                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1877                             pLine0 = pAcc->GetScanline( nTempY );
1878                             pLine1 = pAcc->GetScanline( ++nTempY );
1879 
1880                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1881                             {
1882                                 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1883                                 nTempFX = pMapFX[ nX ];
1884 
1885                                 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1886                                 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1887                                 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1888                                 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
1889 
1890                                 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1891                                 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1892                                 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1893                                 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
1894 
1895                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1896                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1897                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1898                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1899                             }
1900                         }
1901                     }
1902                     else
1903                     {
1904                         Scanline    pTmpY, pTmpX;
1905                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1906                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1907                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1908 
1909                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1910                         {
1911                             nTop = bVMirr ? ( nY + 1 ) : nY;
1912                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
1913 
1914                             if( nY ==nEndY )
1915                             {
1916                                 nLineStart = pMapIY[ nY ];
1917                                 nLineRange = 0;
1918                             }
1919                             else
1920                             {
1921                                 nLineStart = pMapIY[ nTop ] ;
1922                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1923                             }
1924 
1925                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1926                             {
1927                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
1928                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
1929 
1930                                 if( nX == nEndX )
1931                                 {
1932                                     nRowStart = pMapIX[ nX ];
1933                                     nRowRange = 0;
1934                                 }
1935                                 else
1936                                 {
1937                                     nRowStart = pMapIX[ nLeft ];
1938                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1939                                 }
1940 
1941                                 nSumR = nSumG = nSumB = 0;
1942                                 nTotalWeightY = 0;
1943 
1944                                 for(int i = 0; i<= nLineRange; i++)
1945                                 {
1946                                     pTmpY = pAcc->GetScanline( nLineStart + i );
1947                                     pTmpX = pTmpY + 3L * nRowStart;
1948                                     nSumRowR = nSumRowG = nSumRowB = 0;
1949                                     nTotalWeightX = 0;
1950 
1951                                     for(int j = 0; j <= nRowRange; j++)
1952                                     {
1953                                         if(nX == nEndX )
1954                                         {
1955                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1956                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1957                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1958                                             nTotalWeightX += 1 << 7L;
1959                                         }
1960                                         else if( j == 0 )
1961                                         {
1962                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
1963                                             nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1964                                             nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1965                                             nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1966                                             nTotalWeightX += nWeightX;
1967                                         }
1968                                         else if ( nRowRange == j )
1969                                         {
1970                                             nWeightX = pMapFX[ nRight ] ;
1971                                             nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1972                                             nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1973                                             nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1974                                             nTotalWeightX += nWeightX;
1975                                         }
1976                                         else
1977                                         {
1978                                             nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1979                                             nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1980                                             nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1981                                             nTotalWeightX += 1 << 7L;
1982                                         }
1983                                     }
1984 
1985                                     if( nY == nEndY )
1986                                         nWeightY = nMax;
1987                                     else if( i == 0 )
1988                                         nWeightY = nMax - pMapFY[ nTop ];
1989                                     else if( nLineRange == 1 )
1990                                         nWeightY = pMapFY[ nTop ];
1991                                     else if ( nLineRange == i )
1992                                         nWeightY = pMapFY[ nBottom ];
1993                                     else
1994                                         nWeightY = nMax;
1995 
1996                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1997                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1998                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1999                                     nTotalWeightY += nWeightY;
2000                                 }
2001 
2002                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2003                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2004                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2005                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2006 
2007                             }
2008                         }
2009                     }
2010                 }
2011                 else
2012                 {
2013                     if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
2014                     {
2015                         for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2016                         {
2017                             nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
2018 
2019                             for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
2020                             {
2021                                 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
2022 
2023                                 aCol0 = pAcc->GetPixel( nTempY, nTempX );
2024                                 aCol1 = pAcc->GetPixel( nTempY, ++nTempX );
2025                                 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2026                                 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2027                                 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2028 
2029                                 aCol1 = pAcc->GetPixel( ++nTempY, nTempX );
2030                                 aCol0 = pAcc->GetPixel( nTempY--, --nTempX );
2031                                 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2032                                 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2033                                 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2034 
2035                                 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
2036                                 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
2037                                 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
2038                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2039                             }
2040                         }
2041                     }
2042                     else
2043                     {
2044                         long        nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
2045                         long        nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
2046                         long        nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
2047 
2048                         for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2049                         {
2050                             nTop = bVMirr ? ( nY + 1 ) : nY;
2051                             nBottom = bVMirr ? nY : ( nY + 1 ) ;
2052 
2053                             if( nY ==nEndY )
2054                             {
2055                                 nLineStart = pMapIY[ nY ];
2056                                 nLineRange = 0;
2057                             }
2058                             else
2059                             {
2060                                 nLineStart = pMapIY[ nTop ] ;
2061                                 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
2062                             }
2063 
2064                             for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
2065                             {
2066                                 nLeft = bHMirr ? ( nX + 1 ) : nX;
2067                                 nRight = bHMirr ? nX : ( nX + 1 ) ;
2068 
2069                                 if( nX == nEndX )
2070                                 {
2071                                     nRowStart = pMapIX[ nX ];
2072                                     nRowRange = 0;
2073                                 }
2074                                 else
2075                                 {
2076                                     nRowStart = pMapIX[ nLeft ];
2077                                     nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
2078                                 }
2079 
2080                                 nSumR = nSumG = nSumB = 0;
2081                                 nTotalWeightY = 0;
2082 
2083                                 for(int i = 0; i<= nLineRange; i++)
2084                                 {
2085                                     nSumRowR = nSumRowG = nSumRowB = 0;
2086                                     nTotalWeightX = 0;
2087 
2088                                     for(int j = 0; j <= nRowRange; j++)
2089                                     {
2090                                         aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j );
2091 
2092                                         if(nX == nEndX )
2093                                         {
2094 
2095                                             nSumRowB += aCol0.GetBlue() << 7L;
2096                                             nSumRowG += aCol0.GetGreen() << 7L;
2097                                             nSumRowR += aCol0.GetRed() << 7L;
2098                                             nTotalWeightX += 1 << 7L;
2099                                         }
2100                                         else if( j == 0 )
2101                                         {
2102 
2103                                             nWeightX = (nMax- pMapFX[ nLeft ]) ;
2104                                             nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
2105                                             nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
2106                                             nSumRowR += ( nWeightX *aCol0.GetRed()) ;
2107                                             nTotalWeightX += nWeightX;
2108                                         }
2109                                         else if ( nRowRange == j )
2110                                         {
2111 
2112                                             nWeightX = pMapFX[ nRight ] ;
2113                                             nSumRowB += ( nWeightX *aCol0.GetBlue() );
2114                                             nSumRowG += ( nWeightX *aCol0.GetGreen() );
2115                                             nSumRowR += ( nWeightX *aCol0.GetRed() );
2116                                             nTotalWeightX += nWeightX;
2117                                         }
2118                                         else
2119                                         {
2120                                             nSumRowB += aCol0.GetBlue() << 7L;
2121                                             nSumRowG += aCol0.GetGreen() << 7L;
2122                                             nSumRowR += aCol0.GetRed() << 7L;
2123                                             nTotalWeightX += 1 << 7L;
2124                                         }
2125                                     }
2126 
2127                                     if( nY == nEndY )
2128                                         nWeightY = nMax;
2129                                     else if( i == 0 )
2130                                         nWeightY = nMax - pMapFY[ nTop ];
2131                                     else if( nLineRange == 1 )
2132                                         nWeightY = pMapFY[ nTop ];
2133                                     else if ( nLineRange == i )
2134                                         nWeightY = pMapFY[ nBottom ];
2135                                     else
2136                                         nWeightY = nMax;
2137 
2138                                     nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
2139                                     nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
2140                                     nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
2141                                     nTotalWeightY += nWeightY;
2142                                 }
2143 
2144                                 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2145                                 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2146                                 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2147                                 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2148 
2149                             }
2150                         }
2151                     }
2152                 }
2153             }
2154 
2155             bRet = true;
2156         }
2157 
2158         delete[] pMapIX;
2159         delete[] pMapIY;
2160         delete[] pMapFX;
2161         delete[] pMapFY;
2162 
2163         ReleaseAccess( pAcc );
2164         aOutBmp.ReleaseAccess( pWAcc );
2165 
2166         if( bRet )
2167         {
2168             ImplAdaptBitCount(aOutBmp);
2169             ImplAssignWithSize(aOutBmp);
2170         }
2171 
2172         if( !bRet )
2173             bRet = ImplScaleFast( scaleX, scaleY );
2174     }
2175 
2176     return bRet;
2177 }
2178 
2179 //-----------------------------------------------------------------------------------
2180 
2181 namespace
2182 {
ImplCalculateContributions(const sal_uInt32 aSourceSize,const sal_uInt32 aDestinationSize,sal_uInt32 & aNumberOfContributions,double * & pWeights,sal_uInt32 * & pPixels,sal_uInt32 * & pCount,const Kernel & aKernel)2183     void ImplCalculateContributions(
2184         const sal_uInt32 aSourceSize,
2185         const sal_uInt32 aDestinationSize,
2186         sal_uInt32& aNumberOfContributions,
2187         double*& pWeights,
2188         sal_uInt32*& pPixels,
2189         sal_uInt32*& pCount,
2190         const Kernel& aKernel)
2191     {
2192         const double fSamplingRadius(aKernel.GetWidth());
2193         const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
2194         const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
2195         const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
2196 
2197         aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
2198         const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
2199         pWeights = new double[nAllocSize];
2200         pPixels = new sal_uInt32[nAllocSize];
2201         pCount = new sal_uInt32[aDestinationSize];
2202 
2203         for(sal_uInt32 i(0); i < aDestinationSize; i++)
2204         {
2205             const sal_uInt32 aIndex(i * aNumberOfContributions);
2206             const double aCenter(i / fScale);
2207             const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
2208             const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
2209             sal_uInt32 aCurrentCount(0);
2210 
2211             for(sal_Int32 j(aLeft); j <= aRight; j++)
2212             {
2213                 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
2214 
2215                 // Reduce calculations with ignoring weights of 0.0
2216                 if(fabs(aWeight) < 0.0001)
2217                 {
2218                     continue;
2219                 }
2220 
2221                 // Handling on edges
2222                 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
2223                 const sal_uInt32 nIndex(aIndex + aCurrentCount);
2224 
2225                 pWeights[nIndex] = aWeight;
2226                 pPixels[nIndex] = aPixelIndex;
2227 
2228                 aCurrentCount++;
2229             }
2230 
2231             pCount[i] = aCurrentCount;
2232         }
2233     }
2234 
ImplScaleConvolutionHor(Bitmap & rSource,Bitmap & rTarget,const double & rScaleX,const Kernel & aKernel)2235     sal_Bool ImplScaleConvolutionHor(
2236         Bitmap& rSource,
2237         Bitmap& rTarget,
2238         const double& rScaleX,
2239         const Kernel& aKernel)
2240     {
2241         // Do horizontal filtering
2242         OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2243         const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2244         const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
2245 
2246         if(nWidth == nNewWidth)
2247         {
2248             return true;
2249         }
2250 
2251         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2252 
2253         if(pReadAcc)
2254         {
2255             double* pWeights = 0;
2256             sal_uInt32* pPixels = 0;
2257             sal_uInt32* pCount = 0;
2258             sal_uInt32 aNumberOfContributions(0);
2259 
2260             const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2261             ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2262             rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
2263             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2264             bool bResult(0 != pWriteAcc);
2265 
2266             if(bResult)
2267             {
2268                 for(sal_uInt32 y(0); y < nHeight; y++)
2269                 {
2270                     for(sal_uInt32 x(0); x < nNewWidth; x++)
2271                     {
2272                         const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
2273                         double aSum(0.0);
2274                         double aValueRed(0.0);
2275                         double aValueGreen(0.0);
2276                         double aValueBlue(0.0);
2277 
2278                         for(sal_uInt32 j(0); j < pCount[x]; j++)
2279                         {
2280                             const sal_uInt32 aIndex(aBaseIndex + j);
2281                             const double aWeight(pWeights[aIndex]);
2282                             BitmapColor aColor;
2283 
2284                             aSum += aWeight;
2285 
2286                             if(pReadAcc->HasPalette())
2287                             {
2288                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
2289                             }
2290                             else
2291                             {
2292                                 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
2293                             }
2294 
2295                             aValueRed += aWeight * aColor.GetRed();
2296                             aValueGreen += aWeight * aColor.GetGreen();
2297                             aValueBlue += aWeight * aColor.GetBlue();
2298                         }
2299 
2300                         const BitmapColor aResultColor(
2301                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2302                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2303                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2304 
2305                         pWriteAcc->SetPixel(y, x, aResultColor);
2306                     }
2307                 }
2308 
2309                 rTarget.ReleaseAccess(pWriteAcc);
2310             }
2311 
2312             rSource.ReleaseAccess(pReadAcc);
2313             delete[] pWeights;
2314             delete[] pCount;
2315             delete[] pPixels;
2316 
2317             if(bResult)
2318             {
2319                 return true;
2320             }
2321         }
2322 
2323         return false;
2324     }
2325 
ImplScaleConvolutionVer(Bitmap & rSource,Bitmap & rTarget,const double & rScaleY,const Kernel & aKernel)2326     bool ImplScaleConvolutionVer(
2327         Bitmap& rSource,
2328         Bitmap& rTarget,
2329         const double& rScaleY,
2330         const Kernel& aKernel)
2331     {
2332         // Do vertical filtering
2333         OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2334         const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2335         const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
2336 
2337         if(nHeight == nNewHeight)
2338         {
2339             return true;
2340         }
2341 
2342         BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2343 
2344         if(pReadAcc)
2345         {
2346             double* pWeights = 0;
2347             sal_uInt32* pPixels = 0;
2348             sal_uInt32* pCount = 0;
2349             sal_uInt32 aNumberOfContributions(0);
2350 
2351             const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2352             ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2353             rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
2354             BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2355             bool bResult(0 != pWriteAcc);
2356 
2357             if(pWriteAcc)
2358             {
2359                 for(sal_uInt32 x(0); x < nWidth; x++)
2360                 {
2361                     for(sal_uInt32 y(0); y < nNewHeight; y++)
2362                     {
2363                         const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
2364                         double aSum(0.0);
2365                         double aValueRed(0.0);
2366                         double aValueGreen(0.0);
2367                         double aValueBlue(0.0);
2368 
2369                         for(sal_uInt32 j(0); j < pCount[y]; j++)
2370                         {
2371                             const sal_uInt32 aIndex(aBaseIndex + j);
2372                             const double aWeight(pWeights[aIndex]);
2373                             BitmapColor aColor;
2374 
2375                             aSum += aWeight;
2376 
2377                             if(pReadAcc->HasPalette())
2378                             {
2379                                 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
2380                             }
2381                             else
2382                             {
2383                                 aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
2384                             }
2385 
2386                             aValueRed += aWeight * aColor.GetRed();
2387                             aValueGreen += aWeight * aColor.GetGreen();
2388                             aValueBlue += aWeight * aColor.GetBlue();
2389                         }
2390 
2391                         const BitmapColor aResultColor(
2392                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2393                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2394                             static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2395 
2396                         if(pWriteAcc->HasPalette())
2397                         {
2398                             pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
2399                         }
2400                         else
2401                         {
2402                             pWriteAcc->SetPixel(y, x, aResultColor);
2403                         }
2404                     }
2405                 }
2406             }
2407 
2408             rTarget.ReleaseAccess(pWriteAcc);
2409             rSource.ReleaseAccess(pReadAcc);
2410 
2411             delete[] pWeights;
2412             delete[] pCount;
2413             delete[] pPixels;
2414 
2415             if(bResult)
2416             {
2417                 return true;
2418             }
2419         }
2420 
2421         return false;
2422     }
2423 }
2424 
2425 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and
2426 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see
2427 // bugzilla task for deitails) Thanks!
ImplScaleConvolution(const double & rScaleX,const double & rScaleY,const Kernel & aKernel)2428 sal_Bool Bitmap::ImplScaleConvolution(
2429     const double& rScaleX,
2430     const double& rScaleY,
2431     const Kernel& aKernel)
2432 {
2433     const bool bMirrorHor(rScaleX < 0.0);
2434     const bool bMirrorVer(rScaleY < 0.0);
2435     const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
2436     const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
2437     const sal_uInt32 nWidth(GetSizePixel().Width());
2438     const sal_uInt32 nHeight(GetSizePixel().Height());
2439     const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
2440     const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
2441     const bool bScaleHor(nWidth != nNewWidth);
2442     const bool bScaleVer(nHeight != nNewHeight);
2443     const bool bMirror(bMirrorHor || bMirrorVer);
2444 
2445     if(!bMirror && !bScaleHor && !bScaleVer)
2446     {
2447         return true;
2448     }
2449 
2450     bool bResult(true);
2451     sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
2452     bool bMirrorAfter(false);
2453 
2454     if(bMirror)
2455     {
2456         if(bMirrorHor)
2457         {
2458             nMirrorFlags |= BMP_MIRROR_HORZ;
2459         }
2460 
2461         if(bMirrorVer)
2462         {
2463             nMirrorFlags |= BMP_MIRROR_VERT;
2464         }
2465 
2466         const sal_uInt32 nStartSize(nWidth * nHeight);
2467         const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
2468 
2469         bMirrorAfter = nStartSize > nEndSize;
2470 
2471         if(!bMirrorAfter)
2472         {
2473             bResult = Mirror(nMirrorFlags);
2474         }
2475     }
2476 
2477     Bitmap aResult;
2478 
2479     if(bResult)
2480     {
2481         const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
2482         const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
2483         Bitmap aSource(*this);
2484 
2485         if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2486         {
2487             if(bScaleHor)
2488             {
2489                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2490             }
2491 
2492             if(bResult && bScaleVer)
2493             {
2494                 if(bScaleHor)
2495                 {
2496                     // copy partial result, independent of color depth
2497                     aSource = aResult;
2498                 }
2499 
2500                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2501             }
2502         }
2503         else
2504         {
2505             if(bScaleVer)
2506             {
2507                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2508             }
2509 
2510             if(bResult && bScaleHor)
2511             {
2512                 if(bScaleVer)
2513                 {
2514                     // copy partial result, independent of color depth
2515                     aSource = aResult;
2516                 }
2517 
2518                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2519             }
2520         }
2521     }
2522 
2523     if(bResult && bMirrorAfter)
2524     {
2525         bResult = aResult.Mirror(nMirrorFlags);
2526     }
2527 
2528     if(bResult)
2529     {
2530         ImplAdaptBitCount(aResult);
2531         *this = aResult;
2532     }
2533 
2534     return bResult;
2535 }
2536 
2537 // ------------------------------------------------------------------------
2538 
Dither(sal_uLong nDitherFlags)2539 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2540 {
2541     sal_Bool bRet = sal_False;
2542 
2543     const Size aSizePix( GetSizePixel() );
2544 
2545     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2546         bRet = sal_True;
2547     else if( nDitherFlags & BMP_DITHER_MATRIX )
2548         bRet = ImplDitherMatrix();
2549     else if( nDitherFlags & BMP_DITHER_FLOYD )
2550         bRet = ImplDitherFloyd();
2551     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2552         bRet = ImplDitherFloyd16();
2553 
2554     return bRet;
2555 }
2556 
2557 // ------------------------------------------------------------------------
2558 
ImplDitherMatrix()2559 sal_Bool Bitmap::ImplDitherMatrix()
2560 {
2561     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2562     Bitmap              aNewBmp( GetSizePixel(), 8 );
2563     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2564     sal_Bool                bRet = sal_False;
2565 
2566     if( pReadAcc && pWriteAcc )
2567     {
2568         const sal_uLong nWidth = pReadAcc->Width();
2569         const sal_uLong nHeight = pReadAcc->Height();
2570         BitmapColor aIndex( (sal_uInt8) 0 );
2571 
2572         if( pReadAcc->HasPalette() )
2573         {
2574             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2575             {
2576                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2577                 {
2578                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2579                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2580                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2581                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2582                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2583 
2584                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2585                     pWriteAcc->SetPixel( nY, nX, aIndex );
2586                 }
2587             }
2588         }
2589         else
2590         {
2591             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2592             {
2593                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2594                 {
2595                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
2596                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2597                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2598                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2599                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2600 
2601                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2602                     pWriteAcc->SetPixel( nY, nX, aIndex );
2603                 }
2604             }
2605         }
2606 
2607         bRet = sal_True;
2608     }
2609 
2610     ReleaseAccess( pReadAcc );
2611     aNewBmp.ReleaseAccess( pWriteAcc );
2612 
2613     if( bRet )
2614     {
2615         const MapMode   aMap( maPrefMapMode );
2616         const Size      aSize( maPrefSize );
2617 
2618         *this = aNewBmp;
2619 
2620         maPrefMapMode = aMap;
2621         maPrefSize = aSize;
2622     }
2623 
2624     return bRet;
2625 }
2626 
2627 // ------------------------------------------------------------------------
2628 
ImplDitherFloyd()2629 sal_Bool Bitmap::ImplDitherFloyd()
2630 {
2631     const Size  aSize( GetSizePixel() );
2632     sal_Bool        bRet = sal_False;
2633 
2634     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2635     {
2636         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2637         Bitmap              aNewBmp( GetSizePixel(), 8 );
2638         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2639 
2640         if( pReadAcc && pWriteAcc )
2641         {
2642             BitmapColor aColor;
2643             long        nWidth = pReadAcc->Width();
2644             long        nWidth1 = nWidth - 1L;
2645             long        nHeight = pReadAcc->Height();
2646             long        nX;
2647             long        nW = nWidth * 3L;
2648             long        nW2 = nW - 3L;
2649             long        nRErr, nGErr, nBErr;
2650             long        nRC, nGC, nBC;
2651             long        nTemp;
2652             long        nZ;
2653             long*       p1 = new long[ nW ];
2654             long*       p2 = new long[ nW ];
2655             long*       p1T = p1;
2656             long*       p2T = p2;
2657             long*       pTmp;
2658             sal_Bool        bPal = pReadAcc->HasPalette();
2659 
2660             pTmp = p2T;
2661 
2662             if( bPal )
2663             {
2664                 for( nZ = 0; nZ < nWidth; nZ++ )
2665                 {
2666                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2667 
2668                     *pTmp++ = (long) aColor.GetBlue() << 12;
2669                     *pTmp++ = (long) aColor.GetGreen() << 12;
2670                     *pTmp++ = (long) aColor.GetRed() << 12;
2671                 }
2672             }
2673             else
2674             {
2675                 for( nZ = 0; nZ < nWidth; nZ++ )
2676                 {
2677                     aColor = pReadAcc->GetPixel( 0, nZ );
2678 
2679                     *pTmp++ = (long) aColor.GetBlue() << 12;
2680                     *pTmp++ = (long) aColor.GetGreen() << 12;
2681                     *pTmp++ = (long) aColor.GetRed() << 12;
2682                 }
2683             }
2684 
2685             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2686             {
2687                 pTmp = p1T;
2688                 p1T = p2T;
2689                 p2T = pTmp;
2690 
2691                 if( nY < nHeight )
2692                 {
2693                     if( bPal )
2694                     {
2695                         for( nZ = 0; nZ < nWidth; nZ++ )
2696                         {
2697                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2698 
2699                             *pTmp++ = (long) aColor.GetBlue() << 12;
2700                             *pTmp++ = (long) aColor.GetGreen() << 12;
2701                             *pTmp++ = (long) aColor.GetRed() << 12;
2702                         }
2703                     }
2704                     else
2705                     {
2706                         for( nZ = 0; nZ < nWidth; nZ++ )
2707                         {
2708                             aColor = pReadAcc->GetPixel( nY, nZ );
2709 
2710                             *pTmp++ = (long) aColor.GetBlue() << 12;
2711                             *pTmp++ = (long) aColor.GetGreen() << 12;
2712                             *pTmp++ = (long) aColor.GetRed() << 12;
2713                         }
2714                     }
2715                 }
2716 
2717                 // erstes Pixel gesondert betrachten
2718                 nX = 0;
2719                 CALC_ERRORS;
2720                 CALC_TABLES7;
2721                 nX -= 5;
2722                 CALC_TABLES5;
2723                 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2724 
2725                 // mittlere Pixel ueber Schleife
2726                 long nXAcc;
2727                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2728                 {
2729                     CALC_ERRORS;
2730                     CALC_TABLES7;
2731                     nX -= 8;
2732                     CALC_TABLES3;
2733                     CALC_TABLES5;
2734                     pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2735                 }
2736 
2737                 // letztes Pixel gesondert betrachten
2738                 CALC_ERRORS;
2739                 nX -= 5;
2740                 CALC_TABLES3;
2741                 CALC_TABLES5;
2742                 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2743             }
2744 
2745             delete[] p1;
2746             delete[] p2;
2747             bRet = sal_True;
2748         }
2749 
2750         ReleaseAccess( pReadAcc );
2751         aNewBmp.ReleaseAccess( pWriteAcc );
2752 
2753         if( bRet )
2754         {
2755             const MapMode   aMap( maPrefMapMode );
2756             const Size      aPrefSize( maPrefSize );
2757 
2758             *this = aNewBmp;
2759 
2760             maPrefMapMode = aMap;
2761             maPrefSize = aPrefSize;
2762         }
2763     }
2764 
2765     return bRet;
2766 }
2767 
2768 // ------------------------------------------------------------------------
2769 
ImplDitherFloyd16()2770 sal_Bool Bitmap::ImplDitherFloyd16()
2771 {
2772     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
2773     Bitmap              aNewBmp( GetSizePixel(), 24 );
2774     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
2775     sal_Bool                bRet = sal_False;
2776 
2777     if( pReadAcc && pWriteAcc )
2778     {
2779         const long      nWidth = pWriteAcc->Width();
2780         const long      nWidth1 = nWidth - 1L;
2781         const long      nHeight = pWriteAcc->Height();
2782         BitmapColor     aColor;
2783         BitmapColor     aBestCol;
2784         ImpErrorQuad    aErrQuad;
2785         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
2786         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
2787         ImpErrorQuad*   pQLine1 = pErrQuad1;
2788         ImpErrorQuad*   pQLine2 = 0;
2789         long            nX, nY;
2790         long            nYTmp = 0L;
2791         sal_Bool            bQ1 = sal_True;
2792 
2793         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2794             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2795                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2796 
2797         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2798         {
2799             // erstes ZeilenPixel
2800             aBestCol = pQLine1[ 0 ].ImplGetColor();
2801             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2802             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2803             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2804             pWriteAcc->SetPixel( nY, 0, aBestCol );
2805 
2806             for( nX = 1L; nX < nWidth1; nX++ )
2807             {
2808                 aColor = pQLine1[ nX ].ImplGetColor();
2809                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2810                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2811                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2812                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2813                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2814                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2815                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2816                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2817                 pWriteAcc->SetPixel( nY, nX, aBestCol );
2818             }
2819 
2820             // letztes ZeilenPixel
2821             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2822             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2823             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2824             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2825             pWriteAcc->SetPixel( nY, nX, aBestCol );
2826 
2827             // Zeilenpuffer neu fuellen/kopieren
2828             pQLine1 = pQLine2;
2829             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2830 
2831             if( nYTmp < nHeight )
2832                 for( nX = 0L; nX < nWidth; nX++ )
2833                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2834         }
2835 
2836         // Zeilenpuffer zerstoeren
2837         delete[] pErrQuad1;
2838         delete[] pErrQuad2;
2839         bRet = sal_True;
2840     }
2841 
2842     ReleaseAccess( pReadAcc );
2843     aNewBmp.ReleaseAccess( pWriteAcc );
2844 
2845     if( bRet )
2846     {
2847         const MapMode   aMap( maPrefMapMode );
2848         const Size      aSize( maPrefSize );
2849 
2850         *this = aNewBmp;
2851 
2852         maPrefMapMode = aMap;
2853         maPrefSize = aSize;
2854     }
2855 
2856     return bRet;
2857 }
2858 
2859 // ------------------------------------------------------------------------
2860 
ReduceColors(sal_uInt16 nColorCount,BmpReduce eReduce)2861 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2862 {
2863     sal_Bool bRet;
2864 
2865     if( GetColorCount() <= (sal_uLong) nColorCount )
2866         bRet = sal_True;
2867     else if( nColorCount )
2868     {
2869         if( BMP_REDUCE_SIMPLE == eReduce )
2870             bRet = ImplReduceSimple( nColorCount );
2871         else if( BMP_REDUCE_POPULAR == eReduce )
2872             bRet = ImplReducePopular( nColorCount );
2873         else
2874             bRet = ImplReduceMedian( nColorCount );
2875     }
2876     else
2877         bRet = sal_False;
2878 
2879     return bRet;
2880 }
2881 
2882 // ------------------------------------------------------------------------
2883 
ImplReduceSimple(sal_uInt16 nColorCount)2884 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2885 {
2886     Bitmap              aNewBmp;
2887     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2888     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
2889     sal_uInt16              nBitCount;
2890     sal_Bool                bRet = sal_False;
2891 
2892     if( nColCount <= 2 )
2893         nBitCount = 1;
2894     else if( nColCount <= 16 )
2895         nBitCount = 4;
2896     else
2897         nBitCount = 8;
2898 
2899     if( pRAcc )
2900     {
2901         Octree                  aOct( *pRAcc, nColCount );
2902         const BitmapPalette&    rPal = aOct.GetPalette();
2903         BitmapWriteAccess*      pWAcc;
2904 
2905         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2906         pWAcc = aNewBmp.AcquireWriteAccess();
2907 
2908         if( pWAcc )
2909         {
2910             const long nWidth = pRAcc->Width();
2911             const long nHeight = pRAcc->Height();
2912 
2913             if( pRAcc->HasPalette() )
2914             {
2915                 for( long nY = 0L; nY < nHeight; nY++ )
2916                     for( long nX =0L; nX < nWidth; nX++ )
2917                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2918             }
2919             else
2920             {
2921                 for( long nY = 0L; nY < nHeight; nY++ )
2922                     for( long nX =0L; nX < nWidth; nX++ )
2923                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2924             }
2925 
2926             aNewBmp.ReleaseAccess( pWAcc );
2927             bRet = sal_True;
2928         }
2929 
2930         ReleaseAccess( pRAcc );
2931     }
2932 
2933     if( bRet )
2934     {
2935         const MapMode   aMap( maPrefMapMode );
2936         const Size      aSize( maPrefSize );
2937 
2938         *this = aNewBmp;
2939         maPrefMapMode = aMap;
2940         maPrefSize = aSize;
2941     }
2942 
2943     return bRet;
2944 }
2945 
2946 // ------------------------------------------------------------------------
2947 
2948 struct PopularColorCount
2949 {
2950     sal_uInt32  mnIndex;
2951     sal_uInt32  mnCount;
2952 };
2953 
2954 // ------------------------------------------------------------------------
2955 
ImplPopularCmpFnc(const void * p1,const void * p2)2956 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2957 {
2958     int nRet;
2959 
2960     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2961         nRet = 1;
2962     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2963         nRet = 0;
2964     else
2965         nRet = -1;
2966 
2967     return nRet;
2968 }
2969 
2970 // ------------------------------------------------------------------------
2971 
ImplReducePopular(sal_uInt16 nColCount)2972 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2973 {
2974     BitmapReadAccess*   pRAcc = AcquireReadAccess();
2975     sal_uInt16              nBitCount;
2976     sal_Bool                bRet = sal_False;
2977 
2978     if( nColCount > 256 )
2979         nColCount = 256;
2980 
2981     if( nColCount < 17 )
2982         nBitCount = 4;
2983     else
2984         nBitCount = 8;
2985 
2986     if( pRAcc )
2987     {
2988         const sal_uInt32    nValidBits = 4;
2989         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
2990         const sal_uInt32    nLeftShiftBits1 = nValidBits;
2991         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
2992         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
2993         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
2994         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2995         const long          nWidth = pRAcc->Width();
2996         const long          nHeight = pRAcc->Height();
2997         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
2998         long                nX, nY, nR, nG, nB, nIndex;
2999 
3000         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
3001 
3002         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3003         {
3004             for( nG = 0; nG < 256; nG += nColorOffset )
3005             {
3006                 for( nB = 0; nB < 256; nB += nColorOffset )
3007                 {
3008                     pCountTable[ nIndex ].mnIndex = nIndex;
3009                     nIndex++;
3010                 }
3011             }
3012         }
3013 
3014         if( pRAcc->HasPalette() )
3015         {
3016             for( nY = 0L; nY < nHeight; nY++ )
3017             {
3018                 for( nX = 0L; nX < nWidth; nX++ )
3019                 {
3020                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3021                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3022                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3023                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3024                 }
3025             }
3026         }
3027         else
3028         {
3029             for( nY = 0L; nY < nHeight; nY++ )
3030             {
3031                 for( nX = 0L; nX < nWidth; nX++ )
3032                 {
3033                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3034                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3035                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3036                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3037                 }
3038             }
3039         }
3040 
3041         BitmapPalette aNewPal( nColCount );
3042 
3043         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3044 
3045         for( sal_uInt16 n = 0; n < nColCount; n++ )
3046         {
3047             const PopularColorCount& rPop = pCountTable[ n ];
3048             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3049                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3050                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3051         }
3052 
3053         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3054         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3055 
3056         if( pWAcc )
3057         {
3058             BitmapColor aDstCol( (sal_uInt8) 0 );
3059             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
3060 
3061             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3062                 for( nG = 0; nG < 256; nG += nColorOffset )
3063                     for( nB = 0; nB < 256; nB += nColorOffset )
3064                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3065 
3066             if( pRAcc->HasPalette() )
3067             {
3068                 for( nY = 0L; nY < nHeight; nY++ )
3069                 {
3070                     for( nX = 0L; nX < nWidth; nX++ )
3071                     {
3072                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3073                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3074                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3075                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3076                         pWAcc->SetPixel( nY, nX, aDstCol );
3077                     }
3078                 }
3079             }
3080             else
3081             {
3082                 for( nY = 0L; nY < nHeight; nY++ )
3083                 {
3084                     for( nX = 0L; nX < nWidth; nX++ )
3085                     {
3086                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3087                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3088                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3089                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3090                         pWAcc->SetPixel( nY, nX, aDstCol );
3091                     }
3092                 }
3093             }
3094 
3095             delete[] pIndexMap;
3096             aNewBmp.ReleaseAccess( pWAcc );
3097             bRet = sal_True;
3098         }
3099 
3100         delete[] pCountTable;
3101         ReleaseAccess( pRAcc );
3102 
3103         if( bRet )
3104         {
3105             const MapMode   aMap( maPrefMapMode );
3106             const Size      aSize( maPrefSize );
3107 
3108             *this = aNewBmp;
3109             maPrefMapMode = aMap;
3110             maPrefSize = aSize;
3111         }
3112     }
3113 
3114     return bRet;
3115 }
3116 
3117 // ------------------------------------------------------------------------
3118 
ImplReduceMedian(sal_uInt16 nColCount)3119 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3120 {
3121     BitmapReadAccess*   pRAcc = AcquireReadAccess();
3122     sal_uInt16              nBitCount;
3123     sal_Bool                bRet = sal_False;
3124 
3125     if( nColCount < 17 )
3126         nBitCount = 4;
3127     else if( nColCount < 257 )
3128         nBitCount = 8;
3129     else
3130     {
3131         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3132         nBitCount = 8;
3133         nColCount = 256;
3134     }
3135 
3136     if( pRAcc )
3137     {
3138         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
3139         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
3140 
3141         if( pWAcc )
3142         {
3143             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
3144             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3145             const long  nWidth = pWAcc->Width();
3146             const long  nHeight = pWAcc->Height();
3147             long        nIndex = 0L;
3148 
3149             memset( (HPBYTE) pColBuf, 0, nSize );
3150 
3151             // create Buffer
3152             if( pRAcc->HasPalette() )
3153             {
3154                 for( long nY = 0L; nY < nHeight; nY++ )
3155                 {
3156                     for( long nX = 0L; nX < nWidth; nX++ )
3157                     {
3158                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3159                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3160                     }
3161                 }
3162             }
3163             else
3164             {
3165                 for( long nY = 0L; nY < nHeight; nY++ )
3166                 {
3167                     for( long nX = 0L; nX < nWidth; nX++ )
3168                     {
3169                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3170                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3171                     }
3172                 }
3173             }
3174 
3175             // create palette via median cut
3176             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3177             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3178                            nColCount, nWidth * nHeight, nIndex );
3179 
3180             // do mapping of colors to palette
3181             InverseColorMap aMap( aPal );
3182             pWAcc->SetPalette( aPal );
3183             for( long nY = 0L; nY < nHeight; nY++ )
3184                 for( long nX = 0L; nX < nWidth; nX++ )
3185                     pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3186 
3187             rtl_freeMemory( pColBuf );
3188             aNewBmp.ReleaseAccess( pWAcc );
3189             bRet = sal_True;
3190         }
3191 
3192         ReleaseAccess( pRAcc );
3193 
3194         if( bRet )
3195         {
3196             const MapMode   aMap( maPrefMapMode );
3197             const Size      aSize( maPrefSize );
3198 
3199             *this = aNewBmp;
3200             maPrefMapMode = aMap;
3201             maPrefSize = aSize;
3202         }
3203     }
3204 
3205     return bRet;
3206 }
3207 
3208 // ------------------------------------------------------------------------
3209 
ImplMedianCut(sal_uLong * pColBuf,BitmapPalette & rPal,long nR1,long nR2,long nG1,long nG2,long nB1,long nB2,long nColors,long nPixels,long & rIndex)3210 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3211                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3212                             long nColors, long nPixels, long& rIndex )
3213 {
3214     if( !nPixels )
3215         return;
3216 
3217     BitmapColor aCol;
3218     const long  nRLen = nR2 - nR1;
3219     const long  nGLen = nG2 - nG1;
3220     const long  nBLen = nB2 - nB1;
3221     long        nR, nG, nB;
3222     sal_uLong*      pBuf = pColBuf;
3223 
3224     if( !nRLen && !nGLen && !nBLen )
3225     {
3226         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3227         {
3228             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3229             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3230             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3231             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3232         }
3233     }
3234     else
3235     {
3236         if( 1 == nColors || 1 == nPixels )
3237         {
3238             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3239 
3240             for( nR = nR1; nR <= nR2; nR++ )
3241             {
3242                 for( nG = nG1; nG <= nG2; nG++ )
3243                 {
3244                     for( nB = nB1; nB <= nB2; nB++ )
3245                     {
3246                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3247 
3248                         if( nPixSum )
3249                         {
3250                             nRSum += nR * nPixSum;
3251                             nGSum += nG * nPixSum;
3252                             nBSum += nB * nPixSum;
3253                         }
3254                     }
3255                 }
3256             }
3257 
3258             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3259             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3260             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3261             rPal[ (sal_uInt16) rIndex++ ] = aCol;
3262         }
3263         else
3264         {
3265             const long  nTest = ( nPixels >> 1 );
3266             long        nPixOld = 0;
3267             long        nPixNew = 0;
3268 
3269             if( nBLen > nGLen && nBLen > nRLen )
3270             {
3271                 nB = nB1 - 1;
3272 
3273                 while( nPixNew < nTest )
3274                 {
3275                     nB++, nPixOld = nPixNew;
3276                     for( nR = nR1; nR <= nR2; nR++ )
3277                         for( nG = nG1; nG <= nG2; nG++ )
3278                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3279                 }
3280 
3281                 if( nB < nB2 )
3282                 {
3283                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3284                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3285                 }
3286                 else
3287                 {
3288                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3289                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3290                 }
3291             }
3292             else if( nGLen > nRLen )
3293             {
3294                 nG = nG1 - 1;
3295 
3296                 while( nPixNew < nTest )
3297                 {
3298                     nG++, nPixOld = nPixNew;
3299                     for( nR = nR1; nR <= nR2; nR++ )
3300                         for( nB = nB1; nB <= nB2; nB++ )
3301                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3302                 }
3303 
3304                 if( nG < nG2 )
3305                 {
3306                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3307                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3308                 }
3309                 else
3310                 {
3311                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3312                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3313                 }
3314             }
3315             else
3316             {
3317                 nR = nR1 - 1;
3318 
3319                 while( nPixNew < nTest )
3320                 {
3321                     nR++, nPixOld = nPixNew;
3322                     for( nG = nG1; nG <= nG2; nG++ )
3323                         for( nB = nB1; nB <= nB2; nB++ )
3324                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3325                 }
3326 
3327                 if( nR < nR2 )
3328                 {
3329                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3330                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3331                 }
3332                 else
3333                 {
3334                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3335                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3336                 }
3337             }
3338         }
3339     }
3340 }
3341 
3342 // ------------------------------------------------------------------------
3343 
Vectorize(PolyPolygon & rPolyPoly,sal_uLong nFlags,const Link * pProgress)3344 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3345 {
3346     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3347 }
3348 
3349 // ------------------------------------------------------------------------
3350 
Vectorize(GDIMetaFile & rMtf,sal_uInt8 cReduce,sal_uLong nFlags,const Link * pProgress)3351 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3352 {
3353     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3354 }
3355 
3356 // ------------------------------------------------------------------------
3357 
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)3358 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3359                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3360                      double fGamma, sal_Bool bInvert )
3361 {
3362     sal_Bool bRet = sal_False;
3363 
3364     // nothing to do => return quickly
3365     if( !nLuminancePercent && !nContrastPercent &&
3366         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3367         ( fGamma == 1.0 ) && !bInvert )
3368     {
3369         bRet = sal_True;
3370     }
3371     else
3372     {
3373         BitmapWriteAccess* pAcc = AcquireWriteAccess();
3374 
3375         if( pAcc )
3376         {
3377             BitmapColor     aCol;
3378             const long      nW = pAcc->Width();
3379             const long      nH = pAcc->Height();
3380             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
3381             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
3382             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
3383             long            nX, nY;
3384             double          fM, fROff, fGOff, fBOff, fOff;
3385 
3386             // calculate slope
3387             if( nContrastPercent >= 0 )
3388                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3389             else
3390                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3391 
3392             // total offset = luminance offset + contrast offset
3393             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3394 
3395             // channel offset = channel offset  + total offset
3396             fROff = nChannelRPercent * 2.55 + fOff;
3397             fGOff = nChannelGPercent * 2.55 + fOff;
3398             fBOff = nChannelBPercent * 2.55 + fOff;
3399 
3400             // calculate gamma value
3401             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3402             const sal_Bool bGamma = ( fGamma != 1.0 );
3403 
3404             // create mapping table
3405             for( nX = 0L; nX < 256L; nX++ )
3406             {
3407                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3408                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3409                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3410 
3411                 if( bGamma )
3412                 {
3413                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3414                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3415                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3416                 }
3417 
3418                 if( bInvert )
3419                 {
3420                     cMapR[ nX ] = ~cMapR[ nX ];
3421                     cMapG[ nX ] = ~cMapG[ nX ];
3422                     cMapB[ nX ] = ~cMapB[ nX ];
3423                 }
3424             }
3425 
3426             // do modifying
3427             if( pAcc->HasPalette() )
3428             {
3429                 BitmapColor aNewCol;
3430 
3431                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3432                 {
3433                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3434                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3435                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3436                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3437                     pAcc->SetPaletteColor( i, aNewCol );
3438                 }
3439             }
3440             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3441             {
3442                 for( nY = 0L; nY < nH; nY++ )
3443                 {
3444                     Scanline pScan = pAcc->GetScanline( nY );
3445 
3446                     for( nX = 0L; nX < nW; nX++ )
3447                     {
3448                         *pScan = cMapB[ *pScan ]; pScan++;
3449                         *pScan = cMapG[ *pScan ]; pScan++;
3450                         *pScan = cMapR[ *pScan ]; pScan++;
3451                     }
3452                 }
3453             }
3454             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3455             {
3456                 for( nY = 0L; nY < nH; nY++ )
3457                 {
3458                     Scanline pScan = pAcc->GetScanline( nY );
3459 
3460                     for( nX = 0L; nX < nW; nX++ )
3461                     {
3462                         *pScan = cMapR[ *pScan ]; pScan++;
3463                         *pScan = cMapG[ *pScan ]; pScan++;
3464                         *pScan = cMapB[ *pScan ]; pScan++;
3465                     }
3466                 }
3467             }
3468             else
3469             {
3470                 for( nY = 0L; nY < nH; nY++ )
3471                 {
3472                     for( nX = 0L; nX < nW; nX++ )
3473                     {
3474                         aCol = pAcc->GetPixel( nY, nX );
3475                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
3476                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3477                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3478                         pAcc->SetPixel( nY, nX, aCol );
3479                     }
3480                 }
3481             }
3482 
3483             delete[] cMapR;
3484             delete[] cMapG;
3485             delete[] cMapB;
3486             ReleaseAccess( pAcc );
3487             bRet = sal_True;
3488         }
3489     }
3490 
3491     return bRet;
3492 }
3493