xref: /aoo41x/main/vcl/source/gdi/bitmap4.cxx (revision 87bc88d3)
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 #include <vos/macros.hxx>
29 #include <vcl/bmpacc.hxx>
30 #include <vcl/bitmap.hxx>
31 
32 // -----------
33 // - Defines -
34 // -----------
35 
36 #define S2(a,b)				{ register long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } }
37 #define MN3(a,b,c)			S2(a,b); S2(a,c);
38 #define MX3(a,b,c)			S2(b,c); S2(a,c);
39 #define MNMX3(a,b,c)		MX3(a,b,c); S2(a,b);
40 #define MNMX4(a,b,c,d)		S2(a,b); S2(c,d); S2(a,c); S2(b,d);
41 #define MNMX5(a,b,c,d,e)	S2(a,b); S2(c,d); MN3(a,c,e); MX3(b,d,e);
42 #define MNMX6(a,b,c,d,e,f)	S2(a,d); S2(b,e); S2(c,f); MN3(a,b,c); MX3(d,e,f);
43 
44 // ----------
45 // - Bitmap -
46 // ----------
47 
48 sal_Bool Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
49 {
50 	sal_Bool bRet = sal_False;
51 
52 	switch( eFilter )
53 	{
54 		case( BMP_FILTER_SMOOTH ):
55 		{
56 			const long pSmoothMatrix[] = { 1, 2, 1, 2, 5, 2, 1, 2, 1 };
57 			bRet = ImplConvolute3( &pSmoothMatrix[ 0 ], 17, pFilterParam, pProgress );
58 		}
59 		break;
60 
61 		case( BMP_FILTER_SHARPEN ):
62 		{
63 			const long pSharpenMatrix[] = { -1, -1,  -1, -1, 16, -1, -1, -1,  -1 };
64 			bRet = ImplConvolute3( &pSharpenMatrix[ 0 ], 8, pFilterParam, pProgress );
65 		}
66 		break;
67 
68 		case( BMP_FILTER_REMOVENOISE ):
69 			bRet = ImplMedianFilter( pFilterParam, pProgress );
70 		break;
71 
72 		case( BMP_FILTER_SOBEL_GREY ):
73 			bRet = ImplSobelGrey( pFilterParam, pProgress );
74 		break;
75 
76 		case( BMP_FILTER_SOLARIZE ):
77 			bRet = ImplSolarize( pFilterParam, pProgress );
78 		break;
79 
80 		case( BMP_FILTER_SEPIA ):
81 			bRet = ImplSepia( pFilterParam, pProgress );
82 		break;
83 
84 		case( BMP_FILTER_MOSAIC ):
85 			bRet = ImplMosaic( pFilterParam, pProgress );
86 		break;
87 
88 		case( BMP_FILTER_EMBOSS_GREY ):
89 			bRet = ImplEmbossGrey( pFilterParam, pProgress );
90 		break;
91 
92 		case( BMP_FILTER_POPART ):
93 			bRet = ImplPopArt( pFilterParam, pProgress );
94 		break;
95 
96 		default:
97 			DBG_ERROR( "Bitmap::Convert(): Unsupported filter" );
98 		break;
99 	}
100 
101 	return bRet;
102 }
103 
104 // -----------------------------------------------------------------------------
105 
106 sal_Bool Bitmap::ImplConvolute3( const long* pMatrix, long nDivisor,
107 							 const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
108 {
109 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
110 	sal_Bool				bRet = sal_False;
111 
112 	if( pReadAcc )
113 	{
114 		Bitmap				aNewBmp( GetSizePixel(), 24 );
115 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
116 
117 		if( pWriteAcc )
118 		{
119 			const long		nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
120 			const long		nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
121 			long*			pColm = new long[ nWidth2 ];
122 			long*			pRows = new long[ nHeight2 ];
123 			BitmapColor*	pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
124 			BitmapColor*	pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
125 			BitmapColor*	pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
126 			BitmapColor*	pRowTmp1 = pColRow1;
127 			BitmapColor*	pRowTmp2 = pColRow2;
128 			BitmapColor*	pRowTmp3 = pColRow3;
129 			BitmapColor*	pColor;
130 			long			nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp;
131 			long			(*pKoeff)[ 256 ] = new long[ 9 ][ 256 ];
132 			long*			pTmp;
133 
134 			// create LUT of products of matrix value and possible color component values
135 			for( nY = 0; nY < 9; nY++ )
136 				for( nX = nTmp = 0, nMatrixVal = pMatrix[ nY ]; nX < 256; nX++, nTmp += nMatrixVal )
137 					pKoeff[ nY ][ nX ] = nTmp;
138 
139 			// create column LUT
140 			for( i = 0; i < nWidth2; i++ )
141 				pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
142 
143 			pColm[ nWidth + 1 ] = pColm[ nWidth ];
144 
145 			// create row LUT
146 			for( i = 0; i < nHeight2; i++ )
147 				pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
148 
149 			pRows[ nHeight + 1 ] = pRows[ nHeight ];
150 
151 			// read first three rows of bitmap color
152 			for( i = 0; i < nWidth2; i++ )
153 			{
154 				pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
155 				pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
156 				pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
157 			}
158 
159 			// do convolution
160 			for( nY = 0; nY < nHeight; )
161 			{
162 				for( nX = 0; nX < nWidth; nX++ )
163 				{
164 					// first row
165 					nSumR = ( pTmp = pKoeff[ 0 ] )[ ( pColor = pRowTmp1 + nX )->GetRed() ];
166 					nSumG = pTmp[ pColor->GetGreen() ];
167 					nSumB = pTmp[ pColor->GetBlue() ];
168 
169 					nSumR += ( pTmp = pKoeff[ 1 ] )[ ( ++pColor )->GetRed() ];
170 					nSumG += pTmp[ pColor->GetGreen() ];
171 					nSumB += pTmp[ pColor->GetBlue() ];
172 
173 					nSumR += ( pTmp = pKoeff[ 2 ] )[ ( ++pColor )->GetRed() ];
174 					nSumG += pTmp[ pColor->GetGreen() ];
175 					nSumB += pTmp[ pColor->GetBlue() ];
176 
177 					// second row
178 					nSumR += ( pTmp = pKoeff[ 3 ] )[ ( pColor = pRowTmp2 + nX )->GetRed() ];
179 					nSumG += pTmp[ pColor->GetGreen() ];
180 					nSumB += pTmp[ pColor->GetBlue() ];
181 
182 					nSumR += ( pTmp = pKoeff[ 4 ] )[ ( ++pColor )->GetRed() ];
183 					nSumG += pTmp[ pColor->GetGreen() ];
184 					nSumB += pTmp[ pColor->GetBlue() ];
185 
186 					nSumR += ( pTmp = pKoeff[ 5 ] )[ ( ++pColor )->GetRed() ];
187 					nSumG += pTmp[ pColor->GetGreen() ];
188 					nSumB += pTmp[ pColor->GetBlue() ];
189 
190 					// third row
191 					nSumR += ( pTmp = pKoeff[ 6 ] )[ ( pColor = pRowTmp3 + nX )->GetRed() ];
192 					nSumG += pTmp[ pColor->GetGreen() ];
193 					nSumB += pTmp[ pColor->GetBlue() ];
194 
195 					nSumR += ( pTmp = pKoeff[ 7 ] )[ ( ++pColor )->GetRed() ];
196 					nSumG += pTmp[ pColor->GetGreen() ];
197 					nSumB += pTmp[ pColor->GetBlue() ];
198 
199 					nSumR += ( pTmp = pKoeff[ 8 ] )[ ( ++pColor )->GetRed() ];
200 					nSumG += pTmp[ pColor->GetGreen() ];
201 					nSumB += pTmp[ pColor->GetBlue() ];
202 
203 					// calculate destination color
204 					pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) MinMax( nSumR / nDivisor, 0, 255 ),
205 															  (sal_uInt8) MinMax( nSumG / nDivisor, 0, 255 ),
206 															  (sal_uInt8) MinMax( nSumB / nDivisor, 0, 255 ) ) );
207 				}
208 
209 				if( ++nY < nHeight )
210 				{
211 					if( pRowTmp1 == pColRow1 )
212 						pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
213 					else if( pRowTmp1 == pColRow2 )
214 						pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
215 					else
216 						pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
217 
218 					for( i = 0; i < nWidth2; i++ )
219 						pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
220 				}
221 			}
222 
223 			delete[] pKoeff;
224 			delete[] (sal_uInt8*) pColRow1;
225 			delete[] (sal_uInt8*) pColRow2;
226 			delete[] (sal_uInt8*) pColRow3;
227 			delete[] pColm;
228 			delete[] pRows;
229 
230 			aNewBmp.ReleaseAccess( pWriteAcc );
231 
232 			bRet = sal_True;
233 		}
234 
235 		ReleaseAccess( pReadAcc );
236 
237 		if( bRet )
238 		{
239 			const MapMode	aMap( maPrefMapMode );
240 			const Size		aSize( maPrefSize );
241 
242 			*this = aNewBmp;
243 
244 			maPrefMapMode = aMap;
245 			maPrefSize = aSize;
246 		}
247 	}
248 
249 	return bRet;
250 }
251 
252 // -----------------------------------------------------------------------------
253 
254 sal_Bool Bitmap::ImplMedianFilter( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
255 {
256 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
257 	sal_Bool				bRet = sal_False;
258 
259 	if( pReadAcc )
260 	{
261 		Bitmap				aNewBmp( GetSizePixel(), 24 );
262 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
263 
264 		if( pWriteAcc )
265 		{
266 			const long		nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
267 			const long		nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
268 			long*			pColm = new long[ nWidth2 ];
269 			long*			pRows = new long[ nHeight2 ];
270 			BitmapColor*	pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
271 			BitmapColor*	pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
272 			BitmapColor*	pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
273 			BitmapColor*	pRowTmp1 = pColRow1;
274 			BitmapColor*	pRowTmp2 = pColRow2;
275 			BitmapColor*	pRowTmp3 = pColRow3;
276 			BitmapColor*	pColor;
277 			long			nY, nX, i;
278 			long			nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9;
279 			long			nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9;
280 			long			nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9;
281 
282 			// create column LUT
283 			for( i = 0; i < nWidth2; i++ )
284 				pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
285 
286 			pColm[ nWidth + 1 ] = pColm[ nWidth ];
287 
288 			// create row LUT
289 			for( i = 0; i < nHeight2; i++ )
290 				pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
291 
292 			pRows[ nHeight + 1 ] = pRows[ nHeight ];
293 
294 			// read first three rows of bitmap color
295 			if (nHeight2 > 2)
296 			{
297 			    for( i = 0; i < nWidth2; i++ )
298 			    {
299 				    pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
300 				    pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
301 				    pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
302 			    }
303 			}
304 
305 			// do median filtering
306 			for( nY = 0; nY < nHeight; )
307 			{
308 				for( nX = 0; nX < nWidth; nX++ )
309 				{
310 					nR1 = ( pColor = pRowTmp1 + nX )->GetRed(), nG1 = pColor->GetGreen(), nB1 = pColor->GetBlue();
311 					nR2 = ( ++pColor )->GetRed(), nG2 = pColor->GetGreen(), nB2 = pColor->GetBlue();
312 					nR3 = ( ++pColor )->GetRed(), nG3 = pColor->GetGreen(), nB3 = pColor->GetBlue();
313 
314 					nR4 = ( pColor = pRowTmp2 + nX )->GetRed(), nG4 = pColor->GetGreen(), nB4 = pColor->GetBlue();
315 					nR5 = ( ++pColor )->GetRed(), nG5 = pColor->GetGreen(), nB5 = pColor->GetBlue();
316 					nR6 = ( ++pColor )->GetRed(), nG6 = pColor->GetGreen(), nB6 = pColor->GetBlue();
317 
318 					nR7 = ( pColor = pRowTmp3 + nX )->GetRed(), nG7 = pColor->GetGreen(), nB7 = pColor->GetBlue();
319 					nR8 = ( ++pColor )->GetRed(), nG8 = pColor->GetGreen(), nB8 = pColor->GetBlue();
320 					nR9 = ( ++pColor )->GetRed(), nG9 = pColor->GetGreen(), nB9 = pColor->GetBlue();
321 
322 					MNMX6( nR1, nR2, nR3, nR4, nR5, nR6 );
323     				MNMX5( nR7, nR2, nR3, nR4, nR5 );
324     				MNMX4( nR8, nR2, nR3, nR4 );
325     				MNMX3( nR9, nR2, nR3 );
326 
327 					MNMX6( nG1, nG2, nG3, nG4, nG5, nG6 );
328     				MNMX5( nG7, nG2, nG3, nG4, nG5 );
329     				MNMX4( nG8, nG2, nG3, nG4 );
330     				MNMX3( nG9, nG2, nG3 );
331 
332 					MNMX6( nB1, nB2, nB3, nB4, nB5, nB6 );
333     				MNMX5( nB7, nB2, nB3, nB4, nB5 );
334     				MNMX4( nB8, nB2, nB3, nB4 );
335     				MNMX3( nB9, nB2, nB3 );
336 
337 					// set destination color
338 					pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) nR2, (sal_uInt8) nG2, (sal_uInt8) nB2 ) );
339 				}
340 
341 				if( ++nY < nHeight )
342 				{
343 					if( pRowTmp1 == pColRow1 )
344 						pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
345 					else if( pRowTmp1 == pColRow2 )
346 						pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
347 					else
348 						pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
349 
350 					for( i = 0; i < nWidth2; i++ )
351 						pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
352 				}
353 			}
354 
355 			delete[] (sal_uInt8*) pColRow1;
356 			delete[] (sal_uInt8*) pColRow2;
357 			delete[] (sal_uInt8*) pColRow3;
358 			delete[] pColm;
359 			delete[] pRows;
360 
361 			aNewBmp.ReleaseAccess( pWriteAcc );
362 
363 			bRet = sal_True;
364 		}
365 
366 		ReleaseAccess( pReadAcc );
367 
368 		if( bRet )
369 		{
370 			const MapMode	aMap( maPrefMapMode );
371 			const Size		aSize( maPrefSize );
372 
373 			*this = aNewBmp;
374 
375 			maPrefMapMode = aMap;
376 			maPrefSize = aSize;
377 		}
378 	}
379 
380 	return bRet;
381 }
382 
383 // -----------------------------------------------------------------------------
384 
385 sal_Bool Bitmap::ImplSobelGrey( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
386 {
387 	sal_Bool bRet = ImplMakeGreyscales( 256 );
388 
389 	if( bRet )
390 	{
391 		bRet = sal_False;
392 
393 		BitmapReadAccess* pReadAcc = AcquireReadAccess();
394 
395 		if( pReadAcc )
396 		{
397 			Bitmap				aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
398 			BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
399 
400 			if( pWriteAcc )
401 			{
402 				BitmapColor	aGrey( (sal_uInt8) 0 );
403 				const long	nWidth = pWriteAcc->Width();
404 				const long	nHeight = pWriteAcc->Height();
405 				const long	nMask111 = -1, nMask121 =  0, nMask131 =  1;
406 				const long	nMask211 = -2, nMask221 =  0, nMask231 =  2;
407 				const long	nMask311 = -1, nMask321 =  0, nMask331 =  1;
408 				const long	nMask112 =  1, nMask122 =  2, nMask132 =  1;
409 				const long	nMask212 =  0, nMask222 =  0, nMask232 =  0;
410 				const long	nMask312 = -1, nMask322 = -2, nMask332 = -1;
411 				long		nGrey11, nGrey12, nGrey13;
412 				long		nGrey21, nGrey22, nGrey23;
413 				long		nGrey31, nGrey32, nGrey33;
414 				long*		pHMap = new long[ nWidth + 2 ];
415 				long*		pVMap = new long[ nHeight + 2 ];
416 				long		nX, nY, nSum1, nSum2;
417 
418 				// fill mapping tables
419 				pHMap[ 0 ] = 0;
420 				for( nX = 1; nX <= nWidth; nX++ )
421 					pHMap[ nX ] = nX - 1;
422 				pHMap[ nWidth + 1 ] = nWidth - 1;
423 
424 				pVMap[ 0 ] = 0;
425 				for( nY = 1; nY <= nHeight; nY++ )
426 					pVMap[ nY ] = nY - 1;
427 				pVMap[ nHeight + 1 ] = nHeight - 1;
428 
429 				for( nY = 0; nY < nHeight ; nY++ )
430 				{
431 					nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
432 					nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
433 					nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
434 					nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
435 					nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
436 					nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
437 					nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
438 					nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
439 					nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
440 
441 					for( nX = 0; nX < nWidth; nX++ )
442 					{
443 						nSum1 = nSum2 = 0;
444 
445 						nSum1 += nMask111 * nGrey11;
446 						nSum2 += nMask112 * nGrey11;
447 
448 						nSum1 += nMask121 * nGrey12;
449 						nSum2 += nMask122 * nGrey12;
450 
451 						nSum1 += nMask131 * nGrey13;
452 						nSum2 += nMask132 * nGrey13;
453 
454 						nSum1 += nMask211 * nGrey21;
455 						nSum2 += nMask212 * nGrey21;
456 
457 						nSum1 += nMask221 * nGrey22;
458 						nSum2 += nMask222 * nGrey22;
459 
460 						nSum1 += nMask231 * nGrey23;
461 						nSum2 += nMask232 * nGrey23;
462 
463 						nSum1 += nMask311 * nGrey31;
464 						nSum2 += nMask312 * nGrey31;
465 
466 						nSum1 += nMask321 * nGrey32;
467 						nSum2 += nMask322 * nGrey32;
468 
469 						nSum1 += nMask331 * nGrey33;
470 						nSum2 += nMask332 * nGrey33;
471 
472 						nSum1 = (long) sqrt( (double)( nSum1 * nSum1 + nSum2 * nSum2 ) );
473 						aGrey.SetIndex( ~(sal_uInt8) VOS_BOUND( nSum1, 0, 255 ) );
474 						pWriteAcc->SetPixel( nY, nX, aGrey );
475 
476 						if( nX < ( nWidth - 1 ) )
477 						{
478 							const long nNextX = pHMap[ nX + 3 ];
479 
480 							nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
481 							nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
482 							nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
483 						}
484 					}
485 				}
486 
487 				delete[] pHMap;
488 				delete[] pVMap;
489 				aNewBmp.ReleaseAccess( pWriteAcc );
490 				bRet = sal_True;
491 			}
492 
493 			ReleaseAccess( pReadAcc );
494 
495 			if( bRet )
496 			{
497 				const MapMode	aMap( maPrefMapMode );
498 				const Size		aSize( maPrefSize );
499 
500 				*this = aNewBmp;
501 
502 				maPrefMapMode = aMap;
503 				maPrefSize = aSize;
504 			}
505 		}
506 	}
507 
508 	return bRet;
509 }
510 
511 // -----------------------------------------------------------------------------
512 
513 sal_Bool Bitmap::ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
514 {
515 	sal_Bool bRet = ImplMakeGreyscales( 256 );
516 
517 	if( bRet )
518 	{
519 		bRet = sal_False;
520 
521 		BitmapReadAccess* pReadAcc = AcquireReadAccess();
522 
523 		if( pReadAcc )
524 		{
525 			Bitmap				aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
526 			BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
527 
528 			if( pWriteAcc )
529 			{
530 				BitmapColor	aGrey( (sal_uInt8) 0 );
531 				const long	nWidth = pWriteAcc->Width();
532 				const long	nHeight = pWriteAcc->Height();
533 				long		nGrey11, nGrey12, nGrey13;
534 				long		nGrey21, nGrey22, nGrey23;
535 				long		nGrey31, nGrey32, nGrey33;
536 				double		fAzim = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
537 									  ( pFilterParam->maEmbossAngles.mnAzimuthAngle100 * 0.01 ) : 0.0 ) * F_PI180;
538 				double		fElev = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
539 									  ( pFilterParam->maEmbossAngles.mnElevationAngle100 * 0.01 ) : 90.0 ) * F_PI180;
540 				long*		pHMap = new long[ nWidth + 2 ];
541 				long*		pVMap = new long[ nHeight + 2 ];
542 				long	 	nX, nY, nNx, nNy, nDotL;
543 				const long	nLx = FRound( cos( fAzim ) * cos( fElev ) * 255.0 );
544 				const long	nLy = FRound( sin( fAzim ) * cos( fElev ) * 255.0 );
545 				const long	nLz = FRound( sin( fElev ) * 255.0 );
546 				const long	nZ2 = ( ( 6 * 255 ) / 4 ) * ( ( 6 * 255 ) / 4 );
547 				const long	nNzLz = ( ( 6 * 255 ) / 4 ) * nLz;
548 				const sal_uInt8	cLz = (sal_uInt8) VOS_BOUND( nLz, 0, 255 );
549 
550 				// fill mapping tables
551 				pHMap[ 0 ] = 0;
552 				for( nX = 1; nX <= nWidth; nX++ )
553 					pHMap[ nX ] = nX - 1;
554 				pHMap[ nWidth + 1 ] = nWidth - 1;
555 
556 				pVMap[ 0 ] = 0;
557 				for( nY = 1; nY <= nHeight; nY++ )
558 					pVMap[ nY ] = nY - 1;
559 				pVMap[ nHeight + 1 ] = nHeight - 1;
560 
561 				for( nY = 0; nY < nHeight ; nY++ )
562 				{
563 					nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
564 					nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
565 					nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
566 					nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
567 					nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
568 					nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
569 					nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
570 					nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
571 					nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
572 
573 					for( nX = 0; nX < nWidth; nX++ )
574 					{
575 						nNx = nGrey11 + nGrey21 + nGrey31 - nGrey13 - nGrey23 - nGrey33;
576 						nNy = nGrey31 + nGrey32 + nGrey33 - nGrey11 - nGrey12 - nGrey13;
577 
578 						if( !nNx && !nNy )
579 							aGrey.SetIndex( cLz );
580 						else if( ( nDotL = nNx * nLx + nNy * nLy +nNzLz ) < 0 )
581 							aGrey.SetIndex( 0 );
582 						else
583 						{
584 							const double fGrey = nDotL / sqrt( (double)(nNx * nNx + nNy * nNy + nZ2) );
585 							aGrey.SetIndex( (sal_uInt8) VOS_BOUND( fGrey, 0, 255 ) );
586 						}
587 
588 						pWriteAcc->SetPixel( nY, nX, aGrey );
589 
590 						if( nX < ( nWidth - 1 ) )
591 						{
592 							const long nNextX = pHMap[ nX + 3 ];
593 
594 							nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
595 							nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
596 							nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
597 						}
598 					}
599 				}
600 
601 				delete[] pHMap;
602 				delete[] pVMap;
603 				aNewBmp.ReleaseAccess( pWriteAcc );
604 				bRet = sal_True;
605 			}
606 
607 			ReleaseAccess( pReadAcc );
608 
609 			if( bRet )
610 			{
611 				const MapMode	aMap( maPrefMapMode );
612 				const Size		aSize( maPrefSize );
613 
614 				*this = aNewBmp;
615 
616 				maPrefMapMode = aMap;
617 				maPrefSize = aSize;
618 			}
619 		}
620 	}
621 
622 	return bRet;
623 }
624 
625 // -----------------------------------------------------------------------------
626 
627 sal_Bool Bitmap::ImplSolarize( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
628 {
629 	sal_Bool				bRet = sal_False;
630 	BitmapWriteAccess*	pWriteAcc = AcquireWriteAccess();
631 
632 	if( pWriteAcc )
633 	{
634 		const sal_uInt8 cThreshold = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SOLARIZE ) ?
635 								pFilterParam->mcSolarGreyThreshold : 128;
636 
637 		if( pWriteAcc->HasPalette() )
638 		{
639 			const BitmapPalette& rPal = pWriteAcc->GetPalette();
640 
641 			for( sal_uInt16 i = 0, nCount = rPal.GetEntryCount(); i < nCount; i++ )
642 			{
643 				if( rPal[ i ].GetLuminance() >= cThreshold )
644 				{
645 					BitmapColor aCol( rPal[ i ] );
646 					pWriteAcc->SetPaletteColor( i, aCol.Invert() );
647 				}
648 			}
649 		}
650 		else
651 		{
652 			BitmapColor	aCol;
653 			const long	nWidth = pWriteAcc->Width();
654 			const long	nHeight = pWriteAcc->Height();
655 
656 			for( long nY = 0; nY < nHeight ; nY++ )
657 			{
658 				for( long nX = 0; nX < nWidth; nX++ )
659 				{
660 					aCol = pWriteAcc->GetPixel( nY, nX );
661 
662 					if( aCol.GetLuminance() >= cThreshold )
663 						pWriteAcc->SetPixel( nY, nX, aCol.Invert() );
664 				}
665 			}
666 		}
667 
668 		ReleaseAccess( pWriteAcc );
669 		bRet = sal_True;
670 	}
671 
672 	return bRet;
673 }
674 
675 // -----------------------------------------------------------------------------
676 
677 sal_Bool Bitmap::ImplSepia( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
678 {
679 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
680 	sal_Bool				bRet = sal_False;
681 
682 	if( pReadAcc )
683 	{
684 		long			nSepiaPercent = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SEPIA ) ?
685 									    pFilterParam->mcSolarGreyThreshold : 10;
686 		const long		nSepia = 10000 - 100 * VOS_BOUND( nSepiaPercent, 0, 100 );
687 		BitmapPalette	aSepiaPal( 256 );
688 
689 		DBG_ASSERT( nSepiaPercent <= 100, "Bitmap::ImplSepia(): sepia value out of range; defaulting to 100%" );
690 
691 		for( sal_uInt16 i = 0; i < 256; i++ )
692 		{
693 			BitmapColor&	rCol = aSepiaPal[ i ];
694 			const sal_uInt8		cSepiaValue = (sal_uInt8) ( ( nSepia * i ) / 10000 );
695 
696 			rCol.SetRed( (sal_uInt8) i );
697 			rCol.SetGreen( cSepiaValue );
698 			rCol.SetBlue( cSepiaValue );
699 		}
700 
701 		Bitmap				aNewBmp( GetSizePixel(), 8, &aSepiaPal );
702 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
703 
704 		if( pWriteAcc )
705 		{
706 			BitmapColor	aCol( (sal_uInt8) 0 );
707 			const long	nWidth = pWriteAcc->Width();
708 			const long	nHeight = pWriteAcc->Height();
709 
710 			if( pReadAcc->HasPalette() )
711 			{
712 				for( long nY = 0; nY < nHeight ; nY++ )
713 				{
714 					const sal_uInt16	nPalCount = pReadAcc->GetPaletteEntryCount();
715 					sal_uInt8*			pIndexMap = new sal_uInt8[ nPalCount ];
716 
717 					for( sal_uInt16 i = 0; i < nPalCount; i++ )
718 						pIndexMap[ i ] = pReadAcc->GetPaletteColor( i ).GetLuminance();
719 
720 					for( long nX = 0; nX < nWidth; nX++ )
721 					{
722 						aCol.SetIndex( pIndexMap[ pReadAcc->GetPixel( nY, nX ).GetIndex() ] );
723 						pWriteAcc->SetPixel( nY, nX, aCol );
724 					}
725 
726 					delete[] pIndexMap;
727 				}
728 			}
729 			else
730 			{
731 				for( long nY = 0; nY < nHeight ; nY++ )
732 				{
733 					for( long nX = 0; nX < nWidth; nX++ )
734 					{
735 						aCol.SetIndex( pReadAcc->GetPixel( nY, nX ).GetLuminance() );
736 						pWriteAcc->SetPixel( nY, nX, aCol );
737 					}
738 				}
739 			}
740 
741 			aNewBmp.ReleaseAccess( pWriteAcc );
742 			bRet = sal_True;
743 		}
744 
745 		ReleaseAccess( pReadAcc );
746 
747 		if( bRet )
748 		{
749 			const MapMode	aMap( maPrefMapMode );
750 			const Size		aSize( maPrefSize );
751 
752 			*this = aNewBmp;
753 
754 			maPrefMapMode = aMap;
755 			maPrefSize = aSize;
756 		}
757 	}
758 
759 	return bRet;
760 }
761 
762 // -----------------------------------------------------------------------------
763 
764 sal_Bool Bitmap::ImplMosaic( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
765 {
766 	sal_uLong				nTileWidth = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
767 								     pFilterParam->maMosaicTileSize.mnTileWidth : 4;
768 	sal_uLong				nTileHeight = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
769 									  pFilterParam->maMosaicTileSize.mnTileHeight : 4;
770 	sal_Bool				bRet = sal_False;
771 
772 	if( !nTileWidth )
773 		nTileWidth = 1;
774 
775 	if( !nTileHeight )
776 		nTileHeight = 1;
777 
778 	if( nTileWidth > 1 || nTileHeight > 1 )
779 	{
780 		Bitmap*				pNewBmp;
781 		BitmapReadAccess*	pReadAcc;
782 		BitmapWriteAccess*	pWriteAcc;
783 
784 		if( GetBitCount() > 8 )
785 		{
786 			pNewBmp = NULL;
787 			pReadAcc = pWriteAcc = AcquireWriteAccess();
788 		}
789 		else
790 		{
791 			pNewBmp = new Bitmap( GetSizePixel(), 24 );
792 			pReadAcc = AcquireReadAccess();
793 			pWriteAcc = pNewBmp->AcquireWriteAccess();
794 		}
795 
796 		if( pReadAcc && pWriteAcc )
797 		{
798 			BitmapColor	aCol;
799 			long		nWidth = pReadAcc->Width();
800 			long		nHeight = pReadAcc->Height();
801 			long		nX, nY, nX1, nX2, nY1, nY2, nSumR, nSumG, nSumB;
802 			double		fArea_1;
803 
804 			nY1 = 0; nY2 = nTileHeight - 1;
805 
806 			if( nY2 >= nHeight )
807 				nY2 = nHeight - 1;
808 
809 			do
810 			{
811 				nX1 = 0; nX2 = nTileWidth - 1;
812 
813 				if( nX2 >= nWidth )
814 					nX2 = nWidth - 1;
815 
816 				fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
817 
818 				if( !pNewBmp )
819 				{
820 					do
821 					{
822 						for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
823 						{
824 							for( nX = nX1; nX <= nX2; nX++ )
825 							{
826 								aCol = pReadAcc->GetPixel( nY, nX );
827 								nSumR += aCol.GetRed();
828 								nSumG += aCol.GetGreen();
829 								nSumB += aCol.GetBlue();
830 							}
831 						}
832 
833 						aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
834 						aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
835 						aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
836 
837 						for( nY = nY1; nY <= nY2; nY++ )
838 							for( nX = nX1; nX <= nX2; nX++ )
839 								pWriteAcc->SetPixel( nY, nX, aCol );
840 
841 						nX1 += nTileWidth; nX2 += nTileWidth;
842 
843 						if( nX2 >= nWidth )
844 						{
845 							nX2 = nWidth - 1;
846 							fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
847 						}
848 					}
849 					while( nX1 < nWidth );
850 				}
851 				else
852 				{
853 					do
854 					{
855 						for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
856 						{
857 							for( nX = nX1; nX <= nX2; nX++ )
858 							{
859 								const BitmapColor& rCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) );
860 								nSumR += rCol.GetRed();
861 								nSumG += rCol.GetGreen();
862 								nSumB += rCol.GetBlue();
863 							}
864 						}
865 
866 						aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
867 						aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
868 						aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
869 
870 						for( nY = nY1; nY <= nY2; nY++ )
871 							for( nX = nX1; nX <= nX2; nX++ )
872 								pWriteAcc->SetPixel( nY, nX, aCol );
873 
874 						nX1 += nTileWidth; nX2 += nTileWidth;
875 
876 						if( nX2 >= nWidth )
877 						{
878 							nX2 = nWidth - 1;
879 							fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
880 						}
881 					}
882 					while( nX1 < nWidth );
883 				}
884 
885 				nY1 += nTileHeight; nY2 += nTileHeight;
886 
887 				if( nY2 >= nHeight )
888 					nY2 = nHeight - 1;
889 			}
890 			while( nY1 < nHeight );
891 
892 			bRet = sal_True;
893 		}
894 
895 		ReleaseAccess( pReadAcc );
896 
897 		if( pNewBmp )
898 		{
899 			pNewBmp->ReleaseAccess( pWriteAcc );
900 
901 			if( bRet )
902 			{
903 				const MapMode	aMap( maPrefMapMode );
904 				const Size		aSize( maPrefSize );
905 
906 				*this = *pNewBmp;
907 
908 				maPrefMapMode = aMap;
909 				maPrefSize = aSize;
910 			}
911 
912 			delete pNewBmp;
913 		}
914 	}
915 	else
916 		bRet = sal_True;
917 
918 	return bRet;
919 }
920 
921 // -----------------------------------------------------------------------------
922 
923 struct PopArtEntry
924 {
925 	sal_uInt32	mnIndex;
926 	sal_uInt32	mnCount;
927 };
928 
929 // ------------------------------------------------------------------------
930 
931 extern "C" int __LOADONCALLAPI ImplPopArtCmpFnc( const void* p1, const void* p2 )
932 {
933 	int nRet;
934 
935 	if( ( (PopArtEntry*) p1 )->mnCount < ( (PopArtEntry*) p2 )->mnCount )
936 		nRet = 1;
937 	else if( ( (PopArtEntry*) p1 )->mnCount == ( (PopArtEntry*) p2 )->mnCount )
938 		nRet = 0;
939 	else
940 		nRet = -1;
941 
942 	return nRet;
943 }
944 
945 // ------------------------------------------------------------------------
946 
947 sal_Bool Bitmap::ImplPopArt( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
948 {
949 	sal_Bool bRet = ( GetBitCount() > 8 ) ? Convert( BMP_CONVERSION_8BIT_COLORS ) : sal_True;
950 
951 	if( bRet )
952 	{
953 		bRet = sal_False;
954 
955 		BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
956 
957 		if( pWriteAcc )
958 		{
959 			const long		nWidth = pWriteAcc->Width();
960 			const long		nHeight = pWriteAcc->Height();
961 			const sal_uLong		nEntryCount = 1 << pWriteAcc->GetBitCount();
962 			sal_uLong			n;
963 			PopArtEntry*	pPopArtTable = new PopArtEntry[ nEntryCount ];
964 
965 			for( n = 0; n < nEntryCount; n++ )
966 			{
967 				PopArtEntry& rEntry = pPopArtTable[ n ];
968 				rEntry.mnIndex = (sal_uInt16) n;
969 				rEntry.mnCount = 0;
970 			}
971 
972 			// get pixel count for each palette entry
973 			for( long nY = 0; nY < nHeight ; nY++ )
974 				for( long nX = 0; nX < nWidth; nX++ )
975 					pPopArtTable[ pWriteAcc->GetPixel( nY, nX ).GetIndex() ].mnCount++;
976 
977 			// sort table
978 			qsort( pPopArtTable, nEntryCount, sizeof( PopArtEntry ), ImplPopArtCmpFnc );
979 
980 			// get last used entry
981 			sal_uLong nFirstEntry;
982 			sal_uLong nLastEntry = 0;
983 
984 			for( n = 0; n < nEntryCount; n++ )
985 				if( pPopArtTable[ n ].mnCount )
986 					nLastEntry = n;
987 
988 			// rotate palette (one entry)
989 			const BitmapColor aFirstCol( pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ 0 ].mnIndex) ) );
990 			for( nFirstEntry = 0; nFirstEntry < nLastEntry; nFirstEntry++ )
991 			{
992 				pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry ].mnIndex),
993 											pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry + 1 ].mnIndex) ) );
994 			}
995 			pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nLastEntry ].mnIndex), aFirstCol );
996 
997 			// cleanup
998 			delete[] pPopArtTable;
999 			ReleaseAccess( pWriteAcc );
1000 			bRet = sal_True;
1001 		}
1002 	}
1003 
1004 	return bRet;
1005 }
1006