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