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