xref: /AOO41X/main/vcl/source/gdi/bitmap3.cxx (revision cfe4bce3c74d6e28971985f9c7d930b1f6adbdcd)
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         Bitmap aSource(*this);
2485 
2486         if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2487         {
2488             if(bScaleHor)
2489             {
2490                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2491             }
2492 
2493             if(bResult && bScaleVer)
2494             {
2495                 if(bScaleHor)
2496                 {
2497                     // copy partial result, independent of color depth
2498                     aSource = aResult;
2499                 }
2500 
2501                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2502             }
2503         }
2504         else
2505         {
2506             if(bScaleVer)
2507             {
2508                 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2509             }
2510 
2511             if(bResult && bScaleHor)
2512             {
2513                 if(bScaleVer)
2514                 {
2515                     // copy partial result, independent of color depth
2516                     aSource = aResult;
2517                 }
2518 
2519                 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2520             }
2521         }
2522     }
2523 
2524     if(bResult && bMirrorAfter)
2525     {
2526         bResult = aResult.Mirror(nMirrorFlags);
2527     }
2528 
2529     if(bResult)
2530     {
2531         ImplAdaptBitCount(aResult);
2532         *this = aResult;
2533     }
2534 
2535     return bResult;
2536 }
2537 
2538 // ------------------------------------------------------------------------
2539 
2540 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2541 {
2542 	sal_Bool bRet = sal_False;
2543 
2544 	const Size aSizePix( GetSizePixel() );
2545 
2546 	if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2547 		bRet = sal_True;
2548 	else if( nDitherFlags & BMP_DITHER_MATRIX )
2549 		bRet = ImplDitherMatrix();
2550 	else if( nDitherFlags & BMP_DITHER_FLOYD )
2551 		bRet = ImplDitherFloyd();
2552 	else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2553 		bRet = ImplDitherFloyd16();
2554 
2555 	return bRet;
2556 }
2557 
2558 // ------------------------------------------------------------------------
2559 
2560 sal_Bool Bitmap::ImplDitherMatrix()
2561 {
2562 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
2563 	Bitmap				aNewBmp( GetSizePixel(), 8 );
2564 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
2565 	sal_Bool				bRet = sal_False;
2566 
2567 	if( pReadAcc && pWriteAcc )
2568 	{
2569 		const sal_uLong	nWidth = pReadAcc->Width();
2570 		const sal_uLong	nHeight = pReadAcc->Height();
2571 		BitmapColor	aIndex( (sal_uInt8) 0 );
2572 
2573 		if( pReadAcc->HasPalette() )
2574 		{
2575 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2576 			{
2577 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2578 				{
2579 					const BitmapColor	aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2580 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2581 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2582 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2583 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2584 
2585 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2586 					pWriteAcc->SetPixel( nY, nX, aIndex );
2587 				}
2588 			}
2589 		}
2590 		else
2591 		{
2592 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2593 			{
2594 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2595 				{
2596 					const BitmapColor	aCol( pReadAcc->GetPixel( nY, nX ) );
2597 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2598 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2599 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2600 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2601 
2602 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2603 					pWriteAcc->SetPixel( nY, nX, aIndex );
2604 				}
2605 			}
2606 		}
2607 
2608 		bRet = sal_True;
2609 	}
2610 
2611 	ReleaseAccess( pReadAcc );
2612 	aNewBmp.ReleaseAccess( pWriteAcc );
2613 
2614 	if( bRet )
2615 	{
2616 		const MapMode	aMap( maPrefMapMode );
2617 		const Size		aSize( maPrefSize );
2618 
2619 		*this = aNewBmp;
2620 
2621 		maPrefMapMode = aMap;
2622 		maPrefSize = aSize;
2623 	}
2624 
2625 	return bRet;
2626 }
2627 
2628 // ------------------------------------------------------------------------
2629 
2630 sal_Bool Bitmap::ImplDitherFloyd()
2631 {
2632 	const Size	aSize( GetSizePixel() );
2633 	sal_Bool		bRet = sal_False;
2634 
2635 	if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2636 	{
2637 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
2638 		Bitmap				aNewBmp( GetSizePixel(), 8 );
2639 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
2640 
2641 		if( pReadAcc && pWriteAcc )
2642 		{
2643 			BitmapColor	aColor;
2644 			long		nWidth = pReadAcc->Width();
2645 			long		nWidth1 = nWidth - 1L;
2646 			long		nHeight = pReadAcc->Height();
2647 			long		nX;
2648 			long		nW = nWidth * 3L;
2649 			long		nW2 = nW - 3L;
2650 			long		nRErr, nGErr, nBErr;
2651 			long		nRC, nGC, nBC;
2652 			long		nTemp;
2653 			long		nZ;
2654 			long*		p1 = new long[ nW ];
2655 			long*		p2 = new long[ nW ];
2656 			long*		p1T = p1;
2657 			long*		p2T = p2;
2658 			long*		pTmp;
2659 			sal_Bool		bPal = pReadAcc->HasPalette();
2660 
2661 			pTmp = p2T;
2662 
2663 			if( bPal )
2664 			{
2665 				for( nZ = 0; nZ < nWidth; nZ++ )
2666 				{
2667 					aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2668 
2669 					*pTmp++ = (long) aColor.GetBlue() << 12;
2670 					*pTmp++ = (long) aColor.GetGreen() << 12;
2671 					*pTmp++ = (long) aColor.GetRed() << 12;
2672 				}
2673 			}
2674 			else
2675 			{
2676 				for( nZ = 0; nZ < nWidth; nZ++ )
2677 				{
2678 					aColor = pReadAcc->GetPixel( 0, nZ );
2679 
2680 					*pTmp++ = (long) aColor.GetBlue() << 12;
2681 					*pTmp++ = (long) aColor.GetGreen() << 12;
2682 					*pTmp++ = (long) aColor.GetRed() << 12;
2683 				}
2684 			}
2685 
2686 			for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2687 			{
2688 				pTmp = p1T;
2689 				p1T = p2T;
2690 				p2T = pTmp;
2691 
2692 				if( nY < nHeight )
2693 				{
2694 					if( bPal )
2695 					{
2696 						for( nZ = 0; nZ < nWidth; nZ++ )
2697 						{
2698 							aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2699 
2700 							*pTmp++ = (long) aColor.GetBlue() << 12;
2701 							*pTmp++ = (long) aColor.GetGreen() << 12;
2702 							*pTmp++ = (long) aColor.GetRed() << 12;
2703 						}
2704 					}
2705 					else
2706 					{
2707 						for( nZ = 0; nZ < nWidth; nZ++ )
2708 						{
2709 							aColor = pReadAcc->GetPixel( nY, nZ );
2710 
2711 							*pTmp++ = (long) aColor.GetBlue() << 12;
2712 							*pTmp++ = (long) aColor.GetGreen() << 12;
2713 							*pTmp++ = (long) aColor.GetRed() << 12;
2714 						}
2715 					}
2716 				}
2717 
2718 				// erstes Pixel gesondert betrachten
2719 				nX = 0;
2720 				CALC_ERRORS;
2721 				CALC_TABLES7;
2722 				nX -= 5;
2723 				CALC_TABLES5;
2724 				pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2725 
2726 				// mittlere Pixel ueber Schleife
2727 				long nXAcc;
2728 				for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2729 				{
2730 					CALC_ERRORS;
2731 					CALC_TABLES7;
2732 					nX -= 8;
2733 					CALC_TABLES3;
2734 					CALC_TABLES5;
2735 					pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2736 				}
2737 
2738 				// letztes Pixel gesondert betrachten
2739 				CALC_ERRORS;
2740 				nX -= 5;
2741 				CALC_TABLES3;
2742 				CALC_TABLES5;
2743 				pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2744 			}
2745 
2746 			delete[] p1;
2747 			delete[] p2;
2748 			bRet = sal_True;
2749 		}
2750 
2751 		ReleaseAccess( pReadAcc );
2752 		aNewBmp.ReleaseAccess( pWriteAcc );
2753 
2754 		if( bRet )
2755 		{
2756 			const MapMode	aMap( maPrefMapMode );
2757 			const Size		aPrefSize( maPrefSize );
2758 
2759 			*this = aNewBmp;
2760 
2761 			maPrefMapMode = aMap;
2762 			maPrefSize = aPrefSize;
2763 		}
2764 	}
2765 
2766 	return bRet;
2767 }
2768 
2769 // ------------------------------------------------------------------------
2770 
2771 sal_Bool Bitmap::ImplDitherFloyd16()
2772 {
2773 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
2774 	Bitmap				aNewBmp( GetSizePixel(), 24 );
2775 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
2776 	sal_Bool				bRet = sal_False;
2777 
2778 	if( pReadAcc && pWriteAcc )
2779 	{
2780 		const long		nWidth = pWriteAcc->Width();
2781 		const long		nWidth1 = nWidth - 1L;
2782 		const long		nHeight = pWriteAcc->Height();
2783 		BitmapColor 	aColor;
2784 		BitmapColor		aBestCol;
2785 		ImpErrorQuad	aErrQuad;
2786 		ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
2787 		ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
2788 		ImpErrorQuad*	pQLine1 = pErrQuad1;
2789 		ImpErrorQuad*	pQLine2 = 0;
2790 		long			nX, nY;
2791 		long			nYTmp = 0L;
2792 		sal_Bool			bQ1 = sal_True;
2793 
2794 		for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2795 			for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2796 				pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2797 
2798 		for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2799 		{
2800 			// erstes ZeilenPixel
2801 			aBestCol = pQLine1[ 0 ].ImplGetColor();
2802 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2803 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2804 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2805 			pWriteAcc->SetPixel( nY, 0, aBestCol );
2806 
2807 			for( nX = 1L; nX < nWidth1; nX++ )
2808 			{
2809 				aColor = pQLine1[ nX ].ImplGetColor();
2810 				aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2811 				aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2812 				aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2813 				aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2814 				pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2815 				pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2816 				pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2817 				pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2818 				pWriteAcc->SetPixel( nY, nX, aBestCol );
2819 			}
2820 
2821 			// letztes ZeilenPixel
2822 			aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2823 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2824 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2825 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2826 			pWriteAcc->SetPixel( nY, nX, aBestCol );
2827 
2828 			// Zeilenpuffer neu fuellen/kopieren
2829 			pQLine1 = pQLine2;
2830 			pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2831 
2832 			if( nYTmp < nHeight )
2833 				for( nX = 0L; nX < nWidth; nX++ )
2834 					pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2835 		}
2836 
2837 		// Zeilenpuffer zerstoeren
2838 		delete[] pErrQuad1;
2839 		delete[] pErrQuad2;
2840 		bRet = sal_True;
2841 	}
2842 
2843 	ReleaseAccess( pReadAcc );
2844 	aNewBmp.ReleaseAccess( pWriteAcc );
2845 
2846 	if( bRet )
2847 	{
2848 		const MapMode	aMap( maPrefMapMode );
2849 		const Size		aSize( maPrefSize );
2850 
2851 		*this = aNewBmp;
2852 
2853 		maPrefMapMode = aMap;
2854 		maPrefSize = aSize;
2855 	}
2856 
2857 	return bRet;
2858 }
2859 
2860 // ------------------------------------------------------------------------
2861 
2862 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2863 {
2864 	sal_Bool bRet;
2865 
2866 	if( GetColorCount() <= (sal_uLong) nColorCount )
2867 		bRet = sal_True;
2868 	else if( nColorCount )
2869 	{
2870 		if( BMP_REDUCE_SIMPLE == eReduce )
2871 			bRet = ImplReduceSimple( nColorCount );
2872 		else if( BMP_REDUCE_POPULAR == eReduce )
2873 			bRet = ImplReducePopular( nColorCount );
2874 		else
2875 			bRet = ImplReduceMedian( nColorCount );
2876 	}
2877 	else
2878 		bRet = sal_False;
2879 
2880 	return bRet;
2881 }
2882 
2883 // ------------------------------------------------------------------------
2884 
2885 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2886 {
2887 	Bitmap				aNewBmp;
2888 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
2889 	const sal_uInt16		nColCount = Min( nColorCount, (sal_uInt16) 256 );
2890 	sal_uInt16				nBitCount;
2891 	sal_Bool				bRet = sal_False;
2892 
2893 	if( nColCount <= 2 )
2894 		nBitCount = 1;
2895 	else if( nColCount <= 16 )
2896 		nBitCount = 4;
2897 	else
2898 		nBitCount = 8;
2899 
2900 	if( pRAcc )
2901 	{
2902 		Octree					aOct( *pRAcc, nColCount );
2903 		const BitmapPalette&	rPal = aOct.GetPalette();
2904 		BitmapWriteAccess*		pWAcc;
2905 
2906 		aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2907 		pWAcc = aNewBmp.AcquireWriteAccess();
2908 
2909 		if( pWAcc )
2910 		{
2911 			const long nWidth = pRAcc->Width();
2912 			const long nHeight = pRAcc->Height();
2913 
2914 			if( pRAcc->HasPalette() )
2915 			{
2916 				for( long nY = 0L; nY < nHeight; nY++ )
2917 					for( long nX =0L; nX < nWidth; nX++ )
2918 						pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2919 			}
2920 			else
2921 			{
2922 				for( long nY = 0L; nY < nHeight; nY++ )
2923 					for( long nX =0L; nX < nWidth; nX++ )
2924 						pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2925 			}
2926 
2927 			aNewBmp.ReleaseAccess( pWAcc );
2928 			bRet = sal_True;
2929 		}
2930 
2931 		ReleaseAccess( pRAcc );
2932 	}
2933 
2934 	if( bRet )
2935 	{
2936 		const MapMode	aMap( maPrefMapMode );
2937 		const Size		aSize( maPrefSize );
2938 
2939 		*this = aNewBmp;
2940 		maPrefMapMode = aMap;
2941 		maPrefSize = aSize;
2942 	}
2943 
2944 	return bRet;
2945 }
2946 
2947 // ------------------------------------------------------------------------
2948 
2949 struct PopularColorCount
2950 {
2951 	sal_uInt32	mnIndex;
2952 	sal_uInt32	mnCount;
2953 };
2954 
2955 // ------------------------------------------------------------------------
2956 
2957 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2958 {
2959 	int nRet;
2960 
2961 	if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2962 		nRet = 1;
2963 	else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2964 		nRet = 0;
2965 	else
2966 		nRet = -1;
2967 
2968 	return nRet;
2969 }
2970 
2971 // ------------------------------------------------------------------------
2972 
2973 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2974 {
2975 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
2976 	sal_uInt16				nBitCount;
2977 	sal_Bool				bRet = sal_False;
2978 
2979 	if( nColCount > 256 )
2980 		nColCount = 256;
2981 
2982 	if( nColCount < 17 )
2983 		nBitCount = 4;
2984 	else
2985 		nBitCount = 8;
2986 
2987 	if( pRAcc )
2988 	{
2989 		const sal_uInt32	nValidBits = 4;
2990 		const sal_uInt32	nRightShiftBits = 8 - nValidBits;
2991 		const sal_uInt32	nLeftShiftBits1 = nValidBits;
2992 		const sal_uInt32	nLeftShiftBits2 = nValidBits << 1;
2993 		const sal_uInt32	nColorsPerComponent = 1 << nValidBits;
2994 		const sal_uInt32	nColorOffset = 256 / nColorsPerComponent;
2995 		const sal_uInt32	nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2996 		const long			nWidth = pRAcc->Width();
2997 		const long			nHeight = pRAcc->Height();
2998 		PopularColorCount*	pCountTable = new PopularColorCount[ nTotalColors ];
2999 		long				nX, nY, nR, nG, nB, nIndex;
3000 
3001 		rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
3002 
3003 		for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3004         {
3005 			for( nG = 0; nG < 256; nG += nColorOffset )
3006             {
3007 				for( nB = 0; nB < 256; nB += nColorOffset )
3008                 {
3009 					pCountTable[ nIndex ].mnIndex = nIndex;
3010                     nIndex++;
3011                 }
3012             }
3013         }
3014 
3015 		if( pRAcc->HasPalette() )
3016 		{
3017 			for( nY = 0L; nY < nHeight; nY++ )
3018 			{
3019 				for( nX = 0L; nX < nWidth; nX++ )
3020 				{
3021 					const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3022 					pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3023 								 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3024 								 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3025 				}
3026 			}
3027 		}
3028 		else
3029 		{
3030 			for( nY = 0L; nY < nHeight; nY++ )
3031 			{
3032 				for( nX = 0L; nX < nWidth; nX++ )
3033 				{
3034 					const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3035 					pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3036 								 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3037 								 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3038 				}
3039 			}
3040 		}
3041 
3042 		BitmapPalette aNewPal( nColCount );
3043 
3044 		qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3045 
3046 		for( sal_uInt16 n = 0; n < nColCount; n++ )
3047 		{
3048 			const PopularColorCount& rPop = pCountTable[ n ];
3049 			aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3050 										(sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3051 										(sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3052 		}
3053 
3054 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3055 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
3056 
3057 		if( pWAcc )
3058 		{
3059 			BitmapColor	aDstCol( (sal_uInt8) 0 );
3060 			sal_uInt8*		pIndexMap = new sal_uInt8[ nTotalColors ];
3061 
3062 			for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3063 				for( nG = 0; nG < 256; nG += nColorOffset )
3064 					for( nB = 0; nB < 256; nB += nColorOffset )
3065 						pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3066 
3067 			if( pRAcc->HasPalette() )
3068 			{
3069 				for( nY = 0L; nY < nHeight; nY++ )
3070 				{
3071 					for( nX = 0L; nX < nWidth; nX++ )
3072 					{
3073 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3074 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3075 													 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3076 													 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3077 						pWAcc->SetPixel( nY, nX, aDstCol );
3078 					}
3079 				}
3080 			}
3081 			else
3082 			{
3083 				for( nY = 0L; nY < nHeight; nY++ )
3084 				{
3085 					for( nX = 0L; nX < nWidth; nX++ )
3086 					{
3087 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3088 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3089 													 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3090 													 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3091 						pWAcc->SetPixel( nY, nX, aDstCol );
3092 					}
3093 				}
3094 			}
3095 
3096 			delete[] pIndexMap;
3097 			aNewBmp.ReleaseAccess( pWAcc );
3098 			bRet = sal_True;
3099 		}
3100 
3101 		delete[] pCountTable;
3102 		ReleaseAccess( pRAcc );
3103 
3104 		if( bRet )
3105 		{
3106 			const MapMode	aMap( maPrefMapMode );
3107 			const Size		aSize( maPrefSize );
3108 
3109 			*this = aNewBmp;
3110 			maPrefMapMode = aMap;
3111 			maPrefSize = aSize;
3112 		}
3113 	}
3114 
3115 	return bRet;
3116 }
3117 
3118 // ------------------------------------------------------------------------
3119 
3120 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3121 {
3122 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
3123 	sal_uInt16				nBitCount;
3124 	sal_Bool				bRet = sal_False;
3125 
3126 	if( nColCount < 17 )
3127 		nBitCount = 4;
3128 	else if( nColCount < 257 )
3129 		nBitCount = 8;
3130 	else
3131 	{
3132 		DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3133 		nBitCount = 8;
3134 		nColCount = 256;
3135 	}
3136 
3137 	if( pRAcc )
3138 	{
3139 		Bitmap				aNewBmp( GetSizePixel(), nBitCount );
3140 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
3141 
3142 		if( pWAcc )
3143 		{
3144 			const sal_uLong	nSize = 32768UL * sizeof( sal_uLong );
3145 			sal_uLong*		pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3146 			const long	nWidth = pWAcc->Width();
3147 			const long	nHeight = pWAcc->Height();
3148 			long		nIndex = 0L;
3149 
3150 			memset( (HPBYTE) pColBuf, 0, nSize );
3151 
3152 			// create Buffer
3153 			if( pRAcc->HasPalette() )
3154 			{
3155 				for( long nY = 0L; nY < nHeight; nY++ )
3156 				{
3157 					for( long nX = 0L; nX < nWidth; nX++ )
3158 					{
3159 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3160 						pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3161 					}
3162 				}
3163 			}
3164 			else
3165 			{
3166 				for( long nY = 0L; nY < nHeight; nY++ )
3167 				{
3168 					for( long nX = 0L; nX < nWidth; nX++ )
3169 					{
3170 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3171 						pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3172 					}
3173 				}
3174 			}
3175 
3176 			// create palette via median cut
3177 			BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3178 			ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3179 						   nColCount, nWidth * nHeight, nIndex );
3180 
3181 			// do mapping of colors to palette
3182 			InverseColorMap aMap( aPal );
3183 			pWAcc->SetPalette( aPal );
3184 			for( long nY = 0L; nY < nHeight; nY++ )
3185 				for( long nX = 0L; nX < nWidth; nX++ )
3186 					pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3187 
3188 			rtl_freeMemory( pColBuf );
3189 			aNewBmp.ReleaseAccess( pWAcc );
3190 			bRet = sal_True;
3191 		}
3192 
3193 		ReleaseAccess( pRAcc );
3194 
3195 		if( bRet )
3196 		{
3197 			const MapMode	aMap( maPrefMapMode );
3198 			const Size		aSize( maPrefSize );
3199 
3200 			*this = aNewBmp;
3201 			maPrefMapMode = aMap;
3202 			maPrefSize = aSize;
3203 		}
3204 	}
3205 
3206 	return bRet;
3207 }
3208 
3209 // ------------------------------------------------------------------------
3210 
3211 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3212 							long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3213 							long nColors, long nPixels, long& rIndex )
3214 {
3215 	if( !nPixels )
3216 		return;
3217 
3218 	BitmapColor	aCol;
3219 	const long	nRLen = nR2 - nR1;
3220 	const long	nGLen = nG2 - nG1;
3221 	const long	nBLen = nB2 - nB1;
3222 	long 		nR, nG, nB;
3223 	sal_uLong*		pBuf = pColBuf;
3224 
3225 	if( !nRLen && !nGLen && !nBLen )
3226 	{
3227 		if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3228 		{
3229 			aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3230 			aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3231 			aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3232 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
3233 		}
3234 	}
3235 	else
3236 	{
3237 		if( 1 == nColors || 1 == nPixels )
3238 		{
3239 			long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3240 
3241 			for( nR = nR1; nR <= nR2; nR++ )
3242 			{
3243 				for( nG = nG1; nG <= nG2; nG++ )
3244 				{
3245 					for( nB = nB1; nB <= nB2; nB++ )
3246 					{
3247 						nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3248 
3249 						if( nPixSum )
3250 						{
3251 							nRSum += nR * nPixSum;
3252 							nGSum += nG * nPixSum;
3253 							nBSum += nB * nPixSum;
3254 						}
3255 					}
3256 				}
3257 			}
3258 
3259 			aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3260 			aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3261 			aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3262 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
3263 		}
3264 		else
3265 		{
3266 			const long	nTest = ( nPixels >> 1 );
3267 			long		nPixOld = 0;
3268 			long		nPixNew = 0;
3269 
3270 			if( nBLen > nGLen && nBLen > nRLen )
3271 			{
3272 				nB = nB1 - 1;
3273 
3274 				while( nPixNew < nTest )
3275 				{
3276 					nB++, nPixOld = nPixNew;
3277 					for( nR = nR1; nR <= nR2; nR++ )
3278 						for( nG = nG1; nG <= nG2; nG++ )
3279 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3280 				}
3281 
3282 				if( nB < nB2 )
3283 				{
3284 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3285 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3286 				}
3287 				else
3288 				{
3289 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3290 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3291 				}
3292 			}
3293 			else if( nGLen > nRLen )
3294 			{
3295 				nG = nG1 - 1;
3296 
3297 				while( nPixNew < nTest )
3298 				{
3299 					nG++, nPixOld = nPixNew;
3300 					for( nR = nR1; nR <= nR2; nR++ )
3301 						for( nB = nB1; nB <= nB2; nB++ )
3302 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3303 				}
3304 
3305 				if( nG < nG2 )
3306 				{
3307 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3308 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3309 				}
3310 				else
3311 				{
3312 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3313 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3314 				}
3315 			}
3316 			else
3317 			{
3318 				nR = nR1 - 1;
3319 
3320 				while( nPixNew < nTest )
3321 				{
3322 					nR++, nPixOld = nPixNew;
3323 					for( nG = nG1; nG <= nG2; nG++ )
3324 						for( nB = nB1; nB <= nB2; nB++ )
3325 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3326 				}
3327 
3328 				if( nR < nR2 )
3329 				{
3330 					ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3331 					ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3332 				}
3333 				else
3334 				{
3335 					ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3336 					ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3337 				}
3338 			}
3339 		}
3340 	}
3341 }
3342 
3343 // ------------------------------------------------------------------------
3344 
3345 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3346 {
3347 	return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3348 }
3349 
3350 // ------------------------------------------------------------------------
3351 
3352 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3353 {
3354 	return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3355 }
3356 
3357 // ------------------------------------------------------------------------
3358 
3359 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3360 					 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3361 					 double fGamma, sal_Bool bInvert )
3362 {
3363 	sal_Bool bRet = sal_False;
3364 
3365 	// nothing to do => return quickly
3366 	if( !nLuminancePercent && !nContrastPercent &&
3367 		!nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3368 		( fGamma == 1.0 ) && !bInvert )
3369 	{
3370 		bRet = sal_True;
3371 	}
3372 	else
3373 	{
3374 		BitmapWriteAccess* pAcc = AcquireWriteAccess();
3375 
3376 		if( pAcc )
3377 		{
3378 			BitmapColor		aCol;
3379 			const long		nW = pAcc->Width();
3380 			const long		nH = pAcc->Height();
3381 			sal_uInt8*			cMapR = new sal_uInt8[ 256 ];
3382 			sal_uInt8*			cMapG = new sal_uInt8[ 256 ];
3383 			sal_uInt8*			cMapB = new sal_uInt8[ 256 ];
3384 			long			nX, nY;
3385 			double			fM, fROff, fGOff, fBOff, fOff;
3386 
3387 			// calculate slope
3388 			if( nContrastPercent >= 0 )
3389 				fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3390 			else
3391 				fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3392 
3393 			// total offset = luminance offset + contrast offset
3394 			fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3395 
3396 			// channel offset = channel offset  + total offset
3397 			fROff = nChannelRPercent * 2.55 + fOff;
3398 			fGOff = nChannelGPercent * 2.55 + fOff;
3399 			fBOff = nChannelBPercent * 2.55 + fOff;
3400 
3401 			// calculate gamma value
3402 			fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3403 			const sal_Bool bGamma = ( fGamma != 1.0 );
3404 
3405 			// create mapping table
3406 			for( nX = 0L; nX < 256L; nX++ )
3407 			{
3408 				cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3409 				cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3410 				cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3411 
3412 				if( bGamma )
3413 				{
3414 					cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3415 					cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3416 					cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3417 				}
3418 
3419 				if( bInvert )
3420 				{
3421 					cMapR[ nX ] = ~cMapR[ nX ];
3422 					cMapG[ nX ] = ~cMapG[ nX ];
3423 					cMapB[ nX ] = ~cMapB[ nX ];
3424 				}
3425 			}
3426 
3427 			// do modifying
3428 			if( pAcc->HasPalette() )
3429 			{
3430 				BitmapColor aNewCol;
3431 
3432 				for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3433 				{
3434 					const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3435 					aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3436 					aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3437 					aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3438 					pAcc->SetPaletteColor( i, aNewCol );
3439 				}
3440 			}
3441 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3442 			{
3443 				for( nY = 0L; nY < nH; nY++ )
3444 				{
3445 					Scanline pScan = pAcc->GetScanline( nY );
3446 
3447 					for( nX = 0L; nX < nW; nX++ )
3448 					{
3449 						*pScan = cMapB[ *pScan ]; pScan++;
3450 						*pScan = cMapG[ *pScan ]; pScan++;
3451 						*pScan = cMapR[ *pScan ]; pScan++;
3452 					}
3453 				}
3454 			}
3455 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3456 			{
3457 				for( nY = 0L; nY < nH; nY++ )
3458 				{
3459 					Scanline pScan = pAcc->GetScanline( nY );
3460 
3461 					for( nX = 0L; nX < nW; nX++ )
3462 					{
3463 						*pScan = cMapR[ *pScan ]; pScan++;
3464 						*pScan = cMapG[ *pScan ]; pScan++;
3465 						*pScan = cMapB[ *pScan ]; pScan++;
3466 					}
3467 				}
3468 			}
3469 			else
3470 			{
3471 				for( nY = 0L; nY < nH; nY++ )
3472 				{
3473 					for( nX = 0L; nX < nW; nX++ )
3474 					{
3475 						aCol = pAcc->GetPixel( nY, nX );
3476 						aCol.SetRed( cMapR[ aCol.GetRed() ] );
3477 						aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3478 						aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3479 						pAcc->SetPixel( nY, nX, aCol );
3480 					}
3481 				}
3482 			}
3483 
3484 			delete[] cMapR;
3485 			delete[] cMapG;
3486 			delete[] cMapB;
3487 			ReleaseAccess( pAcc );
3488 			bRet = sal_True;
3489 		}
3490 	}
3491 
3492 	return bRet;
3493 }
3494