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