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