xref: /aoo4110/main/vcl/source/gdi/dibtools.cxx (revision b1cdbd2c)
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 
CIEXYZCIEXYZ61     CIEXYZ()
62     :   aXyzX(0L),
63         aXyzY(0L),
64         aXyzZ(0L)
65     {}
66 
~CIEXYZCIEXYZ67     ~CIEXYZ()
68     {}
69 };
70 
71 struct CIEXYZTriple
72 {
73     CIEXYZ          aXyzRed;
74     CIEXYZ          aXyzGreen;
75     CIEXYZ          aXyzBlue;
76 
CIEXYZTripleCIEXYZTriple77     CIEXYZTriple()
78     :   aXyzRed(),
79         aXyzGreen(),
80         aXyzBlue()
81     {}
82 
~CIEXYZTripleCIEXYZTriple83     ~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 
DIBInfoHeaderDIBInfoHeader101     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 
~DIBInfoHeaderDIBInfoHeader115     ~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 
DIBV5HeaderDIBV5Header135     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 
~DIBV5HeaderDIBV5Header152     ~DIBV5Header()
153     {}
154 };
155 
156 //////////////////////////////////////////////////////////////////////////////
157 
158 namespace
159 {
discretizeBitcount(sal_uInt16 nInputCount)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 
isBitfieldCompression(sal_uLong nScanlineFormat)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 
ImplReadDIBInfoHeader(SvStream & rIStm,DIBV5Header & rHeader,bool & bTopDown)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 
ImplReadDIBPalette(SvStream & rIStm,BitmapWriteAccess & rAcc,bool bQuad)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 
ImplDecodeRLE(sal_uInt8 * pBuffer,DIBV5Header & rHeader,BitmapWriteAccess & rAcc,bool bRLE4)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 
ImplReadDIBBits(SvStream & rIStm,DIBV5Header & rHeader,BitmapWriteAccess & rAcc,BitmapWriteAccess * pAccAlpha,bool bTopDown,bool & rAlphaUsed)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 
ImplReadDIBBody(SvStream & rIStm,Bitmap & rBmp,Bitmap * pBmpAlpha,sal_uLong nOffset)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 
ImplReadDIBFileHeader(SvStream & rIStm,sal_uLong & rOffset)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 
ImplWriteDIBPalette(SvStream & rOStm,BitmapReadAccess & rAcc)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 
ImplWriteRLE(SvStream & rOStm,BitmapReadAccess & rAcc,bool bRLE4)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 
ImplWriteDIBBits(SvStream & rOStm,BitmapReadAccess & rAcc,BitmapReadAccess * pAccAlpha,sal_uLong nCompression,sal_uInt32 & rImageSize)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 
ImplWriteDIBBody(const Bitmap & rBitmap,SvStream & rOStm,BitmapReadAccess & rAcc,BitmapReadAccess * pAccAlpha,bool bCompressed)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 
ImplWriteDIBFileHeader(SvStream & rOStm,BitmapReadAccess & rAcc,bool bUseDIBV5)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 
ImplReadDIB(Bitmap & rTarget,Bitmap * pTargetAlpha,SvStream & rIStm,bool bFileHeader)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 
ImplWriteDIB(const Bitmap & rSource,const Bitmap * pSourceAlpha,SvStream & rOStm,bool bCompressed,bool bFileHeader)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 
ReadDIB(Bitmap & rTarget,SvStream & rIStm,bool bFileHeader)1467 bool ReadDIB(
1468     Bitmap& rTarget,
1469     SvStream& rIStm,
1470     bool bFileHeader)
1471 {
1472     return ImplReadDIB(rTarget, 0, rIStm, bFileHeader);
1473 }
1474 
ReadDIBBitmapEx(BitmapEx & rTarget,SvStream & rIStm)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 
ReadDIBV5(Bitmap & rTarget,Bitmap & rTargetAlpha,SvStream & rIStm)1555 bool ReadDIBV5(
1556     Bitmap& rTarget,
1557     Bitmap& rTargetAlpha,
1558     SvStream& rIStm)
1559 {
1560     return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
1561 }
1562 
1563 //////////////////////////////////////////////////////////////////////////////
1564 
WriteDIB(const Bitmap & rSource,SvStream & rOStm,bool bCompressed,bool bFileHeader)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 
WriteDIBBitmapEx(const BitmapEx & rSource,SvStream & rOStm)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 
WriteDIBV5(const Bitmap & rSource,const Bitmap & rSourceAlpha,SvStream & rOStm)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