1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
24 #include <vcl/salbtype.hxx>
25 #include <vcl/dibtools.hxx>
26 #include <tools/zcodec.hxx>
27 #include <tools/stream.hxx>
28 #include <tools/fract.hxx>
29 #include <vcl/bitmapex.hxx>
30 #include <vcl/bitmapaccess.hxx>
31 #include <vcl/outdev.hxx>
35 #define DIBCOREHEADERSIZE ( 12UL )
36 #define DIBINFOHEADERSIZE ( sizeof(DIBInfoHeader) )
37 #define DIBV5HEADERSIZE ( sizeof(DIBV5Header) )
39 // - DIBInfoHeader and DIBV5Header
41 typedef sal_Int32 FXPT2DOT30
;
79 sal_uInt32 nCompression
;
80 sal_uInt32 nSizeImage
;
81 sal_Int32 nXPelsPerMeter
;
82 sal_Int32 nYPelsPerMeter
;
84 sal_uInt32 nColsImportant
;
101 struct DIBV5Header
: public DIBInfoHeader
103 sal_uInt32 nV5RedMask
;
104 sal_uInt32 nV5GreenMask
;
105 sal_uInt32 nV5BlueMask
;
106 sal_uInt32 nV5AlphaMask
;
107 sal_uInt32 nV5CSType
;
108 CIEXYZTriple aV5Endpoints
;
109 sal_uInt32 nV5GammaRed
;
110 sal_uInt32 nV5GammaGreen
;
111 sal_uInt32 nV5GammaBlue
;
112 sal_uInt32 nV5Intent
;
113 sal_uInt32 nV5ProfileData
;
114 sal_uInt32 nV5ProfileSize
;
115 sal_uInt32 nV5Reserved
;
135 inline sal_uInt16
discretizeBitcount( sal_uInt16 nInputCount
)
137 return ( nInputCount
<= 1 ) ? 1 :
138 ( nInputCount
<= 4 ) ? 4 :
139 ( nInputCount
<= 8 ) ? 8 : 24;
142 inline bool isBitfieldCompression( ScanlineFormat nScanlineFormat
)
144 return (ScanlineFormat::N16BitTcLsbMask
== nScanlineFormat
) || (ScanlineFormat::N32BitTcMask
== nScanlineFormat
);
147 bool ImplReadDIBInfoHeader(SvStream
& rIStm
, DIBV5Header
& rHeader
, bool& bTopDown
, bool bMSOFormat
)
149 // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER
150 sal_uInt64
const aStartPos(rIStm
.Tell());
151 rIStm
.ReadUInt32( rHeader
.nSize
);
154 if ( rHeader
.nSize
== DIBCOREHEADERSIZE
)
158 rIStm
.ReadInt16( nTmp16
); rHeader
.nWidth
= nTmp16
;
159 rIStm
.ReadInt16( nTmp16
); rHeader
.nHeight
= nTmp16
;
160 rIStm
.ReadUInt16( rHeader
.nPlanes
);
161 rIStm
.ReadUInt16( rHeader
.nBitCount
);
163 else if ( bMSOFormat
&& rHeader
.nSize
== DIBINFOHEADERSIZE
)
166 rIStm
.ReadInt16(nTmp16
);
167 rHeader
.nWidth
= nTmp16
;
168 rIStm
.ReadInt16(nTmp16
);
169 rHeader
.nHeight
= nTmp16
;
171 rIStm
.ReadUChar(nTmp8
);
172 rHeader
.nPlanes
= nTmp8
;
173 rIStm
.ReadUChar(nTmp8
);
174 rHeader
.nBitCount
= nTmp8
;
175 rIStm
.ReadInt16(nTmp16
);
176 rHeader
.nSizeImage
= nTmp16
;
177 rIStm
.ReadInt16(nTmp16
);
178 rHeader
.nCompression
= nTmp16
;
179 if ( !rHeader
.nSizeImage
) // uncompressed?
180 rHeader
.nSizeImage
= ((rHeader
.nWidth
* rHeader
.nBitCount
+ 31) & ~31) / 8 * rHeader
.nHeight
;
181 rIStm
.ReadInt32( rHeader
.nXPelsPerMeter
);
182 rIStm
.ReadInt32( rHeader
.nYPelsPerMeter
);
183 rIStm
.ReadUInt32( rHeader
.nColsUsed
);
184 rIStm
.ReadUInt32( rHeader
.nColsImportant
);
188 // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible
189 std::size_t nUsed(sizeof(rHeader
.nSize
));
191 auto readUInt16
= [&nUsed
, &rHeader
, &rIStm
](sal_uInt16
& v
) {
192 if (nUsed
< rHeader
.nSize
) {
197 auto readInt32
= [&nUsed
, &rHeader
, &rIStm
](sal_Int32
& v
) {
198 if (nUsed
< rHeader
.nSize
) {
203 auto readUInt32
= [&nUsed
, &rHeader
, &rIStm
](sal_uInt32
& v
) {
204 if (nUsed
< rHeader
.nSize
) {
210 // read DIBInfoHeader entries
211 readInt32( rHeader
.nWidth
);
212 readInt32( rHeader
.nHeight
);
213 readUInt16( rHeader
.nPlanes
);
214 readUInt16( rHeader
.nBitCount
);
215 readUInt32( rHeader
.nCompression
);
216 readUInt32( rHeader
.nSizeImage
);
217 readInt32( rHeader
.nXPelsPerMeter
);
218 readInt32( rHeader
.nYPelsPerMeter
);
219 readUInt32( rHeader
.nColsUsed
);
220 readUInt32( rHeader
.nColsImportant
);
222 // read DIBV5HEADER members
223 readUInt32( rHeader
.nV5RedMask
);
224 readUInt32( rHeader
.nV5GreenMask
);
225 readUInt32( rHeader
.nV5BlueMask
);
226 readUInt32( rHeader
.nV5AlphaMask
);
227 readUInt32( rHeader
.nV5CSType
);
229 // read contained CIEXYZTriple's
230 readInt32( rHeader
.aV5Endpoints
.aXyzRed
.aXyzX
);
231 readInt32( rHeader
.aV5Endpoints
.aXyzRed
.aXyzY
);
232 readInt32( rHeader
.aV5Endpoints
.aXyzRed
.aXyzZ
);
233 readInt32( rHeader
.aV5Endpoints
.aXyzGreen
.aXyzX
);
234 readInt32( rHeader
.aV5Endpoints
.aXyzGreen
.aXyzY
);
235 readInt32( rHeader
.aV5Endpoints
.aXyzGreen
.aXyzZ
);
236 readInt32( rHeader
.aV5Endpoints
.aXyzBlue
.aXyzX
);
237 readInt32( rHeader
.aV5Endpoints
.aXyzBlue
.aXyzY
);
238 readInt32( rHeader
.aV5Endpoints
.aXyzBlue
.aXyzZ
);
240 readUInt32( rHeader
.nV5GammaRed
);
241 readUInt32( rHeader
.nV5GammaGreen
);
242 readUInt32( rHeader
.nV5GammaBlue
);
243 readUInt32( rHeader
.nV5Intent
);
244 readUInt32( rHeader
.nV5ProfileData
);
245 readUInt32( rHeader
.nV5ProfileSize
);
246 readUInt32( rHeader
.nV5Reserved
);
249 rIStm
.Seek(aStartPos
+ rHeader
.nSize
);
252 if ( rHeader
.nHeight
< 0 )
255 rHeader
.nHeight
*= -1;
262 if ( rHeader
.nWidth
< 0 )
264 rIStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
267 // #144105# protect a little against damaged files
268 assert(rHeader
.nHeight
>= 0);
269 if (rHeader
.nHeight
!= 0 && rHeader
.nWidth
>= 0
270 && (rHeader
.nSizeImage
/ 16 / static_cast<sal_uInt32
>(rHeader
.nHeight
)
271 > static_cast<sal_uInt32
>(rHeader
.nWidth
)))
273 rHeader
.nSizeImage
= 0;
277 if (rHeader
.nPlanes
!= 1)
280 if (rHeader
.nBitCount
!= 0 && rHeader
.nBitCount
!= 1 &&
281 rHeader
.nBitCount
!= 4 && rHeader
.nBitCount
!= 8 &&
282 rHeader
.nBitCount
!= 16 && rHeader
.nBitCount
!= 24 &&
283 rHeader
.nBitCount
!= 32)
291 bool ImplReadDIBPalette(SvStream
& rIStm
, BitmapPalette
& rPal
, bool bQuad
)
293 const sal_uInt16 nColors
= rPal
.GetEntryCount();
294 const sal_uLong nPalSize
= nColors
* ( bQuad
? 4UL : 3UL );
295 BitmapColor aPalColor
;
297 std::unique_ptr
<sal_uInt8
[]> pEntries(new sal_uInt8
[ nPalSize
]);
298 if (rIStm
.ReadBytes(pEntries
.get(), nPalSize
) != nPalSize
)
303 sal_uInt8
* pTmpEntry
= pEntries
.get();
304 for( sal_uInt16 i
= 0; i
< nColors
; i
++ )
306 aPalColor
.SetBlue( *pTmpEntry
++ );
307 aPalColor
.SetGreen( *pTmpEntry
++ );
308 aPalColor
.SetRed( *pTmpEntry
++ );
316 return( rIStm
.GetError() == 0UL );
321 sal_uInt8
SanitizePaletteIndex(sal_uInt8 nIndex
, BitmapPalette
& rPalette
, bool bForceToMonoWhileReading
)
323 const sal_uInt16 nPaletteEntryCount
= rPalette
.GetEntryCount();
324 if (nPaletteEntryCount
&& nIndex
>= nPaletteEntryCount
)
326 auto nSanitizedIndex
= nIndex
% nPaletteEntryCount
;
327 SAL_WARN_IF(nIndex
!= nSanitizedIndex
, "vcl", "invalid colormap index: "
328 << static_cast<unsigned int>(nIndex
) << ", colormap len is: "
329 << nPaletteEntryCount
);
330 nIndex
= nSanitizedIndex
;
333 if (nPaletteEntryCount
&& bForceToMonoWhileReading
)
335 return static_cast<sal_uInt8
>(rPalette
[nIndex
].GetLuminance() >= 255);
341 BitmapColor
SanitizeColor(const BitmapColor
&rColor
, bool bForceToMonoWhileReading
)
343 if (!bForceToMonoWhileReading
)
345 return BitmapColor(static_cast<sal_uInt8
>(rColor
.GetLuminance() >= 255));
350 bool ImplDecodeRLE(sal_uInt8
* pBuffer
, DIBV5Header
& rHeader
, BitmapWriteAccess
& rAcc
, BitmapPalette
& rPalette
, bool bForceToMonoWhileReading
, bool bRLE4
)
352 Scanline pRLE
= pBuffer
;
353 Scanline pEndRLE
= pBuffer
+ rHeader
.nSizeImage
;
354 long nY
= rHeader
.nHeight
- 1;
355 const sal_uLong nWidth
= rAcc
.Width();
356 sal_uLong nCountByte
;
360 bool bEndDecoding
= false;
366 if( ( nCountByte
= *pRLE
++ ) == 0 )
376 nCountByte
= nRunByte
>> 1;
378 for( sal_uLong i
= 0UL; i
< nCountByte
; i
++ )
386 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
>> 4, rPalette
, bForceToMonoWhileReading
));
389 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
& 0x0f, rPalette
, bForceToMonoWhileReading
));
398 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(*pRLE
>> 4, rPalette
, bForceToMonoWhileReading
));
403 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
413 for( sal_uLong i
= 0UL; i
< nRunByte
; i
++ )
419 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(*pRLE
, rPalette
, bForceToMonoWhileReading
));
438 else if( nRunByte
== 1 )
461 nRunByte
= nCountByte
>> 1;
463 for( sal_uLong i
= 0UL; i
< nRunByte
; i
++ )
466 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
>> 4, rPalette
, bForceToMonoWhileReading
));
469 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
& 0x0f, rPalette
, bForceToMonoWhileReading
));
472 if( ( nCountByte
& 1 ) && ( nX
< nWidth
) )
473 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
>> 4, rPalette
, bForceToMonoWhileReading
));
477 for( sal_uLong i
= 0UL; ( i
< nCountByte
) && ( nX
< nWidth
); i
++ )
478 rAcc
.SetPixelIndex(nY
, nX
++, SanitizePaletteIndex(cTmp
, rPalette
, bForceToMonoWhileReading
));
482 while (!bEndDecoding
&& (nY
>= 0));
487 bool ImplReadDIBBits(SvStream
& rIStm
, DIBV5Header
& rHeader
, BitmapWriteAccess
& rAcc
, BitmapPalette
& rPalette
, BitmapWriteAccess
* pAccAlpha
,
488 bool bTopDown
, bool& rAlphaUsed
, const sal_uInt64 nAlignedWidth
,
489 const bool bForceToMonoWhileReading
)
491 sal_uInt32
nRMask(( rHeader
.nBitCount
== 16 ) ? 0x00007c00UL
: 0x00ff0000UL
);
492 sal_uInt32
nGMask(( rHeader
.nBitCount
== 16 ) ? 0x000003e0UL
: 0x0000ff00UL
);
493 sal_uInt32
nBMask(( rHeader
.nBitCount
== 16 ) ? 0x0000001fUL
: 0x000000ffUL
);
495 bool bTCMask(!pAccAlpha
&& ((16 == rHeader
.nBitCount
) || (32 == rHeader
.nBitCount
)));
496 bool bRLE((RLE_8
== rHeader
.nCompression
&& 8 == rHeader
.nBitCount
) || (RLE_4
== rHeader
.nCompression
&& 4 == rHeader
.nBitCount
));
499 switch(rAcc
.GetScanlineFormat())
501 case ScanlineFormat::N1BitMsbPal
:
502 case ScanlineFormat::N24BitTcBgr
:
504 // we can't trust arbitrary-sourced index based formats to have correct indexes, so we exclude the pal formats
505 // from raw read and force checking their colormap indexes
506 bNative
= ( ( rAcc
.IsBottomUp() != bTopDown
) && !bRLE
&& !bTCMask
&& ( rAcc
.GetScanlineSize() == nAlignedWidth
) );
520 > std::numeric_limits
<std::size_t>::max() / rHeader
.nHeight
)
524 std::size_t n
= nAlignedWidth
* rHeader
.nHeight
;
525 if (rIStm
.ReadBytes(rAcc
.GetBuffer(), n
) != n
)
533 if(bTCMask
&& BITFIELDS
== rHeader
.nCompression
)
535 rIStm
.SeekRel( -12 );
536 rIStm
.ReadUInt32( nRMask
);
537 rIStm
.ReadUInt32( nGMask
);
538 rIStm
.ReadUInt32( nBMask
);
543 if(!rHeader
.nSizeImage
)
545 rHeader
.nSizeImage
= rIStm
.remainingSize();
548 if (rHeader
.nSizeImage
> rIStm
.remainingSize())
550 std::unique_ptr
<sal_uInt8
[]> pBuffer(new sal_uInt8
[rHeader
.nSizeImage
]);
551 if (rIStm
.ReadBytes(pBuffer
.get(), rHeader
.nSizeImage
)
552 != rHeader
.nSizeImage
)
556 if (!ImplDecodeRLE(pBuffer
.get(), rHeader
, rAcc
, rPalette
, bForceToMonoWhileReading
, RLE_4
== rHeader
.nCompression
))
561 const long nWidth(rHeader
.nWidth
);
562 const long nHeight(rHeader
.nHeight
);
563 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[nAlignedWidth
]);
565 const long nI(bTopDown
? 1 : -1);
566 long nY(bTopDown
? 0 : nHeight
- 1);
567 long nCount(nHeight
);
569 switch(rHeader
.nBitCount
)
573 for( ; nCount
--; nY
+= nI
)
575 sal_uInt8
* pTmp
= pBuf
.get();
576 if (rIStm
.ReadBytes(pTmp
, nAlignedWidth
)
581 sal_uInt8 cTmp
= *pTmp
++;
583 for( long nX
= 0, nShift
= 8; nX
< nWidth
; nX
++ )
591 auto nIndex
= (cTmp
>> --nShift
) & 1;
592 rAcc
.SetPixelIndex(nY
, nX
, SanitizePaletteIndex(nIndex
, rPalette
, bForceToMonoWhileReading
));
600 for( ; nCount
--; nY
+= nI
)
602 sal_uInt8
* pTmp
= pBuf
.get();
603 if (rIStm
.ReadBytes(pTmp
, nAlignedWidth
)
608 sal_uInt8 cTmp
= *pTmp
++;
610 for( long nX
= 0, nShift
= 2; nX
< nWidth
; nX
++ )
618 auto nIndex
= (cTmp
>> ( --nShift
<< 2UL ) ) & 0x0f;
619 rAcc
.SetPixelIndex(nY
, nX
, SanitizePaletteIndex(nIndex
, rPalette
, bForceToMonoWhileReading
));
627 for( ; nCount
--; nY
+= nI
)
629 sal_uInt8
* pTmp
= pBuf
.get();
630 if (rIStm
.ReadBytes(pTmp
, nAlignedWidth
)
636 for( long nX
= 0; nX
< nWidth
; nX
++ )
638 auto nIndex
= *pTmp
++;
639 rAcc
.SetPixelIndex(nY
, nX
, SanitizePaletteIndex(nIndex
, rPalette
, bForceToMonoWhileReading
));
647 ColorMaskElement
aRedMask(nRMask
);
648 if (!aRedMask
.CalcMaskShift())
650 ColorMaskElement
aGreenMask(nGMask
);
651 if (!aGreenMask
.CalcMaskShift())
653 ColorMaskElement
aBlueMask(nBMask
);
654 if (!aBlueMask
.CalcMaskShift())
657 ColorMask
aMask(aRedMask
, aGreenMask
, aBlueMask
);
660 for( ; nCount
--; nY
+= nI
)
662 sal_uInt16
* pTmp16
= reinterpret_cast<sal_uInt16
*>(pBuf
.get());
663 if (rIStm
.ReadBytes(pTmp16
, nAlignedWidth
)
669 for( long nX
= 0; nX
< nWidth
; nX
++ )
671 aMask
.GetColorFor16BitLSB( aColor
, reinterpret_cast<sal_uInt8
*>(pTmp16
++) );
672 rAcc
.SetPixel(nY
, nX
, SanitizeColor(aColor
, bForceToMonoWhileReading
));
680 BitmapColor aPixelColor
;
682 for( ; nCount
--; nY
+= nI
)
684 sal_uInt8
* pTmp
= pBuf
.get();
685 if (rIStm
.ReadBytes(pTmp
, nAlignedWidth
)
691 for( long nX
= 0; nX
< nWidth
; nX
++ )
693 aPixelColor
.SetBlue( *pTmp
++ );
694 aPixelColor
.SetGreen( *pTmp
++ );
695 aPixelColor
.SetRed( *pTmp
++ );
696 rAcc
.SetPixel(nY
, nX
, SanitizeColor(aPixelColor
, bForceToMonoWhileReading
));
704 ColorMaskElement
aRedMask(nRMask
);
705 if (!aRedMask
.CalcMaskShift())
707 ColorMaskElement
aGreenMask(nGMask
);
708 if (!aGreenMask
.CalcMaskShift())
710 ColorMaskElement
aBlueMask(nBMask
);
711 if (!aBlueMask
.CalcMaskShift())
713 ColorMask
aMask(aRedMask
, aGreenMask
, aBlueMask
);
722 for( ; nCount
--; nY
+= nI
)
724 pTmp32
= reinterpret_cast<sal_uInt32
*>(pBuf
.get());
725 if (rIStm
.ReadBytes(pTmp32
, nAlignedWidth
)
731 for( long nX
= 0; nX
< nWidth
; nX
++ )
733 aMask
.GetColorAndAlphaFor32Bit( aColor
, aAlpha
, reinterpret_cast<sal_uInt8
*>(pTmp32
++) );
734 rAcc
.SetPixel(nY
, nX
, SanitizeColor(aColor
, bForceToMonoWhileReading
));
735 pAccAlpha
->SetPixelIndex(nY
, nX
, sal_uInt8(0xff) - aAlpha
);
736 rAlphaUsed
|= bool(0xff != aAlpha
);
742 for( ; nCount
--; nY
+= nI
)
744 pTmp32
= reinterpret_cast<sal_uInt32
*>(pBuf
.get());
745 if (rIStm
.ReadBytes(pTmp32
, nAlignedWidth
)
751 for( long nX
= 0; nX
< nWidth
; nX
++ )
753 aMask
.GetColorFor32Bit( aColor
, reinterpret_cast<sal_uInt8
*>(pTmp32
++) );
754 rAcc
.SetPixel(nY
, nX
, SanitizeColor(aColor
, bForceToMonoWhileReading
));
763 return( rIStm
.GetError() == 0UL );
766 bool ImplReadDIBBody(SvStream
& rIStm
, Bitmap
& rBmp
, AlphaMask
* pBmpAlpha
, sal_uLong nOffset
, bool bIsMask
, bool bMSOFormat
)
769 const sal_uLong nStmPos
= rIStm
.Tell();
770 bool bTopDown(false);
772 if (!ImplReadDIBInfoHeader(rIStm
, aHeader
, bTopDown
, bMSOFormat
) && aHeader
.nWidth
&& aHeader
.nHeight
&& aHeader
.nBitCount
)
775 //BI_BITCOUNT_0 jpeg/png is unsupported
776 if (aHeader
.nBitCount
== 0)
779 // In case ImplReadDIB() didn't call ImplReadDIBFileHeader() before
780 // this method, nOffset is 0, that's OK.
781 if (nOffset
&& aHeader
.nSize
> nOffset
)
783 // Header size claims to extend into the image data.
784 // Looks like an error.
788 sal_uInt16
nColors(0);
790 std::unique_ptr
<SvMemoryStream
> pMemStm
;
791 std::vector
<sal_uInt8
> aData
;
793 if (aHeader
.nBitCount
<= 8)
795 if(aHeader
.nColsUsed
)
797 nColors
= (sal_uInt16
)aHeader
.nColsUsed
;
801 nColors
= ( 1 << aHeader
.nBitCount
);
805 if (ZCOMPRESS
== aHeader
.nCompression
)
807 sal_uInt32
nCodedSize(0);
808 sal_uInt32
nUncodedSize(0);
810 // read coding information
811 rIStm
.ReadUInt32( nCodedSize
).ReadUInt32( nUncodedSize
).ReadUInt32( aHeader
.nCompression
);
812 if (nCodedSize
> rIStm
.remainingSize())
813 nCodedSize
= sal_uInt32(rIStm
.remainingSize());
814 size_t nSizeInc(4 * rIStm
.remainingSize());
815 if (nUncodedSize
< nSizeInc
)
816 nSizeInc
= nUncodedSize
;
821 const sal_uLong nCodedPos
= rIStm
.Tell();
823 aCodec
.BeginCompression();
824 aData
.resize(nSizeInc
);
826 while (nUncodedSize
> nDataPos
)
828 assert(aData
.size() > nDataPos
);
829 const size_t nToRead(std::min
<size_t>(nUncodedSize
- nDataPos
, aData
.size() - nDataPos
));
831 assert(!aData
.empty());
832 const long nRead
= aCodec
.Read(rIStm
, aData
.data() + nDataPos
, sal_uInt32(nToRead
));
835 nDataPos
+= static_cast<unsigned long>(nRead
);
836 // we haven't read everything yet: resize buffer and continue
837 if (nDataPos
< nUncodedSize
)
838 aData
.resize(aData
.size() + nSizeInc
);
845 // truncate the data buffer to actually read size
846 aData
.resize(nDataPos
);
847 // set the real uncoded size
848 nUncodedSize
= sal_uInt32(aData
.size());
849 aCodec
.EndCompression();
851 // Seek behind the encoded block. There might have been bytes left or the codec might have read more than necessary.
852 rIStm
.Seek(nCodedSize
+ nCodedPos
);
857 // add something so we can take address of the first element
862 // set decoded bytes to memory stream,
863 // from which we will read the bitmap data
864 pMemStm
.reset(new SvMemoryStream
);
865 pIStm
= pMemStm
.get();
866 assert(!aData
.empty());
867 pMemStm
->SetBuffer(aData
.data(), nUncodedSize
, nUncodedSize
);
875 const sal_Int64
nBitsPerLine (static_cast<sal_Int64
>(aHeader
.nWidth
) * static_cast<sal_Int64
>(aHeader
.nBitCount
));
876 if (nBitsPerLine
> SAL_MAX_UINT32
)
878 const sal_uInt64
nAlignedWidth(AlignedWidth4Bytes(static_cast<sal_uLong
>(nBitsPerLine
)));
880 switch (aHeader
.nCompression
)
883 if (aHeader
.nBitCount
!= 8)
887 if (aHeader
.nBitCount
!= 4)
895 // (partially) check the image dimensions to avoid potential large bitmap allocation if the input is damaged
896 sal_uInt64 nMaxWidth
= pIStm
->remainingSize();
897 if (aHeader
.nHeight
!= 0)
898 nMaxWidth
/= aHeader
.nHeight
;
899 if (nMaxWidth
< nAlignedWidth
)
907 const Size
aSizePixel(aHeader
.nWidth
, aHeader
.nHeight
);
908 AlphaMask aNewBmpAlpha
;
909 AlphaMask::ScopedWriteAccess pAccAlpha
;
910 bool bAlphaPossible(pBmpAlpha
&& aHeader
.nBitCount
== 32);
914 const bool bRedSet(0 != aHeader
.nV5RedMask
);
915 const bool bGreenSet(0 != aHeader
.nV5GreenMask
);
916 const bool bBlueSet(0 != aHeader
.nV5BlueMask
);
918 // some clipboard entries have alpha mask on zero to say that there is
919 // no alpha; do only use this when the other masks are set. The MS docu
920 // says that masks are only to be set when bV5Compression is set to
921 // BI_BITFIELDS, but there seem to exist a wild variety of usages...
922 if((bRedSet
|| bGreenSet
|| bBlueSet
) && (0 == aHeader
.nV5AlphaMask
))
924 bAlphaPossible
= false;
930 aNewBmpAlpha
= AlphaMask(aSizePixel
);
931 pAccAlpha
= AlphaMask::ScopedWriteAccess(aNewBmpAlpha
);
935 BitmapPalette aPalette
;
938 aPalette
.SetEntryCount(nColors
);
939 ImplReadDIBPalette(*pIStm
, aPalette
, aHeader
.nSize
!= DIBCOREHEADERSIZE
);
942 if (pIStm
->GetError())
945 sal_uInt16
nBitCount(discretizeBitcount(aHeader
.nBitCount
));
946 const BitmapPalette
* pPal
= &aPalette
;
947 //ofz#948 match the surrounding logic of case TransparentType::Bitmap of
948 //ReadDIBBitmapEx but do it while reading for performance
949 const bool bIsAlpha
= (nBitCount
== 8 && !!aPalette
&& aPalette
.IsGreyPalette());
950 const bool bForceToMonoWhileReading
= (bIsMask
&& !bIsAlpha
&& nBitCount
!= 1);
951 if (bForceToMonoWhileReading
)
955 SAL_WARN( "vcl", "forcing mask to monochrome");
958 Bitmap
aNewBmp(aSizePixel
, nBitCount
, pPal
);
959 Bitmap::ScopedWriteAccess
pAcc(aNewBmp
);
962 if (pAcc
->Width() != aHeader
.nWidth
|| pAcc
->Height() != aHeader
.nHeight
)
969 pIStm
->SeekRel(nOffset
- (pIStm
->Tell() - nStmPos
));
973 bool bAlphaUsed(false);
974 bool bRet
= ImplReadDIBBits(*pIStm
, aHeader
, *pAcc
, aPalette
, pAccAlpha
.get(), bTopDown
, bAlphaUsed
, nAlignedWidth
, bForceToMonoWhileReading
);
976 if (bRet
&& aHeader
.nXPelsPerMeter
&& aHeader
.nYPelsPerMeter
)
981 Fraction(1000, aHeader
.nXPelsPerMeter
),
982 Fraction(1000, aHeader
.nYPelsPerMeter
));
984 aNewBmp
.SetPrefMapMode(aMapMode
);
985 aNewBmp
.SetPrefSize(Size(aHeader
.nWidth
, aHeader
.nHeight
));
996 bAlphaPossible
= false;
1006 *pBmpAlpha
= aNewBmpAlpha
;
1013 bool ImplReadDIBFileHeader( SvStream
& rIStm
, sal_uLong
& rOffset
)
1017 const sal_uInt64
nSavedStreamPos( rIStm
.Tell() );
1018 const sal_uInt64
nStreamLength( rIStm
.Seek( STREAM_SEEK_TO_END
) );
1019 rIStm
.Seek( nSavedStreamPos
);
1021 sal_uInt16 nTmp16
= 0;
1022 rIStm
.ReadUInt16( nTmp16
);
1024 if ( ( 0x4D42 == nTmp16
) || ( 0x4142 == nTmp16
) )
1026 sal_uInt32
nTmp32(0);
1027 if ( 0x4142 == nTmp16
)
1029 rIStm
.SeekRel( 12 );
1030 rIStm
.ReadUInt16( nTmp16
);
1032 rIStm
.ReadUInt32( nTmp32
);
1033 rOffset
= nTmp32
- 28UL;
1034 bRet
= ( 0x4D42 == nTmp16
);
1036 else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER
1038 rIStm
.SeekRel( 8 ); // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits
1039 rIStm
.ReadUInt32( nTmp32
); // read bfOffBits
1040 rOffset
= nTmp32
- 14UL; // adapt offset by sizeof(BITMAPFILEHEADER)
1041 bRet
= ( rIStm
.GetError() == 0UL );
1044 if ( rOffset
>= nStreamLength
)
1046 // Offset claims that image starts past the end of the
1047 // stream. Unlikely.
1048 rIStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
1053 rIStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
1058 bool ImplWriteDIBPalette( SvStream
& rOStm
, BitmapReadAccess
& rAcc
)
1060 const sal_uInt16 nColors
= rAcc
.GetPaletteEntryCount();
1061 const sal_uLong nPalSize
= nColors
* 4UL;
1062 std::unique_ptr
<sal_uInt8
[]> pEntries(new sal_uInt8
[ nPalSize
]);
1063 sal_uInt8
* pTmpEntry
= pEntries
.get();
1064 BitmapColor aPalColor
;
1066 for( sal_uInt16 i
= 0; i
< nColors
; i
++ )
1068 const BitmapColor
& rPalColor
= rAcc
.GetPaletteColor( i
);
1070 *pTmpEntry
++ = rPalColor
.GetBlue();
1071 *pTmpEntry
++ = rPalColor
.GetGreen();
1072 *pTmpEntry
++ = rPalColor
.GetRed();
1076 rOStm
.WriteBytes( pEntries
.get(), nPalSize
);
1078 return( rOStm
.GetError() == 0UL );
1081 bool ImplWriteRLE( SvStream
& rOStm
, BitmapReadAccess
& rAcc
, bool bRLE4
)
1083 const sal_uLong nWidth
= rAcc
.Width();
1084 const sal_uLong nHeight
= rAcc
.Height();
1086 sal_uLong nSaveIndex
;
1088 sal_uLong nBufCount
;
1089 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ ( nWidth
<< 1 ) + 2 ]);
1094 for ( long nY
= nHeight
- 1; nY
>= 0; nY
-- )
1096 sal_uInt8
* pTmp
= pBuf
.get();
1097 nX
= nBufCount
= 0UL;
1099 while( nX
< nWidth
)
1102 cPix
= rAcc
.GetPixelIndex( nY
, nX
++ );
1104 while( ( nX
< nWidth
) && ( nCount
< 255 )
1105 && ( cPix
== rAcc
.GetPixelIndex( nY
, nX
) ) )
1113 *pTmp
++ = (sal_uInt8
) nCount
;
1114 *pTmp
++ = ( bRLE4
? ( ( cPix
<< 4 ) | cPix
) : cPix
);
1120 nSaveIndex
= nX
- 1UL;
1123 while( ( nX
< nWidth
) && ( nCount
< 256 )
1124 && ( cPix
= rAcc
.GetPixelIndex( nY
, nX
) ) != cLast
)
1137 *pTmp
++ = (sal_uInt8
) --nCount
;
1141 for ( sal_uLong i
= 0; i
< nCount
; i
++, pTmp
++ )
1143 *pTmp
= rAcc
.GetPixelIndex( nY
, nSaveIndex
++ ) << 4;
1146 *pTmp
|= rAcc
.GetPixelIndex( nY
, nSaveIndex
++ );
1149 nCount
= ( nCount
+ 1 ) >> 1;
1153 for( sal_uLong i
= 0UL; i
< nCount
; i
++ )
1154 *pTmp
++ = rAcc
.GetPixelIndex( nY
, nSaveIndex
++ );
1160 nBufCount
+= ( nCount
+ 3 );
1163 nBufCount
+= ( nCount
+ 2 );
1168 *pTmp
++ = rAcc
.GetPixelIndex( nY
, nSaveIndex
) << (bRLE4
? 4 : 0);
1173 *pTmp
++ = rAcc
.GetPixelIndex( nY
, ++nSaveIndex
) << ( bRLE4
? 4 : 0 );
1182 pBuf
[ nBufCount
++ ] = 0;
1183 pBuf
[ nBufCount
++ ] = 0;
1185 rOStm
.WriteBytes( pBuf
.get(), nBufCount
);
1188 rOStm
.WriteUChar( 0 );
1189 rOStm
.WriteUChar( 1 );
1191 return( rOStm
.GetError() == 0UL );
1194 bool ImplWriteDIBBits(SvStream
& rOStm
, BitmapReadAccess
& rAcc
, BitmapReadAccess
* pAccAlpha
, sal_uLong nCompression
, sal_uInt32
& rImageSize
)
1196 if(!pAccAlpha
&& BITFIELDS
== nCompression
)
1198 const ColorMask
& rMask
= rAcc
.GetColorMask();
1201 UInt32ToSVBT32( rMask
.GetRedMask(), aVal32
);
1202 rOStm
.WriteBytes( aVal32
, 4UL );
1204 UInt32ToSVBT32( rMask
.GetGreenMask(), aVal32
);
1205 rOStm
.WriteBytes( aVal32
, 4UL );
1207 UInt32ToSVBT32( rMask
.GetBlueMask(), aVal32
);
1208 rOStm
.WriteBytes( aVal32
, 4UL );
1210 rImageSize
= rOStm
.Tell();
1212 if( rAcc
.IsBottomUp() )
1213 rOStm
.WriteBytes(rAcc
.GetBuffer(), rAcc
.Height() * rAcc
.GetScanlineSize());
1216 for( long nY
= rAcc
.Height() - 1, nScanlineSize
= rAcc
.GetScanlineSize(); nY
>= 0; nY
-- )
1217 rOStm
.WriteBytes( rAcc
.GetScanline(nY
), nScanlineSize
);
1220 else if(!pAccAlpha
&& ((RLE_4
== nCompression
) || (RLE_8
== nCompression
)))
1222 rImageSize
= rOStm
.Tell();
1223 ImplWriteRLE( rOStm
, rAcc
, RLE_4
== nCompression
);
1225 else if(!nCompression
)
1227 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
1228 // handled properly below (would have to set color masks, and
1229 // nCompression=BITFIELDS - but color mask is not set for
1230 // formats != *_TC_*). Note that this very problem might cause
1231 // trouble at other places - the introduction of 32 bit RGBA
1232 // bitmaps is relatively recent.
1233 // #i59239# discretize bitcount for aligned width to 1,4,8,24
1234 // (other cases are not written below)
1235 const sal_uInt16
nBitCount(pAccAlpha
? 32 : discretizeBitcount(rAcc
.GetBitCount()));
1236 const sal_uLong
nAlignedWidth(AlignedWidth4Bytes(rAcc
.Width() * nBitCount
));
1237 bool bNative(false);
1239 switch(rAcc
.GetScanlineFormat())
1241 case ScanlineFormat::N1BitMsbPal
:
1242 case ScanlineFormat::N4BitMsnPal
:
1243 case ScanlineFormat::N8BitPal
:
1244 case ScanlineFormat::N24BitTcBgr
:
1246 if(!pAccAlpha
&& rAcc
.IsBottomUp() && (rAcc
.GetScanlineSize() == nAlignedWidth
))
1260 rImageSize
= rOStm
.Tell();
1264 rOStm
.WriteBytes(rAcc
.GetBuffer(), nAlignedWidth
* rAcc
.Height());
1268 const long nWidth(rAcc
.Width());
1269 const long nHeight(rAcc
.Height());
1270 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ nAlignedWidth
]);
1275 //valgrind, zero out the trailing unused alignment bytes
1276 size_t nUnusedBytes
= nAlignedWidth
- ((nWidth
+7) / 8);
1277 memset(pBuf
.get() + nAlignedWidth
- nUnusedBytes
, 0, nUnusedBytes
);
1279 for( long nY
= nHeight
- 1; nY
>= 0; nY
-- )
1281 sal_uInt8
* pTmp
= pBuf
.get();
1284 for( long nX
= 0, nShift
= 8; nX
< nWidth
; nX
++ )
1293 cTmp
|= rAcc
.GetPixelIndex( nY
, nX
) << --nShift
;
1297 rOStm
.WriteBytes( pBuf
.get(), nAlignedWidth
);
1304 //valgrind, zero out the trailing unused alignment bytes
1305 size_t nUnusedBytes
= nAlignedWidth
- ((nWidth
+1) / 2);
1306 memset(pBuf
.get() + nAlignedWidth
- nUnusedBytes
, 0, nUnusedBytes
);
1308 for( long nY
= nHeight
- 1; nY
>= 0; nY
-- )
1310 sal_uInt8
* pTmp
= pBuf
.get();
1313 for( long nX
= 0, nShift
= 2; nX
< nWidth
; nX
++ )
1322 cTmp
|= rAcc
.GetPixelIndex( nY
, nX
) << ( --nShift
<< 2 );
1325 rOStm
.WriteBytes( pBuf
.get(), nAlignedWidth
);
1332 for( long nY
= nHeight
- 1; nY
>= 0; nY
-- )
1334 sal_uInt8
* pTmp
= pBuf
.get();
1336 for( long nX
= 0; nX
< nWidth
; nX
++ )
1337 *pTmp
++ = rAcc
.GetPixelIndex( nY
, nX
);
1339 rOStm
.WriteBytes( pBuf
.get(), nAlignedWidth
);
1346 //valgrind, zero out the trailing unused alignment bytes
1347 size_t nUnusedBytes
= nAlignedWidth
- nWidth
* 3;
1348 memset(pBuf
.get() + nAlignedWidth
- nUnusedBytes
, 0, nUnusedBytes
);
1351 // #i59239# fallback to 24 bit format, if bitcount is non-default
1354 BitmapColor aPixelColor
;
1355 const bool bWriteAlpha(32 == nBitCount
&& pAccAlpha
);
1357 for( long nY
= nHeight
- 1; nY
>= 0; nY
-- )
1359 sal_uInt8
* pTmp
= pBuf
.get();
1361 for( long nX
= 0; nX
< nWidth
; nX
++ )
1363 // when alpha is used, this may be non-24bit main bitmap, so use GetColor
1364 // instead of GetPixel to ensure RGB value
1365 aPixelColor
= rAcc
.GetColor( nY
, nX
);
1367 *pTmp
++ = aPixelColor
.GetBlue();
1368 *pTmp
++ = aPixelColor
.GetGreen();
1369 *pTmp
++ = aPixelColor
.GetRed();
1373 *pTmp
++ = (sal_uInt8
)0xff - pAccAlpha
->GetPixelIndex( nY
, nX
);
1377 rOStm
.WriteBytes( pBuf
.get(), nAlignedWidth
);
1385 rImageSize
= rOStm
.Tell() - rImageSize
;
1387 return (!rOStm
.GetError());
1390 bool ImplWriteDIBBody(const Bitmap
& rBitmap
, SvStream
& rOStm
, BitmapReadAccess
& rAcc
, BitmapReadAccess
* pAccAlpha
, bool bCompressed
)
1392 const MapMode
aMapPixel(MapUnit::MapPixel
);
1393 DIBV5Header aHeader
;
1394 sal_uLong
nImageSizePos(0);
1395 sal_uLong
nEndPos(0);
1396 sal_uInt32
nCompression(COMPRESS_NONE
);
1399 aHeader
.nSize
= pAccAlpha
? DIBV5HEADERSIZE
: DIBINFOHEADERSIZE
; // size dependent on CF_DIB type to use
1400 aHeader
.nWidth
= rAcc
.Width();
1401 aHeader
.nHeight
= rAcc
.Height();
1402 aHeader
.nPlanes
= 1;
1404 if(!pAccAlpha
&& isBitfieldCompression(rAcc
.GetScanlineFormat()))
1406 aHeader
.nBitCount
= (ScanlineFormat::N16BitTcLsbMask
== rAcc
.GetScanlineFormat()) ? 16 : 32;
1407 aHeader
.nSizeImage
= rAcc
.Height() * rAcc
.GetScanlineSize();
1408 nCompression
= BITFIELDS
;
1412 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
1413 // not handled properly below (would have to set color
1414 // masks, and nCompression=BITFIELDS - but color mask is
1415 // not set for formats != *_TC_*). Note that this very
1416 // problem might cause trouble at other places - the
1417 // introduction of 32 bit RGBA bitmaps is relatively
1419 // #i59239# discretize bitcount to 1,4,8,24 (other cases
1420 // are not written below)
1421 const sal_uInt16
nBitCount(pAccAlpha
? 32 : discretizeBitcount(rAcc
.GetBitCount()));
1422 aHeader
.nBitCount
= nBitCount
;
1423 aHeader
.nSizeImage
= rAcc
.Height() * AlignedWidth4Bytes(rAcc
.Width() * aHeader
.nBitCount
);
1429 nCompression
= RLE_4
;
1431 else if(8 == nBitCount
)
1433 nCompression
= RLE_8
;
1438 if((rOStm
.GetCompressMode() & SvStreamCompressFlags::ZBITMAP
) && (rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_40
))
1440 aHeader
.nCompression
= ZCOMPRESS
;
1444 aHeader
.nCompression
= nCompression
;
1447 if(rBitmap
.GetPrefSize().Width() && rBitmap
.GetPrefSize().Height() && (rBitmap
.GetPrefMapMode() != aMapPixel
))
1449 // #i48108# Try to recover xpels/ypels as previously stored on
1450 // disk. The problem with just converting maPrefSize to 100th
1451 // mm and then relating that to the bitmap pixel size is that
1452 // MapMode is integer-based, and suffers from roundoffs,
1453 // especially if maPrefSize is small. Trying to circumvent
1454 // that by performing part of the math in floating point.
1455 const Size
aScale100000(OutputDevice::LogicToLogic(Size(100000, 100000), MapUnit::Map100thMM
, rBitmap
.GetPrefMapMode()));
1456 const double fBmpWidthM((double)rBitmap
.GetPrefSize().Width() / aScale100000
.Width());
1457 const double fBmpHeightM((double)rBitmap
.GetPrefSize().Height() / aScale100000
.Height());
1459 if(!basegfx::fTools::equalZero(fBmpWidthM
) && !basegfx::fTools::equalZero(fBmpHeightM
))
1461 aHeader
.nXPelsPerMeter
= basegfx::fround(rAcc
.Width() / fabs(fBmpWidthM
));
1462 aHeader
.nYPelsPerMeter
= basegfx::fround(rAcc
.Height() / fabs(fBmpHeightM
));
1466 aHeader
.nColsUsed
= ((!pAccAlpha
&& aHeader
.nBitCount
<= 8) ? rAcc
.GetPaletteEntryCount() : 0);
1467 aHeader
.nColsImportant
= 0;
1469 rOStm
.WriteUInt32( aHeader
.nSize
);
1470 rOStm
.WriteInt32( aHeader
.nWidth
);
1471 rOStm
.WriteInt32( aHeader
.nHeight
);
1472 rOStm
.WriteUInt16( aHeader
.nPlanes
);
1473 rOStm
.WriteUInt16( aHeader
.nBitCount
);
1474 rOStm
.WriteUInt32( aHeader
.nCompression
);
1476 nImageSizePos
= rOStm
.Tell();
1477 rOStm
.SeekRel( sizeof( aHeader
.nSizeImage
) );
1479 rOStm
.WriteInt32( aHeader
.nXPelsPerMeter
);
1480 rOStm
.WriteInt32( aHeader
.nYPelsPerMeter
);
1481 rOStm
.WriteUInt32( aHeader
.nColsUsed
);
1482 rOStm
.WriteUInt32( aHeader
.nColsImportant
);
1484 if(pAccAlpha
) // only write DIBV5 when asked to do so
1486 aHeader
.nV5CSType
= 0x57696E20; // LCS_WINDOWS_COLOR_SPACE
1487 aHeader
.nV5Intent
= 0x00000004; // LCS_GM_IMAGES
1489 rOStm
.WriteUInt32( aHeader
.nV5RedMask
);
1490 rOStm
.WriteUInt32( aHeader
.nV5GreenMask
);
1491 rOStm
.WriteUInt32( aHeader
.nV5BlueMask
);
1492 rOStm
.WriteUInt32( aHeader
.nV5AlphaMask
);
1493 rOStm
.WriteUInt32( aHeader
.nV5CSType
);
1495 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzRed
.aXyzX
);
1496 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzRed
.aXyzY
);
1497 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzRed
.aXyzZ
);
1498 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzGreen
.aXyzX
);
1499 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzGreen
.aXyzY
);
1500 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzGreen
.aXyzZ
);
1501 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzBlue
.aXyzX
);
1502 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzBlue
.aXyzY
);
1503 rOStm
.WriteInt32( aHeader
.aV5Endpoints
.aXyzBlue
.aXyzZ
);
1505 rOStm
.WriteUInt32( aHeader
.nV5GammaRed
);
1506 rOStm
.WriteUInt32( aHeader
.nV5GammaGreen
);
1507 rOStm
.WriteUInt32( aHeader
.nV5GammaBlue
);
1508 rOStm
.WriteUInt32( aHeader
.nV5Intent
);
1509 rOStm
.WriteUInt32( aHeader
.nV5ProfileData
);
1510 rOStm
.WriteUInt32( aHeader
.nV5ProfileSize
);
1511 rOStm
.WriteUInt32( aHeader
.nV5Reserved
);
1514 if(ZCOMPRESS
== aHeader
.nCompression
)
1517 SvMemoryStream
aMemStm(aHeader
.nSizeImage
+ 4096, 65535);
1518 sal_uLong
nCodedPos(rOStm
.Tell());
1519 sal_uLong
nLastPos(0);
1520 sal_uInt32
nCodedSize(0);
1521 sal_uInt32
nUncodedSize(0);
1523 // write uncoded data palette
1524 if(aHeader
.nColsUsed
)
1526 ImplWriteDIBPalette(aMemStm
, rAcc
);
1529 // write uncoded bits
1530 bRet
= ImplWriteDIBBits(aMemStm
, rAcc
, pAccAlpha
, nCompression
, aHeader
.nSizeImage
);
1533 nUncodedSize
= aMemStm
.Tell();
1535 // seek over compress info
1538 // write compressed data
1539 aCodec
.BeginCompression(3);
1540 aCodec
.Write(rOStm
, static_cast<sal_uInt8
const *>(aMemStm
.GetData()), nUncodedSize
);
1541 aCodec
.EndCompression();
1543 // update compress info ( coded size, uncoded size, uncoded compression )
1544 nLastPos
= rOStm
.Tell();
1545 nCodedSize
= nLastPos
- nCodedPos
- 12;
1546 rOStm
.Seek(nCodedPos
);
1547 rOStm
.WriteUInt32( nCodedSize
).WriteUInt32( nUncodedSize
).WriteUInt32( nCompression
);
1548 rOStm
.Seek(nLastPos
);
1552 bRet
= (ERRCODE_NONE
== rOStm
.GetError());
1557 if(aHeader
.nColsUsed
)
1559 ImplWriteDIBPalette(rOStm
, rAcc
);
1562 bRet
= ImplWriteDIBBits(rOStm
, rAcc
, pAccAlpha
, aHeader
.nCompression
, aHeader
.nSizeImage
);
1565 nEndPos
= rOStm
.Tell();
1566 rOStm
.Seek(nImageSizePos
);
1567 rOStm
.WriteUInt32( aHeader
.nSizeImage
);
1568 rOStm
.Seek(nEndPos
);
1573 bool ImplWriteDIBFileHeader(SvStream
& rOStm
, BitmapReadAccess
& rAcc
, bool bUseDIBV5
)
1575 const sal_uInt32
nPalCount((rAcc
.HasPalette() ? rAcc
.GetPaletteEntryCount() : isBitfieldCompression(rAcc
.GetScanlineFormat()) ? 3UL : 0UL));
1576 const sal_uInt32
nOffset(14 + (bUseDIBV5
? DIBV5HEADERSIZE
: DIBINFOHEADERSIZE
) + nPalCount
* 4UL);
1578 rOStm
.WriteUInt16( 0x4D42 ); // 'MB' from BITMAPFILEHEADER
1579 rOStm
.WriteUInt32( nOffset
+ (rAcc
.Height() * rAcc
.GetScanlineSize()) );
1580 rOStm
.WriteUInt16( 0 );
1581 rOStm
.WriteUInt16( 0 );
1582 rOStm
.WriteUInt32( nOffset
);
1584 return( rOStm
.GetError() == 0UL );
1589 AlphaMask
* pTargetAlpha
,
1593 bool bMSOFormat
=false)
1595 const SvStreamEndian
nOldFormat(rIStm
.GetEndian());
1596 const sal_uLong
nOldPos(rIStm
.Tell());
1597 sal_uLong
nOffset(0UL);
1600 rIStm
.SetEndian(SvStreamEndian::LITTLE
);
1604 if(ImplReadDIBFileHeader(rIStm
, nOffset
))
1606 bRet
= ImplReadDIBBody(rIStm
, rTarget
, nOffset
>= DIBV5HEADERSIZE
? pTargetAlpha
: nullptr, nOffset
, bIsMask
, bMSOFormat
);
1611 bRet
= ImplReadDIBBody(rIStm
, rTarget
, nullptr, nOffset
, bIsMask
, bMSOFormat
);
1616 if(!rIStm
.GetError())
1618 rIStm
.SetError(SVSTREAM_GENERALERROR
);
1621 rIStm
.Seek(nOldPos
);
1624 rIStm
.SetEndian(nOldFormat
);
1630 const Bitmap
& rSource
,
1631 const Bitmap
* pSourceAlpha
,
1636 const Size
aSizePix(rSource
.GetSizePixel());
1639 if(aSizePix
.Width() && aSizePix
.Height())
1641 Bitmap::ScopedReadAccess
pAcc(const_cast< Bitmap
& >(rSource
));
1642 Bitmap::ScopedReadAccess pAccAlpha
;
1643 const SvStreamEndian
nOldFormat(rOStm
.GetEndian());
1644 const sal_uLong
nOldPos(rOStm
.Tell());
1648 const Size
aSizePixAlpha(pSourceAlpha
->GetSizePixel());
1650 if(aSizePixAlpha
== aSizePix
)
1652 pAccAlpha
= Bitmap::ScopedReadAccess(const_cast< Bitmap
& >(*pSourceAlpha
));
1656 OSL_ENSURE(false, "WriteDIB got an alpha channel, but it's pixel size differs from the base bitmap (!)");
1660 rOStm
.SetEndian(SvStreamEndian::LITTLE
);
1666 if(ImplWriteDIBFileHeader(rOStm
, *pAcc
, nullptr != pSourceAlpha
))
1668 bRet
= ImplWriteDIBBody(rSource
, rOStm
, *pAcc
, pAccAlpha
.get(), bCompressed
);
1673 bRet
= ImplWriteDIBBody(rSource
, rOStm
, *pAcc
, pAccAlpha
.get(), bCompressed
);
1683 rOStm
.SetError(SVSTREAM_GENERALERROR
);
1684 rOStm
.Seek(nOldPos
);
1687 rOStm
.SetEndian(nOldFormat
);
1693 } // unnamed namespace
1701 return ImplReadDIB(rTarget
, nullptr, rIStm
, bFileHeader
, false, bMSOFormat
);
1704 bool ReadDIBBitmapEx(
1709 bool bRetval(ImplReadDIB(aBmp
, nullptr, rIStm
, true) && !rIStm
.GetError());
1713 // base bitmap was read, set as return value and try to read alpha extra-data
1714 const sal_uLong
nStmPos(rIStm
.Tell());
1715 sal_uInt32
nMagic1(0);
1716 sal_uInt32
nMagic2(0);
1718 rTarget
= BitmapEx(aBmp
);
1719 rIStm
.ReadUInt32( nMagic1
).ReadUInt32( nMagic2
);
1720 bRetval
= (0x25091962 == nMagic1
) && (0xACB20201 == nMagic2
) && !rIStm
.GetError();
1725 rIStm
.ReadUChar( tmp
);
1726 TransparentType transparent
= (TransparentType
)tmp
;
1727 bRetval
= !rIStm
.GetError();
1731 switch (transparent
)
1733 case TransparentType::Bitmap
:
1737 bRetval
= ImplReadDIB(aMask
, nullptr, rIStm
, true, true);
1743 // do we have an alpha mask?
1744 if((8 == aMask
.GetBitCount()) && aMask
.HasGreyPalette())
1748 // create alpha mask quickly (without greyscale conversion)
1749 aAlpha
.ImplSetBitmap(aMask
);
1750 rTarget
= BitmapEx(aBmp
, aAlpha
);
1754 rTarget
= BitmapEx(aBmp
, aMask
);
1760 case TransparentType::Color
:
1762 Color aTransparentColor
;
1764 ReadColor( rIStm
, aTransparentColor
);
1765 bRetval
= !rIStm
.GetError();
1769 rTarget
= BitmapEx(aBmp
, aTransparentColor
);
1780 // alpha extra data could not be read; reset, but use base bitmap as result
1782 rIStm
.Seek(nStmPos
);
1792 AlphaMask
& rTargetAlpha
,
1795 return ImplReadDIB(rTarget
, &rTargetAlpha
, rIStm
, true);
1799 const Bitmap
& rSource
,
1804 return ImplWriteDIB(rSource
, nullptr, rOStm
, bCompressed
, bFileHeader
);
1807 bool WriteDIBBitmapEx(
1808 const BitmapEx
& rSource
,
1811 if(ImplWriteDIB(rSource
.GetBitmap(), nullptr, rOStm
, true, true))
1813 rOStm
.WriteUInt32( 0x25091962 );
1814 rOStm
.WriteUInt32( 0xACB20201 );
1815 rOStm
.WriteUChar( (sal_uChar
)rSource
.eTransparent
);
1817 if(TransparentType::Bitmap
== rSource
.eTransparent
)
1819 return ImplWriteDIB(rSource
.aMask
, nullptr, rOStm
, true, true);
1821 else if(TransparentType::Color
== rSource
.eTransparent
)
1823 WriteColor( rOStm
, rSource
.aTransparentColor
);
1831 sal_uInt32
getDIBV5HeaderSize()
1833 return DIBV5HEADERSIZE
;
1836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */