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