xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision e1d5bd03a6ea7ac2b26b792c9e2a94e9f347a43b)
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 
44 #define CALC_ERRORS                                                             \
45                         nTemp   = p1T[nX++] >> 12;                              \
46                         nBErr = MinMax( nTemp, 0, 255 );                        \
47                         nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
48                         nTemp   = p1T[nX++] >> 12;                              \
49                         nGErr = MinMax( nTemp, 0, 255 );                        \
50                         nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
51                         nTemp   = p1T[nX] >> 12;                                \
52                         nRErr = MinMax( nTemp, 0, 255 );                        \
53                         nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
54 
55 #define CALC_TABLES3                                        \
56                         p2T[nX++] += FloydError3[nBErr];    \
57                         p2T[nX++] += FloydError3[nGErr];    \
58                         p2T[nX++] += FloydError3[nRErr];
59 
60 #define CALC_TABLES5                                        \
61                         p2T[nX++] += FloydError5[nBErr];    \
62                         p2T[nX++] += FloydError5[nGErr];    \
63                         p2T[nX++] += FloydError5[nRErr];
64 
65 #define CALC_TABLES7                                        \
66                         p1T[++nX] += FloydError7[nBErr];    \
67                         p2T[nX++] += FloydError1[nBErr];    \
68                         p1T[nX] += FloydError7[nGErr];      \
69                         p2T[nX++] += FloydError1[nGErr];    \
70                         p1T[nX] += FloydError7[nRErr];      \
71                         p2T[nX] += FloydError1[nRErr];
72 
73 // -----------
74 // - Statics -
75 // -----------
76 
77 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
78 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
79 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
80 
81 // ------------------------------------------------------------------------
82 
83 sal_uLong nVCLDitherLut[ 256 ] =
84 {
85        0, 49152, 12288, 61440,  3072, 52224, 15360, 64512,   768, 49920, 13056,
86    62208,  3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
87    48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
88    57344,  4096, 53248, 11264, 60416,  7168, 56320,  8960, 58112,  4864, 54016,
89    12032, 61184,  7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
90    23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
91    14336, 63488,  1024, 50176, 13312, 62464,  2816, 51968, 15104, 64256,  1792,
92    50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
93    35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392,  6144,
94    55296,  9216, 58368,  5120, 54272, 11008, 60160,  6912, 56064,  9984, 59136,
95     5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
96    27392, 39680, 23296, 42752, 26368, 38656, 22272,   512, 49664, 12800, 61952,
97     3584, 52736, 15872, 65024,   256, 49408, 12544, 61696,  3328, 52480, 15616,
98    64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
99    45312, 28928, 36096, 19712, 48384, 32000,  8704, 57856,  4608, 53760, 11776,
100    60928,  7680, 56832,  8448, 57600,  4352, 53504, 11520, 60672,  7424, 56576,
101    41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
102    20736, 44288, 27904, 40192, 23808,  2560, 51712, 14848, 64000,  1536, 50688,
103    13824, 62976,  2304, 51456, 14592, 63744,  1280, 50432, 13568, 62720, 35328,
104    18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
105    34048, 17664, 46336, 29952, 10752, 59904,  6656, 55808,  9728, 58880,  5632,
106    54784, 10496, 59648,  6400, 55552,  9472, 58624,  5376, 54528, 43520, 27136,
107    39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
108    25856, 38144, 21760
109 };
110 
111 // ------------------------------------------------------------------------
112 
113 sal_uLong nVCLLut[ 256 ] =
114 {
115          0,  1286,  2572,  3858,  5144,  6430,  7716,  9002,
116      10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
117      20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
118      30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
119      41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
120      51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
121      61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
122      72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
123      82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
124      92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
125     102880,104166,105452,106738,108024,109310,110596,111882,
126     113168,114454,115740,117026,118312,119598,120884,122170,
127     123456,124742,126028,127314,128600,129886,131172,132458,
128     133744,135030,136316,137602,138888,140174,141460,142746,
129     144032,145318,146604,147890,149176,150462,151748,153034,
130     154320,155606,156892,158178,159464,160750,162036,163322,
131     164608,165894,167180,168466,169752,171038,172324,173610,
132     174896,176182,177468,178754,180040,181326,182612,183898,
133     185184,186470,187756,189042,190328,191614,192900,194186,
134     195472,196758,198044,199330,200616,201902,203188,204474,
135     205760,207046,208332,209618,210904,212190,213476,214762,
136     216048,217334,218620,219906,221192,222478,223764,225050,
137     226336,227622,228908,230194,231480,232766,234052,235338,
138     236624,237910,239196,240482,241768,243054,244340,245626,
139     246912,248198,249484,250770,252056,253342,254628,255914,
140     257200,258486,259772,261058,262344,263630,264916,266202,
141     267488,268774,270060,271346,272632,273918,275204,276490,
142     277776,279062,280348,281634,282920,284206,285492,286778,
143     288064,289350,290636,291922,293208,294494,295780,297066,
144     298352,299638,300924,302210,303496,304782,306068,307354,
145     308640,309926,311212,312498,313784,315070,316356,317642,
146     318928,320214,321500,322786,324072,325358,326644,327930
147 };
148 
149 // ------------------------------------------------------------------------
150 
151 long FloydMap[256] =
152 {
153     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
154     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
155     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 2, 2, 2,
158     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
165     4, 4, 4, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
168     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
169 };
170 
171 // ------------------------------------------------------------------------
172 
173 long FloydError1[61] =
174 {
175     -7680, -7424, -7168, -6912, -6656, -6400, -6144,
176     -5888, -5632, -5376, -5120, -4864, -4608, -4352,
177     -4096, -3840, -3584, -3328, -3072, -2816, -2560,
178     -2304, -2048, -1792, -1536, -1280, -1024, -768,
179     -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
180     1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
181     3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
182     5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
183 };
184 
185 // ------------------------------------------------------------------------
186 
187 long FloydError3[61] =
188 {
189     -23040, -22272, -21504, -20736, -19968, -19200,
190     -18432, -17664, -16896, -16128, -15360, -14592,
191     -13824, -13056, -12288, -11520, -10752, -9984,
192     -9216, -8448, -7680, -6912, -6144, -5376, -4608,
193     -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
194     2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
195     8448, 9216, 9984, 10752, 11520, 12288, 13056,
196     13824, 14592, 15360, 16128, 16896, 17664, 18432,
197     19200, 19968, 20736, 21504, 22272, 23040
198 };
199 
200 // ------------------------------------------------------------------------
201 
202 long FloydError5[61] =
203 {
204     -38400, -37120, -35840, -34560, -33280, -32000,
205     -30720, -29440, -28160, -26880, -25600, -24320,
206     -23040, -21760, -20480, -19200, -17920, -16640,
207     -15360, -14080, -12800, -11520, -10240, -8960,
208     -7680, -6400, -5120, -3840, -2560, -1280,   0,
209     1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
210     11520, 12800, 14080, 15360, 16640, 17920, 19200,
211     20480, 21760, 23040, 24320, 25600, 26880, 28160,
212     29440, 30720, 32000, 33280, 34560, 35840, 37120,
213     38400
214 };
215 
216 // ------------------------------------------------------------------------
217 
218 long FloydError7[61] =
219 {
220     -53760, -51968, -50176, -48384, -46592, -44800,
221     -43008, -41216, -39424, -37632, -35840, -34048,
222     -32256, -30464, -28672, -26880, -25088, -23296,
223     -21504, -19712, -17920, -16128, -14336, -12544,
224     -10752, -8960, -7168, -5376, -3584, -1792,  0,
225     1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
226     16128, 17920, 19712, 21504, 23296, 25088, 26880,
227     28672, 30464, 32256, 34048, 35840, 37632, 39424,
228     41216, 43008, 44800, 46592, 48384, 50176, 51968,
229     53760
230 };
231 
232 // ------------------------------------------------------------------------
233 
234 long FloydIndexMap[6] =
235 {
236     -30,  21, 72, 123, 174, 225
237 };
238 
239 // --------------------------
240 // - ImplCreateDitherMatrix -
241 // --------------------------
242 
243 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
244 {
245     double          fVal = 3.125;
246     const double    fVal16 = fVal / 16.;
247     long            i, j, k, l;
248     sal_uInt16          pMtx[ 16 ][ 16 ];
249     sal_uInt16          nMax = 0;
250     static sal_uInt8    pMagic[4][4] = { { 0, 14,  3, 13, },
251                                      {11,  5,  8,  6, },
252                                      {12,  2, 15,  1, },
253                                      {7,   9,  4, 10 } };
254 
255     // MagicSquare aufbauen
256     for ( i = 0; i < 4; i++ )
257        for ( j = 0; j < 4; j++ )
258            for ( k = 0; k < 4; k++ )
259                 for ( l = 0; l < 4; l++ )
260                     nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
261                     (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
262 
263     // auf Intervall [0;254] skalieren
264     for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
265         for( j = 0; j < 16; j++ )
266             (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] );
267 }
268 
269 // ----------
270 // - Bitmap -
271 // ----------
272 
273 sal_Bool Bitmap::Convert( BmpConversion eConversion )
274 {
275     const sal_uInt16    nBitCount = GetBitCount();
276     sal_Bool            bRet = sal_False;
277 
278     switch( eConversion )
279     {
280         case( BMP_CONVERSION_1BIT_THRESHOLD ):
281             bRet = ImplMakeMono( 128 );
282         break;
283 
284         case( BMP_CONVERSION_1BIT_MATRIX ):
285             bRet = ImplMakeMonoDither();
286         break;
287 
288         case( BMP_CONVERSION_4BIT_GREYS ):
289             bRet = ImplMakeGreyscales( 16 );
290         break;
291 
292         case( BMP_CONVERSION_4BIT_COLORS ):
293         {
294             if( nBitCount < 4 )
295                 bRet = ImplConvertUp( 4, NULL );
296             else if( nBitCount > 4 )
297                 bRet = ImplConvertDown( 4, NULL );
298             else
299                 bRet = sal_True;
300         }
301         break;
302 
303         case( BMP_CONVERSION_4BIT_TRANS ):
304         {
305             Color aTrans( BMP_COL_TRANS );
306 
307             if( nBitCount < 4 )
308                 bRet = ImplConvertUp( 4, &aTrans );
309             else
310                 bRet = ImplConvertDown( 4, &aTrans );
311         }
312         break;
313 
314         case( BMP_CONVERSION_8BIT_GREYS ):
315             bRet = ImplMakeGreyscales( 256 );
316         break;
317 
318         case( BMP_CONVERSION_8BIT_COLORS ):
319         {
320             if( nBitCount < 8 )
321                 bRet = ImplConvertUp( 8 );
322             else if( nBitCount > 8 )
323                 bRet = ImplConvertDown( 8 );
324             else
325                 bRet = sal_True;
326         }
327         break;
328 
329         case( BMP_CONVERSION_8BIT_TRANS ):
330         {
331             Color aTrans( BMP_COL_TRANS );
332 
333             if( nBitCount < 8 )
334                 bRet = ImplConvertUp( 8, &aTrans );
335             else
336                 bRet = ImplConvertDown( 8, &aTrans );
337         }
338         break;
339 
340         case( BMP_CONVERSION_24BIT ):
341         {
342             if( nBitCount < 24 )
343                 bRet = ImplConvertUp( 24, sal_False );
344             else
345                 bRet = sal_True;
346         }
347         break;
348 
349         case( BMP_CONVERSION_GHOSTED ):
350             bRet = ImplConvertGhosted();
351         break;
352 
353         default:
354             DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
355         break;
356     }
357 
358     return bRet;
359 }
360 
361 // ------------------------------------------------------------------------
362 
363 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
364 {
365     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
366     sal_Bool                bRet = sal_False;
367 
368     if( pReadAcc )
369     {
370         Bitmap              aNewBmp( GetSizePixel(), 1 );
371         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
372 
373         if( pWriteAcc )
374         {
375             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
376             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
377             const long          nWidth = pWriteAcc->Width();
378             const long          nHeight = pWriteAcc->Height();
379 
380             if( pReadAcc->HasPalette() )
381             {
382                 for( long nY = 0L; nY < nHeight; nY++ )
383                 {
384                     for( long nX = 0L; nX < nWidth; nX++ )
385                     {
386                         if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >=
387                             cThreshold )
388                         {
389                             pWriteAcc->SetPixel( nY, nX, aWhite );
390                         }
391                         else
392                             pWriteAcc->SetPixel( nY, nX, aBlack );
393                     }
394                 }
395             }
396             else
397             {
398                 for( long nY = 0L; nY < nHeight; nY++ )
399                 {
400                     for( long nX = 0L; nX < nWidth; nX++ )
401                     {
402                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
403                             cThreshold )
404                         {
405                             pWriteAcc->SetPixel( nY, nX, aWhite );
406                         }
407                         else
408                             pWriteAcc->SetPixel( nY, nX, aBlack );
409                     }
410                 }
411             }
412 
413             aNewBmp.ReleaseAccess( pWriteAcc );
414             bRet = sal_True;
415         }
416 
417         ReleaseAccess( pReadAcc );
418 
419         if( bRet )
420         {
421             const MapMode   aMap( maPrefMapMode );
422             const Size      aSize( maPrefSize );
423 
424             *this = aNewBmp;
425 
426             maPrefMapMode = aMap;
427             maPrefSize = aSize;
428         }
429     }
430 
431     return bRet;
432 }
433 
434 // ------------------------------------------------------------------------
435 
436 sal_Bool Bitmap::ImplMakeMonoDither()
437 {
438     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
439     sal_Bool                bRet = sal_False;
440 
441     if( pReadAcc )
442     {
443         Bitmap              aNewBmp( GetSizePixel(), 1 );
444         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
445 
446         if( pWriteAcc )
447         {
448             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
449             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
450             const long          nWidth = pWriteAcc->Width();
451             const long          nHeight = pWriteAcc->Height();
452             sal_uInt8               pDitherMatrix[ 16 ][ 16 ];
453 
454             ImplCreateDitherMatrix( &pDitherMatrix );
455 
456             if( pReadAcc->HasPalette() )
457             {
458                 for( long nY = 0L; nY < nHeight; nY++ )
459                 {
460                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
461                     {
462                         if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >
463                             pDitherMatrix[ nModY ][ nX % 16 ] )
464                         {
465                             pWriteAcc->SetPixel( nY, nX, aWhite );
466                         }
467                         else
468                             pWriteAcc->SetPixel( nY, nX, aBlack );
469                     }
470                 }
471             }
472             else
473             {
474                 for( long nY = 0L; nY < nHeight; nY++ )
475                 {
476                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
477                     {
478                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
479                             pDitherMatrix[ nModY ][ nX % 16 ]  )
480                         {
481                             pWriteAcc->SetPixel( nY, nX, aWhite );
482                         }
483                         else
484                             pWriteAcc->SetPixel( nY, nX, aBlack );
485                     }
486                 }
487             }
488 
489             aNewBmp.ReleaseAccess( pWriteAcc );
490             bRet = sal_True;
491         }
492 
493         ReleaseAccess( pReadAcc );
494 
495         if( bRet )
496         {
497             const MapMode   aMap( maPrefMapMode );
498             const Size      aSize( maPrefSize );
499 
500             *this = aNewBmp;
501 
502             maPrefMapMode = aMap;
503             maPrefSize = aSize;
504         }
505     }
506 
507     return bRet;
508 }
509 
510 // ------------------------------------------------------------------------
511 
512 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
513 {
514     DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
515 
516     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
517     sal_Bool                bRet = sal_False;
518 
519     if( pReadAcc )
520     {
521         const BitmapPalette&    rPal = GetGreyPalette( nGreys );
522         sal_uLong                   nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
523         sal_Bool                    bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
524 
525         if( !bPalDiffers )
526             bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
527 
528         if( bPalDiffers )
529         {
530             Bitmap              aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
531             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
532 
533             if( pWriteAcc )
534             {
535                 const long  nWidth = pWriteAcc->Width();
536                 const long  nHeight = pWriteAcc->Height();
537 
538                 if( pReadAcc->HasPalette() )
539                 {
540                     for( long nY = 0L; nY < nHeight; nY++ )
541                     {
542                         for( long nX = 0L; nX < nWidth; nX++ )
543                         {
544                             pWriteAcc->SetPixel( nY, nX,
545                                 (sal_uInt8) ( pReadAcc->GetPaletteColor(
546                                     pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) );
547                         }
548                     }
549                 }
550                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
551                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
552                 {
553                     nShift += 8;
554 
555                     for( long nY = 0L; nY < nHeight; nY++ )
556                     {
557                         Scanline pReadScan = pReadAcc->GetScanline( nY );
558                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
559 
560                         for( long nX = 0L; nX < nWidth; nX++ )
561                         {
562                             const sal_uLong nB = *pReadScan++;
563                             const sal_uLong nG = *pReadScan++;
564                             const sal_uLong nR = *pReadScan++;
565 
566                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
567                         }
568                     }
569                 }
570                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
571                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
572                 {
573                     nShift += 8;
574 
575                     for( long nY = 0L; nY < nHeight; nY++ )
576                     {
577                         Scanline pReadScan = pReadAcc->GetScanline( nY );
578                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
579 
580                         for( long nX = 0L; nX < nWidth; nX++ )
581                         {
582                             const sal_uLong nR = *pReadScan++;
583                             const sal_uLong nG = *pReadScan++;
584                             const sal_uLong nB = *pReadScan++;
585 
586                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
587                         }
588                     }
589                 }
590                 else
591                 {
592                     for( long nY = 0L; nY < nHeight; nY++ )
593                         for( long nX = 0L; nX < nWidth; nX++ )
594                             pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) );
595                 }
596 
597                 aNewBmp.ReleaseAccess( pWriteAcc );
598                 bRet = sal_True;
599             }
600 
601             ReleaseAccess( pReadAcc );
602 
603             if( bRet )
604             {
605                 const MapMode   aMap( maPrefMapMode );
606                 const Size      aSize( maPrefSize );
607 
608                 *this = aNewBmp;
609 
610                 maPrefMapMode = aMap;
611                 maPrefSize = aSize;
612             }
613         }
614         else
615         {
616             ReleaseAccess( pReadAcc );
617             bRet = sal_True;
618         }
619     }
620 
621     return bRet;
622 }
623 
624 // ------------------------------------------------------------------------
625 
626 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
627 {
628     DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
629 
630     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
631     sal_Bool                bRet = sal_False;
632 
633     if( pReadAcc )
634     {
635         BitmapPalette       aPal;
636         Bitmap              aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
637         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
638 
639         if( pWriteAcc )
640         {
641             const long  nWidth = pWriteAcc->Width();
642             const long  nHeight = pWriteAcc->Height();
643 
644             if( pWriteAcc->HasPalette() )
645             {
646                 const sal_uInt16            nOldCount = 1 << GetBitCount();
647                 const BitmapPalette&    rOldPal = pReadAcc->GetPalette();
648 
649                 aPal.SetEntryCount( 1 << nBitCount );
650 
651                 for( sal_uInt16 i = 0; i < nOldCount; i++ )
652                     aPal[ i ] = rOldPal[ i ];
653 
654                 if( pExtColor )
655                     aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
656 
657                 pWriteAcc->SetPalette( aPal );
658 
659                 for( long nY = 0L; nY < nHeight; nY++ )
660                     for( long nX = 0L; nX < nWidth; nX++ )
661                         pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
662             }
663             else
664             {
665                 if( pReadAcc->HasPalette() )
666                 {
667                     for( long nY = 0L; nY < nHeight; nY++ )
668                         for( long nX = 0L; nX < nWidth; nX++ )
669                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
670                 }
671                 else
672                 {
673                     for( long nY = 0L; nY < nHeight; nY++ )
674                         for( long nX = 0L; nX < nWidth; nX++ )
675                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
676                 }
677             }
678 
679             aNewBmp.ReleaseAccess( pWriteAcc );
680             bRet = sal_True;
681         }
682 
683         ReleaseAccess( pReadAcc );
684 
685         if( bRet )
686         {
687             const MapMode   aMap( maPrefMapMode );
688             const Size      aSize( maPrefSize );
689 
690             *this = aNewBmp;
691 
692             maPrefMapMode = aMap;
693             maPrefSize = aSize;
694         }
695     }
696 
697     return bRet;
698 }
699 
700 // ------------------------------------------------------------------------
701 
702 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
703 {
704     DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
705 
706     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
707     sal_Bool                bRet = sal_False;
708 
709     if( pReadAcc )
710     {
711         BitmapPalette       aPal;
712         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aPal );
713         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
714 
715         if( pWriteAcc )
716         {
717             const sal_uInt16    nCount = 1 << nBitCount;
718             const long      nWidth = pWriteAcc->Width();
719             const long      nWidth1 = nWidth - 1L;
720             const long      nHeight = pWriteAcc->Height();
721             Octree          aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
722             InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
723             BitmapColor     aColor;
724             ImpErrorQuad    aErrQuad;
725             ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
726             ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
727             ImpErrorQuad*   pQLine1 = pErrQuad1;
728             ImpErrorQuad*   pQLine2 = 0;
729             long            nX, nY;
730             long            nYTmp = 0L;
731             sal_uInt8           cIndex;
732             sal_Bool            bQ1 = sal_True;
733 
734             if( pExtColor )
735             {
736                 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
737                 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
738             }
739 
740             // set Black/White always, if we have enough space
741             if( aPal.GetEntryCount() < ( nCount - 1 ) )
742             {
743                 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
744                 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
745                 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
746             }
747 
748             pWriteAcc->SetPalette( aPal );
749 
750             for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
751             {
752                 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
753                 {
754                     if( pReadAcc->HasPalette() )
755                         pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
756                     else
757                         pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
758                 }
759             }
760 
761             for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
762             {
763                 // erstes ZeilenPixel
764                 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
765                 pWriteAcc->SetPixel( nY, 0, cIndex );
766 
767                 for( nX = 1L; nX < nWidth1; nX++ )
768                 {
769                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
770                     aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
771                     pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
772                     pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
773                     pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
774                     pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
775                     pWriteAcc->SetPixel( nY, nX, cIndex );
776                 }
777 
778                 // letztes ZeilenPixel
779                 if( nX < nWidth )
780                 {
781                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
782                     pWriteAcc->SetPixel( nY, nX, cIndex );
783                 }
784 
785                 // Zeilenpuffer neu fuellen/kopieren
786                 pQLine1 = pQLine2;
787                 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
788 
789                 if( nYTmp < nHeight )
790                 {
791                     for( nX = 0L; nX < nWidth; nX++ )
792                     {
793                         if( pReadAcc->HasPalette() )
794                                 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
795                         else
796                             pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
797                     }
798                 }
799             }
800 
801             // Zeilenpuffer zerstoeren
802             delete[] pErrQuad1;
803             delete[] pErrQuad2;
804 
805             aNewBmp.ReleaseAccess( pWriteAcc );
806             bRet = sal_True;
807         }
808 
809         ReleaseAccess( pReadAcc );
810 
811         if( bRet )
812         {
813             const MapMode   aMap( maPrefMapMode );
814             const Size      aSize( maPrefSize );
815 
816             *this = aNewBmp;
817 
818             maPrefMapMode = aMap;
819             maPrefSize = aSize;
820         }
821     }
822 
823     return bRet;
824 }
825 
826 // ------------------------------------------------------------------------
827 
828 sal_Bool Bitmap::ImplConvertGhosted()
829 {
830     Bitmap              aNewBmp;
831     BitmapReadAccess*   pR = AcquireReadAccess();
832     sal_Bool                bRet = sal_False;
833 
834     if( pR )
835     {
836         if( pR->HasPalette() )
837         {
838             BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
839 
840             for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
841             {
842                 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
843                 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
844                                                      ( rOld.GetGreen() >> 1 ) | 0x80,
845                                                      ( rOld.GetBlue() >> 1 ) | 0x80 );
846             }
847 
848             aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
849             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
850 
851             if( pW )
852             {
853                 pW->CopyBuffer( *pR );
854                 aNewBmp.ReleaseAccess( pW );
855                 bRet = sal_True;
856             }
857         }
858         else
859         {
860             aNewBmp = Bitmap( GetSizePixel(), 24 );
861 
862             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
863 
864             if( pW )
865             {
866                 const long nWidth = pR->Width(), nHeight = pR->Height();
867 
868                 for( long nY = 0; nY < nHeight; nY++ )
869                 {
870                     for( long nX = 0; nX < nWidth; nX++ )
871                     {
872                         const BitmapColor aOld( pR->GetPixel( nY, nX ) );
873                         pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
874                                                            ( aOld.GetGreen() >> 1 ) | 0x80,
875                                                            ( aOld.GetBlue() >> 1 ) | 0x80 ) );
876 
877                     }
878                 }
879 
880                 aNewBmp.ReleaseAccess( pW );
881                 bRet = sal_True;
882             }
883         }
884 
885         ReleaseAccess( pR );
886     }
887 
888     if( bRet )
889     {
890         const MapMode   aMap( maPrefMapMode );
891         const Size      aSize( maPrefSize );
892 
893         *this = aNewBmp;
894 
895         maPrefMapMode = aMap;
896         maPrefSize = aSize;
897     }
898 
899     return bRet;
900 }
901 
902 // ------------------------------------------------------------------------
903 
904 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
905 {
906     sal_Bool bRet;
907 
908     if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
909     {
910         if( BMP_SCALE_FAST == nScaleFlag )
911             bRet = ImplScaleFast( rScaleX, rScaleY );
912         else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
913             bRet = ImplScaleInterpolate( rScaleX, rScaleY );
914         else
915             bRet = sal_False;
916     }
917     else
918         bRet = sal_True;
919 
920     return bRet;
921 }
922 
923 // ------------------------------------------------------------------------
924 
925 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
926 {
927     const Size  aSize( GetSizePixel() );
928     sal_Bool        bRet;
929 
930     if( aSize.Width() && aSize.Height() )
931     {
932         bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
933                       (double) rNewSize.Height() / aSize.Height(),
934                       nScaleFlag );
935     }
936     else
937         bRet = sal_True;
938 
939     return bRet;
940 }
941 
942 // ------------------------------------------------------------------------
943 
944 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
945 {
946     const Size  aSizePix( GetSizePixel() );
947     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
948     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
949     sal_Bool        bRet = sal_False;
950 
951     if( nNewWidth && nNewHeight )
952     {
953         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
954         Bitmap              aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
955         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
956 
957         if( pReadAcc && pWriteAcc )
958         {
959             const long  nScanlineSize = pWriteAcc->GetScanlineSize();
960             const long  nNewWidth1 = nNewWidth - 1L;
961             const long  nNewHeight1 = nNewHeight - 1L;
962             const long  nWidth = pReadAcc->Width();
963             const long  nHeight = pReadAcc->Height();
964             long*       pLutX = new long[ nNewWidth ];
965             long*       pLutY = new long[ nNewHeight ];
966             long        nX, nY, nMapY, nActY = 0L;
967 
968             if( nNewWidth1 && nNewHeight1 )
969             {
970                 for( nX = 0L; nX < nNewWidth; nX++ )
971                     pLutX[ nX ] = nX * nWidth / nNewWidth;
972 
973                 for( nY = 0L; nY < nNewHeight; nY++ )
974                     pLutY[ nY ] = nY * nHeight / nNewHeight;
975 
976                 while( nActY < nNewHeight )
977                 {
978                     nMapY = pLutY[ nActY ];
979 
980                     for( nX = 0L; nX < nNewWidth; nX++ )
981                         pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
982 
983                     while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
984                     {
985                         memcpy( pWriteAcc->GetScanline( nActY + 1L ),
986                                  pWriteAcc->GetScanline( nActY ), nScanlineSize );
987                         nActY++;
988                     }
989 
990                     nActY++;
991                 }
992 
993                 bRet = sal_True;
994             }
995 
996             delete[] pLutX;
997             delete[] pLutY;
998         }
999 
1000         ReleaseAccess( pReadAcc );
1001         aNewBmp.ReleaseAccess( pWriteAcc );
1002 
1003         if( bRet )
1004             ImplAssignWithSize( aNewBmp );
1005     }
1006 
1007     return bRet;
1008 }
1009 
1010 // ------------------------------------------------------------------------
1011 
1012 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1013 {
1014     const Size  aSizePix( GetSizePixel() );
1015     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1016     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1017     sal_Bool        bRet = sal_False;
1018 
1019     if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1020     {
1021         BitmapColor         aCol0;
1022         BitmapColor         aCol1;
1023         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1024         long                nWidth = pReadAcc->Width();
1025         long                nHeight = pReadAcc->Height();
1026         Bitmap              aNewBmp( Size( nNewWidth, nHeight ), 24 );
1027         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1028         long*               pLutInt;
1029         long*               pLutFrac;
1030         long                nX, nY;
1031         long                lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1032         double              fTemp;
1033         long                nTemp;
1034 
1035         if( pReadAcc && pWriteAcc )
1036         {
1037             const long      nNewWidth1 = nNewWidth - 1L;
1038             const long      nWidth1 = pReadAcc->Width() - 1L;
1039             const double    fRevScaleX = (double) nWidth1 / nNewWidth1;
1040 
1041             pLutInt = new long[ nNewWidth ];
1042             pLutFrac = new long[ nNewWidth ];
1043 
1044             for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1045             {
1046                 fTemp = nX * fRevScaleX;
1047                 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1048                 fTemp -= pLutInt[ nX ];
1049                 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1050             }
1051 
1052             if( pReadAcc->HasPalette() )
1053             {
1054                 for( nY = 0L; nY < nHeight; nY++ )
1055                 {
1056                     if( 1 == nWidth )
1057                     {
1058                         aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
1059 
1060                         for( nX = 0L; nX < nNewWidth; nX++ )
1061                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1062                     }
1063                     else
1064                     {
1065                         for( nX = 0L; nX < nNewWidth; nX++ )
1066                         {
1067                             nTemp = pLutInt[ nX ];
1068 
1069                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
1070                             aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
1071 
1072                             nTemp = pLutFrac[ nX ];
1073 
1074                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1075                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1076                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1077 
1078                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1079                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1080                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1081 
1082                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1083                         }
1084                     }
1085                 }
1086             }
1087             else
1088             {
1089                 for( nY = 0L; nY < nHeight; nY++ )
1090                 {
1091                     if( 1 == nWidth )
1092                     {
1093                         aCol0 = pReadAcc->GetPixel( nY, 0 );
1094 
1095                         for( nX = 0L; nX < nNewWidth; nX++ )
1096                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1097                     }
1098                     else
1099                     {
1100                         for( nX = 0L; nX < nNewWidth; nX++ )
1101                         {
1102                             nTemp = pLutInt[ nX ];
1103 
1104                             aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1105                             aCol1 = pReadAcc->GetPixel( nY, nTemp );
1106 
1107                             nTemp = pLutFrac[ nX ];
1108 
1109                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1110                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1111                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1112 
1113                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1114                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1115                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1116 
1117                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1118                         }
1119                     }
1120                 }
1121             }
1122 
1123             delete[] pLutInt;
1124             delete[] pLutFrac;
1125             bRet = sal_True;
1126         }
1127 
1128         ReleaseAccess( pReadAcc );
1129         aNewBmp.ReleaseAccess( pWriteAcc );
1130 
1131         if( bRet )
1132         {
1133             bRet = sal_False;
1134             ImplAssignWithSize( aNewBmp );
1135             pReadAcc = AcquireReadAccess();
1136             aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1137             pWriteAcc = aNewBmp.AcquireWriteAccess();
1138 
1139             if( pReadAcc && pWriteAcc )
1140             {
1141                 const long      nNewHeight1 = nNewHeight - 1L;
1142                 const long      nHeight1 = pReadAcc->Height() - 1L;
1143                 const double    fRevScaleY = (double) nHeight1 / nNewHeight1;
1144 
1145                 pLutInt = new long[ nNewHeight ];
1146                 pLutFrac = new long[ nNewHeight ];
1147 
1148                 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1149                 {
1150                     fTemp = nY * fRevScaleY;
1151                     pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1152                     fTemp -= pLutInt[ nY ];
1153                     pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1154                 }
1155 
1156                 if( pReadAcc->HasPalette() )
1157                 {
1158                     for( nX = 0L; nX < nNewWidth; nX++ )
1159                     {
1160                         if( 1 == nHeight )
1161                         {
1162                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
1163 
1164                             for( nY = 0L; nY < nNewHeight; nY++ )
1165                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1166                         }
1167                         else
1168                         {
1169                             for( nY = 0L; nY < nNewHeight; nY++ )
1170                             {
1171                                 nTemp = pLutInt[ nY ];
1172 
1173                                 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
1174                                 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
1175 
1176                                 nTemp = pLutFrac[ nY ];
1177 
1178                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1179                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1180                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1181 
1182                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1183                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1184                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1185 
1186                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1187                             }
1188                         }
1189                     }
1190                 }
1191                 else
1192                 {
1193                     for( nX = 0L; nX < nNewWidth; nX++ )
1194                     {
1195                         if( 1 == nHeight )
1196                         {
1197                             aCol0 = pReadAcc->GetPixel( 0, nX );
1198 
1199                             for( nY = 0L; nY < nNewHeight; nY++ )
1200                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1201                         }
1202                         else
1203                         {
1204                             for( nY = 0L; nY < nNewHeight; nY++ )
1205                             {
1206                                 nTemp = pLutInt[ nY ];
1207 
1208                                 aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1209                                 aCol1 = pReadAcc->GetPixel( nTemp, nX );
1210 
1211                                 nTemp = pLutFrac[ nY ];
1212 
1213                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1214                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1215                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1216 
1217                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1218                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1219                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1220 
1221                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1222                             }
1223                         }
1224                     }
1225                 }
1226 
1227                 delete[] pLutInt;
1228                 delete[] pLutFrac;
1229                 bRet = sal_True;
1230             }
1231 
1232             ReleaseAccess( pReadAcc );
1233             aNewBmp.ReleaseAccess( pWriteAcc );
1234 
1235             if( bRet )
1236                 ImplAssignWithSize( aNewBmp );
1237         }
1238     }
1239 
1240     if( !bRet )
1241         bRet = ImplScaleFast( rScaleX, rScaleY );
1242 
1243     return bRet;
1244 }
1245 
1246 // ------------------------------------------------------------------------
1247 
1248 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1249 {
1250     sal_Bool bRet = sal_False;
1251 
1252     const Size aSizePix( GetSizePixel() );
1253 
1254     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1255         bRet = sal_True;
1256     else if( nDitherFlags & BMP_DITHER_MATRIX )
1257         bRet = ImplDitherMatrix();
1258     else if( nDitherFlags & BMP_DITHER_FLOYD )
1259         bRet = ImplDitherFloyd();
1260     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1261         bRet = ImplDitherFloyd16();
1262 
1263     return bRet;
1264 }
1265 
1266 // ------------------------------------------------------------------------
1267 
1268 sal_Bool Bitmap::ImplDitherMatrix()
1269 {
1270     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1271     Bitmap              aNewBmp( GetSizePixel(), 8 );
1272     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1273     sal_Bool                bRet = sal_False;
1274 
1275     if( pReadAcc && pWriteAcc )
1276     {
1277         const sal_uLong nWidth = pReadAcc->Width();
1278         const sal_uLong nHeight = pReadAcc->Height();
1279         BitmapColor aIndex( (sal_uInt8) 0 );
1280 
1281         if( pReadAcc->HasPalette() )
1282         {
1283             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1284             {
1285                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1286                 {
1287                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
1288                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1289                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1290                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1291                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1292 
1293                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1294                     pWriteAcc->SetPixel( nY, nX, aIndex );
1295                 }
1296             }
1297         }
1298         else
1299         {
1300             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1301             {
1302                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1303                 {
1304                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
1305                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1306                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1307                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1308                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1309 
1310                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1311                     pWriteAcc->SetPixel( nY, nX, aIndex );
1312                 }
1313             }
1314         }
1315 
1316         bRet = sal_True;
1317     }
1318 
1319     ReleaseAccess( pReadAcc );
1320     aNewBmp.ReleaseAccess( pWriteAcc );
1321 
1322     if( bRet )
1323     {
1324         const MapMode   aMap( maPrefMapMode );
1325         const Size      aSize( maPrefSize );
1326 
1327         *this = aNewBmp;
1328 
1329         maPrefMapMode = aMap;
1330         maPrefSize = aSize;
1331     }
1332 
1333     return bRet;
1334 }
1335 
1336 // ------------------------------------------------------------------------
1337 
1338 sal_Bool Bitmap::ImplDitherFloyd()
1339 {
1340     const Size  aSize( GetSizePixel() );
1341     sal_Bool        bRet = sal_False;
1342 
1343     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1344     {
1345         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1346         Bitmap              aNewBmp( GetSizePixel(), 8 );
1347         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1348 
1349         if( pReadAcc && pWriteAcc )
1350         {
1351             BitmapColor aColor;
1352             long        nWidth = pReadAcc->Width();
1353             long        nWidth1 = nWidth - 1L;
1354             long        nHeight = pReadAcc->Height();
1355             long        nX;
1356             long        nW = nWidth * 3L;
1357             long        nW2 = nW - 3L;
1358             long        nRErr, nGErr, nBErr;
1359             long        nRC, nGC, nBC;
1360             long        nTemp;
1361             long        nZ;
1362             long*       p1 = new long[ nW ];
1363             long*       p2 = new long[ nW ];
1364             long*       p1T = p1;
1365             long*       p2T = p2;
1366             long*       pTmp;
1367             sal_Bool        bPal = pReadAcc->HasPalette();
1368 
1369             pTmp = p2T;
1370 
1371             if( bPal )
1372             {
1373                 for( nZ = 0; nZ < nWidth; nZ++ )
1374                 {
1375                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
1376 
1377                     *pTmp++ = (long) aColor.GetBlue() << 12;
1378                     *pTmp++ = (long) aColor.GetGreen() << 12;
1379                     *pTmp++ = (long) aColor.GetRed() << 12;
1380                 }
1381             }
1382             else
1383             {
1384                 for( nZ = 0; nZ < nWidth; nZ++ )
1385                 {
1386                     aColor = pReadAcc->GetPixel( 0, nZ );
1387 
1388                     *pTmp++ = (long) aColor.GetBlue() << 12;
1389                     *pTmp++ = (long) aColor.GetGreen() << 12;
1390                     *pTmp++ = (long) aColor.GetRed() << 12;
1391                 }
1392             }
1393 
1394             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1395             {
1396                 pTmp = p1T;
1397                 p1T = p2T;
1398                 p2T = pTmp;
1399 
1400                 if( nY < nHeight )
1401                 {
1402                     if( bPal )
1403                     {
1404                         for( nZ = 0; nZ < nWidth; nZ++ )
1405                         {
1406                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
1407 
1408                             *pTmp++ = (long) aColor.GetBlue() << 12;
1409                             *pTmp++ = (long) aColor.GetGreen() << 12;
1410                             *pTmp++ = (long) aColor.GetRed() << 12;
1411                         }
1412                     }
1413                     else
1414                     {
1415                         for( nZ = 0; nZ < nWidth; nZ++ )
1416                         {
1417                             aColor = pReadAcc->GetPixel( nY, nZ );
1418 
1419                             *pTmp++ = (long) aColor.GetBlue() << 12;
1420                             *pTmp++ = (long) aColor.GetGreen() << 12;
1421                             *pTmp++ = (long) aColor.GetRed() << 12;
1422                         }
1423                     }
1424                 }
1425 
1426                 // erstes Pixel gesondert betrachten
1427                 nX = 0;
1428                 CALC_ERRORS;
1429                 CALC_TABLES7;
1430                 nX -= 5;
1431                 CALC_TABLES5;
1432                 pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1433 
1434                 // mittlere Pixel ueber Schleife
1435                 long nXAcc;
1436                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1437                 {
1438                     CALC_ERRORS;
1439                     CALC_TABLES7;
1440                     nX -= 8;
1441                     CALC_TABLES3;
1442                     CALC_TABLES5;
1443                     pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1444                 }
1445 
1446                 // letztes Pixel gesondert betrachten
1447                 CALC_ERRORS;
1448                 nX -= 5;
1449                 CALC_TABLES3;
1450                 CALC_TABLES5;
1451                 pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1452             }
1453 
1454             delete[] p1;
1455             delete[] p2;
1456             bRet = sal_True;
1457         }
1458 
1459         ReleaseAccess( pReadAcc );
1460         aNewBmp.ReleaseAccess( pWriteAcc );
1461 
1462         if( bRet )
1463         {
1464             const MapMode   aMap( maPrefMapMode );
1465             const Size      aPrefSize( maPrefSize );
1466 
1467             *this = aNewBmp;
1468 
1469             maPrefMapMode = aMap;
1470             maPrefSize = aPrefSize;
1471         }
1472     }
1473 
1474     return bRet;
1475 }
1476 
1477 // ------------------------------------------------------------------------
1478 
1479 sal_Bool Bitmap::ImplDitherFloyd16()
1480 {
1481     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1482     Bitmap              aNewBmp( GetSizePixel(), 24 );
1483     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1484     sal_Bool                bRet = sal_False;
1485 
1486     if( pReadAcc && pWriteAcc )
1487     {
1488         const long      nWidth = pWriteAcc->Width();
1489         const long      nWidth1 = nWidth - 1L;
1490         const long      nHeight = pWriteAcc->Height();
1491         BitmapColor     aColor;
1492         BitmapColor     aBestCol;
1493         ImpErrorQuad    aErrQuad;
1494         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
1495         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
1496         ImpErrorQuad*   pQLine1 = pErrQuad1;
1497         ImpErrorQuad*   pQLine2 = 0;
1498         long            nX, nY;
1499         long            nYTmp = 0L;
1500         sal_Bool            bQ1 = sal_True;
1501 
1502         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1503             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1504                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1505 
1506         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1507         {
1508             // erstes ZeilenPixel
1509             aBestCol = pQLine1[ 0 ].ImplGetColor();
1510             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1511             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1512             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1513             pWriteAcc->SetPixel( nY, 0, aBestCol );
1514 
1515             for( nX = 1L; nX < nWidth1; nX++ )
1516             {
1517                 aColor = pQLine1[ nX ].ImplGetColor();
1518                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1519                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1520                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1521                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1522                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1523                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1524                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1525                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1526                 pWriteAcc->SetPixel( nY, nX, aBestCol );
1527             }
1528 
1529             // letztes ZeilenPixel
1530             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1531             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1532             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1533             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1534             pWriteAcc->SetPixel( nY, nX, aBestCol );
1535 
1536             // Zeilenpuffer neu fuellen/kopieren
1537             pQLine1 = pQLine2;
1538             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1539 
1540             if( nYTmp < nHeight )
1541                 for( nX = 0L; nX < nWidth; nX++ )
1542                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1543         }
1544 
1545         // Zeilenpuffer zerstoeren
1546         delete[] pErrQuad1;
1547         delete[] pErrQuad2;
1548         bRet = sal_True;
1549     }
1550 
1551     ReleaseAccess( pReadAcc );
1552     aNewBmp.ReleaseAccess( pWriteAcc );
1553 
1554     if( bRet )
1555     {
1556         const MapMode   aMap( maPrefMapMode );
1557         const Size      aSize( maPrefSize );
1558 
1559         *this = aNewBmp;
1560 
1561         maPrefMapMode = aMap;
1562         maPrefSize = aSize;
1563     }
1564 
1565     return bRet;
1566 }
1567 
1568 // ------------------------------------------------------------------------
1569 
1570 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1571 {
1572     sal_Bool bRet;
1573 
1574     if( GetColorCount() <= (sal_uLong) nColorCount )
1575         bRet = sal_True;
1576     else if( nColorCount )
1577     {
1578         if( BMP_REDUCE_SIMPLE == eReduce )
1579             bRet = ImplReduceSimple( nColorCount );
1580         else if( BMP_REDUCE_POPULAR == eReduce )
1581             bRet = ImplReducePopular( nColorCount );
1582         else
1583             bRet = ImplReduceMedian( nColorCount );
1584     }
1585     else
1586         bRet = sal_False;
1587 
1588     return bRet;
1589 }
1590 
1591 // ------------------------------------------------------------------------
1592 
1593 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1594 {
1595     Bitmap              aNewBmp;
1596     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1597     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
1598     sal_uInt16              nBitCount;
1599     sal_Bool                bRet = sal_False;
1600 
1601     if( nColCount <= 2 )
1602         nBitCount = 1;
1603     else if( nColCount <= 16 )
1604         nBitCount = 4;
1605     else
1606         nBitCount = 8;
1607 
1608     if( pRAcc )
1609     {
1610         Octree                  aOct( *pRAcc, nColCount );
1611         const BitmapPalette&    rPal = aOct.GetPalette();
1612         BitmapWriteAccess*      pWAcc;
1613 
1614         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1615         pWAcc = aNewBmp.AcquireWriteAccess();
1616 
1617         if( pWAcc )
1618         {
1619             const long nWidth = pRAcc->Width();
1620             const long nHeight = pRAcc->Height();
1621 
1622             if( pRAcc->HasPalette() )
1623             {
1624                 for( long nY = 0L; nY < nHeight; nY++ )
1625                     for( long nX =0L; nX < nWidth; nX++ )
1626                         pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
1627             }
1628             else
1629             {
1630                 for( long nY = 0L; nY < nHeight; nY++ )
1631                     for( long nX =0L; nX < nWidth; nX++ )
1632                         pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
1633             }
1634 
1635             aNewBmp.ReleaseAccess( pWAcc );
1636             bRet = sal_True;
1637         }
1638 
1639         ReleaseAccess( pRAcc );
1640     }
1641 
1642     if( bRet )
1643     {
1644         const MapMode   aMap( maPrefMapMode );
1645         const Size      aSize( maPrefSize );
1646 
1647         *this = aNewBmp;
1648         maPrefMapMode = aMap;
1649         maPrefSize = aSize;
1650     }
1651 
1652     return bRet;
1653 }
1654 
1655 // ------------------------------------------------------------------------
1656 
1657 struct PopularColorCount
1658 {
1659     sal_uInt32  mnIndex;
1660     sal_uInt32  mnCount;
1661 };
1662 
1663 // ------------------------------------------------------------------------
1664 
1665 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1666 {
1667     int nRet;
1668 
1669     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1670         nRet = 1;
1671     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1672         nRet = 0;
1673     else
1674         nRet = -1;
1675 
1676     return nRet;
1677 }
1678 
1679 // ------------------------------------------------------------------------
1680 
1681 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1682 {
1683     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1684     sal_uInt16              nBitCount;
1685     sal_Bool                bRet = sal_False;
1686 
1687     if( nColCount > 256 )
1688         nColCount = 256;
1689 
1690     if( nColCount < 17 )
1691         nBitCount = 4;
1692     else
1693         nBitCount = 8;
1694 
1695     if( pRAcc )
1696     {
1697         const sal_uInt32    nValidBits = 4;
1698         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
1699         const sal_uInt32    nLeftShiftBits1 = nValidBits;
1700         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
1701         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
1702         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
1703         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1704         const long          nWidth = pRAcc->Width();
1705         const long          nHeight = pRAcc->Height();
1706         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
1707         long                nX, nY, nR, nG, nB, nIndex;
1708 
1709         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1710 
1711         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1712         {
1713             for( nG = 0; nG < 256; nG += nColorOffset )
1714             {
1715                 for( nB = 0; nB < 256; nB += nColorOffset )
1716                 {
1717                     pCountTable[ nIndex ].mnIndex = nIndex;
1718                     nIndex++;
1719                 }
1720             }
1721         }
1722 
1723         if( pRAcc->HasPalette() )
1724         {
1725             for( nY = 0L; nY < nHeight; nY++ )
1726             {
1727                 for( nX = 0L; nX < nWidth; nX++ )
1728                 {
1729                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1730                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1731                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1732                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1733                 }
1734             }
1735         }
1736         else
1737         {
1738             for( nY = 0L; nY < nHeight; nY++ )
1739             {
1740                 for( nX = 0L; nX < nWidth; nX++ )
1741                 {
1742                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1743                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1744                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1745                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1746                 }
1747             }
1748         }
1749 
1750         BitmapPalette aNewPal( nColCount );
1751 
1752         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1753 
1754         for( sal_uInt16 n = 0; n < nColCount; n++ )
1755         {
1756             const PopularColorCount& rPop = pCountTable[ n ];
1757             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1758                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1759                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1760         }
1761 
1762         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1763         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1764 
1765         if( pWAcc )
1766         {
1767             BitmapColor aDstCol( (sal_uInt8) 0 );
1768             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
1769 
1770             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1771                 for( nG = 0; nG < 256; nG += nColorOffset )
1772                     for( nB = 0; nB < 256; nB += nColorOffset )
1773                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1774 
1775             if( pRAcc->HasPalette() )
1776             {
1777                 for( nY = 0L; nY < nHeight; nY++ )
1778                 {
1779                     for( nX = 0L; nX < nWidth; nX++ )
1780                     {
1781                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1782                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1783                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1784                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1785                         pWAcc->SetPixel( nY, nX, aDstCol );
1786                     }
1787                 }
1788             }
1789             else
1790             {
1791                 for( nY = 0L; nY < nHeight; nY++ )
1792                 {
1793                     for( nX = 0L; nX < nWidth; nX++ )
1794                     {
1795                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1796                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1797                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1798                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1799                         pWAcc->SetPixel( nY, nX, aDstCol );
1800                     }
1801                 }
1802             }
1803 
1804             delete[] pIndexMap;
1805             aNewBmp.ReleaseAccess( pWAcc );
1806             bRet = sal_True;
1807         }
1808 
1809         delete[] pCountTable;
1810         ReleaseAccess( pRAcc );
1811 
1812         if( bRet )
1813         {
1814             const MapMode   aMap( maPrefMapMode );
1815             const Size      aSize( maPrefSize );
1816 
1817             *this = aNewBmp;
1818             maPrefMapMode = aMap;
1819             maPrefSize = aSize;
1820         }
1821     }
1822 
1823     return bRet;
1824 }
1825 
1826 // ------------------------------------------------------------------------
1827 
1828 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1829 {
1830     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1831     sal_uInt16              nBitCount;
1832     sal_Bool                bRet = sal_False;
1833 
1834     if( nColCount < 17 )
1835         nBitCount = 4;
1836     else if( nColCount < 257 )
1837         nBitCount = 8;
1838     else
1839     {
1840         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1841         nBitCount = 8;
1842         nColCount = 256;
1843     }
1844 
1845     if( pRAcc )
1846     {
1847         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
1848         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1849 
1850         if( pWAcc )
1851         {
1852             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
1853             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1854             const long  nWidth = pWAcc->Width();
1855             const long  nHeight = pWAcc->Height();
1856             long        nIndex = 0L;
1857 
1858             memset( (HPBYTE) pColBuf, 0, nSize );
1859 
1860             // create Buffer
1861             if( pRAcc->HasPalette() )
1862             {
1863                 for( long nY = 0L; nY < nHeight; nY++ )
1864                 {
1865                     for( long nX = 0L; nX < nWidth; nX++ )
1866                     {
1867                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1868                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1869                     }
1870                 }
1871             }
1872             else
1873             {
1874                 for( long nY = 0L; nY < nHeight; nY++ )
1875                 {
1876                     for( long nX = 0L; nX < nWidth; nX++ )
1877                     {
1878                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1879                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1880                     }
1881                 }
1882             }
1883 
1884             // create palette via median cut
1885             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1886             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1887                            nColCount, nWidth * nHeight, nIndex );
1888 
1889             // do mapping of colors to palette
1890             InverseColorMap aMap( aPal );
1891             pWAcc->SetPalette( aPal );
1892             for( long nY = 0L; nY < nHeight; nY++ )
1893                 for( long nX = 0L; nX < nWidth; nX++ )
1894                     pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
1895 
1896             rtl_freeMemory( pColBuf );
1897             aNewBmp.ReleaseAccess( pWAcc );
1898             bRet = sal_True;
1899         }
1900 
1901         ReleaseAccess( pRAcc );
1902 
1903         if( bRet )
1904         {
1905             const MapMode   aMap( maPrefMapMode );
1906             const Size      aSize( maPrefSize );
1907 
1908             *this = aNewBmp;
1909             maPrefMapMode = aMap;
1910             maPrefSize = aSize;
1911         }
1912     }
1913 
1914     return bRet;
1915 }
1916 
1917 // ------------------------------------------------------------------------
1918 
1919 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1920                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1921                             long nColors, long nPixels, long& rIndex )
1922 {
1923     if( !nPixels )
1924         return;
1925 
1926     BitmapColor aCol;
1927     const long  nRLen = nR2 - nR1;
1928     const long  nGLen = nG2 - nG1;
1929     const long  nBLen = nB2 - nB1;
1930     long        nR, nG, nB;
1931     sal_uLong*      pBuf = pColBuf;
1932 
1933     if( !nRLen && !nGLen && !nBLen )
1934     {
1935         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1936         {
1937             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1938             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1939             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1940             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1941         }
1942     }
1943     else
1944     {
1945         if( 1 == nColors || 1 == nPixels )
1946         {
1947             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1948 
1949             for( nR = nR1; nR <= nR2; nR++ )
1950             {
1951                 for( nG = nG1; nG <= nG2; nG++ )
1952                 {
1953                     for( nB = nB1; nB <= nB2; nB++ )
1954                     {
1955                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1956 
1957                         if( nPixSum )
1958                         {
1959                             nRSum += nR * nPixSum;
1960                             nGSum += nG * nPixSum;
1961                             nBSum += nB * nPixSum;
1962                         }
1963                     }
1964                 }
1965             }
1966 
1967             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1968             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1969             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1970             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1971         }
1972         else
1973         {
1974             const long  nTest = ( nPixels >> 1 );
1975             long        nPixOld = 0;
1976             long        nPixNew = 0;
1977 
1978             if( nBLen > nGLen && nBLen > nRLen )
1979             {
1980                 nB = nB1 - 1;
1981 
1982                 while( nPixNew < nTest )
1983                 {
1984                     nB++, nPixOld = nPixNew;
1985                     for( nR = nR1; nR <= nR2; nR++ )
1986                         for( nG = nG1; nG <= nG2; nG++ )
1987                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1988                 }
1989 
1990                 if( nB < nB2 )
1991                 {
1992                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1993                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1994                 }
1995                 else
1996                 {
1997                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
1998                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
1999                 }
2000             }
2001             else if( nGLen > nRLen )
2002             {
2003                 nG = nG1 - 1;
2004 
2005                 while( nPixNew < nTest )
2006                 {
2007                     nG++, nPixOld = nPixNew;
2008                     for( nR = nR1; nR <= nR2; nR++ )
2009                         for( nB = nB1; nB <= nB2; nB++ )
2010                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2011                 }
2012 
2013                 if( nG < nG2 )
2014                 {
2015                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2016                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2017                 }
2018                 else
2019                 {
2020                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2021                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2022                 }
2023             }
2024             else
2025             {
2026                 nR = nR1 - 1;
2027 
2028                 while( nPixNew < nTest )
2029                 {
2030                     nR++, nPixOld = nPixNew;
2031                     for( nG = nG1; nG <= nG2; nG++ )
2032                         for( nB = nB1; nB <= nB2; nB++ )
2033                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2034                 }
2035 
2036                 if( nR < nR2 )
2037                 {
2038                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2039                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2040                 }
2041                 else
2042                 {
2043                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2044                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2045                 }
2046             }
2047         }
2048     }
2049 }
2050 
2051 // ------------------------------------------------------------------------
2052 
2053 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2054 {
2055     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2056 }
2057 
2058 // ------------------------------------------------------------------------
2059 
2060 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2061 {
2062     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2063 }
2064 
2065 // ------------------------------------------------------------------------
2066 
2067 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2068                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2069                      double fGamma, sal_Bool bInvert )
2070 {
2071     sal_Bool bRet = sal_False;
2072 
2073     // nothing to do => return quickly
2074     if( !nLuminancePercent && !nContrastPercent &&
2075         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2076         ( fGamma == 1.0 ) && !bInvert )
2077     {
2078         bRet = sal_True;
2079     }
2080     else
2081     {
2082         BitmapWriteAccess* pAcc = AcquireWriteAccess();
2083 
2084         if( pAcc )
2085         {
2086             BitmapColor     aCol;
2087             const long      nW = pAcc->Width();
2088             const long      nH = pAcc->Height();
2089             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
2090             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
2091             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
2092             long            nX, nY;
2093             double          fM, fROff, fGOff, fBOff, fOff;
2094 
2095             // calculate slope
2096             if( nContrastPercent >= 0 )
2097                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2098             else
2099                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2100 
2101             // total offset = luminance offset + contrast offset
2102             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2103 
2104             // channel offset = channel offset  + total offset
2105             fROff = nChannelRPercent * 2.55 + fOff;
2106             fGOff = nChannelGPercent * 2.55 + fOff;
2107             fBOff = nChannelBPercent * 2.55 + fOff;
2108 
2109             // calculate gamma value
2110             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2111             const sal_Bool bGamma = ( fGamma != 1.0 );
2112 
2113             // create mapping table
2114             for( nX = 0L; nX < 256L; nX++ )
2115             {
2116                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2117                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2118                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2119 
2120                 if( bGamma )
2121                 {
2122                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2123                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2124                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2125                 }
2126 
2127                 if( bInvert )
2128                 {
2129                     cMapR[ nX ] = ~cMapR[ nX ];
2130                     cMapG[ nX ] = ~cMapG[ nX ];
2131                     cMapB[ nX ] = ~cMapB[ nX ];
2132                 }
2133             }
2134 
2135             // do modifying
2136             if( pAcc->HasPalette() )
2137             {
2138                 BitmapColor aNewCol;
2139 
2140                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2141                 {
2142                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2143                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2144                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2145                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2146                     pAcc->SetPaletteColor( i, aNewCol );
2147                 }
2148             }
2149             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2150             {
2151                 for( nY = 0L; nY < nH; nY++ )
2152                 {
2153                     Scanline pScan = pAcc->GetScanline( nY );
2154 
2155                     for( nX = 0L; nX < nW; nX++ )
2156                     {
2157                         *pScan = cMapB[ *pScan ]; pScan++;
2158                         *pScan = cMapG[ *pScan ]; pScan++;
2159                         *pScan = cMapR[ *pScan ]; pScan++;
2160                     }
2161                 }
2162             }
2163             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2164             {
2165                 for( nY = 0L; nY < nH; nY++ )
2166                 {
2167                     Scanline pScan = pAcc->GetScanline( nY );
2168 
2169                     for( nX = 0L; nX < nW; nX++ )
2170                     {
2171                         *pScan = cMapR[ *pScan ]; pScan++;
2172                         *pScan = cMapG[ *pScan ]; pScan++;
2173                         *pScan = cMapB[ *pScan ]; pScan++;
2174                     }
2175                 }
2176             }
2177             else
2178             {
2179                 for( nY = 0L; nY < nH; nY++ )
2180                 {
2181                     for( nX = 0L; nX < nW; nX++ )
2182                     {
2183                         aCol = pAcc->GetPixel( nY, nX );
2184                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
2185                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2186                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2187                         pAcc->SetPixel( nY, nX, aCol );
2188                     }
2189                 }
2190             }
2191 
2192             delete[] cMapR;
2193             delete[] cMapG;
2194             delete[] cMapB;
2195             ReleaseAccess( pAcc );
2196             bRet = sal_True;
2197         }
2198     }
2199 
2200     return bRet;
2201 }
2202