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