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