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