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