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 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 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 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 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 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 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 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 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 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 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