Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <stdlib.h>
22 : #include <vcl/bmpacc.hxx>
23 : #include <vcl/bitmap.hxx>
24 :
25 : // -----------
26 : // - Defines -
27 : // -----------
28 :
29 : #define S2(a,b) { register long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } }
30 : #define MN3(a,b,c) S2(a,b); S2(a,c);
31 : #define MX3(a,b,c) S2(b,c); S2(a,c);
32 : #define MNMX3(a,b,c) MX3(a,b,c); S2(a,b);
33 : #define MNMX4(a,b,c,d) S2(a,b); S2(c,d); S2(a,c); S2(b,d);
34 : #define MNMX5(a,b,c,d,e) S2(a,b); S2(c,d); MN3(a,c,e); MX3(b,d,e);
35 : #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);
36 :
37 : // ----------
38 : // - Bitmap -
39 : // ----------
40 :
41 0 : sal_Bool Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
42 : {
43 0 : sal_Bool bRet = sal_False;
44 :
45 0 : switch( eFilter )
46 : {
47 : case( BMP_FILTER_SMOOTH ):
48 : {
49 : // Blur for positive values of mnRadius
50 0 : if (pFilterParam->mnRadius > 0.0)
51 : {
52 0 : bRet = ImplSeparableBlurFilter(pFilterParam->mnRadius);
53 : }
54 : // Unsharpen Mask for negative values of mnRadius
55 0 : else if (pFilterParam->mnRadius < 0.0)
56 : {
57 0 : bRet = ImplSeparableUnsharpenFilter(pFilterParam->mnRadius);
58 : }
59 : else
60 : {
61 0 : bRet = sal_False;
62 : }
63 : }
64 0 : break;
65 :
66 : case( BMP_FILTER_SHARPEN ):
67 : {
68 0 : const long pSharpenMatrix[] = { -1, -1, -1, -1, 16, -1, -1, -1, -1 };
69 0 : bRet = ImplConvolute3( &pSharpenMatrix[ 0 ], 8, pFilterParam, pProgress );
70 : }
71 0 : break;
72 :
73 : case( BMP_FILTER_REMOVENOISE ):
74 0 : bRet = ImplMedianFilter( pFilterParam, pProgress );
75 0 : break;
76 :
77 : case( BMP_FILTER_SOBEL_GREY ):
78 0 : bRet = ImplSobelGrey( pFilterParam, pProgress );
79 0 : break;
80 :
81 : case( BMP_FILTER_SOLARIZE ):
82 0 : bRet = ImplSolarize( pFilterParam, pProgress );
83 0 : break;
84 :
85 : case( BMP_FILTER_SEPIA ):
86 0 : bRet = ImplSepia( pFilterParam, pProgress );
87 0 : break;
88 :
89 : case( BMP_FILTER_MOSAIC ):
90 0 : bRet = ImplMosaic( pFilterParam, pProgress );
91 0 : break;
92 :
93 : case( BMP_FILTER_EMBOSS_GREY ):
94 0 : bRet = ImplEmbossGrey( pFilterParam, pProgress );
95 0 : break;
96 :
97 : case( BMP_FILTER_POPART ):
98 0 : bRet = ImplPopArt( pFilterParam, pProgress );
99 0 : break;
100 :
101 : default:
102 : OSL_FAIL( "Bitmap::Convert(): Unsupported filter" );
103 0 : break;
104 : }
105 :
106 0 : return bRet;
107 : }
108 :
109 : // -----------------------------------------------------------------------------
110 :
111 0 : sal_Bool Bitmap::ImplConvolute3( const long* pMatrix, long nDivisor,
112 : const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
113 : {
114 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
115 0 : sal_Bool bRet = sal_False;
116 :
117 0 : if( pReadAcc )
118 : {
119 0 : Bitmap aNewBmp( GetSizePixel(), 24 );
120 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
121 :
122 0 : if( pWriteAcc )
123 : {
124 0 : const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
125 0 : const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
126 0 : long* pColm = new long[ nWidth2 ];
127 0 : long* pRows = new long[ nHeight2 ];
128 0 : BitmapColor* pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
129 0 : BitmapColor* pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
130 0 : BitmapColor* pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
131 0 : BitmapColor* pRowTmp1 = pColRow1;
132 0 : BitmapColor* pRowTmp2 = pColRow2;
133 0 : BitmapColor* pRowTmp3 = pColRow3;
134 : BitmapColor* pColor;
135 : long nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp;
136 0 : long (*pKoeff)[ 256 ] = new long[ 9 ][ 256 ];
137 : long* pTmp;
138 :
139 : // create LUT of products of matrix value and possible color component values
140 0 : for( nY = 0; nY < 9; nY++ )
141 0 : for( nX = nTmp = 0, nMatrixVal = pMatrix[ nY ]; nX < 256; nX++, nTmp += nMatrixVal )
142 0 : pKoeff[ nY ][ nX ] = nTmp;
143 :
144 : // create column LUT
145 0 : for( i = 0; i < nWidth2; i++ )
146 0 : pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
147 :
148 0 : pColm[ nWidth + 1 ] = pColm[ nWidth ];
149 :
150 : // create row LUT
151 0 : for( i = 0; i < nHeight2; i++ )
152 0 : pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
153 :
154 0 : pRows[ nHeight + 1 ] = pRows[ nHeight ];
155 :
156 : // read first three rows of bitmap color
157 0 : for( i = 0; i < nWidth2; i++ )
158 : {
159 0 : pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
160 0 : pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
161 0 : pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
162 : }
163 :
164 : // do convolution
165 0 : for( nY = 0; nY < nHeight; )
166 : {
167 0 : for( nX = 0; nX < nWidth; nX++ )
168 : {
169 : // first row
170 0 : nSumR = ( pTmp = pKoeff[ 0 ] )[ ( pColor = pRowTmp1 + nX )->GetRed() ];
171 0 : nSumG = pTmp[ pColor->GetGreen() ];
172 0 : nSumB = pTmp[ pColor->GetBlue() ];
173 :
174 0 : nSumR += ( pTmp = pKoeff[ 1 ] )[ ( ++pColor )->GetRed() ];
175 0 : nSumG += pTmp[ pColor->GetGreen() ];
176 0 : nSumB += pTmp[ pColor->GetBlue() ];
177 :
178 0 : nSumR += ( pTmp = pKoeff[ 2 ] )[ ( ++pColor )->GetRed() ];
179 0 : nSumG += pTmp[ pColor->GetGreen() ];
180 0 : nSumB += pTmp[ pColor->GetBlue() ];
181 :
182 : // second row
183 0 : nSumR += ( pTmp = pKoeff[ 3 ] )[ ( pColor = pRowTmp2 + nX )->GetRed() ];
184 0 : nSumG += pTmp[ pColor->GetGreen() ];
185 0 : nSumB += pTmp[ pColor->GetBlue() ];
186 :
187 0 : nSumR += ( pTmp = pKoeff[ 4 ] )[ ( ++pColor )->GetRed() ];
188 0 : nSumG += pTmp[ pColor->GetGreen() ];
189 0 : nSumB += pTmp[ pColor->GetBlue() ];
190 :
191 0 : nSumR += ( pTmp = pKoeff[ 5 ] )[ ( ++pColor )->GetRed() ];
192 0 : nSumG += pTmp[ pColor->GetGreen() ];
193 0 : nSumB += pTmp[ pColor->GetBlue() ];
194 :
195 : // third row
196 0 : nSumR += ( pTmp = pKoeff[ 6 ] )[ ( pColor = pRowTmp3 + nX )->GetRed() ];
197 0 : nSumG += pTmp[ pColor->GetGreen() ];
198 0 : nSumB += pTmp[ pColor->GetBlue() ];
199 :
200 0 : nSumR += ( pTmp = pKoeff[ 7 ] )[ ( ++pColor )->GetRed() ];
201 0 : nSumG += pTmp[ pColor->GetGreen() ];
202 0 : nSumB += pTmp[ pColor->GetBlue() ];
203 :
204 0 : nSumR += ( pTmp = pKoeff[ 8 ] )[ ( ++pColor )->GetRed() ];
205 0 : nSumG += pTmp[ pColor->GetGreen() ];
206 0 : nSumB += pTmp[ pColor->GetBlue() ];
207 :
208 : // calculate destination color
209 0 : pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) MinMax( nSumR / nDivisor, 0, 255 ),
210 0 : (sal_uInt8) MinMax( nSumG / nDivisor, 0, 255 ),
211 0 : (sal_uInt8) MinMax( nSumB / nDivisor, 0, 255 ) ) );
212 : }
213 :
214 0 : if( ++nY < nHeight )
215 : {
216 0 : if( pRowTmp1 == pColRow1 )
217 0 : pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
218 0 : else if( pRowTmp1 == pColRow2 )
219 0 : pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
220 : else
221 0 : pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
222 :
223 0 : for( i = 0; i < nWidth2; i++ )
224 0 : pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
225 : }
226 : }
227 :
228 0 : delete[] pKoeff;
229 0 : delete[] (sal_uInt8*) pColRow1;
230 0 : delete[] (sal_uInt8*) pColRow2;
231 0 : delete[] (sal_uInt8*) pColRow3;
232 0 : delete[] pColm;
233 0 : delete[] pRows;
234 :
235 0 : aNewBmp.ReleaseAccess( pWriteAcc );
236 :
237 0 : bRet = sal_True;
238 : }
239 :
240 0 : ReleaseAccess( pReadAcc );
241 :
242 0 : if( bRet )
243 : {
244 0 : const MapMode aMap( maPrefMapMode );
245 0 : const Size aSize( maPrefSize );
246 :
247 0 : *this = aNewBmp;
248 :
249 0 : maPrefMapMode = aMap;
250 0 : maPrefSize = aSize;
251 0 : }
252 : }
253 :
254 0 : return bRet;
255 : }
256 :
257 : // -----------------------------------------------------------------------------
258 :
259 0 : sal_Bool Bitmap::ImplMedianFilter( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
260 : {
261 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
262 0 : sal_Bool bRet = sal_False;
263 :
264 0 : if( pReadAcc )
265 : {
266 0 : Bitmap aNewBmp( GetSizePixel(), 24 );
267 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
268 :
269 0 : if( pWriteAcc )
270 : {
271 0 : const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
272 0 : const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
273 0 : long* pColm = new long[ nWidth2 ];
274 0 : long* pRows = new long[ nHeight2 ];
275 0 : BitmapColor* pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
276 0 : BitmapColor* pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
277 0 : BitmapColor* pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
278 0 : BitmapColor* pRowTmp1 = pColRow1;
279 0 : BitmapColor* pRowTmp2 = pColRow2;
280 0 : BitmapColor* pRowTmp3 = pColRow3;
281 : BitmapColor* pColor;
282 : long nY, nX, i;
283 : long nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9;
284 : long nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9;
285 : long nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9;
286 :
287 : // create column LUT
288 0 : for( i = 0; i < nWidth2; i++ )
289 0 : pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
290 :
291 0 : pColm[ nWidth + 1 ] = pColm[ nWidth ];
292 :
293 : // create row LUT
294 0 : for( i = 0; i < nHeight2; i++ )
295 0 : pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
296 :
297 0 : pRows[ nHeight + 1 ] = pRows[ nHeight ];
298 :
299 : // read first three rows of bitmap color
300 0 : if (nHeight2 > 2)
301 : {
302 0 : for( i = 0; i < nWidth2; i++ )
303 : {
304 0 : pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
305 0 : pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
306 0 : pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
307 : }
308 : }
309 :
310 : // do median filtering
311 0 : for( nY = 0; nY < nHeight; )
312 : {
313 0 : for( nX = 0; nX < nWidth; nX++ )
314 : {
315 0 : nR1 = ( pColor = pRowTmp1 + nX )->GetRed(), nG1 = pColor->GetGreen(), nB1 = pColor->GetBlue();
316 0 : nR2 = ( ++pColor )->GetRed(), nG2 = pColor->GetGreen(), nB2 = pColor->GetBlue();
317 0 : nR3 = ( ++pColor )->GetRed(), nG3 = pColor->GetGreen(), nB3 = pColor->GetBlue();
318 :
319 0 : nR4 = ( pColor = pRowTmp2 + nX )->GetRed(), nG4 = pColor->GetGreen(), nB4 = pColor->GetBlue();
320 0 : nR5 = ( ++pColor )->GetRed(), nG5 = pColor->GetGreen(), nB5 = pColor->GetBlue();
321 0 : nR6 = ( ++pColor )->GetRed(), nG6 = pColor->GetGreen(), nB6 = pColor->GetBlue();
322 :
323 0 : nR7 = ( pColor = pRowTmp3 + nX )->GetRed(), nG7 = pColor->GetGreen(), nB7 = pColor->GetBlue();
324 0 : nR8 = ( ++pColor )->GetRed(), nG8 = pColor->GetGreen(), nB8 = pColor->GetBlue();
325 0 : nR9 = ( ++pColor )->GetRed(), nG9 = pColor->GetGreen(), nB9 = pColor->GetBlue();
326 :
327 0 : MNMX6( nR1, nR2, nR3, nR4, nR5, nR6 );
328 0 : MNMX5( nR7, nR2, nR3, nR4, nR5 );
329 0 : MNMX4( nR8, nR2, nR3, nR4 );
330 0 : MNMX3( nR9, nR2, nR3 );
331 :
332 0 : MNMX6( nG1, nG2, nG3, nG4, nG5, nG6 );
333 0 : MNMX5( nG7, nG2, nG3, nG4, nG5 );
334 0 : MNMX4( nG8, nG2, nG3, nG4 );
335 0 : MNMX3( nG9, nG2, nG3 );
336 :
337 0 : MNMX6( nB1, nB2, nB3, nB4, nB5, nB6 );
338 0 : MNMX5( nB7, nB2, nB3, nB4, nB5 );
339 0 : MNMX4( nB8, nB2, nB3, nB4 );
340 0 : MNMX3( nB9, nB2, nB3 );
341 :
342 : // set destination color
343 0 : pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) nR2, (sal_uInt8) nG2, (sal_uInt8) nB2 ) );
344 : }
345 :
346 0 : if( ++nY < nHeight )
347 : {
348 0 : if( pRowTmp1 == pColRow1 )
349 0 : pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
350 0 : else if( pRowTmp1 == pColRow2 )
351 0 : pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
352 : else
353 0 : pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
354 :
355 0 : for( i = 0; i < nWidth2; i++ )
356 0 : pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
357 : }
358 : }
359 :
360 0 : delete[] (sal_uInt8*) pColRow1;
361 0 : delete[] (sal_uInt8*) pColRow2;
362 0 : delete[] (sal_uInt8*) pColRow3;
363 0 : delete[] pColm;
364 0 : delete[] pRows;
365 :
366 0 : aNewBmp.ReleaseAccess( pWriteAcc );
367 :
368 0 : bRet = sal_True;
369 : }
370 :
371 0 : ReleaseAccess( pReadAcc );
372 :
373 0 : if( bRet )
374 : {
375 0 : const MapMode aMap( maPrefMapMode );
376 0 : const Size aSize( maPrefSize );
377 :
378 0 : *this = aNewBmp;
379 :
380 0 : maPrefMapMode = aMap;
381 0 : maPrefSize = aSize;
382 0 : }
383 : }
384 :
385 0 : return bRet;
386 : }
387 :
388 : // -----------------------------------------------------------------------------
389 :
390 0 : sal_Bool Bitmap::ImplSobelGrey( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
391 : {
392 0 : sal_Bool bRet = ImplMakeGreyscales( 256 );
393 :
394 0 : if( bRet )
395 : {
396 0 : bRet = sal_False;
397 :
398 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
399 :
400 0 : if( pReadAcc )
401 : {
402 0 : Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
403 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
404 :
405 0 : if( pWriteAcc )
406 : {
407 0 : BitmapColor aGrey( (sal_uInt8) 0 );
408 0 : const long nWidth = pWriteAcc->Width();
409 0 : const long nHeight = pWriteAcc->Height();
410 0 : const long nMask111 = -1, nMask121 = 0, nMask131 = 1;
411 0 : const long nMask211 = -2, nMask221 = 0, nMask231 = 2;
412 0 : const long nMask311 = -1, nMask321 = 0, nMask331 = 1;
413 0 : const long nMask112 = 1, nMask122 = 2, nMask132 = 1;
414 0 : const long nMask212 = 0, nMask222 = 0, nMask232 = 0;
415 0 : const long nMask312 = -1, nMask322 = -2, nMask332 = -1;
416 : long nGrey11, nGrey12, nGrey13;
417 : long nGrey21, nGrey22, nGrey23;
418 : long nGrey31, nGrey32, nGrey33;
419 0 : long* pHMap = new long[ nWidth + 2 ];
420 0 : long* pVMap = new long[ nHeight + 2 ];
421 : long nX, nY, nSum1, nSum2;
422 :
423 : // fill mapping tables
424 0 : pHMap[ 0 ] = 0;
425 0 : for( nX = 1; nX <= nWidth; nX++ )
426 0 : pHMap[ nX ] = nX - 1;
427 0 : pHMap[ nWidth + 1 ] = nWidth - 1;
428 :
429 0 : pVMap[ 0 ] = 0;
430 0 : for( nY = 1; nY <= nHeight; nY++ )
431 0 : pVMap[ nY ] = nY - 1;
432 0 : pVMap[ nHeight + 1 ] = nHeight - 1;
433 :
434 0 : for( nY = 0; nY < nHeight ; nY++ )
435 : {
436 0 : nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
437 0 : nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
438 0 : nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
439 0 : nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
440 0 : nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
441 0 : nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
442 0 : nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
443 0 : nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
444 0 : nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
445 :
446 0 : for( nX = 0; nX < nWidth; nX++ )
447 : {
448 0 : nSum1 = nSum2 = 0;
449 :
450 0 : nSum1 += nMask111 * nGrey11;
451 0 : nSum2 += nMask112 * nGrey11;
452 :
453 0 : nSum1 += nMask121 * nGrey12;
454 0 : nSum2 += nMask122 * nGrey12;
455 :
456 0 : nSum1 += nMask131 * nGrey13;
457 0 : nSum2 += nMask132 * nGrey13;
458 :
459 0 : nSum1 += nMask211 * nGrey21;
460 0 : nSum2 += nMask212 * nGrey21;
461 :
462 0 : nSum1 += nMask221 * nGrey22;
463 0 : nSum2 += nMask222 * nGrey22;
464 :
465 0 : nSum1 += nMask231 * nGrey23;
466 0 : nSum2 += nMask232 * nGrey23;
467 :
468 0 : nSum1 += nMask311 * nGrey31;
469 0 : nSum2 += nMask312 * nGrey31;
470 :
471 0 : nSum1 += nMask321 * nGrey32;
472 0 : nSum2 += nMask322 * nGrey32;
473 :
474 0 : nSum1 += nMask331 * nGrey33;
475 0 : nSum2 += nMask332 * nGrey33;
476 :
477 0 : nSum1 = (long) sqrt( (double)( nSum1 * nSum1 + nSum2 * nSum2 ) );
478 0 : aGrey.SetIndex( ~(sal_uInt8) SAL_BOUND( nSum1, 0, 255 ) );
479 0 : pWriteAcc->SetPixel( nY, nX, aGrey );
480 :
481 0 : if( nX < ( nWidth - 1 ) )
482 : {
483 0 : const long nNextX = pHMap[ nX + 3 ];
484 :
485 0 : nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
486 0 : nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
487 0 : nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
488 : }
489 : }
490 : }
491 :
492 0 : delete[] pHMap;
493 0 : delete[] pVMap;
494 0 : aNewBmp.ReleaseAccess( pWriteAcc );
495 0 : bRet = sal_True;
496 : }
497 :
498 0 : ReleaseAccess( pReadAcc );
499 :
500 0 : if( bRet )
501 : {
502 0 : const MapMode aMap( maPrefMapMode );
503 0 : const Size aSize( maPrefSize );
504 :
505 0 : *this = aNewBmp;
506 :
507 0 : maPrefMapMode = aMap;
508 0 : maPrefSize = aSize;
509 0 : }
510 : }
511 : }
512 :
513 0 : return bRet;
514 : }
515 :
516 : // -----------------------------------------------------------------------------
517 :
518 0 : sal_Bool Bitmap::ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
519 : {
520 0 : sal_Bool bRet = ImplMakeGreyscales( 256 );
521 :
522 0 : if( bRet )
523 : {
524 0 : bRet = sal_False;
525 :
526 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
527 :
528 0 : if( pReadAcc )
529 : {
530 0 : Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
531 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
532 :
533 0 : if( pWriteAcc )
534 : {
535 0 : BitmapColor aGrey( (sal_uInt8) 0 );
536 0 : const long nWidth = pWriteAcc->Width();
537 0 : const long nHeight = pWriteAcc->Height();
538 : long nGrey11, nGrey12, nGrey13;
539 : long nGrey21, nGrey22, nGrey23;
540 : long nGrey31, nGrey32, nGrey33;
541 : double fAzim = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
542 0 : ( pFilterParam->maEmbossAngles.mnAzimuthAngle100 * 0.01 ) : 0.0 ) * F_PI180;
543 : double fElev = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
544 0 : ( pFilterParam->maEmbossAngles.mnElevationAngle100 * 0.01 ) : 90.0 ) * F_PI180;
545 0 : long* pHMap = new long[ nWidth + 2 ];
546 0 : long* pVMap = new long[ nHeight + 2 ];
547 : long nX, nY, nNx, nNy, nDotL;
548 0 : const long nLx = FRound( cos( fAzim ) * cos( fElev ) * 255.0 );
549 0 : const long nLy = FRound( sin( fAzim ) * cos( fElev ) * 255.0 );
550 0 : const long nLz = FRound( sin( fElev ) * 255.0 );
551 0 : const long nZ2 = ( ( 6 * 255 ) / 4 ) * ( ( 6 * 255 ) / 4 );
552 0 : const long nNzLz = ( ( 6 * 255 ) / 4 ) * nLz;
553 0 : const sal_uInt8 cLz = (sal_uInt8) SAL_BOUND( nLz, 0, 255 );
554 :
555 : // fill mapping tables
556 0 : pHMap[ 0 ] = 0;
557 0 : for( nX = 1; nX <= nWidth; nX++ )
558 0 : pHMap[ nX ] = nX - 1;
559 0 : pHMap[ nWidth + 1 ] = nWidth - 1;
560 :
561 0 : pVMap[ 0 ] = 0;
562 0 : for( nY = 1; nY <= nHeight; nY++ )
563 0 : pVMap[ nY ] = nY - 1;
564 0 : pVMap[ nHeight + 1 ] = nHeight - 1;
565 :
566 0 : for( nY = 0; nY < nHeight ; nY++ )
567 : {
568 0 : nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
569 0 : nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
570 0 : nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
571 0 : nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
572 0 : nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
573 0 : nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
574 0 : nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
575 0 : nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
576 0 : nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
577 :
578 0 : for( nX = 0; nX < nWidth; nX++ )
579 : {
580 0 : nNx = nGrey11 + nGrey21 + nGrey31 - nGrey13 - nGrey23 - nGrey33;
581 0 : nNy = nGrey31 + nGrey32 + nGrey33 - nGrey11 - nGrey12 - nGrey13;
582 :
583 0 : if( !nNx && !nNy )
584 0 : aGrey.SetIndex( cLz );
585 0 : else if( ( nDotL = nNx * nLx + nNy * nLy +nNzLz ) < 0 )
586 0 : aGrey.SetIndex( 0 );
587 : else
588 : {
589 0 : const double fGrey = nDotL / sqrt( (double)(nNx * nNx + nNy * nNy + nZ2) );
590 0 : aGrey.SetIndex( (sal_uInt8) SAL_BOUND( fGrey, 0, 255 ) );
591 : }
592 :
593 0 : pWriteAcc->SetPixel( nY, nX, aGrey );
594 :
595 0 : if( nX < ( nWidth - 1 ) )
596 : {
597 0 : const long nNextX = pHMap[ nX + 3 ];
598 :
599 0 : nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
600 0 : nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
601 0 : nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
602 : }
603 : }
604 : }
605 :
606 0 : delete[] pHMap;
607 0 : delete[] pVMap;
608 0 : aNewBmp.ReleaseAccess( pWriteAcc );
609 0 : bRet = sal_True;
610 : }
611 :
612 0 : ReleaseAccess( pReadAcc );
613 :
614 0 : if( bRet )
615 : {
616 0 : const MapMode aMap( maPrefMapMode );
617 0 : const Size aSize( maPrefSize );
618 :
619 0 : *this = aNewBmp;
620 :
621 0 : maPrefMapMode = aMap;
622 0 : maPrefSize = aSize;
623 0 : }
624 : }
625 : }
626 :
627 0 : return bRet;
628 : }
629 :
630 : // -----------------------------------------------------------------------------
631 :
632 0 : sal_Bool Bitmap::ImplSolarize( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
633 : {
634 0 : sal_Bool bRet = sal_False;
635 0 : BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
636 :
637 0 : if( pWriteAcc )
638 : {
639 : const sal_uInt8 cThreshold = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SOLARIZE ) ?
640 0 : pFilterParam->mcSolarGreyThreshold : 128;
641 :
642 0 : if( pWriteAcc->HasPalette() )
643 : {
644 0 : const BitmapPalette& rPal = pWriteAcc->GetPalette();
645 :
646 0 : for( sal_uInt16 i = 0, nCount = rPal.GetEntryCount(); i < nCount; i++ )
647 : {
648 0 : if( rPal[ i ].GetLuminance() >= cThreshold )
649 : {
650 0 : BitmapColor aCol( rPal[ i ] );
651 0 : pWriteAcc->SetPaletteColor( i, aCol.Invert() );
652 : }
653 : }
654 : }
655 : else
656 : {
657 0 : BitmapColor aCol;
658 0 : const long nWidth = pWriteAcc->Width();
659 0 : const long nHeight = pWriteAcc->Height();
660 :
661 0 : for( long nY = 0; nY < nHeight ; nY++ )
662 : {
663 0 : for( long nX = 0; nX < nWidth; nX++ )
664 : {
665 0 : aCol = pWriteAcc->GetPixel( nY, nX );
666 :
667 0 : if( aCol.GetLuminance() >= cThreshold )
668 0 : pWriteAcc->SetPixel( nY, nX, aCol.Invert() );
669 : }
670 0 : }
671 : }
672 :
673 0 : ReleaseAccess( pWriteAcc );
674 0 : bRet = sal_True;
675 : }
676 :
677 0 : return bRet;
678 : }
679 :
680 : // -----------------------------------------------------------------------------
681 :
682 0 : sal_Bool Bitmap::ImplSepia( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
683 : {
684 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
685 0 : sal_Bool bRet = sal_False;
686 :
687 0 : if( pReadAcc )
688 : {
689 : long nSepiaPercent = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SEPIA ) ?
690 0 : pFilterParam->mcSolarGreyThreshold : 10;
691 0 : const long nSepia = 10000 - 100 * SAL_BOUND( nSepiaPercent, 0, 100 );
692 0 : BitmapPalette aSepiaPal( 256 );
693 :
694 : DBG_ASSERT( nSepiaPercent <= 100, "Bitmap::ImplSepia(): sepia value out of range; defaulting to 100%" );
695 :
696 0 : for( sal_uInt16 i = 0; i < 256; i++ )
697 : {
698 0 : BitmapColor& rCol = aSepiaPal[ i ];
699 0 : const sal_uInt8 cSepiaValue = (sal_uInt8) ( ( nSepia * i ) / 10000 );
700 :
701 0 : rCol.SetRed( (sal_uInt8) i );
702 0 : rCol.SetGreen( cSepiaValue );
703 0 : rCol.SetBlue( cSepiaValue );
704 : }
705 :
706 0 : Bitmap aNewBmp( GetSizePixel(), 8, &aSepiaPal );
707 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
708 :
709 0 : if( pWriteAcc )
710 : {
711 0 : BitmapColor aCol( (sal_uInt8) 0 );
712 0 : const long nWidth = pWriteAcc->Width();
713 0 : const long nHeight = pWriteAcc->Height();
714 :
715 0 : if( pReadAcc->HasPalette() )
716 : {
717 0 : for( long nY = 0; nY < nHeight ; nY++ )
718 : {
719 0 : const sal_uInt16 nPalCount = pReadAcc->GetPaletteEntryCount();
720 0 : sal_uInt8* pIndexMap = new sal_uInt8[ nPalCount ];
721 :
722 0 : for( sal_uInt16 i = 0; i < nPalCount; i++ )
723 0 : pIndexMap[ i ] = pReadAcc->GetPaletteColor( i ).GetLuminance();
724 :
725 0 : for( long nX = 0; nX < nWidth; nX++ )
726 : {
727 0 : aCol.SetIndex( pIndexMap[ pReadAcc->GetPixel( nY, nX ).GetIndex() ] );
728 0 : pWriteAcc->SetPixel( nY, nX, aCol );
729 : }
730 :
731 0 : delete[] pIndexMap;
732 : }
733 : }
734 : else
735 : {
736 0 : for( long nY = 0; nY < nHeight ; nY++ )
737 : {
738 0 : for( long nX = 0; nX < nWidth; nX++ )
739 : {
740 0 : aCol.SetIndex( pReadAcc->GetPixel( nY, nX ).GetLuminance() );
741 0 : pWriteAcc->SetPixel( nY, nX, aCol );
742 : }
743 : }
744 : }
745 :
746 0 : aNewBmp.ReleaseAccess( pWriteAcc );
747 0 : bRet = sal_True;
748 : }
749 :
750 0 : ReleaseAccess( pReadAcc );
751 :
752 0 : if( bRet )
753 : {
754 0 : const MapMode aMap( maPrefMapMode );
755 0 : const Size aSize( maPrefSize );
756 :
757 0 : *this = aNewBmp;
758 :
759 0 : maPrefMapMode = aMap;
760 0 : maPrefSize = aSize;
761 0 : }
762 : }
763 :
764 0 : return bRet;
765 : }
766 :
767 : // -----------------------------------------------------------------------------
768 :
769 0 : sal_Bool Bitmap::ImplMosaic( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
770 : {
771 : sal_uLong nTileWidth = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
772 0 : pFilterParam->maMosaicTileSize.mnTileWidth : 4;
773 : sal_uLong nTileHeight = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
774 0 : pFilterParam->maMosaicTileSize.mnTileHeight : 4;
775 0 : sal_Bool bRet = sal_False;
776 :
777 0 : if( !nTileWidth )
778 0 : nTileWidth = 1;
779 :
780 0 : if( !nTileHeight )
781 0 : nTileHeight = 1;
782 :
783 0 : if( nTileWidth > 1 || nTileHeight > 1 )
784 : {
785 : Bitmap* pNewBmp;
786 : BitmapReadAccess* pReadAcc;
787 : BitmapWriteAccess* pWriteAcc;
788 :
789 0 : if( GetBitCount() > 8 )
790 : {
791 0 : pNewBmp = NULL;
792 0 : pReadAcc = pWriteAcc = AcquireWriteAccess();
793 : }
794 : else
795 : {
796 0 : pNewBmp = new Bitmap( GetSizePixel(), 24 );
797 0 : pReadAcc = AcquireReadAccess();
798 0 : pWriteAcc = pNewBmp->AcquireWriteAccess();
799 : }
800 :
801 0 : if( pReadAcc && pWriteAcc )
802 : {
803 0 : BitmapColor aCol;
804 0 : long nWidth = pReadAcc->Width();
805 0 : long nHeight = pReadAcc->Height();
806 : long nX, nY, nX1, nX2, nY1, nY2, nSumR, nSumG, nSumB;
807 : double fArea_1;
808 :
809 0 : nY1 = 0; nY2 = nTileHeight - 1;
810 :
811 0 : if( nY2 >= nHeight )
812 0 : nY2 = nHeight - 1;
813 :
814 0 : do
815 : {
816 0 : nX1 = 0; nX2 = nTileWidth - 1;
817 :
818 0 : if( nX2 >= nWidth )
819 0 : nX2 = nWidth - 1;
820 :
821 0 : fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
822 :
823 0 : if( !pNewBmp )
824 : {
825 0 : do
826 : {
827 0 : for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
828 : {
829 0 : for( nX = nX1; nX <= nX2; nX++ )
830 : {
831 0 : aCol = pReadAcc->GetPixel( nY, nX );
832 0 : nSumR += aCol.GetRed();
833 0 : nSumG += aCol.GetGreen();
834 0 : nSumB += aCol.GetBlue();
835 : }
836 : }
837 :
838 0 : aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
839 0 : aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
840 0 : aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
841 :
842 0 : for( nY = nY1; nY <= nY2; nY++ )
843 0 : for( nX = nX1; nX <= nX2; nX++ )
844 0 : pWriteAcc->SetPixel( nY, nX, aCol );
845 :
846 0 : nX1 += nTileWidth; nX2 += nTileWidth;
847 :
848 0 : if( nX2 >= nWidth )
849 : {
850 0 : nX2 = nWidth - 1;
851 0 : fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
852 : }
853 : }
854 : while( nX1 < nWidth );
855 : }
856 : else
857 : {
858 0 : do
859 : {
860 0 : for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
861 : {
862 0 : for( nX = nX1; nX <= nX2; nX++ )
863 : {
864 0 : const BitmapColor& rCol = pReadAcc->GetPaletteColor( (sal_uInt8) pReadAcc->GetPixel( nY, nX ) );
865 0 : nSumR += rCol.GetRed();
866 0 : nSumG += rCol.GetGreen();
867 0 : nSumB += rCol.GetBlue();
868 : }
869 : }
870 :
871 0 : aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
872 0 : aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
873 0 : aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
874 :
875 0 : for( nY = nY1; nY <= nY2; nY++ )
876 0 : for( nX = nX1; nX <= nX2; nX++ )
877 0 : pWriteAcc->SetPixel( nY, nX, aCol );
878 :
879 0 : nX1 += nTileWidth; nX2 += nTileWidth;
880 :
881 0 : if( nX2 >= nWidth )
882 : {
883 0 : nX2 = nWidth - 1;
884 0 : fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
885 : }
886 : }
887 : while( nX1 < nWidth );
888 : }
889 :
890 0 : nY1 += nTileHeight; nY2 += nTileHeight;
891 :
892 0 : if( nY2 >= nHeight )
893 0 : nY2 = nHeight - 1;
894 : }
895 : while( nY1 < nHeight );
896 :
897 0 : bRet = sal_True;
898 : }
899 :
900 0 : ReleaseAccess( pReadAcc );
901 :
902 0 : if( pNewBmp )
903 : {
904 0 : pNewBmp->ReleaseAccess( pWriteAcc );
905 :
906 0 : if( bRet )
907 : {
908 0 : const MapMode aMap( maPrefMapMode );
909 0 : const Size aSize( maPrefSize );
910 :
911 0 : *this = *pNewBmp;
912 :
913 0 : maPrefMapMode = aMap;
914 0 : maPrefSize = aSize;
915 : }
916 :
917 0 : delete pNewBmp;
918 0 : }
919 : }
920 : else
921 0 : bRet = sal_True;
922 :
923 0 : return bRet;
924 : }
925 :
926 : // -----------------------------------------------------------------------------
927 :
928 : struct PopArtEntry
929 : {
930 : sal_uInt32 mnIndex;
931 : sal_uInt32 mnCount;
932 : };
933 :
934 : // ------------------------------------------------------------------------
935 :
936 0 : extern "C" int SAL_CALL ImplPopArtCmpFnc( const void* p1, const void* p2 )
937 : {
938 : int nRet;
939 :
940 0 : if( ( (PopArtEntry*) p1 )->mnCount < ( (PopArtEntry*) p2 )->mnCount )
941 0 : nRet = 1;
942 0 : else if( ( (PopArtEntry*) p1 )->mnCount == ( (PopArtEntry*) p2 )->mnCount )
943 0 : nRet = 0;
944 : else
945 0 : nRet = -1;
946 :
947 0 : return nRet;
948 : }
949 :
950 : // ------------------------------------------------------------------------
951 :
952 0 : sal_Bool Bitmap::ImplPopArt( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
953 : {
954 0 : sal_Bool bRet = ( GetBitCount() > 8 ) ? Convert( BMP_CONVERSION_8BIT_COLORS ) : sal_True;
955 :
956 0 : if( bRet )
957 : {
958 0 : bRet = sal_False;
959 :
960 0 : BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
961 :
962 0 : if( pWriteAcc )
963 : {
964 0 : const long nWidth = pWriteAcc->Width();
965 0 : const long nHeight = pWriteAcc->Height();
966 0 : const sal_uLong nEntryCount = 1 << pWriteAcc->GetBitCount();
967 : sal_uLong n;
968 0 : PopArtEntry* pPopArtTable = new PopArtEntry[ nEntryCount ];
969 :
970 0 : for( n = 0; n < nEntryCount; n++ )
971 : {
972 0 : PopArtEntry& rEntry = pPopArtTable[ n ];
973 0 : rEntry.mnIndex = (sal_uInt16) n;
974 0 : rEntry.mnCount = 0;
975 : }
976 :
977 : // get pixel count for each palette entry
978 0 : for( long nY = 0; nY < nHeight ; nY++ )
979 0 : for( long nX = 0; nX < nWidth; nX++ )
980 0 : pPopArtTable[ pWriteAcc->GetPixel( nY, nX ).GetIndex() ].mnCount++;
981 :
982 : // sort table
983 0 : qsort( pPopArtTable, nEntryCount, sizeof( PopArtEntry ), ImplPopArtCmpFnc );
984 :
985 : // get last used entry
986 : sal_uLong nFirstEntry;
987 0 : sal_uLong nLastEntry = 0;
988 :
989 0 : for( n = 0; n < nEntryCount; n++ )
990 0 : if( pPopArtTable[ n ].mnCount )
991 0 : nLastEntry = n;
992 :
993 : // rotate palette (one entry)
994 0 : const BitmapColor aFirstCol( pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ 0 ].mnIndex) ) );
995 0 : for( nFirstEntry = 0; nFirstEntry < nLastEntry; nFirstEntry++ )
996 : {
997 0 : pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry ].mnIndex),
998 0 : pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry + 1 ].mnIndex) ) );
999 : }
1000 0 : pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nLastEntry ].mnIndex), aFirstCol );
1001 :
1002 : // cleanup
1003 0 : delete[] pPopArtTable;
1004 0 : ReleaseAccess( pWriteAcc );
1005 0 : bRet = sal_True;
1006 : }
1007 : }
1008 :
1009 0 : return bRet;
1010 : }
1011 :
1012 :
1013 0 : double* MakeBlurKernel(const double radius, int& rows) {
1014 0 : int intRadius = (int) radius + 1.0;
1015 0 : rows = intRadius * 2 + 1;
1016 0 : double* matrix = new double[rows];
1017 :
1018 0 : double sigma = radius / 3;
1019 0 : double radius2 = radius * radius;
1020 0 : int index = 0;
1021 0 : for (int row = -intRadius; row <= intRadius; row++)
1022 : {
1023 0 : double distance = row*row;
1024 0 : if (distance > radius2) {
1025 0 : matrix[index] = 0.0;
1026 : }else {
1027 0 : matrix[index] = exp( -distance / (2.0 * sigma * sigma) ) / sqrt( 2.0 * M_PI * sigma );
1028 : }
1029 0 : index++;
1030 : }
1031 0 : return matrix;
1032 : }
1033 :
1034 0 : void Bitmap::ImplBlurContributions( const int aSize, const int aNumberOfContributions,
1035 : double* pBlurVector, double*& pWeights, int*& pPixels, int*& pCount )
1036 : {
1037 0 : pWeights = new double[ aSize*aNumberOfContributions ];
1038 0 : pPixels = new int[ aSize*aNumberOfContributions ];
1039 0 : pCount = new int[ aSize ];
1040 :
1041 : int aLeft, aRight, aCurrentCount, aPixelIndex;
1042 : double aWeight;
1043 :
1044 0 : for ( int i = 0; i < aSize; i++ )
1045 : {
1046 0 : aLeft = (int) i - aNumberOfContributions / 2;
1047 0 : aRight = (int) i + aNumberOfContributions / 2;
1048 0 : aCurrentCount = 0;
1049 0 : for ( int j = aLeft; j <= aRight; j++ )
1050 : {
1051 0 : aWeight = pBlurVector[aCurrentCount];
1052 :
1053 : // Mirror edges
1054 0 : if (j < 0)
1055 : {
1056 0 : aPixelIndex = -j;
1057 : }
1058 0 : else if ( j >= aSize )
1059 : {
1060 0 : aPixelIndex = (aSize - j) + aSize - 1;
1061 : }
1062 : else
1063 : {
1064 0 : aPixelIndex = j;
1065 : }
1066 :
1067 : // Edge case for small bitmaps
1068 0 : if ( aPixelIndex < 0 || aPixelIndex >= aSize )
1069 : {
1070 0 : aWeight = 0.0;
1071 : }
1072 :
1073 0 : pWeights[ i*aNumberOfContributions + aCurrentCount ] = aWeight;
1074 0 : pPixels[ i*aNumberOfContributions + aCurrentCount ] = aPixelIndex;
1075 :
1076 0 : aCurrentCount++;
1077 : }
1078 0 : pCount[ i ] = aCurrentCount;
1079 : }
1080 0 : }
1081 :
1082 : // Separable Gaussian Blur
1083 : //
1084 : // Separable Gaussian Blur filter and accepts a blur radius
1085 : // as a parameter so the user can change the strength of the blur.
1086 : // Radius of 1.0 is 3 * standard deviation of gauss function.
1087 : //
1088 : // Separable Blur implementation uses 2x separable 1D convolution
1089 : // to process the image.
1090 0 : bool Bitmap::ImplSeparableBlurFilter(const double radius)
1091 : {
1092 0 : const long nWidth = GetSizePixel().Width();
1093 0 : const long nHeight = GetSizePixel().Height();
1094 :
1095 : // Prepare Blur Vector
1096 : int aNumberOfContributions;
1097 0 : double* pBlurVector = MakeBlurKernel(radius, aNumberOfContributions);
1098 :
1099 : double* pWeights;
1100 : int* pPixels;
1101 : int* pCount;
1102 :
1103 : // Do horizontal filtering
1104 0 : ImplBlurContributions( nWidth, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount);
1105 :
1106 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1107 :
1108 : // switch coordinates as convolution pass transposes result
1109 0 : Bitmap aNewBitmap( Size( nHeight, nWidth ), 24 );
1110 :
1111 0 : bool bResult = ImplConvolutionPass( aNewBitmap, nWidth, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount );
1112 :
1113 : // Cleanup
1114 0 : ReleaseAccess( pReadAcc );
1115 0 : delete[] pWeights;
1116 0 : delete[] pPixels;
1117 0 : delete[] pCount;
1118 :
1119 0 : if ( !bResult )
1120 0 : return bResult;
1121 :
1122 : // Swap current bitmap with new bitmap
1123 0 : ImplAssignWithSize( aNewBitmap );
1124 :
1125 : // Do vertical filtering
1126 0 : ImplBlurContributions(nHeight, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount );
1127 :
1128 0 : pReadAcc = AcquireReadAccess();
1129 0 : aNewBitmap = Bitmap( Size( nWidth, nHeight ), 24 );
1130 0 : bResult = ImplConvolutionPass( aNewBitmap, nHeight, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount );
1131 :
1132 : // Cleanup
1133 0 : ReleaseAccess( pReadAcc );
1134 0 : delete[] pWeights;
1135 0 : delete[] pCount;
1136 0 : delete[] pPixels;
1137 0 : delete[] pBlurVector;
1138 :
1139 0 : if ( !bResult )
1140 0 : return bResult;
1141 :
1142 : // Swap current bitmap with new bitmap
1143 0 : ImplAssignWithSize( aNewBitmap );
1144 :
1145 0 : return true;
1146 : }
1147 :
1148 : // Separable Unsharepn Mask filter is actually a substracted blured
1149 : // image from the original image.
1150 0 : bool Bitmap::ImplSeparableUnsharpenFilter(const double radius) {
1151 0 : const long nWidth = GetSizePixel().Width();
1152 0 : const long nHeight = GetSizePixel().Height();
1153 :
1154 0 : Bitmap aBlur( *this );
1155 0 : aBlur.ImplSeparableBlurFilter(-radius);
1156 :
1157 : // Amount of unsharpening effect on image - currently set to a fixed value
1158 0 : double aAmount = 2.0;
1159 :
1160 0 : Bitmap aResultBitmap( Size( nWidth, nHeight ), 24);
1161 :
1162 0 : BitmapReadAccess* pReadAccBlur = aBlur.AcquireReadAccess();
1163 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1164 0 : BitmapWriteAccess* pWriteAcc = aResultBitmap.AcquireWriteAccess();
1165 :
1166 0 : BitmapColor aColor, aColorBlur;
1167 :
1168 : // For all pixels in original image substract pixels values from blured image.
1169 0 : for( int x = 0; x < nWidth; x++ )
1170 : {
1171 0 : for( int y = 0; y < nHeight; y++ )
1172 : {
1173 0 : aColorBlur = pReadAccBlur->GetPixel( y , x );
1174 0 : if( pReadAccBlur->HasPalette() )
1175 : {
1176 0 : pReadAccBlur->GetPaletteColor( aColorBlur );
1177 : }
1178 :
1179 0 : aColor = pReadAcc->GetPixel( y , x );
1180 0 : if( pReadAcc->HasPalette() )
1181 : {
1182 0 : aColor = pReadAcc->GetPaletteColor( aColor );
1183 : }
1184 :
1185 : BitmapColor aResultColor(
1186 0 : (sal_uInt8) MinMax( aColor.GetRed() + (aColor.GetRed() - aColorBlur.GetRed()) * aAmount, 0, 255 ),
1187 0 : (sal_uInt8) MinMax( aColor.GetGreen() + (aColor.GetGreen() - aColorBlur.GetGreen()) * aAmount, 0, 255 ),
1188 0 : (sal_uInt8) MinMax( aColor.GetBlue() + (aColor.GetBlue() - aColorBlur.GetBlue()) * aAmount, 0, 255 ) );
1189 :
1190 0 : pWriteAcc->SetPixel( y, x, aResultColor );
1191 0 : }
1192 : }
1193 :
1194 0 : ReleaseAccess( pWriteAcc );
1195 0 : ReleaseAccess( pReadAcc );
1196 0 : ReleaseAccess( pReadAccBlur );
1197 0 : ImplAssignWithSize ( aResultBitmap );
1198 0 : return true;
1199 : }
1200 :
1201 :
1202 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|