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