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