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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_vcl.hxx" 24 25 #include <vcl/salbtype.hxx> 26 #include <vcl/dibtools.hxx> 27 #include <tools/zcodec.hxx> 28 #include <tools/stream.hxx> 29 #include <vcl/bitmapex.hxx> 30 #include <vcl/bmpacc.hxx> 31 #include <vcl/outdev.hxx> 32 33 ////////////////////////////////////////////////////////////////////////////// 34 // - Defines - 35 36 #define DIBCOREHEADERSIZE ( 12UL ) 37 #define DIBINFOHEADERSIZE ( sizeof(DIBInfoHeader) ) 38 #define DIBV5HEADERSIZE ( sizeof(DIBV5Header) ) 39 40 ////////////////////////////////////////////////////////////////////////////// 41 // - Compression defines 42 43 #define COMPRESS_OWN ('S'|('D'<<8UL)) 44 #define COMPRESS_NONE ( 0UL ) 45 #define RLE_8 ( 1UL ) 46 #define RLE_4 ( 2UL ) 47 #define BITFIELDS ( 3UL ) 48 #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */ 49 50 ////////////////////////////////////////////////////////////////////////////// 51 // - DIBInfoHeader and DIBV5Header 52 53 typedef sal_Int32 FXPT2DOT30; 54 55 struct CIEXYZ 56 { 57 FXPT2DOT30 aXyzX; 58 FXPT2DOT30 aXyzY; 59 FXPT2DOT30 aXyzZ; 60 61 CIEXYZ() 62 : aXyzX(0L), 63 aXyzY(0L), 64 aXyzZ(0L) 65 {} 66 67 ~CIEXYZ() 68 {} 69 }; 70 71 struct CIEXYZTriple 72 { 73 CIEXYZ aXyzRed; 74 CIEXYZ aXyzGreen; 75 CIEXYZ aXyzBlue; 76 77 CIEXYZTriple() 78 : aXyzRed(), 79 aXyzGreen(), 80 aXyzBlue() 81 {} 82 83 ~CIEXYZTriple() 84 {} 85 }; 86 87 struct DIBInfoHeader 88 { 89 sal_uInt32 nSize; 90 sal_Int32 nWidth; 91 sal_Int32 nHeight; 92 sal_uInt16 nPlanes; 93 sal_uInt16 nBitCount; 94 sal_uInt32 nCompression; 95 sal_uInt32 nSizeImage; 96 sal_Int32 nXPelsPerMeter; 97 sal_Int32 nYPelsPerMeter; 98 sal_uInt32 nColsUsed; 99 sal_uInt32 nColsImportant; 100 101 DIBInfoHeader() 102 : nSize(0UL), 103 nWidth(0UL), 104 nHeight(0UL), 105 nPlanes(0), 106 nBitCount(0), 107 nCompression(0), 108 nSizeImage(0), 109 nXPelsPerMeter(0UL), 110 nYPelsPerMeter(0UL), 111 nColsUsed(0UL), 112 nColsImportant(0UL) 113 {} 114 115 ~DIBInfoHeader() 116 {} 117 }; 118 119 struct DIBV5Header : public DIBInfoHeader 120 { 121 sal_uInt32 nV5RedMask; 122 sal_uInt32 nV5GreenMask; 123 sal_uInt32 nV5BlueMask; 124 sal_uInt32 nV5AlphaMask; 125 sal_uInt32 nV5CSType; 126 CIEXYZTriple aV5Endpoints; 127 sal_uInt32 nV5GammaRed; 128 sal_uInt32 nV5GammaGreen; 129 sal_uInt32 nV5GammaBlue; 130 sal_uInt32 nV5Intent; 131 sal_uInt32 nV5ProfileData; 132 sal_uInt32 nV5ProfileSize; 133 sal_uInt32 nV5Reserved; 134 135 DIBV5Header() 136 : DIBInfoHeader(), 137 nV5RedMask(0UL), 138 nV5GreenMask(0UL), 139 nV5BlueMask(0UL), 140 nV5AlphaMask(0UL), 141 nV5CSType(0UL), 142 aV5Endpoints(), 143 nV5GammaRed(0UL), 144 nV5GammaGreen(0UL), 145 nV5GammaBlue(0UL), 146 nV5Intent(0UL), 147 nV5ProfileData(0UL), 148 nV5ProfileSize(0UL), 149 nV5Reserved(0UL) 150 {} 151 152 ~DIBV5Header() 153 {} 154 }; 155 156 ////////////////////////////////////////////////////////////////////////////// 157 158 namespace 159 { 160 inline sal_uInt16 discretizeBitcount( sal_uInt16 nInputCount ) 161 { 162 return ( nInputCount <= 1 ) ? 1 : 163 ( nInputCount <= 4 ) ? 4 : 164 ( nInputCount <= 8 ) ? 8 : 24; 165 } 166 167 inline bool isBitfieldCompression( sal_uLong nScanlineFormat ) 168 { 169 return (BMP_FORMAT_16BIT_TC_LSB_MASK == nScanlineFormat) || (BMP_FORMAT_32BIT_TC_MASK == nScanlineFormat); 170 } 171 } 172 173 ////////////////////////////////////////////////////////////////////////////// 174 175 bool ImplReadDIBInfoHeader(SvStream& rIStm, DIBV5Header& rHeader, bool& bTopDown) 176 { 177 // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER 178 const sal_Size aStartPos(rIStm.Tell()); 179 rIStm >> rHeader.nSize; 180 181 // BITMAPCOREHEADER 182 if ( rHeader.nSize == DIBCOREHEADERSIZE ) 183 { 184 sal_Int16 nTmp16; 185 186 rIStm >> nTmp16; rHeader.nWidth = nTmp16; 187 rIStm >> nTmp16; rHeader.nHeight = nTmp16; 188 rIStm >> rHeader.nPlanes; 189 rIStm >> rHeader.nBitCount; 190 } 191 else 192 { 193 // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible 194 sal_Size nUsed(sizeof(rHeader.nSize)); 195 196 // read DIBInfoHeader entries 197 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nWidth; nUsed += sizeof(rHeader.nWidth); } 198 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nHeight; nUsed += sizeof(rHeader.nHeight); } 199 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nPlanes; nUsed += sizeof(rHeader.nPlanes); } 200 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nBitCount; nUsed += sizeof(rHeader.nBitCount); } 201 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nCompression; nUsed += sizeof(rHeader.nCompression); } 202 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nSizeImage; nUsed += sizeof(rHeader.nSizeImage); } 203 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nXPelsPerMeter; nUsed += sizeof(rHeader.nXPelsPerMeter); } 204 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nYPelsPerMeter; nUsed += sizeof(rHeader.nYPelsPerMeter); } 205 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsUsed; nUsed += sizeof(rHeader.nColsUsed); } 206 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsImportant; nUsed += sizeof(rHeader.nColsImportant); } 207 208 // read DIBV5HEADER members 209 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5RedMask; nUsed += sizeof(rHeader.nV5RedMask); } 210 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GreenMask; nUsed += sizeof(rHeader.nV5GreenMask); } 211 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5BlueMask; nUsed += sizeof(rHeader.nV5BlueMask); } 212 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5AlphaMask; nUsed += sizeof(rHeader.nV5AlphaMask); } 213 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5CSType; nUsed += sizeof(rHeader.nV5CSType); } 214 215 // read contained CIEXYZTriple's 216 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzX); } 217 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzY); } 218 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzZ); } 219 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzX); } 220 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzY); } 221 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzZ); } 222 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzX); } 223 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzY); } 224 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzZ); } 225 226 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaRed; nUsed += sizeof(rHeader.nV5GammaRed); } 227 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaGreen; nUsed += sizeof(rHeader.nV5GammaGreen); } 228 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaBlue; nUsed += sizeof(rHeader.nV5GammaBlue); } 229 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Intent; nUsed += sizeof(rHeader.nV5Intent); } 230 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileData; nUsed += sizeof(rHeader.nV5ProfileData); } 231 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileSize; nUsed += sizeof(rHeader.nV5ProfileSize); } 232 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Reserved; nUsed += sizeof(rHeader.nV5Reserved); } 233 234 // seek to EndPos 235 rIStm.Seek(aStartPos + rHeader.nSize); 236 } 237 238 if ( rHeader.nHeight < 0 ) 239 { 240 bTopDown = true; 241 rHeader.nHeight *= -1; 242 } 243 else 244 { 245 bTopDown = false; 246 } 247 248 if ( rHeader.nWidth < 0 ) 249 { 250 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); 251 } 252 253 // #144105# protect a little against damaged files 254 if( rHeader.nSizeImage > ( 16 * static_cast< sal_uInt32 >( rHeader.nWidth * rHeader.nHeight ) ) ) 255 { 256 rHeader.nSizeImage = 0; 257 } 258 259 return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) ); 260 } 261 262 bool ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, bool bQuad ) 263 { 264 const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); 265 const sal_uLong nPalSize = nColors * ( bQuad ? 4UL : 3UL ); 266 BitmapColor aPalColor; 267 268 sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; 269 rIStm.Read( pEntries, nPalSize ); 270 271 sal_uInt8* pTmpEntry = pEntries; 272 for( sal_uInt16 i = 0; i < nColors; i++ ) 273 { 274 aPalColor.SetBlue( *pTmpEntry++ ); 275 aPalColor.SetGreen( *pTmpEntry++ ); 276 aPalColor.SetRed( *pTmpEntry++ ); 277 278 if( bQuad ) 279 pTmpEntry++; 280 281 rAcc.SetPaletteColor( i, aPalColor ); 282 } 283 284 delete[] pEntries; 285 286 return( rIStm.GetError() == 0UL ); 287 } 288 289 void ImplDecodeRLE( sal_uInt8* pBuffer, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, bool bRLE4 ) 290 { 291 Scanline pRLE = pBuffer; 292 long nY = rHeader.nHeight - 1L; 293 const sal_uLong nWidth = rAcc.Width(); 294 sal_uLong nCountByte; 295 sal_uLong nRunByte; 296 sal_uLong nX = 0UL; 297 sal_uInt8 cTmp; 298 bool bEndDecoding = false; 299 300 do 301 { 302 if( ( nCountByte = *pRLE++ ) == 0 ) 303 { 304 nRunByte = *pRLE++; 305 306 if( nRunByte > 2 ) 307 { 308 if( bRLE4 ) 309 { 310 nCountByte = nRunByte >> 1; 311 312 for( sal_uLong i = 0UL; i < nCountByte; i++ ) 313 { 314 cTmp = *pRLE++; 315 316 if( nX < nWidth ) 317 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 318 319 if( nX < nWidth ) 320 rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); 321 } 322 323 if( nRunByte & 1 ) 324 { 325 if( nX < nWidth ) 326 rAcc.SetPixelIndex( nY, nX++, *pRLE >> 4 ); 327 328 pRLE++; 329 } 330 331 if( ( ( nRunByte + 1 ) >> 1 ) & 1 ) 332 pRLE++; 333 } 334 else 335 { 336 for( sal_uLong i = 0UL; i < nRunByte; i++ ) 337 { 338 if( nX < nWidth ) 339 rAcc.SetPixelIndex( nY, nX++, *pRLE ); 340 341 pRLE++; 342 } 343 344 if( nRunByte & 1 ) 345 pRLE++; 346 } 347 } 348 else if( !nRunByte ) 349 { 350 nY--; 351 nX = 0UL; 352 } 353 else if( nRunByte == 1 ) 354 bEndDecoding = true; 355 else 356 { 357 nX += *pRLE++; 358 nY -= *pRLE++; 359 } 360 } 361 else 362 { 363 cTmp = *pRLE++; 364 365 if( bRLE4 ) 366 { 367 nRunByte = nCountByte >> 1; 368 369 for( sal_uLong i = 0UL; i < nRunByte; i++ ) 370 { 371 if( nX < nWidth ) 372 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 373 374 if( nX < nWidth ) 375 rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); 376 } 377 378 if( ( nCountByte & 1 ) && ( nX < nWidth ) ) 379 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 380 } 381 else 382 { 383 for( sal_uLong i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ ) 384 rAcc.SetPixelIndex( nY, nX++, cTmp ); 385 } 386 } 387 } 388 while ( !bEndDecoding && ( nY >= 0L ) ); 389 } 390 391 bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, BitmapWriteAccess* pAccAlpha, bool bTopDown, bool& rAlphaUsed) 392 { 393 const sal_Int64 nBitsPerLine (static_cast<sal_Int64>(rHeader.nWidth) * static_cast<sal_Int64>(rHeader.nBitCount)); 394 if (nBitsPerLine > SAL_MAX_UINT32) 395 return false; 396 397 const sal_uLong nAlignedWidth = AlignedWidth4Bytes(static_cast<sal_uLong>(nBitsPerLine)); 398 sal_uInt32 nRMask(( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL); 399 sal_uInt32 nGMask(( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL); 400 sal_uInt32 nBMask(( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL); 401 bool bNative(false); 402 bool bTCMask(!pAccAlpha && ((16 == rHeader.nBitCount) || (32 == rHeader.nBitCount))); 403 bool bRLE((RLE_8 == rHeader.nCompression && 8 == rHeader.nBitCount) || (RLE_4 == rHeader.nCompression && 4 == rHeader.nBitCount)); 404 405 // Is native format? 406 switch(rAcc.GetScanlineFormat()) 407 { 408 case( BMP_FORMAT_1BIT_MSB_PAL ): 409 case( BMP_FORMAT_4BIT_MSN_PAL ): 410 case( BMP_FORMAT_8BIT_PAL ): 411 case( BMP_FORMAT_24BIT_TC_BGR ): 412 { 413 bNative = ( ( static_cast< bool >(rAcc.IsBottomUp()) != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) ); 414 break; 415 } 416 417 default: 418 { 419 break; 420 } 421 } 422 423 // Read data 424 if(bNative) 425 { 426 rIStm.Read(rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth); 427 } 428 else 429 { 430 // Read color mask 431 if(bTCMask && BITFIELDS == rHeader.nCompression) 432 { 433 rIStm.SeekRel( -12L ); 434 rIStm >> nRMask; 435 rIStm >> nGMask; 436 rIStm >> nBMask; 437 } 438 439 if(bRLE) 440 { 441 if(!rHeader.nSizeImage) 442 { 443 const sal_uLong nOldPos(rIStm.Tell()); 444 445 rIStm.Seek(STREAM_SEEK_TO_END); 446 rHeader.nSizeImage = rIStm.Tell() - nOldPos; 447 rIStm.Seek(nOldPos); 448 } 449 450 sal_uInt8* pBuffer = (sal_uInt8*)rtl_allocateMemory(rHeader.nSizeImage); 451 rIStm.Read((char*)pBuffer, rHeader.nSizeImage); 452 ImplDecodeRLE(pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression); 453 rtl_freeMemory(pBuffer); 454 } 455 else 456 { 457 const long nWidth(rHeader.nWidth); 458 const long nHeight(rHeader.nHeight); 459 sal_uInt8* pBuf = new sal_uInt8[nAlignedWidth]; 460 461 const long nI(bTopDown ? 1 : -1); 462 long nY(bTopDown ? 0 : nHeight - 1); 463 long nCount(nHeight); 464 465 switch(rHeader.nBitCount) 466 { 467 case( 1 ): 468 { 469 sal_uInt8* pTmp; 470 sal_uInt8 cTmp; 471 472 for( ; nCount--; nY += nI ) 473 { 474 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 475 cTmp = *pTmp++; 476 477 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) 478 { 479 if( !nShift ) 480 { 481 nShift = 8L, 482 cTmp = *pTmp++; 483 } 484 485 rAcc.SetPixelIndex( nY, nX, (cTmp >> --nShift) & 1); 486 } 487 } 488 } 489 break; 490 491 case( 4 ): 492 { 493 sal_uInt8* pTmp; 494 sal_uInt8 cTmp; 495 496 for( ; nCount--; nY += nI ) 497 { 498 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 499 cTmp = *pTmp++; 500 501 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) 502 { 503 if( !nShift ) 504 { 505 nShift = 2UL, 506 cTmp = *pTmp++; 507 } 508 509 rAcc.SetPixelIndex( nY, nX, (cTmp >> ( --nShift << 2UL ) ) & 0x0f); 510 } 511 } 512 } 513 break; 514 515 case( 8 ): 516 { 517 sal_uInt8* pTmp; 518 519 for( ; nCount--; nY += nI ) 520 { 521 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 522 523 for( long nX = 0L; nX < nWidth; nX++ ) 524 rAcc.SetPixelIndex( nY, nX, *pTmp++ ); 525 } 526 } 527 break; 528 529 case( 16 ): 530 { 531 ColorMask aMask( nRMask, nGMask, nBMask ); 532 BitmapColor aColor; 533 sal_uInt16* pTmp16; 534 535 for( ; nCount--; nY += nI ) 536 { 537 rIStm.Read( (char*)( pTmp16 = (sal_uInt16*) pBuf ), nAlignedWidth ); 538 539 for( long nX = 0L; nX < nWidth; nX++ ) 540 { 541 aMask.GetColorFor16BitLSB( aColor, (sal_uInt8*) pTmp16++ ); 542 rAcc.SetPixel( nY, nX, aColor ); 543 } 544 } 545 } 546 break; 547 548 case( 24 ): 549 { 550 BitmapColor aPixelColor; 551 sal_uInt8* pTmp; 552 553 for( ; nCount--; nY += nI ) 554 { 555 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 556 557 for( long nX = 0L; nX < nWidth; nX++ ) 558 { 559 aPixelColor.SetBlue( *pTmp++ ); 560 aPixelColor.SetGreen( *pTmp++ ); 561 aPixelColor.SetRed( *pTmp++ ); 562 rAcc.SetPixel( nY, nX, aPixelColor ); 563 } 564 } 565 } 566 break; 567 568 case( 32 ): 569 { 570 ColorMask aMask(nRMask, nGMask, nBMask); 571 BitmapColor aColor; 572 sal_uInt32* pTmp32; 573 574 if(pAccAlpha) 575 { 576 sal_uInt8 aAlpha; 577 578 for( ; nCount--; nY += nI ) 579 { 580 rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); 581 582 for( long nX = 0L; nX < nWidth; nX++ ) 583 { 584 aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, (sal_uInt8*) pTmp32++ ); 585 rAcc.SetPixel( nY, nX, aColor ); 586 pAccAlpha->SetPixelIndex(nY, nX, sal_uInt8(0xff) - aAlpha); 587 rAlphaUsed |= bool(0xff != aAlpha); 588 } 589 } 590 } 591 else 592 { 593 for( ; nCount--; nY += nI ) 594 { 595 rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); 596 597 for( long nX = 0L; nX < nWidth; nX++ ) 598 { 599 aMask.GetColorFor32Bit( aColor, (sal_uInt8*) pTmp32++ ); 600 rAcc.SetPixel( nY, nX, aColor ); 601 } 602 } 603 } 604 } 605 } 606 607 delete[] pBuf; 608 } 609 } 610 611 return( rIStm.GetError() == 0UL ); 612 } 613 614 bool ImplReadDIBBody( SvStream& rIStm, Bitmap& rBmp, Bitmap* pBmpAlpha, sal_uLong nOffset ) 615 { 616 DIBV5Header aHeader; 617 const sal_uLong nStmPos = rIStm.Tell(); 618 bool bRet( false ); 619 bool bTopDown( false ); 620 621 if ( ImplReadDIBInfoHeader( rIStm, aHeader, bTopDown ) 622 && aHeader.nWidth != 0 623 && aHeader.nHeight != 0 624 && aHeader.nBitCount != 0 ) 625 { 626 if ( nOffset > 0 && aHeader.nSize > nOffset ) 627 { 628 // Header size claims to extend into the image data. 629 // Looks like an error. 630 return false; 631 } 632 633 const sal_uInt16 nBitCount(discretizeBitcount(aHeader.nBitCount)); 634 const Size aSizePixel(aHeader.nWidth, aHeader.nHeight); 635 BitmapPalette aDummyPal; 636 Bitmap aNewBmp(aSizePixel, nBitCount, &aDummyPal); 637 Bitmap aNewBmpAlpha; 638 BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess(); 639 BitmapWriteAccess* pAccAlpha = 0; 640 bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32); 641 642 if(bAlphaPossible) 643 { 644 const bool bRedSet(0 != aHeader.nV5RedMask); 645 const bool bGreenSet(0 != aHeader.nV5GreenMask); 646 const bool bBlueSet(0 != aHeader.nV5BlueMask); 647 648 // some clipboard entries have alpha mask on zero to say that there is 649 // no alpha; do only use this when the other masks are set. The MS docu 650 // says that that masks are only to be set when bV5Compression is set to 651 // BI_BITFIELDS, but there seem to exist a wild variety of usages... 652 if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask)) 653 { 654 bAlphaPossible = false; 655 } 656 } 657 658 if(bAlphaPossible) 659 { 660 aNewBmpAlpha = Bitmap(aSizePixel, 8); 661 pAccAlpha = aNewBmpAlpha.AcquireWriteAccess(); 662 } 663 664 if(pAcc) 665 { 666 sal_uInt16 nColors(0); 667 SvStream* pIStm; 668 SvMemoryStream* pMemStm = NULL; 669 sal_uInt8* pData = NULL; 670 671 if(nBitCount <= 8) 672 { 673 if(aHeader.nColsUsed) 674 { 675 nColors = (sal_uInt16)aHeader.nColsUsed; 676 } 677 else 678 { 679 nColors = ( 1 << aHeader.nBitCount ); 680 } 681 } 682 683 if(ZCOMPRESS == aHeader.nCompression) 684 { 685 ZCodec aCodec; 686 sal_uInt32 nCodedSize(0); 687 sal_uInt32 nUncodedSize(0); 688 sal_uLong nCodedPos(0); 689 690 // read coding information 691 rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression; 692 pData = (sal_uInt8*) rtl_allocateMemory( nUncodedSize ); 693 694 // decode buffer 695 nCodedPos = rIStm.Tell(); 696 aCodec.BeginCompression(); 697 aCodec.Read( rIStm, pData, nUncodedSize ); 698 aCodec.EndCompression(); 699 700 // skip unread bytes from coded buffer 701 rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) ); 702 703 // set decoded bytes to memory stream, 704 // from which we will read the bitmap data 705 pIStm = pMemStm = new SvMemoryStream; 706 pMemStm->SetBuffer( (char*) pData, nUncodedSize, false, nUncodedSize ); 707 nOffset = 0; 708 } 709 else 710 { 711 pIStm = &rIStm; 712 } 713 714 // read palette 715 if(nColors) 716 { 717 pAcc->SetPaletteEntryCount(nColors); 718 ImplReadDIBPalette(*pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE); 719 } 720 721 // read bits 722 bool bAlphaUsed(false); 723 724 if(!pIStm->GetError()) 725 { 726 if(nOffset) 727 { 728 pIStm->SeekRel(nOffset - (pIStm->Tell() - nStmPos)); 729 } 730 731 bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, pAccAlpha, bTopDown, bAlphaUsed); 732 733 if(bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter) 734 { 735 MapMode aMapMode( 736 MAP_MM, 737 Point(), 738 Fraction(1000, aHeader.nXPelsPerMeter), 739 Fraction(1000, aHeader.nYPelsPerMeter)); 740 741 aNewBmp.SetPrefMapMode(aMapMode); 742 aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight)); 743 } 744 } 745 746 if( pData ) 747 { 748 rtl_freeMemory(pData); 749 } 750 751 delete pMemStm; 752 aNewBmp.ReleaseAccess(pAcc); 753 754 if(bAlphaPossible) 755 { 756 aNewBmpAlpha.ReleaseAccess(pAccAlpha); 757 758 if(!bAlphaUsed) 759 { 760 bAlphaPossible = false; 761 } 762 } 763 764 if(bRet) 765 { 766 rBmp = aNewBmp; 767 768 if(bAlphaPossible) 769 { 770 *pBmpAlpha = aNewBmpAlpha; 771 } 772 } 773 } 774 } 775 776 return bRet; 777 } 778 779 bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset ) 780 { 781 bool bRet = false; 782 783 const sal_Int64 nSavedStreamPos( rIStm.Tell() ); 784 const sal_Int64 nStreamLength( rIStm.Seek( STREAM_SEEK_TO_END ) ); 785 rIStm.Seek( nSavedStreamPos ); 786 787 sal_uInt16 nTmp16 = 0; 788 rIStm >> nTmp16; 789 790 if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) ) 791 { 792 sal_uInt32 nTmp32; 793 if ( 0x4142 == nTmp16 ) 794 { 795 rIStm.SeekRel( 12L ); 796 rIStm >> nTmp16; 797 rIStm.SeekRel( 8L ); 798 rIStm >> nTmp32; 799 rOffset = nTmp32 - 28UL; 800 bRet = ( 0x4D42 == nTmp16 ); 801 } 802 else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER 803 { 804 rIStm.SeekRel( 8L ); // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits 805 rIStm >> nTmp32; // read bfOffBits 806 rOffset = nTmp32 - 14UL; // adapt offset by sizeof(BITMAPFILEHEADER) 807 bRet = ( rIStm.GetError() == 0UL ); 808 } 809 810 if ( rOffset >= nStreamLength ) 811 { 812 // Offset claims that image starts past the end of the 813 // stream. Unlikely. 814 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); 815 bRet = false; 816 } 817 } 818 else 819 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); 820 821 return bRet; 822 } 823 824 bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc ) 825 { 826 const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); 827 const sal_uLong nPalSize = nColors * 4UL; 828 sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; 829 sal_uInt8* pTmpEntry = pEntries; 830 BitmapColor aPalColor; 831 832 for( sal_uInt16 i = 0; i < nColors; i++ ) 833 { 834 const BitmapColor& rPalColor = rAcc.GetPaletteColor( i ); 835 836 *pTmpEntry++ = rPalColor.GetBlue(); 837 *pTmpEntry++ = rPalColor.GetGreen(); 838 *pTmpEntry++ = rPalColor.GetRed(); 839 *pTmpEntry++ = 0; 840 } 841 842 rOStm.Write( pEntries, nPalSize ); 843 delete[] pEntries; 844 845 return( rOStm.GetError() == 0UL ); 846 } 847 848 bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, bool bRLE4 ) 849 { 850 const sal_uLong nWidth = rAcc.Width(); 851 const sal_uLong nHeight = rAcc.Height(); 852 sal_uLong nX; 853 sal_uLong nSaveIndex; 854 sal_uLong nCount; 855 sal_uLong nBufCount; 856 sal_uInt8* pBuf = new sal_uInt8[ ( nWidth << 1 ) + 2 ]; 857 sal_uInt8* pTmp; 858 sal_uInt8 cPix; 859 sal_uInt8 cLast; 860 bool bFound; 861 862 for ( long nY = nHeight - 1L; nY >= 0L; nY-- ) 863 { 864 pTmp = pBuf; 865 nX = nBufCount = 0UL; 866 867 while( nX < nWidth ) 868 { 869 nCount = 1L; 870 cPix = rAcc.GetPixelIndex( nY, nX++ ); 871 872 while( ( nX < nWidth ) && ( nCount < 255L ) 873 && ( cPix == rAcc.GetPixelIndex( nY, nX ) ) ) 874 { 875 nX++; 876 nCount++; 877 } 878 879 if ( nCount > 1 ) 880 { 881 *pTmp++ = (sal_uInt8) nCount; 882 *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix ); 883 nBufCount += 2; 884 } 885 else 886 { 887 cLast = cPix; 888 nSaveIndex = nX - 1UL; 889 bFound = false; 890 891 while( ( nX < nWidth ) && ( nCount < 256L ) 892 && ( cPix = rAcc.GetPixelIndex( nY, nX ) ) != cLast ) 893 { 894 nX++; nCount++; 895 cLast = cPix; 896 bFound = true; 897 } 898 899 if ( bFound ) 900 nX--; 901 902 if ( nCount > 3 ) 903 { 904 *pTmp++ = 0; 905 *pTmp++ = (sal_uInt8) --nCount; 906 907 if( bRLE4 ) 908 { 909 for ( sal_uLong i = 0; i < nCount; i++, pTmp++ ) 910 { 911 *pTmp = rAcc.GetPixelIndex( nY, nSaveIndex++ ) << 4; 912 913 if ( ++i < nCount ) 914 *pTmp |= rAcc.GetPixelIndex( nY, nSaveIndex++ ); 915 } 916 917 nCount = ( nCount + 1 ) >> 1; 918 } 919 else 920 { 921 for( sal_uLong i = 0UL; i < nCount; i++ ) 922 *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex++ ); 923 } 924 925 if ( nCount & 1 ) 926 { 927 *pTmp++ = 0; 928 nBufCount += ( nCount + 3 ); 929 } 930 else 931 nBufCount += ( nCount + 2 ); 932 } 933 else 934 { 935 *pTmp++ = 1; 936 *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex ) << (bRLE4 ? 4 : 0); 937 938 if ( nCount == 3 ) 939 { 940 *pTmp++ = 1; 941 *pTmp++ = rAcc.GetPixelIndex( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 ); 942 nBufCount += 4; 943 } 944 else 945 nBufCount += 2; 946 } 947 } 948 } 949 950 pBuf[ nBufCount++ ] = 0; 951 pBuf[ nBufCount++ ] = 0; 952 953 rOStm.Write( pBuf, nBufCount ); 954 } 955 956 rOStm << (sal_uInt8) 0; 957 rOStm << (sal_uInt8) 1; 958 959 delete[] pBuf; 960 961 return( rOStm.GetError() == 0UL ); 962 } 963 964 bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, sal_uLong nCompression, sal_uInt32& rImageSize) 965 { 966 if(!pAccAlpha && BITFIELDS == nCompression) 967 { 968 const ColorMask& rMask = rAcc.GetColorMask(); 969 SVBT32 aVal32; 970 971 UInt32ToSVBT32( rMask.GetRedMask(), aVal32 ); 972 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 973 974 UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 ); 975 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 976 977 UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 ); 978 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 979 980 rImageSize = rOStm.Tell(); 981 982 if( rAcc.IsBottomUp() ) 983 rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() ); 984 else 985 { 986 for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- ) 987 rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize ); 988 } 989 } 990 else if(!pAccAlpha && ((RLE_4 == nCompression) || (RLE_8 == nCompression))) 991 { 992 rImageSize = rOStm.Tell(); 993 ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression ); 994 } 995 else if(!nCompression) 996 { 997 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not 998 // handled properly below (would have to set color masks, and 999 // nCompression=BITFIELDS - but color mask is not set for 1000 // formats != *_TC_*). Note that this very problem might cause 1001 // trouble at other places - the introduction of 32 bit RGBA 1002 // bitmaps is relatively recent. 1003 // #i59239# discretize bitcount for aligned width to 1,4,8,24 1004 // (other cases are not written below) 1005 const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); 1006 const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * nBitCount)); 1007 bool bNative(false); 1008 1009 switch(rAcc.GetScanlineFormat()) 1010 { 1011 case( BMP_FORMAT_1BIT_MSB_PAL ): 1012 case( BMP_FORMAT_4BIT_MSN_PAL ): 1013 case( BMP_FORMAT_8BIT_PAL ): 1014 case( BMP_FORMAT_24BIT_TC_BGR ): 1015 { 1016 if(!pAccAlpha && rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth)) 1017 { 1018 bNative = true; 1019 } 1020 1021 break; 1022 } 1023 1024 default: 1025 { 1026 break; 1027 } 1028 } 1029 1030 rImageSize = rOStm.Tell(); 1031 1032 if(bNative) 1033 { 1034 rOStm.Write(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height()); 1035 } 1036 else 1037 { 1038 const long nWidth(rAcc.Width()); 1039 const long nHeight(rAcc.Height()); 1040 sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ]; 1041 sal_uInt8* pTmp(0); 1042 sal_uInt8 cTmp(0); 1043 1044 switch( nBitCount ) 1045 { 1046 case( 1 ): 1047 { 1048 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1049 { 1050 pTmp = pBuf; 1051 cTmp = 0; 1052 1053 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) 1054 { 1055 if( !nShift ) 1056 { 1057 nShift = 8L; 1058 *pTmp++ = cTmp; 1059 cTmp = 0; 1060 } 1061 1062 cTmp |= rAcc.GetPixelIndex( nY, nX ) << --nShift; 1063 } 1064 1065 *pTmp = cTmp; 1066 rOStm.Write( pBuf, nAlignedWidth ); 1067 } 1068 } 1069 break; 1070 1071 case( 4 ): 1072 { 1073 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1074 { 1075 pTmp = pBuf; 1076 cTmp = 0; 1077 1078 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) 1079 { 1080 if( !nShift ) 1081 { 1082 nShift = 2L; 1083 *pTmp++ = cTmp; 1084 cTmp = 0; 1085 } 1086 1087 cTmp |= rAcc.GetPixelIndex( nY, nX ) << ( --nShift << 2L ); 1088 } 1089 *pTmp = cTmp; 1090 rOStm.Write( pBuf, nAlignedWidth ); 1091 } 1092 } 1093 break; 1094 1095 case( 8 ): 1096 { 1097 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1098 { 1099 pTmp = pBuf; 1100 1101 for( long nX = 0L; nX < nWidth; nX++ ) 1102 *pTmp++ = rAcc.GetPixelIndex( nY, nX ); 1103 1104 rOStm.Write( pBuf, nAlignedWidth ); 1105 } 1106 } 1107 break; 1108 1109 // #i59239# fallback to 24 bit format, if bitcount is non-default 1110 default: 1111 // FALLTHROUGH intended 1112 case( 24 ): 1113 { 1114 BitmapColor aPixelColor; 1115 const bool bWriteAlpha(32 == nBitCount && pAccAlpha); 1116 1117 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1118 { 1119 pTmp = pBuf; 1120 1121 for( long nX = 0L; nX < nWidth; nX++ ) 1122 { 1123 // when alpha is used, this may be non-24bit main bitmap, so use GetColor 1124 // instead of GetPixel to ensure RGB value 1125 aPixelColor = rAcc.GetColor( nY, nX ); 1126 1127 *pTmp++ = aPixelColor.GetBlue(); 1128 *pTmp++ = aPixelColor.GetGreen(); 1129 *pTmp++ = aPixelColor.GetRed(); 1130 1131 if(bWriteAlpha) 1132 { 1133 if(pAccAlpha) 1134 { 1135 *pTmp++ = (sal_uInt8)0xff - (sal_uInt8)pAccAlpha->GetPixelIndex( nY, nX ); 1136 } 1137 else 1138 { 1139 *pTmp++ = (sal_uInt8)0xff; 1140 } 1141 } 1142 } 1143 1144 rOStm.Write( pBuf, nAlignedWidth ); 1145 } 1146 } 1147 break; 1148 } 1149 1150 delete[] pBuf; 1151 } 1152 } 1153 1154 rImageSize = rOStm.Tell() - rImageSize; 1155 1156 return (!rOStm.GetError()); 1157 } 1158 1159 bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, bool bCompressed) 1160 { 1161 const MapMode aMapPixel(MAP_PIXEL); 1162 DIBV5Header aHeader; 1163 sal_uLong nImageSizePos(0); 1164 sal_uLong nEndPos(0); 1165 sal_uInt32 nCompression(COMPRESS_NONE); 1166 bool bRet(false); 1167 1168 aHeader.nSize = pAccAlpha ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use 1169 aHeader.nWidth = rAcc.Width(); 1170 aHeader.nHeight = rAcc.Height(); 1171 aHeader.nPlanes = 1; 1172 1173 if(!pAccAlpha && isBitfieldCompression(rAcc.GetScanlineFormat())) 1174 { 1175 aHeader.nBitCount = (BMP_FORMAT_16BIT_TC_LSB_MASK == rAcc.GetScanlineFormat()) ? 16 : 32; 1176 aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize(); 1177 nCompression = BITFIELDS; 1178 } 1179 else 1180 { 1181 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are 1182 // not handled properly below (would have to set color 1183 // masks, and nCompression=BITFIELDS - but color mask is 1184 // not set for formats != *_TC_*). Note that this very 1185 // problem might cause trouble at other places - the 1186 // introduction of 32 bit RGBA bitmaps is relatively 1187 // recent. 1188 // #i59239# discretize bitcount to 1,4,8,24 (other cases 1189 // are not written below) 1190 const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); 1191 aHeader.nBitCount = nBitCount; 1192 aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount); 1193 1194 if(bCompressed) 1195 { 1196 if(4 == nBitCount) 1197 { 1198 nCompression = RLE_4; 1199 } 1200 else if(8 == nBitCount) 1201 { 1202 nCompression = RLE_8; 1203 } 1204 } 1205 } 1206 1207 if((rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40)) 1208 { 1209 aHeader.nCompression = ZCOMPRESS; 1210 } 1211 else 1212 { 1213 aHeader.nCompression = nCompression; 1214 } 1215 1216 if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel)) 1217 { 1218 // #i48108# Try to recover xpels/ypels as previously stored on 1219 // disk. The problem with just converting maPrefSize to 100th 1220 // mm and then relating that to the bitmap pixel size is that 1221 // MapMode is integer-based, and suffers from roundoffs, 1222 // especially if maPrefSize is small. Trying to circumvent 1223 // that by performing part of the math in floating point. 1224 const Size aScale100000(OutputDevice::LogicToLogic(Size(100000L, 100000L), MAP_100TH_MM, rBitmap.GetPrefMapMode())); 1225 const double fBmpWidthM((double)rBitmap.GetPrefSize().Width() / aScale100000.Width()); 1226 const double fBmpHeightM((double)rBitmap.GetPrefSize().Height() / aScale100000.Height()); 1227 1228 if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM)) 1229 { 1230 aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM)); 1231 aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM)); 1232 } 1233 } 1234 1235 aHeader.nColsUsed = ((!pAccAlpha && aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0); 1236 aHeader.nColsImportant = 0; 1237 1238 rOStm << aHeader.nSize; 1239 rOStm << aHeader.nWidth; 1240 rOStm << aHeader.nHeight; 1241 rOStm << aHeader.nPlanes; 1242 rOStm << aHeader.nBitCount; 1243 rOStm << aHeader.nCompression; 1244 1245 nImageSizePos = rOStm.Tell(); 1246 rOStm.SeekRel( sizeof( aHeader.nSizeImage ) ); 1247 1248 rOStm << aHeader.nXPelsPerMeter; 1249 rOStm << aHeader.nYPelsPerMeter; 1250 rOStm << aHeader.nColsUsed; 1251 rOStm << aHeader.nColsImportant; 1252 1253 if(pAccAlpha) // only write DIBV5 when asked to do so 1254 { 1255 aHeader.nV5CSType = 0x57696E20; // LCS_WINDOWS_COLOR_SPACE 1256 aHeader.nV5Intent = 0x00000004; // LCS_GM_IMAGES 1257 1258 rOStm << aHeader.nV5RedMask; 1259 rOStm << aHeader.nV5GreenMask; 1260 rOStm << aHeader.nV5BlueMask; 1261 rOStm << aHeader.nV5AlphaMask; 1262 rOStm << aHeader.nV5CSType; 1263 1264 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzX; 1265 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzY; 1266 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzZ; 1267 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzX; 1268 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzY; 1269 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzZ; 1270 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzX; 1271 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzY; 1272 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzZ; 1273 1274 rOStm << aHeader.nV5GammaRed; 1275 rOStm << aHeader.nV5GammaGreen; 1276 rOStm << aHeader.nV5GammaBlue; 1277 rOStm << aHeader.nV5Intent; 1278 rOStm << aHeader.nV5ProfileData; 1279 rOStm << aHeader.nV5ProfileSize; 1280 rOStm << aHeader.nV5Reserved; 1281 } 1282 1283 if(ZCOMPRESS == aHeader.nCompression) 1284 { 1285 ZCodec aCodec; 1286 SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535); 1287 sal_uLong nCodedPos(rOStm.Tell()); 1288 sal_uLong nLastPos(0); 1289 sal_uInt32 nCodedSize(0); 1290 sal_uInt32 nUncodedSize(0); 1291 1292 // write uncoded data palette 1293 if(aHeader.nColsUsed) 1294 { 1295 ImplWriteDIBPalette(aMemStm, rAcc); 1296 } 1297 1298 // write uncoded bits 1299 bRet = ImplWriteDIBBits(aMemStm, rAcc, pAccAlpha, nCompression, aHeader.nSizeImage); 1300 1301 // get uncoded size 1302 nUncodedSize = aMemStm.Tell(); 1303 1304 // seek over compress info 1305 rOStm.SeekRel(12); 1306 1307 // write compressed data 1308 aCodec.BeginCompression(3); 1309 aCodec.Write(rOStm, (sal_uInt8*)aMemStm.GetData(), nUncodedSize); 1310 aCodec.EndCompression(); 1311 1312 // update compress info ( coded size, uncoded size, uncoded compression ) 1313 nLastPos = rOStm.Tell(); 1314 nCodedSize = nLastPos - nCodedPos - 12; 1315 rOStm.Seek(nCodedPos); 1316 rOStm << nCodedSize << nUncodedSize << nCompression; 1317 rOStm.Seek(nLastPos); 1318 1319 if(bRet) 1320 { 1321 bRet = (ERRCODE_NONE == rOStm.GetError()); 1322 } 1323 } 1324 else 1325 { 1326 if(aHeader.nColsUsed) 1327 { 1328 ImplWriteDIBPalette(rOStm, rAcc); 1329 } 1330 1331 bRet = ImplWriteDIBBits(rOStm, rAcc, pAccAlpha, aHeader.nCompression, aHeader.nSizeImage); 1332 } 1333 1334 nEndPos = rOStm.Tell(); 1335 rOStm.Seek(nImageSizePos); 1336 rOStm << aHeader.nSizeImage; 1337 rOStm.Seek(nEndPos); 1338 1339 return bRet; 1340 } 1341 1342 bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess& rAcc, bool bUseDIBV5) 1343 { 1344 const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : isBitfieldCompression(rAcc.GetScanlineFormat()) ? 3UL : 0UL)); 1345 const sal_uInt32 nOffset(14 + (bUseDIBV5 ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE) + nPalCount * 4UL); 1346 1347 rOStm << (sal_uInt16)0x4D42; // 'MB' from BITMAPFILEHEADER 1348 rOStm << (sal_uInt32)(nOffset + (rAcc.Height() * rAcc.GetScanlineSize())); 1349 rOStm << (sal_uInt16)0; 1350 rOStm << (sal_uInt16)0; 1351 rOStm << nOffset; 1352 1353 return( rOStm.GetError() == 0UL ); 1354 } 1355 1356 ////////////////////////////////////////////////////////////////////////////// 1357 1358 bool ImplReadDIB( 1359 Bitmap& rTarget, Bitmap* 1360 pTargetAlpha, 1361 SvStream& rIStm, 1362 bool bFileHeader) 1363 { 1364 const sal_uInt16 nOldFormat(rIStm.GetNumberFormatInt()); 1365 const sal_uLong nOldPos(rIStm.Tell()); 1366 sal_uLong nOffset(0UL); 1367 bool bRet(false); 1368 1369 rIStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); 1370 1371 if(bFileHeader) 1372 { 1373 if(ImplReadDIBFileHeader(rIStm, nOffset)) 1374 { 1375 bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : 0, nOffset); 1376 } 1377 } 1378 else 1379 { 1380 bRet = ImplReadDIBBody(rIStm, rTarget, 0, nOffset); 1381 } 1382 1383 if(!bRet) 1384 { 1385 if(!rIStm.GetError()) 1386 { 1387 rIStm.SetError(SVSTREAM_GENERALERROR); 1388 } 1389 1390 rIStm.Seek(nOldPos); 1391 } 1392 1393 rIStm.SetNumberFormatInt(nOldFormat); 1394 1395 return bRet; 1396 } 1397 1398 bool ImplWriteDIB( 1399 const Bitmap& rSource, 1400 const Bitmap* pSourceAlpha, 1401 SvStream& rOStm, 1402 bool bCompressed, 1403 bool bFileHeader) 1404 { 1405 const Size aSizePix(rSource.GetSizePixel()); 1406 bool bRet(false); 1407 1408 if(aSizePix.Width() && aSizePix.Height()) 1409 { 1410 BitmapReadAccess* pAcc = const_cast< Bitmap& >(rSource).AcquireReadAccess(); 1411 BitmapReadAccess* pAccAlpha = 0; 1412 const sal_uInt16 nOldFormat(rOStm.GetNumberFormatInt()); 1413 const sal_uLong nOldPos(rOStm.Tell()); 1414 1415 if(pSourceAlpha) 1416 { 1417 const Size aSizePixAlpha(pSourceAlpha->GetSizePixel()); 1418 1419 if(aSizePixAlpha == aSizePix) 1420 { 1421 pAccAlpha = const_cast< Bitmap* >(pSourceAlpha)->AcquireReadAccess(); 1422 } 1423 else 1424 { 1425 OSL_ENSURE(false, "WriteDIB got an alpha channel, but it's pixel size differs from the base bitmap (!)"); 1426 } 1427 } 1428 1429 rOStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); 1430 1431 if(pAcc) 1432 { 1433 if(bFileHeader) 1434 { 1435 if(ImplWriteDIBFileHeader(rOStm, *pAcc, 0 != pSourceAlpha)) 1436 { 1437 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); 1438 } 1439 } 1440 else 1441 { 1442 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); 1443 } 1444 1445 const_cast< Bitmap& >(rSource).ReleaseAccess(pAcc); 1446 1447 if(pAccAlpha) 1448 { 1449 const_cast< Bitmap* >(pSourceAlpha)->ReleaseAccess(pAccAlpha); 1450 } 1451 } 1452 1453 if(!bRet) 1454 { 1455 rOStm.SetError(SVSTREAM_GENERALERROR); 1456 rOStm.Seek(nOldPos); 1457 } 1458 1459 rOStm.SetNumberFormatInt(nOldFormat); 1460 } 1461 1462 return bRet; 1463 } 1464 1465 ////////////////////////////////////////////////////////////////////////////// 1466 1467 bool ReadDIB( 1468 Bitmap& rTarget, 1469 SvStream& rIStm, 1470 bool bFileHeader) 1471 { 1472 return ImplReadDIB(rTarget, 0, rIStm, bFileHeader); 1473 } 1474 1475 bool ReadDIBBitmapEx( 1476 BitmapEx& rTarget, 1477 SvStream& rIStm) 1478 { 1479 Bitmap aBmp; 1480 bool bRetval(ImplReadDIB(aBmp, 0, rIStm, true) && !rIStm.GetError()); 1481 1482 if(bRetval) 1483 { 1484 // base bitmap was read, set as return value and try to read alpha extra-data 1485 const sal_uLong nStmPos(rIStm.Tell()); 1486 sal_uInt32 nMagic1(0); 1487 sal_uInt32 nMagic2(0); 1488 1489 rTarget = BitmapEx(aBmp); 1490 rIStm >> nMagic1 >> nMagic2; 1491 bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError(); 1492 1493 if(bRetval) 1494 { 1495 sal_uInt8 bTransparent(false); 1496 1497 rIStm >> bTransparent; 1498 bRetval = !rIStm.GetError(); 1499 1500 if(bRetval) 1501 { 1502 if((sal_uInt8)TRANSPARENT_BITMAP == bTransparent) 1503 { 1504 Bitmap aMask; 1505 1506 bRetval = ImplReadDIB(aMask, 0, rIStm, true); 1507 1508 if(bRetval) 1509 { 1510 if(!!aMask) 1511 { 1512 // do we have an alpha mask? 1513 if((8 == aMask.GetBitCount()) && aMask.HasGreyPalette()) 1514 { 1515 AlphaMask aAlpha; 1516 1517 // create alpha mask quickly (without greyscale conversion) 1518 aAlpha.ImplSetBitmap(aMask); 1519 rTarget = BitmapEx(aBmp, aAlpha); 1520 } 1521 else 1522 { 1523 rTarget = BitmapEx(aBmp, aMask); 1524 } 1525 } 1526 } 1527 } 1528 else if((sal_uInt8)TRANSPARENT_COLOR == bTransparent) 1529 { 1530 Color aTransparentColor; 1531 1532 rIStm >> aTransparentColor; 1533 bRetval = !rIStm.GetError(); 1534 1535 if(bRetval) 1536 { 1537 rTarget = BitmapEx(aBmp, aTransparentColor); 1538 } 1539 } 1540 } 1541 } 1542 1543 if(!bRetval) 1544 { 1545 // alpha extra data could not be read; reset, but use base bitmap as result 1546 rIStm.ResetError(); 1547 rIStm.Seek(nStmPos); 1548 bRetval = true; 1549 } 1550 } 1551 1552 return bRetval; 1553 } 1554 1555 bool ReadDIBV5( 1556 Bitmap& rTarget, 1557 Bitmap& rTargetAlpha, 1558 SvStream& rIStm) 1559 { 1560 return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true); 1561 } 1562 1563 ////////////////////////////////////////////////////////////////////////////// 1564 1565 bool WriteDIB( 1566 const Bitmap& rSource, 1567 SvStream& rOStm, 1568 bool bCompressed, 1569 bool bFileHeader) 1570 { 1571 return ImplWriteDIB(rSource, 0, rOStm, bCompressed, bFileHeader); 1572 } 1573 1574 bool WriteDIBBitmapEx( 1575 const BitmapEx& rSource, 1576 SvStream& rOStm) 1577 { 1578 if(ImplWriteDIB(rSource.GetBitmap(), 0, rOStm, true, true)) 1579 { 1580 rOStm << (sal_uInt32)0x25091962; 1581 rOStm << (sal_uInt32)0xACB20201; 1582 rOStm << (sal_uInt8)rSource.eTransparent; 1583 1584 if(TRANSPARENT_BITMAP == rSource.eTransparent) 1585 { 1586 return ImplWriteDIB(rSource.aMask, 0, rOStm, true, true); 1587 } 1588 else if(TRANSPARENT_COLOR == rSource.eTransparent) 1589 { 1590 rOStm << rSource.aTransparentColor; 1591 return true; 1592 } 1593 } 1594 1595 return false; 1596 } 1597 1598 bool WriteDIBV5( 1599 const Bitmap& rSource, 1600 const Bitmap& rSourceAlpha, 1601 SvStream& rOStm) 1602 { 1603 return ImplWriteDIB(rSource, &rSourceAlpha, rOStm, false, true); 1604 } 1605 1606 ////////////////////////////////////////////////////////////////////////////// 1607 // eof 1608