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 <vcl/salbtype.hxx> 28 #include <vcl/bitmap.hxx> 29 #include <vcl/bmpacc.hxx> 30 31 #include <impbmp.hxx> 32 33 #include <string.h> 34 35 // -------------------- 36 // - BitmapReadAccess - 37 // -------------------- 38 39 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) : 40 mpBuffer ( NULL ), 41 mpScanBuf ( NULL ), 42 mFncGetPixel ( NULL ), 43 mFncSetPixel ( NULL ), 44 mbModify ( bModify ) 45 { 46 ImplCreate( rBitmap ); 47 } 48 49 // ------------------------------------------------------------------ 50 51 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) : 52 mpBuffer ( NULL ), 53 mpScanBuf ( NULL ), 54 mFncGetPixel ( NULL ), 55 mFncSetPixel ( NULL ), 56 mbModify ( sal_False ) 57 { 58 ImplCreate( rBitmap ); 59 } 60 61 // ------------------------------------------------------------------ 62 63 BitmapReadAccess::~BitmapReadAccess() 64 { 65 ImplDestroy(); 66 } 67 68 // ------------------------------------------------------------------ 69 70 void BitmapReadAccess::ImplCreate( Bitmap& rBitmap ) 71 { 72 ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); 73 74 DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" ); 75 76 if( pImpBmp ) 77 { 78 if( mbModify && !maBitmap.ImplGetImpBitmap() ) 79 { 80 rBitmap.ImplMakeUnique(); 81 pImpBmp = rBitmap.ImplGetImpBitmap(); 82 } 83 else 84 { 85 DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2, 86 "Unpredictable results: bitmap is referenced more than once!" ); 87 } 88 89 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); 90 91 if( !mpBuffer ) 92 { 93 ImpBitmap* pNewImpBmp = new ImpBitmap; 94 95 if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) ) 96 { 97 pImpBmp = pNewImpBmp; 98 rBitmap.ImplSetImpBitmap( pImpBmp ); 99 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); 100 } 101 else 102 delete pNewImpBmp; 103 } 104 105 if( mpBuffer ) 106 { 107 const long nHeight = mpBuffer->mnHeight; 108 Scanline pTmpLine = mpBuffer->mpBits; 109 110 try { 111 mpScanBuf = new Scanline[ nHeight ]; 112 } catch (std::bad_alloc &) { 113 mpScanBuf = NULL; 114 } 115 if (mpScanBuf) { 116 maColorMask = mpBuffer->maColorMask; 117 118 if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) 119 { 120 for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize ) 121 mpScanBuf[ nY ] = pTmpLine; 122 } 123 else 124 { 125 for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize ) 126 mpScanBuf[ nY ] = pTmpLine; 127 } 128 129 if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) ) 130 { 131 delete[] mpScanBuf; 132 mpScanBuf = NULL; 133 134 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); 135 mpBuffer = NULL; 136 } 137 else 138 maBitmap = rBitmap; 139 } else { 140 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); 141 mpBuffer = NULL; 142 } 143 } 144 } 145 } 146 147 // ------------------------------------------------------------------ 148 149 void BitmapReadAccess::ImplDestroy() 150 { 151 ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); 152 153 delete[] mpScanBuf; 154 mpScanBuf = NULL; 155 156 if( mpBuffer && pImpBmp ) 157 { 158 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); 159 mpBuffer = NULL; 160 } 161 } 162 163 // ------------------------------------------------------------------ 164 165 sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat ) 166 { 167 sal_Bool bRet = sal_True; 168 169 switch( nFormat ) 170 { 171 CASE_FORMAT( _1BIT_MSB_PAL ) 172 CASE_FORMAT( _1BIT_LSB_PAL ) 173 CASE_FORMAT( _4BIT_MSN_PAL ) 174 CASE_FORMAT( _4BIT_LSN_PAL ) 175 CASE_FORMAT( _8BIT_PAL ) 176 CASE_FORMAT( _8BIT_TC_MASK ) 177 CASE_FORMAT( _16BIT_TC_MSB_MASK ) 178 CASE_FORMAT( _16BIT_TC_LSB_MASK ) 179 CASE_FORMAT( _24BIT_TC_BGR ) 180 CASE_FORMAT( _24BIT_TC_RGB ) 181 CASE_FORMAT( _24BIT_TC_MASK ) 182 CASE_FORMAT( _32BIT_TC_ABGR ) 183 CASE_FORMAT( _32BIT_TC_ARGB ) 184 CASE_FORMAT( _32BIT_TC_BGRA ) 185 CASE_FORMAT( _32BIT_TC_RGBA ) 186 CASE_FORMAT( _32BIT_TC_MASK ) 187 188 default: 189 bRet = sal_False; 190 break; 191 } 192 193 return bRet; 194 } 195 196 // ------------------------------------------------------------------ 197 198 void BitmapReadAccess::ImplZeroInitUnusedBits() 199 { 200 const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize(); 201 202 if( nWidth && nHeight && nScanSize && GetBuffer() ) 203 { 204 sal_uInt32 nBits; 205 bool bMsb; 206 207 const sal_uLong nScanlineFormat = GetScanlineFormat(); 208 switch( nScanlineFormat ) 209 { 210 case( BMP_FORMAT_1BIT_MSB_PAL ): 211 nBits = 1; 212 bMsb = true; 213 break; 214 215 case( BMP_FORMAT_1BIT_LSB_PAL ): 216 nBits = 1; 217 bMsb = false; 218 break; 219 220 case( BMP_FORMAT_4BIT_MSN_PAL ): 221 nBits = 4; 222 bMsb = true; 223 break; 224 225 case( BMP_FORMAT_4BIT_LSN_PAL ): 226 nBits = 4; 227 bMsb = false; 228 break; 229 230 case( BMP_FORMAT_8BIT_PAL ): 231 case( BMP_FORMAT_8BIT_TC_MASK ): 232 bMsb = true; 233 nBits = 8; 234 break; 235 236 case( BMP_FORMAT_16BIT_TC_MSB_MASK ): 237 case( BMP_FORMAT_16BIT_TC_LSB_MASK ): 238 bMsb = true; 239 nBits = 16; 240 break; 241 242 case( BMP_FORMAT_24BIT_TC_BGR ): 243 case( BMP_FORMAT_24BIT_TC_RGB ): 244 case( BMP_FORMAT_24BIT_TC_MASK ): 245 bMsb = true; 246 nBits = 24; 247 break; 248 249 case( BMP_FORMAT_32BIT_TC_ABGR ): 250 case( BMP_FORMAT_32BIT_TC_ARGB ): 251 case( BMP_FORMAT_32BIT_TC_BGRA ): 252 case( BMP_FORMAT_32BIT_TC_RGBA ): 253 case( BMP_FORMAT_32BIT_TC_MASK ): 254 bMsb = true; 255 nBits = 32; 256 break; 257 258 default: 259 { 260 DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format"); 261 nBits = 0; 262 bMsb = true; 263 } 264 break; 265 } 266 267 nBits *= nWidth; 268 if( nScanSize % 4 || !bMsb ) 269 { 270 DBG_ASSERT( 8*nScanSize >= nBits, 271 "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!"); 272 const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits; 273 if( nLeftOverBits != 0 ) // else there is really nothing to do 274 { 275 const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U; 276 sal_uInt8 nMask; 277 278 if( bMsb ) 279 nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL)); 280 else 281 nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL)); 282 283 sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes ); 284 for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize ) 285 { 286 *pLastBytes &= nMask; 287 for( sal_uInt32 j = 1; j < nBytes; j++ ) 288 pLastBytes[j] = 0; 289 } 290 } 291 } 292 else if( nBits & 0x1f ) 293 { 294 sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits ); 295 sal_uInt8* pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 ); 296 297 #ifdef OSL_LITENDIAN 298 nMask = SWAPLONG( nMask ); 299 #endif 300 for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize ) 301 ( *(sal_uInt32*) pLast4Bytes ) &= nMask; 302 } 303 } 304 } 305 306 // ------------------------------------------------------------------ 307 308 void BitmapReadAccess::Flush() 309 { 310 ImplDestroy(); 311 } 312 313 // ------------------------------------------------------------------ 314 315 void BitmapReadAccess::ReAccess( sal_Bool bModify ) 316 { 317 const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); 318 319 DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" ); 320 DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" ); 321 322 if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) ) 323 { 324 mbModify = bModify; 325 ImplCreate( maBitmap ); 326 } 327 } 328 329 // ------------------------------------------------------------------ 330 331 sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const 332 { 333 return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 ); 334 } 335 336 BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const 337 { 338 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative 339 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!) 340 if(mpBuffer && fX >= 0.0 && fY >= 0.0) 341 { 342 const sal_Int32 nX(static_cast< sal_Int32 >(fX)); 343 const sal_Int32 nY(static_cast< sal_Int32 >(fY)); 344 345 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 346 { 347 // get base-return value from inside pixel 348 BitmapColor aRetval(GetColor(nY, nX)); 349 350 // calculate deltas and indices for neighbour accesses 351 sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255] 352 sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255] 353 sal_Int16 nIndX(0); 354 sal_Int16 nIndY(0); 355 356 if(nDeltaX > 0) 357 { 358 nIndX = nX + 1; 359 } 360 else 361 { 362 nIndX = nX - 1; 363 nDeltaX = -nDeltaX; 364 } 365 366 if(nDeltaY > 0) 367 { 368 nIndY = nY + 1; 369 } 370 else 371 { 372 nIndY = nY - 1; 373 nDeltaY = -nDeltaY; 374 } 375 376 // get right/left neighbour 377 BitmapColor aXCol(rFallback); 378 379 if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth) 380 { 381 aXCol = GetColor(nY, nIndX); 382 } 383 384 // get top/bottom neighbour 385 BitmapColor aYCol(rFallback); 386 387 if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight) 388 { 389 aYCol = GetColor(nIndY, nX); 390 } 391 392 // get one of four edge neighbours 393 BitmapColor aXYCol(rFallback); 394 395 if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight) 396 { 397 aXYCol = GetColor(nIndY, nIndX); 398 } 399 400 // merge return value with right/left neighbour 401 if(aXCol != aRetval) 402 { 403 aRetval.Merge(aXCol, 255 - nDeltaX); 404 } 405 406 // merge top/bottom neighbour with edge 407 if(aYCol != aXYCol) 408 { 409 aYCol.Merge(aXYCol, 255 - nDeltaX); 410 } 411 412 // merge return value with already merged top/bottom neighbour 413 if(aRetval != aYCol) 414 { 415 aRetval.Merge(aYCol, 255 - nDeltaY); 416 } 417 418 return aRetval; 419 } 420 } 421 422 return rFallback; 423 } 424 425 BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const 426 { 427 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative 428 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!) 429 if(mpBuffer && fX >= 0.0 && fY >= 0.0) 430 { 431 const sal_Int32 nX(static_cast< sal_Int32 >(fX)); 432 const sal_Int32 nY(static_cast< sal_Int32 >(fY)); 433 434 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 435 { 436 return GetColor(nY, nX); 437 } 438 } 439 440 return rFallback; 441 } 442 443 BitmapColor BitmapReadAccess::GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const 444 { 445 if(mpBuffer) 446 { 447 if(nX >= 0 && nY >= 0 && nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 448 { 449 return GetColor(nY, nX); 450 } 451 } 452 453 return rFallback; 454 } 455 456 // --------------------- 457 // - BitmapWriteAccess - 458 // --------------------- 459 460 BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) : 461 BitmapReadAccess( rBitmap, sal_True ), 462 mpLineColor ( NULL ), 463 mpFillColor ( NULL ) 464 { 465 } 466 467 // ------------------------------------------------------------------ 468 469 BitmapWriteAccess::~BitmapWriteAccess() 470 { 471 delete mpLineColor; 472 delete mpFillColor; 473 } 474 475 // ------------------------------------------------------------------ 476 477 void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc ) 478 { 479 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); 480 DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" ); 481 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); 482 483 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && 484 ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) ) 485 { 486 memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() ); 487 } 488 else 489 // TODO: use fastbmp infrastructure 490 for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ ) 491 SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) ); 492 } 493 494 // ------------------------------------------------------------------ 495 496 void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline, 497 sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize ) 498 { 499 const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat ); 500 501 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); 502 DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) || 503 ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ), 504 "No copying possible between palette and non palette scanlines!" ); 505 506 const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize ); 507 508 if( nCount ) 509 { 510 if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) ) 511 memcpy( mpScanBuf[ nY ], aSrcScanline, nCount ); 512 else 513 { 514 DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK && 515 nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK && 516 nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK, 517 "No support for pixel formats with color masks yet!" ); 518 519 // TODO: use fastbmp infrastructure 520 FncGetPixel pFncGetPixel; 521 522 switch( nFormat ) 523 { 524 case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break; 525 case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break; 526 case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break; 527 case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break; 528 case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break; 529 case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break; 530 case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break; 531 case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break; 532 case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break; 533 case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break; 534 case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break; 535 case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break; 536 case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break; 537 case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break; 538 case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break; 539 case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break; 540 541 default: 542 pFncGetPixel = NULL; 543 break; 544 } 545 546 if( pFncGetPixel ) 547 { 548 const ColorMask aDummyMask; 549 550 for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ ) 551 SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) ); 552 } 553 } 554 } 555 } 556 557 558 // ------------------------------------------------------------------ 559 560 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc ) 561 { 562 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); 563 564 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && 565 ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) ) 566 { 567 const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); 568 const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize; 569 570 memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount ); 571 } 572 else 573 for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ ) 574 CopyScanline( nY, rReadAcc ); 575 } 576