xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision 87bc88d3ed834c36654f277ed18005c290f77bdd)
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                         const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
387                         if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
388                             cThreshold )
389                         {
390                             pWriteAcc->SetPixel( nY, nX, aWhite );
391                         }
392                         else
393                             pWriteAcc->SetPixel( nY, nX, aBlack );
394                     }
395                 }
396             }
397             else
398             {
399                 for( long nY = 0L; nY < nHeight; nY++ )
400                 {
401                     for( long nX = 0L; nX < nWidth; nX++ )
402                     {
403                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
404                             cThreshold )
405                         {
406                             pWriteAcc->SetPixel( nY, nX, aWhite );
407                         }
408                         else
409                             pWriteAcc->SetPixel( nY, nX, aBlack );
410                     }
411                 }
412             }
413 
414             aNewBmp.ReleaseAccess( pWriteAcc );
415             bRet = sal_True;
416         }
417 
418         ReleaseAccess( pReadAcc );
419 
420         if( bRet )
421         {
422             const MapMode   aMap( maPrefMapMode );
423             const Size      aSize( maPrefSize );
424 
425             *this = aNewBmp;
426 
427             maPrefMapMode = aMap;
428             maPrefSize = aSize;
429         }
430     }
431 
432     return bRet;
433 }
434 
435 // ------------------------------------------------------------------------
436 
437 sal_Bool Bitmap::ImplMakeMonoDither()
438 {
439     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
440     sal_Bool                bRet = sal_False;
441 
442     if( pReadAcc )
443     {
444         Bitmap              aNewBmp( GetSizePixel(), 1 );
445         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
446 
447         if( pWriteAcc )
448         {
449             const BitmapColor   aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
450             const BitmapColor   aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
451             const long          nWidth = pWriteAcc->Width();
452             const long          nHeight = pWriteAcc->Height();
453             sal_uInt8               pDitherMatrix[ 16 ][ 16 ];
454 
455             ImplCreateDitherMatrix( &pDitherMatrix );
456 
457             if( pReadAcc->HasPalette() )
458             {
459                 for( long nY = 0L; nY < nHeight; nY++ )
460                 {
461                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
462                     {
463                         const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
464                         if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
465                             pDitherMatrix[ nModY ][ nX % 16 ] )
466                         {
467                             pWriteAcc->SetPixel( nY, nX, aWhite );
468                         }
469                         else
470                             pWriteAcc->SetPixel( nY, nX, aBlack );
471                     }
472                 }
473             }
474             else
475             {
476                 for( long nY = 0L; nY < nHeight; nY++ )
477                 {
478                     for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
479                     {
480                         if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
481                             pDitherMatrix[ nModY ][ nX % 16 ]  )
482                         {
483                             pWriteAcc->SetPixel( nY, nX, aWhite );
484                         }
485                         else
486                             pWriteAcc->SetPixel( nY, nX, aBlack );
487                     }
488                 }
489             }
490 
491             aNewBmp.ReleaseAccess( pWriteAcc );
492             bRet = sal_True;
493         }
494 
495         ReleaseAccess( pReadAcc );
496 
497         if( bRet )
498         {
499             const MapMode   aMap( maPrefMapMode );
500             const Size      aSize( maPrefSize );
501 
502             *this = aNewBmp;
503 
504             maPrefMapMode = aMap;
505             maPrefSize = aSize;
506         }
507     }
508 
509     return bRet;
510 }
511 
512 // ------------------------------------------------------------------------
513 
514 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
515 {
516     DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
517 
518     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
519     sal_Bool                bRet = sal_False;
520 
521     if( pReadAcc )
522     {
523         const BitmapPalette&    rPal = GetGreyPalette( nGreys );
524         sal_uLong                   nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
525         sal_Bool                    bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
526 
527         if( !bPalDiffers )
528             bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
529 
530         if( bPalDiffers )
531         {
532             Bitmap              aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
533             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
534 
535             if( pWriteAcc )
536             {
537                 const long  nWidth = pWriteAcc->Width();
538                 const long  nHeight = pWriteAcc->Height();
539 
540                 if( pReadAcc->HasPalette() )
541                 {
542                     for( long nY = 0L; nY < nHeight; nY++ )
543                     {
544                         for( long nX = 0L; nX < nWidth; nX++ )
545                         {
546                             const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
547                             pWriteAcc->SetPixelIndex( nY, nX,
548                                 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
549                         }
550                     }
551                 }
552                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
553                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
554                 {
555                     nShift += 8;
556 
557                     for( long nY = 0L; nY < nHeight; nY++ )
558                     {
559                         Scanline pReadScan = pReadAcc->GetScanline( nY );
560                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
561 
562                         for( long nX = 0L; nX < nWidth; nX++ )
563                         {
564                             const sal_uLong nB = *pReadScan++;
565                             const sal_uLong nG = *pReadScan++;
566                             const sal_uLong nR = *pReadScan++;
567 
568                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
569                         }
570                     }
571                 }
572                 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
573                          pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
574                 {
575                     nShift += 8;
576 
577                     for( long nY = 0L; nY < nHeight; nY++ )
578                     {
579                         Scanline pReadScan = pReadAcc->GetScanline( nY );
580                         Scanline pWriteScan = pWriteAcc->GetScanline( nY );
581 
582                         for( long nX = 0L; nX < nWidth; nX++ )
583                         {
584                             const sal_uLong nR = *pReadScan++;
585                             const sal_uLong nG = *pReadScan++;
586                             const sal_uLong nB = *pReadScan++;
587 
588                             *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
589                         }
590                     }
591                 }
592                 else
593                 {
594                     for( long nY = 0L; nY < nHeight; nY++ )
595                         for( long nX = 0L; nX < nWidth; nX++ )
596                             pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
597                 }
598 
599                 aNewBmp.ReleaseAccess( pWriteAcc );
600                 bRet = sal_True;
601             }
602 
603             ReleaseAccess( pReadAcc );
604 
605             if( bRet )
606             {
607                 const MapMode   aMap( maPrefMapMode );
608                 const Size      aSize( maPrefSize );
609 
610                 *this = aNewBmp;
611 
612                 maPrefMapMode = aMap;
613                 maPrefSize = aSize;
614             }
615         }
616         else
617         {
618             ReleaseAccess( pReadAcc );
619             bRet = sal_True;
620         }
621     }
622 
623     return bRet;
624 }
625 
626 // ------------------------------------------------------------------------
627 
628 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
629 {
630     DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
631 
632     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
633     sal_Bool                bRet = sal_False;
634 
635     if( pReadAcc )
636     {
637         BitmapPalette       aPal;
638         Bitmap              aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
639         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
640 
641         if( pWriteAcc )
642         {
643             const long  nWidth = pWriteAcc->Width();
644             const long  nHeight = pWriteAcc->Height();
645 
646             if( pWriteAcc->HasPalette() )
647             {
648                 const sal_uInt16            nOldCount = 1 << GetBitCount();
649                 const BitmapPalette&    rOldPal = pReadAcc->GetPalette();
650 
651                 aPal.SetEntryCount( 1 << nBitCount );
652 
653                 for( sal_uInt16 i = 0; i < nOldCount; i++ )
654                     aPal[ i ] = rOldPal[ i ];
655 
656                 if( pExtColor )
657                     aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
658 
659                 pWriteAcc->SetPalette( aPal );
660 
661                 for( long nY = 0L; nY < nHeight; nY++ )
662                     for( long nX = 0L; nX < nWidth; nX++ )
663                         pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
664             }
665             else
666             {
667                 if( pReadAcc->HasPalette() )
668                 {
669                     for( long nY = 0L; nY < nHeight; nY++ )
670                         for( long nX = 0L; nX < nWidth; nX++ )
671                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
672                 }
673                 else
674                 {
675                     for( long nY = 0L; nY < nHeight; nY++ )
676                         for( long nX = 0L; nX < nWidth; nX++ )
677                             pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
678                 }
679             }
680 
681             aNewBmp.ReleaseAccess( pWriteAcc );
682             bRet = sal_True;
683         }
684 
685         ReleaseAccess( pReadAcc );
686 
687         if( bRet )
688         {
689             const MapMode   aMap( maPrefMapMode );
690             const Size      aSize( maPrefSize );
691 
692             *this = aNewBmp;
693 
694             maPrefMapMode = aMap;
695             maPrefSize = aSize;
696         }
697     }
698 
699     return bRet;
700 }
701 
702 // ------------------------------------------------------------------------
703 
704 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
705 {
706     DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
707 
708     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
709     sal_Bool                bRet = sal_False;
710 
711     if( pReadAcc )
712     {
713         BitmapPalette       aPal;
714         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aPal );
715         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
716 
717         if( pWriteAcc )
718         {
719             const sal_uInt16    nCount = 1 << nBitCount;
720             const long      nWidth = pWriteAcc->Width();
721             const long      nWidth1 = nWidth - 1L;
722             const long      nHeight = pWriteAcc->Height();
723             Octree          aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
724             InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
725             BitmapColor     aColor;
726             ImpErrorQuad    aErrQuad;
727             ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
728             ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
729             ImpErrorQuad*   pQLine1 = pErrQuad1;
730             ImpErrorQuad*   pQLine2 = 0;
731             long            nX, nY;
732             long            nYTmp = 0L;
733             sal_uInt8           cIndex;
734             sal_Bool            bQ1 = sal_True;
735 
736             if( pExtColor )
737             {
738                 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
739                 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
740             }
741 
742             // set Black/White always, if we have enough space
743             if( aPal.GetEntryCount() < ( nCount - 1 ) )
744             {
745                 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
746                 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
747                 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
748             }
749 
750             pWriteAcc->SetPalette( aPal );
751 
752             for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
753             {
754                 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
755                 {
756                     if( pReadAcc->HasPalette() )
757                         pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
758                     else
759                         pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
760                 }
761             }
762 
763             for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
764             {
765                 // first pixel in the line
766                 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
767                 pWriteAcc->SetPixelIndex( nY, 0, cIndex );
768 
769                 for( nX = 1L; nX < nWidth1; nX++ )
770                 {
771                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
772                     aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
773                     pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
774                     pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
775                     pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
776                     pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
777                     pWriteAcc->SetPixelIndex( nY, nX, cIndex );
778                 }
779 
780                 // letztes ZeilenPixel
781                 if( nX < nWidth )
782                 {
783                     cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
784                     pWriteAcc->SetPixelIndex( nY, nX, cIndex );
785                 }
786 
787                 // Zeilenpuffer neu fuellen/kopieren
788                 pQLine1 = pQLine2;
789                 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
790 
791                 if( nYTmp < nHeight )
792                 {
793                     for( nX = 0L; nX < nWidth; nX++ )
794                     {
795                         if( pReadAcc->HasPalette() )
796                             pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
797                         else
798                             pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
799                     }
800                 }
801             }
802 
803             // Zeilenpuffer zerstoeren
804             delete[] pErrQuad1;
805             delete[] pErrQuad2;
806 
807             aNewBmp.ReleaseAccess( pWriteAcc );
808             bRet = sal_True;
809         }
810 
811         ReleaseAccess( pReadAcc );
812 
813         if( bRet )
814         {
815             const MapMode   aMap( maPrefMapMode );
816             const Size      aSize( maPrefSize );
817 
818             *this = aNewBmp;
819 
820             maPrefMapMode = aMap;
821             maPrefSize = aSize;
822         }
823     }
824 
825     return bRet;
826 }
827 
828 // ------------------------------------------------------------------------
829 
830 sal_Bool Bitmap::ImplConvertGhosted()
831 {
832     Bitmap              aNewBmp;
833     BitmapReadAccess*   pR = AcquireReadAccess();
834     sal_Bool                bRet = sal_False;
835 
836     if( pR )
837     {
838         if( pR->HasPalette() )
839         {
840             BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
841 
842             for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
843             {
844                 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
845                 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
846                                                      ( rOld.GetGreen() >> 1 ) | 0x80,
847                                                      ( rOld.GetBlue() >> 1 ) | 0x80 );
848             }
849 
850             aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
851             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
852 
853             if( pW )
854             {
855                 pW->CopyBuffer( *pR );
856                 aNewBmp.ReleaseAccess( pW );
857                 bRet = sal_True;
858             }
859         }
860         else
861         {
862             aNewBmp = Bitmap( GetSizePixel(), 24 );
863 
864             BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
865 
866             if( pW )
867             {
868                 const long nWidth = pR->Width(), nHeight = pR->Height();
869 
870                 for( long nY = 0; nY < nHeight; nY++ )
871                 {
872                     for( long nX = 0; nX < nWidth; nX++ )
873                     {
874                         const BitmapColor aOld( pR->GetPixel( nY, nX ) );
875                         pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
876                                                            ( aOld.GetGreen() >> 1 ) | 0x80,
877                                                            ( aOld.GetBlue() >> 1 ) | 0x80 ) );
878 
879                     }
880                 }
881 
882                 aNewBmp.ReleaseAccess( pW );
883                 bRet = sal_True;
884             }
885         }
886 
887         ReleaseAccess( pR );
888     }
889 
890     if( bRet )
891     {
892         const MapMode   aMap( maPrefMapMode );
893         const Size      aSize( maPrefSize );
894 
895         *this = aNewBmp;
896 
897         maPrefMapMode = aMap;
898         maPrefSize = aSize;
899     }
900 
901     return bRet;
902 }
903 
904 // ------------------------------------------------------------------------
905 
906 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
907 {
908     sal_Bool bRet;
909 
910     if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
911     {
912         if( BMP_SCALE_FAST == nScaleFlag )
913             bRet = ImplScaleFast( rScaleX, rScaleY );
914         else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
915             bRet = ImplScaleInterpolate( rScaleX, rScaleY );
916         else
917             bRet = sal_False;
918     }
919     else
920         bRet = sal_True;
921 
922     return bRet;
923 }
924 
925 // ------------------------------------------------------------------------
926 
927 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
928 {
929     const Size  aSize( GetSizePixel() );
930     sal_Bool        bRet;
931 
932     if( aSize.Width() && aSize.Height() )
933     {
934         bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
935                       (double) rNewSize.Height() / aSize.Height(),
936                       nScaleFlag );
937     }
938     else
939         bRet = sal_True;
940 
941     return bRet;
942 }
943 
944 // ------------------------------------------------------------------------
945 
946 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
947 {
948     const Size  aSizePix( GetSizePixel() );
949     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
950     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
951     sal_Bool        bRet = sal_False;
952 
953     if( nNewWidth && nNewHeight )
954     {
955         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
956         if ( !pReadAcc )
957             return sal_False;
958 
959         Bitmap              aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
960         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
961 
962         if( pWriteAcc )
963         {
964             const long  nScanlineSize = pWriteAcc->GetScanlineSize();
965             const long  nNewWidth1 = nNewWidth - 1L;
966             const long  nNewHeight1 = nNewHeight - 1L;
967             const long  nWidth = pReadAcc->Width();
968             const long  nHeight = pReadAcc->Height();
969             long*       pLutX = new long[ nNewWidth ];
970             long*       pLutY = new long[ nNewHeight ];
971             long        nX, nY, nMapY, nActY = 0L;
972 
973             if( nNewWidth1 && nNewHeight1 )
974             {
975                 for( nX = 0L; nX < nNewWidth; nX++ )
976                     pLutX[ nX ] = nX * nWidth / nNewWidth;
977 
978                 for( nY = 0L; nY < nNewHeight; nY++ )
979                     pLutY[ nY ] = nY * nHeight / nNewHeight;
980 
981                 while( nActY < nNewHeight )
982                 {
983                     nMapY = pLutY[ nActY ];
984 
985                     for( nX = 0L; nX < nNewWidth; nX++ )
986                         pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
987 
988                     while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
989                     {
990                         memcpy( pWriteAcc->GetScanline( nActY + 1L ),
991                                  pWriteAcc->GetScanline( nActY ), nScanlineSize );
992                         nActY++;
993                     }
994 
995                     nActY++;
996                 }
997 
998                 bRet = sal_True;
999             }
1000 
1001             delete[] pLutX;
1002             delete[] pLutY;
1003         }
1004 
1005         ReleaseAccess( pReadAcc );
1006         aNewBmp.ReleaseAccess( pWriteAcc );
1007 
1008         if( bRet )
1009             ImplAssignWithSize( aNewBmp );
1010     }
1011 
1012     return bRet;
1013 }
1014 
1015 // ------------------------------------------------------------------------
1016 
1017 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1018 {
1019     const Size  aSizePix( GetSizePixel() );
1020     const long  nNewWidth = FRound( aSizePix.Width() * rScaleX );
1021     const long  nNewHeight = FRound( aSizePix.Height() * rScaleY );
1022     sal_Bool        bRet = sal_False;
1023 
1024     if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1025     {
1026         BitmapColor         aCol0;
1027         BitmapColor         aCol1;
1028         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1029         long                nWidth = pReadAcc->Width();
1030         long                nHeight = pReadAcc->Height();
1031         Bitmap              aNewBmp( Size( nNewWidth, nHeight ), 24 );
1032         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1033         long*               pLutInt;
1034         long*               pLutFrac;
1035         long                nX, nY;
1036         long                lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1037         double              fTemp;
1038         long                nTemp;
1039 
1040         if( pReadAcc && pWriteAcc )
1041         {
1042             const long      nNewWidth1 = nNewWidth - 1L;
1043             const long      nWidth1 = pReadAcc->Width() - 1L;
1044             const double    fRevScaleX = (double) nWidth1 / nNewWidth1;
1045 
1046             pLutInt = new long[ nNewWidth ];
1047             pLutFrac = new long[ nNewWidth ];
1048 
1049             for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1050             {
1051                 fTemp = nX * fRevScaleX;
1052                 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1053                 fTemp -= pLutInt[ nX ];
1054                 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1055             }
1056 
1057             if( pReadAcc->HasPalette() )
1058             {
1059                 for( nY = 0L; nY < nHeight; nY++ )
1060                 {
1061                     if( 1 == nWidth )
1062                     {
1063                         aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1064 
1065                         for( nX = 0L; nX < nNewWidth; nX++ )
1066                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1067                     }
1068                     else
1069                     {
1070                         for( nX = 0L; nX < nNewWidth; nX++ )
1071                         {
1072                             nTemp = pLutInt[ nX ];
1073 
1074                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1075                             aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1076 
1077                             nTemp = pLutFrac[ nX ];
1078 
1079                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1080                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1081                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1082 
1083                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1084                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1085                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1086 
1087                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1088                         }
1089                     }
1090                 }
1091             }
1092             else
1093             {
1094                 for( nY = 0L; nY < nHeight; nY++ )
1095                 {
1096                     if( 1 == nWidth )
1097                     {
1098                         aCol0 = pReadAcc->GetPixel( nY, 0 );
1099 
1100                         for( nX = 0L; nX < nNewWidth; nX++ )
1101                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1102                     }
1103                     else
1104                     {
1105                         for( nX = 0L; nX < nNewWidth; nX++ )
1106                         {
1107                             nTemp = pLutInt[ nX ];
1108 
1109                             aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1110                             aCol1 = pReadAcc->GetPixel( nY, nTemp );
1111 
1112                             nTemp = pLutFrac[ nX ];
1113 
1114                             lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1115                             lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1116                             lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1117 
1118                             aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1119                             aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1120                             aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1121 
1122                             pWriteAcc->SetPixel( nY, nX, aCol0 );
1123                         }
1124                     }
1125                 }
1126             }
1127 
1128             delete[] pLutInt;
1129             delete[] pLutFrac;
1130             bRet = sal_True;
1131         }
1132 
1133         ReleaseAccess( pReadAcc );
1134         aNewBmp.ReleaseAccess( pWriteAcc );
1135 
1136         if( bRet )
1137         {
1138             bRet = sal_False;
1139             ImplAssignWithSize( aNewBmp );
1140             pReadAcc = AcquireReadAccess();
1141             aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1142             pWriteAcc = aNewBmp.AcquireWriteAccess();
1143 
1144             if( pReadAcc && pWriteAcc )
1145             {
1146                 const long      nNewHeight1 = nNewHeight - 1L;
1147                 const long      nHeight1 = pReadAcc->Height() - 1L;
1148                 const double    fRevScaleY = (double) nHeight1 / nNewHeight1;
1149 
1150                 pLutInt = new long[ nNewHeight ];
1151                 pLutFrac = new long[ nNewHeight ];
1152 
1153                 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1154                 {
1155                     fTemp = nY * fRevScaleY;
1156                     pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1157                     fTemp -= pLutInt[ nY ];
1158                     pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1159                 }
1160 
1161                 if( pReadAcc->HasPalette() )
1162                 {
1163                     for( nX = 0L; nX < nNewWidth; nX++ )
1164                     {
1165                         if( 1 == nHeight )
1166                         {
1167                             aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nX ) );
1168 
1169                             for( nY = 0L; nY < nNewHeight; nY++ )
1170                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1171                         }
1172                         else
1173                         {
1174                             for( nY = 0L; nY < nNewHeight; nY++ )
1175                             {
1176                                 nTemp = pLutInt[ nY ];
1177 
1178                                 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp++, nX ) );
1179                                 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp, nX ) );
1180 
1181                                 nTemp = pLutFrac[ nY ];
1182 
1183                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1184                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1185                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1186 
1187                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1188                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1189                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1190 
1191                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1192                             }
1193                         }
1194                     }
1195                 }
1196                 else
1197                 {
1198                     for( nX = 0L; nX < nNewWidth; nX++ )
1199                     {
1200                         if( 1 == nHeight )
1201                         {
1202                             aCol0 = pReadAcc->GetPixel( 0, nX );
1203 
1204                             for( nY = 0L; nY < nNewHeight; nY++ )
1205                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1206                         }
1207                         else
1208                         {
1209                             for( nY = 0L; nY < nNewHeight; nY++ )
1210                             {
1211                                 nTemp = pLutInt[ nY ];
1212 
1213                                 aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1214                                 aCol1 = pReadAcc->GetPixel( nTemp, nX );
1215 
1216                                 nTemp = pLutFrac[ nY ];
1217 
1218                                 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1219                                 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1220                                 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1221 
1222                                 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1223                                 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1224                                 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1225 
1226                                 pWriteAcc->SetPixel( nY, nX, aCol0 );
1227                             }
1228                         }
1229                     }
1230                 }
1231 
1232                 delete[] pLutInt;
1233                 delete[] pLutFrac;
1234                 bRet = sal_True;
1235             }
1236 
1237             ReleaseAccess( pReadAcc );
1238             aNewBmp.ReleaseAccess( pWriteAcc );
1239 
1240             if( bRet )
1241                 ImplAssignWithSize( aNewBmp );
1242         }
1243     }
1244 
1245     if( !bRet )
1246         bRet = ImplScaleFast( rScaleX, rScaleY );
1247 
1248     return bRet;
1249 }
1250 
1251 // ------------------------------------------------------------------------
1252 
1253 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1254 {
1255     sal_Bool bRet = sal_False;
1256 
1257     const Size aSizePix( GetSizePixel() );
1258 
1259     if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1260         bRet = sal_True;
1261     else if( nDitherFlags & BMP_DITHER_MATRIX )
1262         bRet = ImplDitherMatrix();
1263     else if( nDitherFlags & BMP_DITHER_FLOYD )
1264         bRet = ImplDitherFloyd();
1265     else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1266         bRet = ImplDitherFloyd16();
1267 
1268     return bRet;
1269 }
1270 
1271 // ------------------------------------------------------------------------
1272 
1273 sal_Bool Bitmap::ImplDitherMatrix()
1274 {
1275     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1276     Bitmap              aNewBmp( GetSizePixel(), 8 );
1277     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1278     sal_Bool                bRet = sal_False;
1279 
1280     if( pReadAcc && pWriteAcc )
1281     {
1282         const sal_uLong nWidth = pReadAcc->Width();
1283         const sal_uLong nHeight = pReadAcc->Height();
1284         BitmapColor aIndex( (sal_uInt8) 0 );
1285 
1286         if( pReadAcc->HasPalette() )
1287         {
1288             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1289             {
1290                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1291                 {
1292                     const BitmapColor   aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
1293                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1294                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1295                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1296                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1297 
1298                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1299                     pWriteAcc->SetPixel( nY, nX, aIndex );
1300                 }
1301             }
1302         }
1303         else
1304         {
1305             for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1306             {
1307                 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1308                 {
1309                     const BitmapColor   aCol( pReadAcc->GetPixel( nY, nX ) );
1310                     const sal_uLong         nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1311                     const sal_uLong         nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1312                     const sal_uLong         nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1313                     const sal_uLong         nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1314 
1315                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1316                     pWriteAcc->SetPixel( nY, nX, aIndex );
1317                 }
1318             }
1319         }
1320 
1321         bRet = sal_True;
1322     }
1323 
1324     ReleaseAccess( pReadAcc );
1325     aNewBmp.ReleaseAccess( pWriteAcc );
1326 
1327     if( bRet )
1328     {
1329         const MapMode   aMap( maPrefMapMode );
1330         const Size      aSize( maPrefSize );
1331 
1332         *this = aNewBmp;
1333 
1334         maPrefMapMode = aMap;
1335         maPrefSize = aSize;
1336     }
1337 
1338     return bRet;
1339 }
1340 
1341 // ------------------------------------------------------------------------
1342 
1343 sal_Bool Bitmap::ImplDitherFloyd()
1344 {
1345     const Size  aSize( GetSizePixel() );
1346     sal_Bool        bRet = sal_False;
1347 
1348     if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1349     {
1350         BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1351         Bitmap              aNewBmp( GetSizePixel(), 8 );
1352         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1353 
1354         if( pReadAcc && pWriteAcc )
1355         {
1356             BitmapColor aColor;
1357             long        nWidth = pReadAcc->Width();
1358             long        nWidth1 = nWidth - 1L;
1359             long        nHeight = pReadAcc->Height();
1360             long        nX;
1361             long        nW = nWidth * 3L;
1362             long        nW2 = nW - 3L;
1363             long        nRErr, nGErr, nBErr;
1364             long        nRC, nGC, nBC;
1365             long        nTemp;
1366             long        nZ;
1367             long*       p1 = new long[ nW ];
1368             long*       p2 = new long[ nW ];
1369             long*       p1T = p1;
1370             long*       p2T = p2;
1371             long*       pTmp;
1372             sal_Bool        bPal = pReadAcc->HasPalette();
1373 
1374             pTmp = p2T;
1375 
1376             if( bPal )
1377             {
1378                 for( nZ = 0; nZ < nWidth; nZ++ )
1379                 {
1380                     aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
1381 
1382                     *pTmp++ = (long) aColor.GetBlue() << 12;
1383                     *pTmp++ = (long) aColor.GetGreen() << 12;
1384                     *pTmp++ = (long) aColor.GetRed() << 12;
1385                 }
1386             }
1387             else
1388             {
1389                 for( nZ = 0; nZ < nWidth; nZ++ )
1390                 {
1391                     aColor = pReadAcc->GetPixel( 0, nZ );
1392 
1393                     *pTmp++ = (long) aColor.GetBlue() << 12;
1394                     *pTmp++ = (long) aColor.GetGreen() << 12;
1395                     *pTmp++ = (long) aColor.GetRed() << 12;
1396                 }
1397             }
1398 
1399             for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1400             {
1401                 pTmp = p1T;
1402                 p1T = p2T;
1403                 p2T = pTmp;
1404 
1405                 if( nY < nHeight )
1406                 {
1407                     if( bPal )
1408                     {
1409                         for( nZ = 0; nZ < nWidth; nZ++ )
1410                         {
1411                             aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
1412 
1413                             *pTmp++ = (long) aColor.GetBlue() << 12;
1414                             *pTmp++ = (long) aColor.GetGreen() << 12;
1415                             *pTmp++ = (long) aColor.GetRed() << 12;
1416                         }
1417                     }
1418                     else
1419                     {
1420                         for( nZ = 0; nZ < nWidth; nZ++ )
1421                         {
1422                             aColor = pReadAcc->GetPixel( nY, nZ );
1423 
1424                             *pTmp++ = (long) aColor.GetBlue() << 12;
1425                             *pTmp++ = (long) aColor.GetGreen() << 12;
1426                             *pTmp++ = (long) aColor.GetRed() << 12;
1427                         }
1428                     }
1429                 }
1430 
1431                 // erstes Pixel gesondert betrachten
1432                 nX = 0;
1433                 CALC_ERRORS;
1434                 CALC_TABLES7;
1435                 nX -= 5;
1436                 CALC_TABLES5;
1437                 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1438 
1439                 // mittlere Pixel ueber Schleife
1440                 long nXAcc;
1441                 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1442                 {
1443                     CALC_ERRORS;
1444                     CALC_TABLES7;
1445                     nX -= 8;
1446                     CALC_TABLES3;
1447                     CALC_TABLES5;
1448                     pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1449                 }
1450 
1451                 // letztes Pixel gesondert betrachten
1452                 CALC_ERRORS;
1453                 nX -= 5;
1454                 CALC_TABLES3;
1455                 CALC_TABLES5;
1456                 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1457             }
1458 
1459             delete[] p1;
1460             delete[] p2;
1461             bRet = sal_True;
1462         }
1463 
1464         ReleaseAccess( pReadAcc );
1465         aNewBmp.ReleaseAccess( pWriteAcc );
1466 
1467         if( bRet )
1468         {
1469             const MapMode   aMap( maPrefMapMode );
1470             const Size      aPrefSize( maPrefSize );
1471 
1472             *this = aNewBmp;
1473 
1474             maPrefMapMode = aMap;
1475             maPrefSize = aPrefSize;
1476         }
1477     }
1478 
1479     return bRet;
1480 }
1481 
1482 // ------------------------------------------------------------------------
1483 
1484 sal_Bool Bitmap::ImplDitherFloyd16()
1485 {
1486     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
1487     Bitmap              aNewBmp( GetSizePixel(), 24 );
1488     BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
1489     sal_Bool                bRet = sal_False;
1490 
1491     if( pReadAcc && pWriteAcc )
1492     {
1493         const long      nWidth = pWriteAcc->Width();
1494         const long      nWidth1 = nWidth - 1L;
1495         const long      nHeight = pWriteAcc->Height();
1496         BitmapColor     aColor;
1497         BitmapColor     aBestCol;
1498         ImpErrorQuad    aErrQuad;
1499         ImpErrorQuad*   pErrQuad1 = new ImpErrorQuad[ nWidth ];
1500         ImpErrorQuad*   pErrQuad2 = new ImpErrorQuad[ nWidth ];
1501         ImpErrorQuad*   pQLine1 = pErrQuad1;
1502         ImpErrorQuad*   pQLine2 = 0;
1503         long            nX, nY;
1504         long            nYTmp = 0L;
1505         sal_Bool            bQ1 = sal_True;
1506 
1507         for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1508             for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1509                 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1510 
1511         for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1512         {
1513             // erstes ZeilenPixel
1514             aBestCol = pQLine1[ 0 ].ImplGetColor();
1515             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1516             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1517             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1518             pWriteAcc->SetPixel( nY, 0, aBestCol );
1519 
1520             for( nX = 1L; nX < nWidth1; nX++ )
1521             {
1522                 aColor = pQLine1[ nX ].ImplGetColor();
1523                 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1524                 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1525                 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1526                 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1527                 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1528                 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1529                 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1530                 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1531                 pWriteAcc->SetPixel( nY, nX, aBestCol );
1532             }
1533 
1534             // letztes ZeilenPixel
1535             aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1536             aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1537             aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1538             aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1539             pWriteAcc->SetPixel( nY, nX, aBestCol );
1540 
1541             // Zeilenpuffer neu fuellen/kopieren
1542             pQLine1 = pQLine2;
1543             pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1544 
1545             if( nYTmp < nHeight )
1546                 for( nX = 0L; nX < nWidth; nX++ )
1547                     pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1548         }
1549 
1550         // Zeilenpuffer zerstoeren
1551         delete[] pErrQuad1;
1552         delete[] pErrQuad2;
1553         bRet = sal_True;
1554     }
1555 
1556     ReleaseAccess( pReadAcc );
1557     aNewBmp.ReleaseAccess( pWriteAcc );
1558 
1559     if( bRet )
1560     {
1561         const MapMode   aMap( maPrefMapMode );
1562         const Size      aSize( maPrefSize );
1563 
1564         *this = aNewBmp;
1565 
1566         maPrefMapMode = aMap;
1567         maPrefSize = aSize;
1568     }
1569 
1570     return bRet;
1571 }
1572 
1573 // ------------------------------------------------------------------------
1574 
1575 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1576 {
1577     sal_Bool bRet;
1578 
1579     if( GetColorCount() <= (sal_uLong) nColorCount )
1580         bRet = sal_True;
1581     else if( nColorCount )
1582     {
1583         if( BMP_REDUCE_SIMPLE == eReduce )
1584             bRet = ImplReduceSimple( nColorCount );
1585         else if( BMP_REDUCE_POPULAR == eReduce )
1586             bRet = ImplReducePopular( nColorCount );
1587         else
1588             bRet = ImplReduceMedian( nColorCount );
1589     }
1590     else
1591         bRet = sal_False;
1592 
1593     return bRet;
1594 }
1595 
1596 // ------------------------------------------------------------------------
1597 
1598 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1599 {
1600     Bitmap              aNewBmp;
1601     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1602     const sal_uInt16        nColCount = Min( nColorCount, (sal_uInt16) 256 );
1603     sal_uInt16              nBitCount;
1604     sal_Bool                bRet = sal_False;
1605 
1606     if( nColCount <= 2 )
1607         nBitCount = 1;
1608     else if( nColCount <= 16 )
1609         nBitCount = 4;
1610     else
1611         nBitCount = 8;
1612 
1613     if( pRAcc )
1614     {
1615         Octree                  aOct( *pRAcc, nColCount );
1616         const BitmapPalette&    rPal = aOct.GetPalette();
1617         BitmapWriteAccess*      pWAcc;
1618 
1619         aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1620         pWAcc = aNewBmp.AcquireWriteAccess();
1621 
1622         if( pWAcc )
1623         {
1624             const long nWidth = pRAcc->Width();
1625             const long nHeight = pRAcc->Height();
1626 
1627             if( pRAcc->HasPalette() )
1628             {
1629                 for( long nY = 0L; nY < nHeight; nY++ )
1630                     for( long nX =0L; nX < nWidth; nX++ )
1631                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
1632             }
1633             else
1634             {
1635                 for( long nY = 0L; nY < nHeight; nY++ )
1636                     for( long nX =0L; nX < nWidth; nX++ )
1637                         pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
1638             }
1639 
1640             aNewBmp.ReleaseAccess( pWAcc );
1641             bRet = sal_True;
1642         }
1643 
1644         ReleaseAccess( pRAcc );
1645     }
1646 
1647     if( bRet )
1648     {
1649         const MapMode   aMap( maPrefMapMode );
1650         const Size      aSize( maPrefSize );
1651 
1652         *this = aNewBmp;
1653         maPrefMapMode = aMap;
1654         maPrefSize = aSize;
1655     }
1656 
1657     return bRet;
1658 }
1659 
1660 // ------------------------------------------------------------------------
1661 
1662 struct PopularColorCount
1663 {
1664     sal_uInt32  mnIndex;
1665     sal_uInt32  mnCount;
1666 };
1667 
1668 // ------------------------------------------------------------------------
1669 
1670 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1671 {
1672     int nRet;
1673 
1674     if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1675         nRet = 1;
1676     else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1677         nRet = 0;
1678     else
1679         nRet = -1;
1680 
1681     return nRet;
1682 }
1683 
1684 // ------------------------------------------------------------------------
1685 
1686 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1687 {
1688     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1689     sal_uInt16              nBitCount;
1690     sal_Bool                bRet = sal_False;
1691 
1692     if( nColCount > 256 )
1693         nColCount = 256;
1694 
1695     if( nColCount < 17 )
1696         nBitCount = 4;
1697     else
1698         nBitCount = 8;
1699 
1700     if( pRAcc )
1701     {
1702         const sal_uInt32    nValidBits = 4;
1703         const sal_uInt32    nRightShiftBits = 8 - nValidBits;
1704         const sal_uInt32    nLeftShiftBits1 = nValidBits;
1705         const sal_uInt32    nLeftShiftBits2 = nValidBits << 1;
1706         const sal_uInt32    nColorsPerComponent = 1 << nValidBits;
1707         const sal_uInt32    nColorOffset = 256 / nColorsPerComponent;
1708         const sal_uInt32    nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1709         const long          nWidth = pRAcc->Width();
1710         const long          nHeight = pRAcc->Height();
1711         PopularColorCount*  pCountTable = new PopularColorCount[ nTotalColors ];
1712         long                nX, nY, nR, nG, nB, nIndex;
1713 
1714         rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1715 
1716         for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1717         {
1718             for( nG = 0; nG < 256; nG += nColorOffset )
1719             {
1720                 for( nB = 0; nB < 256; nB += nColorOffset )
1721                 {
1722                     pCountTable[ nIndex ].mnIndex = nIndex;
1723                     nIndex++;
1724                 }
1725             }
1726         }
1727 
1728         if( pRAcc->HasPalette() )
1729         {
1730             for( nY = 0L; nY < nHeight; nY++ )
1731             {
1732                 for( nX = 0L; nX < nWidth; nX++ )
1733                 {
1734                     const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1735                     pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1736                                  ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1737                                  ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1738                 }
1739             }
1740         }
1741         else
1742         {
1743             for( nY = 0L; nY < nHeight; nY++ )
1744             {
1745                 for( nX = 0L; nX < nWidth; nX++ )
1746                 {
1747                     const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1748                     pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1749                                  ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1750                                  ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1751                 }
1752             }
1753         }
1754 
1755         BitmapPalette aNewPal( nColCount );
1756 
1757         qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1758 
1759         for( sal_uInt16 n = 0; n < nColCount; n++ )
1760         {
1761             const PopularColorCount& rPop = pCountTable[ n ];
1762             aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1763                                         (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1764                                         (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1765         }
1766 
1767         Bitmap              aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1768         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1769 
1770         if( pWAcc )
1771         {
1772             BitmapColor aDstCol( (sal_uInt8) 0 );
1773             sal_uInt8*      pIndexMap = new sal_uInt8[ nTotalColors ];
1774 
1775             for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1776                 for( nG = 0; nG < 256; nG += nColorOffset )
1777                     for( nB = 0; nB < 256; nB += nColorOffset )
1778                         pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1779 
1780             if( pRAcc->HasPalette() )
1781             {
1782                 for( nY = 0L; nY < nHeight; nY++ )
1783                 {
1784                     for( nX = 0L; nX < nWidth; nX++ )
1785                     {
1786                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1787                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1788                                                      ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1789                                                      ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1790                         pWAcc->SetPixel( nY, nX, aDstCol );
1791                     }
1792                 }
1793             }
1794             else
1795             {
1796                 for( nY = 0L; nY < nHeight; nY++ )
1797                 {
1798                     for( nX = 0L; nX < nWidth; nX++ )
1799                     {
1800                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1801                         aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1802                                                      ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1803                                                      ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1804                         pWAcc->SetPixel( nY, nX, aDstCol );
1805                     }
1806                 }
1807             }
1808 
1809             delete[] pIndexMap;
1810             aNewBmp.ReleaseAccess( pWAcc );
1811             bRet = sal_True;
1812         }
1813 
1814         delete[] pCountTable;
1815         ReleaseAccess( pRAcc );
1816 
1817         if( bRet )
1818         {
1819             const MapMode   aMap( maPrefMapMode );
1820             const Size      aSize( maPrefSize );
1821 
1822             *this = aNewBmp;
1823             maPrefMapMode = aMap;
1824             maPrefSize = aSize;
1825         }
1826     }
1827 
1828     return bRet;
1829 }
1830 
1831 // ------------------------------------------------------------------------
1832 
1833 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1834 {
1835     BitmapReadAccess*   pRAcc = AcquireReadAccess();
1836     sal_uInt16              nBitCount;
1837     sal_Bool                bRet = sal_False;
1838 
1839     if( nColCount < 17 )
1840         nBitCount = 4;
1841     else if( nColCount < 257 )
1842         nBitCount = 8;
1843     else
1844     {
1845         DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1846         nBitCount = 8;
1847         nColCount = 256;
1848     }
1849 
1850     if( pRAcc )
1851     {
1852         Bitmap              aNewBmp( GetSizePixel(), nBitCount );
1853         BitmapWriteAccess*  pWAcc = aNewBmp.AcquireWriteAccess();
1854 
1855         if( pWAcc )
1856         {
1857             const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
1858             sal_uLong*      pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1859             const long  nWidth = pWAcc->Width();
1860             const long  nHeight = pWAcc->Height();
1861             long        nIndex = 0L;
1862 
1863             memset( (HPBYTE) pColBuf, 0, nSize );
1864 
1865             // create Buffer
1866             if( pRAcc->HasPalette() )
1867             {
1868                 for( long nY = 0L; nY < nHeight; nY++ )
1869                 {
1870                     for( long nX = 0L; nX < nWidth; nX++ )
1871                     {
1872                         const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1873                         pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1874                     }
1875                 }
1876             }
1877             else
1878             {
1879                 for( long nY = 0L; nY < nHeight; nY++ )
1880                 {
1881                     for( long nX = 0L; nX < nWidth; nX++ )
1882                     {
1883                         const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1884                         pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1885                     }
1886                 }
1887             }
1888 
1889             // create palette via median cut
1890             BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1891             ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1892                            nColCount, nWidth * nHeight, nIndex );
1893 
1894             // do mapping of colors to palette
1895             InverseColorMap aMap( aPal );
1896             pWAcc->SetPalette( aPal );
1897             for( long nY = 0L; nY < nHeight; nY++ )
1898                 for( long nX = 0L; nX < nWidth; nX++ )
1899                     pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
1900 
1901             rtl_freeMemory( pColBuf );
1902             aNewBmp.ReleaseAccess( pWAcc );
1903             bRet = sal_True;
1904         }
1905 
1906         ReleaseAccess( pRAcc );
1907 
1908         if( bRet )
1909         {
1910             const MapMode   aMap( maPrefMapMode );
1911             const Size      aSize( maPrefSize );
1912 
1913             *this = aNewBmp;
1914             maPrefMapMode = aMap;
1915             maPrefSize = aSize;
1916         }
1917     }
1918 
1919     return bRet;
1920 }
1921 
1922 // ------------------------------------------------------------------------
1923 
1924 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1925                             long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1926                             long nColors, long nPixels, long& rIndex )
1927 {
1928     if( !nPixels )
1929         return;
1930 
1931     BitmapColor aCol;
1932     const long  nRLen = nR2 - nR1;
1933     const long  nGLen = nG2 - nG1;
1934     const long  nBLen = nB2 - nB1;
1935     long        nR, nG, nB;
1936     sal_uLong*      pBuf = pColBuf;
1937 
1938     if( !nRLen && !nGLen && !nBLen )
1939     {
1940         if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1941         {
1942             aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1943             aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1944             aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1945             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1946         }
1947     }
1948     else
1949     {
1950         if( 1 == nColors || 1 == nPixels )
1951         {
1952             long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1953 
1954             for( nR = nR1; nR <= nR2; nR++ )
1955             {
1956                 for( nG = nG1; nG <= nG2; nG++ )
1957                 {
1958                     for( nB = nB1; nB <= nB2; nB++ )
1959                     {
1960                         nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1961 
1962                         if( nPixSum )
1963                         {
1964                             nRSum += nR * nPixSum;
1965                             nGSum += nG * nPixSum;
1966                             nBSum += nB * nPixSum;
1967                         }
1968                     }
1969                 }
1970             }
1971 
1972             aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1973             aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1974             aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1975             rPal[ (sal_uInt16) rIndex++ ] = aCol;
1976         }
1977         else
1978         {
1979             const long  nTest = ( nPixels >> 1 );
1980             long        nPixOld = 0;
1981             long        nPixNew = 0;
1982 
1983             if( nBLen > nGLen && nBLen > nRLen )
1984             {
1985                 nB = nB1 - 1;
1986 
1987                 while( nPixNew < nTest )
1988                 {
1989                     nB++, nPixOld = nPixNew;
1990                     for( nR = nR1; nR <= nR2; nR++ )
1991                         for( nG = nG1; nG <= nG2; nG++ )
1992                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1993                 }
1994 
1995                 if( nB < nB2 )
1996                 {
1997                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1998                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1999                 }
2000                 else
2001                 {
2002                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2003                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2004                 }
2005             }
2006             else if( nGLen > nRLen )
2007             {
2008                 nG = nG1 - 1;
2009 
2010                 while( nPixNew < nTest )
2011                 {
2012                     nG++, nPixOld = nPixNew;
2013                     for( nR = nR1; nR <= nR2; nR++ )
2014                         for( nB = nB1; nB <= nB2; nB++ )
2015                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2016                 }
2017 
2018                 if( nG < nG2 )
2019                 {
2020                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2021                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2022                 }
2023                 else
2024                 {
2025                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2026                     ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2027                 }
2028             }
2029             else
2030             {
2031                 nR = nR1 - 1;
2032 
2033                 while( nPixNew < nTest )
2034                 {
2035                     nR++, nPixOld = nPixNew;
2036                     for( nG = nG1; nG <= nG2; nG++ )
2037                         for( nB = nB1; nB <= nB2; nB++ )
2038                             nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2039                 }
2040 
2041                 if( nR < nR2 )
2042                 {
2043                     ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2044                     ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2045                 }
2046                 else
2047                 {
2048                     ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2049                     ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2050                 }
2051             }
2052         }
2053     }
2054 }
2055 
2056 // ------------------------------------------------------------------------
2057 
2058 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2059 {
2060     return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2061 }
2062 
2063 // ------------------------------------------------------------------------
2064 
2065 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2066 {
2067     return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2068 }
2069 
2070 // ------------------------------------------------------------------------
2071 
2072 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2073                      short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2074                      double fGamma, sal_Bool bInvert )
2075 {
2076     sal_Bool bRet = sal_False;
2077 
2078     // nothing to do => return quickly
2079     if( !nLuminancePercent && !nContrastPercent &&
2080         !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2081         ( fGamma == 1.0 ) && !bInvert )
2082     {
2083         bRet = sal_True;
2084     }
2085     else
2086     {
2087         BitmapWriteAccess* pAcc = AcquireWriteAccess();
2088 
2089         if( pAcc )
2090         {
2091             BitmapColor     aCol;
2092             const long      nW = pAcc->Width();
2093             const long      nH = pAcc->Height();
2094             sal_uInt8*          cMapR = new sal_uInt8[ 256 ];
2095             sal_uInt8*          cMapG = new sal_uInt8[ 256 ];
2096             sal_uInt8*          cMapB = new sal_uInt8[ 256 ];
2097             long            nX, nY;
2098             double          fM, fROff, fGOff, fBOff, fOff;
2099 
2100             // calculate slope
2101             if( nContrastPercent >= 0 )
2102                 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2103             else
2104                 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2105 
2106             // total offset = luminance offset + contrast offset
2107             fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2108 
2109             // channel offset = channel offset  + total offset
2110             fROff = nChannelRPercent * 2.55 + fOff;
2111             fGOff = nChannelGPercent * 2.55 + fOff;
2112             fBOff = nChannelBPercent * 2.55 + fOff;
2113 
2114             // calculate gamma value
2115             fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2116             const sal_Bool bGamma = ( fGamma != 1.0 );
2117 
2118             // create mapping table
2119             for( nX = 0L; nX < 256L; nX++ )
2120             {
2121                 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2122                 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2123                 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2124 
2125                 if( bGamma )
2126                 {
2127                     cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2128                     cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2129                     cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2130                 }
2131 
2132                 if( bInvert )
2133                 {
2134                     cMapR[ nX ] = ~cMapR[ nX ];
2135                     cMapG[ nX ] = ~cMapG[ nX ];
2136                     cMapB[ nX ] = ~cMapB[ nX ];
2137                 }
2138             }
2139 
2140             // do modifying
2141             if( pAcc->HasPalette() )
2142             {
2143                 BitmapColor aNewCol;
2144 
2145                 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2146                 {
2147                     const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2148                     aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2149                     aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2150                     aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2151                     pAcc->SetPaletteColor( i, aNewCol );
2152                 }
2153             }
2154             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2155             {
2156                 for( nY = 0L; nY < nH; nY++ )
2157                 {
2158                     Scanline pScan = pAcc->GetScanline( nY );
2159 
2160                     for( nX = 0L; nX < nW; nX++ )
2161                     {
2162                         *pScan = cMapB[ *pScan ]; pScan++;
2163                         *pScan = cMapG[ *pScan ]; pScan++;
2164                         *pScan = cMapR[ *pScan ]; pScan++;
2165                     }
2166                 }
2167             }
2168             else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2169             {
2170                 for( nY = 0L; nY < nH; nY++ )
2171                 {
2172                     Scanline pScan = pAcc->GetScanline( nY );
2173 
2174                     for( nX = 0L; nX < nW; nX++ )
2175                     {
2176                         *pScan = cMapR[ *pScan ]; pScan++;
2177                         *pScan = cMapG[ *pScan ]; pScan++;
2178                         *pScan = cMapB[ *pScan ]; pScan++;
2179                     }
2180                 }
2181             }
2182             else
2183             {
2184                 for( nY = 0L; nY < nH; nY++ )
2185                 {
2186                     for( nX = 0L; nX < nW; nX++ )
2187                     {
2188                         aCol = pAcc->GetPixel( nY, nX );
2189                         aCol.SetRed( cMapR[ aCol.GetRed() ] );
2190                         aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2191                         aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2192                         pAcc->SetPixel( nY, nX, aCol );
2193                     }
2194                 }
2195             }
2196 
2197             delete[] cMapR;
2198             delete[] cMapG;
2199             delete[] cMapB;
2200             ReleaseAccess( pAcc );
2201             bRet = sal_True;
2202         }
2203     }
2204 
2205     return bRet;
2206 }
2207