xref: /AOO41X/main/vcl/source/gdi/dibtools.cxx (revision 6a6ec68d792bd477e5b23798f42a1a9de0925497)
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)
392 {
393     const sal_uLong nAlignedWidth = AlignedWidth4Bytes(rHeader.nWidth * rHeader.nBitCount);
394     sal_uInt32 nRMask(0);
395     sal_uInt32 nGMask(0);
396     sal_uInt32 nBMask(0);
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)
434         {
435             if(BITFIELDS == rHeader.nCompression)
436             {
437                 rIStm.SeekRel( -12L );
438                 rIStm >> nRMask;
439                 rIStm >> nGMask;
440                 rIStm >> nBMask;
441             }
442             else
443             {
444                 nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL;
445                 nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL;
446                 nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL;
447             }
448         }
449 
450         if(bRLE)
451         {
452             if(!rHeader.nSizeImage)
453             {
454                 const sal_uLong nOldPos(rIStm.Tell());
455 
456                 rIStm.Seek(STREAM_SEEK_TO_END);
457                 rHeader.nSizeImage = rIStm.Tell() - nOldPos;
458                 rIStm.Seek(nOldPos);
459             }
460 
461             sal_uInt8* pBuffer = (sal_uInt8*)rtl_allocateMemory(rHeader.nSizeImage);
462             rIStm.Read((char*)pBuffer, rHeader.nSizeImage);
463             ImplDecodeRLE(pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression);
464             rtl_freeMemory(pBuffer);
465         }
466         else
467         {
468             const long nWidth(rHeader.nWidth);
469             const long nHeight(rHeader.nHeight);
470             sal_uInt8* pBuf = new sal_uInt8[nAlignedWidth];
471 
472             // true color DIB's can have a (optimization) palette
473             if(rHeader.nColsUsed && 8 < rHeader.nBitCount)
474             {
475                 rIStm.SeekRel(rHeader.nColsUsed * ((rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3));
476             }
477 
478             const long nI(bTopDown ? 1 : -1);
479             long nY(bTopDown ? 0 : nHeight - 1);
480             long nCount(nHeight);
481 
482             switch(rHeader.nBitCount)
483             {
484                 case( 1 ):
485                 {
486                     sal_uInt8*  pTmp;
487                     sal_uInt8   cTmp;
488 
489                     for( ; nCount--; nY += nI )
490                     {
491                         rIStm.Read( pTmp = pBuf, nAlignedWidth );
492                         cTmp = *pTmp++;
493 
494                         for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
495                         {
496                             if( !nShift )
497                             {
498                                 nShift = 8L,
499                                 cTmp = *pTmp++;
500                             }
501 
502                             rAcc.SetPixelIndex( nY, nX, (cTmp >> --nShift) & 1);
503                         }
504                     }
505                 }
506                 break;
507 
508                 case( 4 ):
509                 {
510                     sal_uInt8*  pTmp;
511                     sal_uInt8   cTmp;
512 
513                     for( ; nCount--; nY += nI )
514                     {
515                         rIStm.Read( pTmp = pBuf, nAlignedWidth );
516                         cTmp = *pTmp++;
517 
518                         for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
519                         {
520                             if( !nShift )
521                             {
522                                 nShift = 2UL,
523                                 cTmp = *pTmp++;
524                             }
525 
526                             rAcc.SetPixelIndex( nY, nX, (cTmp >> ( --nShift << 2UL ) ) & 0x0f);
527                         }
528                     }
529                 }
530                 break;
531 
532                 case( 8 ):
533                 {
534                     sal_uInt8*  pTmp;
535 
536                     for( ; nCount--; nY += nI )
537                     {
538                         rIStm.Read( pTmp = pBuf, nAlignedWidth );
539 
540                         for( long nX = 0L; nX < nWidth; nX++ )
541                             rAcc.SetPixelIndex( nY, nX, *pTmp++ );
542                     }
543                 }
544                 break;
545 
546                 case( 16 ):
547                 {
548                     ColorMask   aMask( nRMask, nGMask, nBMask );
549                     BitmapColor aColor;
550                     sal_uInt16*     pTmp16;
551 
552                     for( ; nCount--; nY += nI )
553                     {
554                         rIStm.Read( (char*)( pTmp16 = (sal_uInt16*) pBuf ), nAlignedWidth );
555 
556                         for( long nX = 0L; nX < nWidth; nX++ )
557                         {
558                             aMask.GetColorFor16BitLSB( aColor, (sal_uInt8*) pTmp16++ );
559                             rAcc.SetPixel( nY, nX, aColor );
560                         }
561                     }
562                 }
563                 break;
564 
565                 case( 24 ):
566                 {
567                     BitmapColor aPixelColor;
568                     sal_uInt8*      pTmp;
569 
570                     for( ; nCount--; nY += nI )
571                     {
572                         rIStm.Read( pTmp = pBuf, nAlignedWidth );
573 
574                         for( long nX = 0L; nX < nWidth; nX++ )
575                         {
576                             aPixelColor.SetBlue( *pTmp++ );
577                             aPixelColor.SetGreen( *pTmp++ );
578                             aPixelColor.SetRed( *pTmp++ );
579                             rAcc.SetPixel( nY, nX, aPixelColor );
580                         }
581                     }
582                 }
583                 break;
584 
585                 case( 32 ):
586                 {
587                     ColorMask aMask(nRMask, nGMask, nBMask);
588                     BitmapColor aColor;
589                     sal_uInt32* pTmp32;
590 
591                     if(pAccAlpha)
592                     {
593                         sal_uInt8 aAlpha;
594 
595                         for( ; nCount--; nY += nI )
596                         {
597                             rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth );
598 
599                             for( long nX = 0L; nX < nWidth; nX++ )
600                             {
601                                 aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, (sal_uInt8*) pTmp32++ );
602                                 rAcc.SetPixel( nY, nX, aColor );
603                                 pAccAlpha->SetPixelIndex(nY, nX, sal_uInt8(0xff) - aAlpha);
604                             }
605                         }
606                     }
607                     else
608                     {
609                         for( ; nCount--; nY += nI )
610                         {
611                             rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth );
612 
613                             for( long nX = 0L; nX < nWidth; nX++ )
614                             {
615                                 aMask.GetColorFor32Bit( aColor, (sal_uInt8*) pTmp32++ );
616                                 rAcc.SetPixel( nY, nX, aColor );
617                             }
618                         }
619                     }
620                 }
621             }
622 
623             delete[] pBuf;
624         }
625     }
626 
627     return( rIStm.GetError() == 0UL );
628 }
629 
630 bool ImplReadDIBBody( SvStream& rIStm, Bitmap& rBmp, Bitmap* pBmpAlpha, sal_uLong nOffset )
631 {
632     DIBV5Header aHeader;
633     const sal_uLong nStmPos = rIStm.Tell();
634     bool bRet(false);
635     bool bTopDown(false);
636 
637     if(ImplReadDIBInfoHeader(rIStm, aHeader, bTopDown) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount)
638     {
639         const sal_uInt16 nBitCount(discretizeBitcount(aHeader.nBitCount));
640         const Size aSizePixel(aHeader.nWidth, aHeader.nHeight);
641         BitmapPalette aDummyPal;
642         Bitmap aNewBmp(aSizePixel, nBitCount, &aDummyPal);
643         Bitmap aNewBmpAlpha;
644         BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess();
645         BitmapWriteAccess* pAccAlpha = 0;
646         bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32);
647 
648         if(bAlphaPossible)
649         {
650             const bool bRedSet(0 != aHeader.nV5RedMask);
651             const bool bGreenSet(0 != aHeader.nV5GreenMask);
652             const bool bBlueSet(0 != aHeader.nV5BlueMask);
653 
654             // some clipboard entries have alpha mask on zero to say that there is
655             // no alpha; do only use this when the other masks are set. The MS docu
656             // says that that masks are only to be set when bV5Compression is set to
657             // BI_BITFIELDS, but there seem to exist a wild variety of usages...
658             if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask))
659             {
660                 bAlphaPossible = false;
661             }
662         }
663 
664         if(bAlphaPossible)
665         {
666             aNewBmpAlpha = Bitmap(aSizePixel, 8);
667             pAccAlpha = aNewBmpAlpha.AcquireWriteAccess();
668         }
669 
670         if(pAcc)
671         {
672             sal_uInt16 nColors(0);
673             SvStream* pIStm;
674             SvMemoryStream* pMemStm = NULL;
675             sal_uInt8* pData = NULL;
676 
677             if(nBitCount <= 8)
678             {
679                 if(aHeader.nColsUsed)
680                 {
681                     nColors = (sal_uInt16)aHeader.nColsUsed;
682                 }
683                 else
684                 {
685                     nColors = ( 1 << aHeader.nBitCount );
686                 }
687             }
688 
689             if(ZCOMPRESS == aHeader.nCompression)
690             {
691                 ZCodec aCodec;
692                 sal_uInt32 nCodedSize(0);
693                 sal_uInt32  nUncodedSize(0);
694                 sal_uLong nCodedPos(0);
695 
696                 // read coding information
697                 rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression;
698                 pData = (sal_uInt8*) rtl_allocateMemory( nUncodedSize );
699 
700                 // decode buffer
701                 nCodedPos = rIStm.Tell();
702                 aCodec.BeginCompression();
703                 aCodec.Read( rIStm, pData, nUncodedSize );
704                 aCodec.EndCompression();
705 
706                 // skip unread bytes from coded buffer
707                 rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) );
708 
709                 // set decoded bytes to memory stream,
710                 // from which we will read the bitmap data
711                 pIStm = pMemStm = new SvMemoryStream;
712                 pMemStm->SetBuffer( (char*) pData, nUncodedSize, false, nUncodedSize );
713                 nOffset = 0;
714             }
715             else
716             {
717                 pIStm = &rIStm;
718             }
719 
720             // read palette
721             if(nColors)
722             {
723                 pAcc->SetPaletteEntryCount(nColors);
724                 ImplReadDIBPalette(*pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE);
725             }
726 
727             // read bits
728             if(!pIStm->GetError())
729             {
730                 if(nOffset)
731                 {
732                     pIStm->SeekRel(nOffset - (pIStm->Tell() - nStmPos));
733                 }
734 
735                 bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, pAccAlpha, bTopDown);
736 
737                 if(bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter)
738                 {
739                     MapMode aMapMode(
740                         MAP_MM,
741                         Point(),
742                         Fraction(1000, aHeader.nXPelsPerMeter),
743                         Fraction(1000, aHeader.nYPelsPerMeter));
744 
745                     aNewBmp.SetPrefMapMode(aMapMode);
746                     aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight));
747                 }
748             }
749 
750             if( pData )
751             {
752                 rtl_freeMemory(pData);
753             }
754 
755             delete pMemStm;
756             aNewBmp.ReleaseAccess(pAcc);
757 
758             if(bAlphaPossible)
759             {
760                 aNewBmpAlpha.ReleaseAccess(pAccAlpha);
761             }
762 
763             if(bRet)
764             {
765                 rBmp = aNewBmp;
766 
767                 if(bAlphaPossible)
768                 {
769                     *pBmpAlpha = aNewBmpAlpha;
770                 }
771             }
772         }
773     }
774 
775     return bRet;
776 }
777 
778 bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset )
779 {
780     sal_uInt32  nTmp32;
781     sal_uInt16  nTmp16 = 0;
782     bool    bRet = false;
783 
784     rIStm >> nTmp16;
785 
786     if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
787     {
788         if ( 0x4142 == nTmp16 )
789         {
790             rIStm.SeekRel( 12L );
791             rIStm >> nTmp16;
792             rIStm.SeekRel( 8L );
793             rIStm >> nTmp32;
794             rOffset = nTmp32 - 28UL;
795             bRet = ( 0x4D42 == nTmp16 );
796         }
797         else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER
798         {
799             rIStm.SeekRel( 8L );        // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits
800             rIStm >> nTmp32;            // read bfOffBits
801             rOffset = nTmp32 - 14UL;    // adapt offset by sizeof(BITMAPFILEHEADER)
802             bRet = ( rIStm.GetError() == 0UL );
803         }
804     }
805     else
806         rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
807 
808     return bRet;
809 }
810 
811 bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc )
812 {
813     const sal_uInt16    nColors = rAcc.GetPaletteEntryCount();
814     const sal_uLong     nPalSize = nColors * 4UL;
815     sal_uInt8*          pEntries = new sal_uInt8[ nPalSize ];
816     sal_uInt8*          pTmpEntry = pEntries;
817     BitmapColor     aPalColor;
818 
819     for( sal_uInt16 i = 0; i < nColors; i++ )
820     {
821         const BitmapColor& rPalColor = rAcc.GetPaletteColor( i );
822 
823         *pTmpEntry++ = rPalColor.GetBlue();
824         *pTmpEntry++ = rPalColor.GetGreen();
825         *pTmpEntry++ = rPalColor.GetRed();
826         *pTmpEntry++ = 0;
827     }
828 
829     rOStm.Write( pEntries, nPalSize );
830     delete[] pEntries;
831 
832     return( rOStm.GetError() == 0UL );
833 }
834 
835 bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, bool bRLE4 )
836 {
837     const sal_uLong nWidth = rAcc.Width();
838     const sal_uLong nHeight = rAcc.Height();
839     sal_uLong       nX;
840     sal_uLong       nSaveIndex;
841     sal_uLong       nCount;
842     sal_uLong       nBufCount;
843     sal_uInt8*      pBuf = new sal_uInt8[ ( nWidth << 1 ) + 2 ];
844     sal_uInt8*      pTmp;
845     sal_uInt8       cPix;
846     sal_uInt8       cLast;
847     bool        bFound;
848 
849     for ( long nY = nHeight - 1L; nY >= 0L; nY-- )
850     {
851         pTmp = pBuf;
852         nX = nBufCount = 0UL;
853 
854         while( nX < nWidth )
855         {
856             nCount = 1L;
857             cPix = rAcc.GetPixelIndex( nY, nX++ );
858 
859             while( ( nX < nWidth ) && ( nCount < 255L )
860                 && ( cPix == rAcc.GetPixelIndex( nY, nX ) ) )
861             {
862                 nX++;
863                 nCount++;
864             }
865 
866             if ( nCount > 1 )
867             {
868                 *pTmp++ = (sal_uInt8) nCount;
869                 *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
870                 nBufCount += 2;
871             }
872             else
873             {
874                 cLast = cPix;
875                 nSaveIndex = nX - 1UL;
876                 bFound = false;
877 
878                 while( ( nX < nWidth ) && ( nCount < 256L )
879                     && ( cPix = rAcc.GetPixelIndex( nY, nX ) ) != cLast )
880                 {
881                     nX++; nCount++;
882                     cLast = cPix;
883                     bFound = true;
884                 }
885 
886                 if ( bFound )
887                     nX--;
888 
889                 if ( nCount > 3 )
890                 {
891                     *pTmp++ = 0;
892                     *pTmp++ = (sal_uInt8) --nCount;
893 
894                     if( bRLE4 )
895                     {
896                         for ( sal_uLong i = 0; i < nCount; i++, pTmp++ )
897                         {
898                             *pTmp = rAcc.GetPixelIndex( nY, nSaveIndex++ ) << 4;
899 
900                             if ( ++i < nCount )
901                                 *pTmp |= rAcc.GetPixelIndex( nY, nSaveIndex++ );
902                         }
903 
904                         nCount = ( nCount + 1 ) >> 1;
905                     }
906                     else
907                     {
908                         for( sal_uLong i = 0UL; i < nCount; i++ )
909                             *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex++ );
910                     }
911 
912                     if ( nCount & 1 )
913                     {
914                         *pTmp++ = 0;
915                         nBufCount += ( nCount + 3 );
916                     }
917                     else
918                         nBufCount += ( nCount + 2 );
919                 }
920                 else
921                 {
922                     *pTmp++ = 1;
923                     *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex ) << (bRLE4 ? 4 : 0);
924 
925                     if ( nCount == 3 )
926                     {
927                         *pTmp++ = 1;
928                         *pTmp++ = rAcc.GetPixelIndex( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
929                         nBufCount += 4;
930                     }
931                     else
932                         nBufCount += 2;
933                 }
934             }
935         }
936 
937         pBuf[ nBufCount++ ] = 0;
938         pBuf[ nBufCount++ ] = 0;
939 
940         rOStm.Write( pBuf, nBufCount );
941     }
942 
943     rOStm << (sal_uInt8) 0;
944     rOStm << (sal_uInt8) 1;
945 
946     delete[] pBuf;
947 
948     return( rOStm.GetError() == 0UL );
949 }
950 
951 bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, sal_uLong nCompression, sal_uInt32& rImageSize)
952 {
953     if(!pAccAlpha && BITFIELDS == nCompression)
954     {
955         const ColorMask&    rMask = rAcc.GetColorMask();
956         SVBT32              aVal32;
957 
958         UInt32ToSVBT32( rMask.GetRedMask(), aVal32 );
959         rOStm.Write( (sal_uInt8*) aVal32, 4UL );
960 
961         UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 );
962         rOStm.Write( (sal_uInt8*) aVal32, 4UL );
963 
964         UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 );
965         rOStm.Write( (sal_uInt8*) aVal32, 4UL );
966 
967         rImageSize = rOStm.Tell();
968 
969         if( rAcc.IsBottomUp() )
970             rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() );
971         else
972         {
973             for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- )
974                 rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize );
975         }
976     }
977     else if(!pAccAlpha && ((RLE_4 == nCompression) || (RLE_8 == nCompression)))
978     {
979         rImageSize = rOStm.Tell();
980         ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression );
981     }
982     else if(!nCompression)
983     {
984         // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
985         // handled properly below (would have to set color masks, and
986         // nCompression=BITFIELDS - but color mask is not set for
987         // formats != *_TC_*). Note that this very problem might cause
988         // trouble at other places - the introduction of 32 bit RGBA
989         // bitmaps is relatively recent.
990         // #i59239# discretize bitcount for aligned width to 1,4,8,24
991         // (other cases are not written below)
992         const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount())));
993         const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * nBitCount));
994         bool bNative(false);
995 
996         switch(rAcc.GetScanlineFormat())
997         {
998             case( BMP_FORMAT_1BIT_MSB_PAL ):
999             case( BMP_FORMAT_4BIT_MSN_PAL ):
1000             case( BMP_FORMAT_8BIT_PAL ):
1001             case( BMP_FORMAT_24BIT_TC_BGR ):
1002             {
1003                 if(!pAccAlpha && rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth))
1004                 {
1005                     bNative = true;
1006                 }
1007 
1008                 break;
1009             }
1010 
1011             default:
1012             {
1013                 break;
1014             }
1015         }
1016 
1017         rImageSize = rOStm.Tell();
1018 
1019         if(bNative)
1020         {
1021             rOStm.Write(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height());
1022         }
1023         else
1024         {
1025             const long nWidth(rAcc.Width());
1026             const long nHeight(rAcc.Height());
1027             sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ];
1028             sal_uInt8* pTmp(0);
1029             sal_uInt8 cTmp(0);
1030 
1031             switch( nBitCount )
1032             {
1033                 case( 1 ):
1034                 {
1035                     for( long nY = nHeight - 1; nY >= 0L; nY-- )
1036                     {
1037                         pTmp = pBuf;
1038                         cTmp = 0;
1039 
1040                         for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
1041                         {
1042                             if( !nShift )
1043                             {
1044                                 nShift = 8L;
1045                                 *pTmp++ = cTmp;
1046                                 cTmp = 0;
1047                             }
1048 
1049                             cTmp |= rAcc.GetPixelIndex( nY, nX ) << --nShift;
1050                         }
1051 
1052                         *pTmp = cTmp;
1053                         rOStm.Write( pBuf, nAlignedWidth );
1054                     }
1055                 }
1056                 break;
1057 
1058                 case( 4 ):
1059                 {
1060                     for( long nY = nHeight - 1; nY >= 0L; nY-- )
1061                     {
1062                         pTmp = pBuf;
1063                         cTmp = 0;
1064 
1065                         for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
1066                         {
1067                             if( !nShift )
1068                             {
1069                                 nShift = 2L;
1070                                 *pTmp++ = cTmp;
1071                                 cTmp = 0;
1072                             }
1073 
1074                             cTmp |= rAcc.GetPixelIndex( nY, nX ) << ( --nShift << 2L );
1075                         }
1076                         *pTmp = cTmp;
1077                         rOStm.Write( pBuf, nAlignedWidth );
1078                     }
1079                 }
1080                 break;
1081 
1082                 case( 8 ):
1083                 {
1084                     for( long nY = nHeight - 1; nY >= 0L; nY-- )
1085                     {
1086                         pTmp = pBuf;
1087 
1088                         for( long nX = 0L; nX < nWidth; nX++ )
1089                             *pTmp++ = rAcc.GetPixelIndex( nY, nX );
1090 
1091                         rOStm.Write( pBuf, nAlignedWidth );
1092                     }
1093                 }
1094                 break;
1095 
1096                 // #i59239# fallback to 24 bit format, if bitcount is non-default
1097                 default:
1098                     // FALLTHROUGH intended
1099                 case( 24 ):
1100                 {
1101                     BitmapColor aPixelColor;
1102                     const bool bWriteAlpha(32 == nBitCount && pAccAlpha);
1103 
1104                     for( long nY = nHeight - 1; nY >= 0L; nY-- )
1105                     {
1106                         pTmp = pBuf;
1107 
1108                         for( long nX = 0L; nX < nWidth; nX++ )
1109                         {
1110                             // when alpha is used, this may be non-24bit main bitmap, so use GetColor
1111                             // instead of GetPixel to ensure RGB value
1112                             aPixelColor = rAcc.GetColor( nY, nX );
1113 
1114                             *pTmp++ = aPixelColor.GetBlue();
1115                             *pTmp++ = aPixelColor.GetGreen();
1116                             *pTmp++ = aPixelColor.GetRed();
1117 
1118                             if(bWriteAlpha)
1119                             {
1120                                 if(pAccAlpha)
1121                                 {
1122                                     *pTmp++ = (sal_uInt8)0xff - (sal_uInt8)pAccAlpha->GetPixelIndex( nY, nX );
1123                                 }
1124                                 else
1125                                 {
1126                                     *pTmp++ = (sal_uInt8)0xff;
1127                                 }
1128                             }
1129                         }
1130 
1131                         rOStm.Write( pBuf, nAlignedWidth );
1132                     }
1133                 }
1134                 break;
1135             }
1136 
1137             delete[] pBuf;
1138         }
1139     }
1140 
1141     rImageSize = rOStm.Tell() - rImageSize;
1142 
1143     return (!rOStm.GetError());
1144 }
1145 
1146 bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, bool bCompressed)
1147 {
1148     const MapMode aMapPixel(MAP_PIXEL);
1149     DIBV5Header aHeader;
1150     sal_uLong nImageSizePos(0);
1151     sal_uLong nEndPos(0);
1152     sal_uInt32 nCompression(COMPRESS_NONE);
1153     bool bRet(false);
1154 
1155     aHeader.nSize = pAccAlpha ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use
1156     aHeader.nWidth = rAcc.Width();
1157     aHeader.nHeight = rAcc.Height();
1158     aHeader.nPlanes = 1;
1159 
1160     if(!pAccAlpha && isBitfieldCompression(rAcc.GetScanlineFormat()))
1161     {
1162         aHeader.nBitCount = (BMP_FORMAT_16BIT_TC_LSB_MASK == rAcc.GetScanlineFormat()) ? 16 : 32;
1163         aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize();
1164         nCompression = BITFIELDS;
1165     }
1166     else
1167     {
1168         // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
1169         // not handled properly below (would have to set color
1170         // masks, and nCompression=BITFIELDS - but color mask is
1171         // not set for formats != *_TC_*). Note that this very
1172         // problem might cause trouble at other places - the
1173         // introduction of 32 bit RGBA bitmaps is relatively
1174         // recent.
1175         // #i59239# discretize bitcount to 1,4,8,24 (other cases
1176         // are not written below)
1177         const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount())));
1178         aHeader.nBitCount = nBitCount;
1179         aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount);
1180 
1181         if(bCompressed)
1182         {
1183             if(4 == nBitCount)
1184             {
1185                 nCompression = RLE_4;
1186             }
1187             else if(8 == nBitCount)
1188             {
1189                 nCompression = RLE_8;
1190             }
1191         }
1192     }
1193 
1194     if((rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40))
1195     {
1196         aHeader.nCompression = ZCOMPRESS;
1197     }
1198     else
1199     {
1200         aHeader.nCompression = nCompression;
1201     }
1202 
1203     if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel))
1204     {
1205         // #i48108# Try to recover xpels/ypels as previously stored on
1206         // disk. The problem with just converting maPrefSize to 100th
1207         // mm and then relating that to the bitmap pixel size is that
1208         // MapMode is integer-based, and suffers from roundoffs,
1209         // especially if maPrefSize is small. Trying to circumvent
1210         // that by performing part of the math in floating point.
1211         const Size aScale100000(OutputDevice::LogicToLogic(Size(100000L, 100000L), MAP_100TH_MM, rBitmap.GetPrefMapMode()));
1212         const double fBmpWidthM((double)rBitmap.GetPrefSize().Width() / aScale100000.Width());
1213         const double fBmpHeightM((double)rBitmap.GetPrefSize().Height() / aScale100000.Height());
1214 
1215         if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM))
1216         {
1217             aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM));
1218             aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM));
1219         }
1220     }
1221 
1222     aHeader.nColsUsed = ((!pAccAlpha && aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0);
1223     aHeader.nColsImportant = 0;
1224 
1225     rOStm << aHeader.nSize;
1226     rOStm << aHeader.nWidth;
1227     rOStm << aHeader.nHeight;
1228     rOStm << aHeader.nPlanes;
1229     rOStm << aHeader.nBitCount;
1230     rOStm << aHeader.nCompression;
1231 
1232     nImageSizePos = rOStm.Tell();
1233     rOStm.SeekRel( sizeof( aHeader.nSizeImage ) );
1234 
1235     rOStm << aHeader.nXPelsPerMeter;
1236     rOStm << aHeader.nYPelsPerMeter;
1237     rOStm << aHeader.nColsUsed;
1238     rOStm << aHeader.nColsImportant;
1239 
1240     if(pAccAlpha) // only write DIBV5 when asked to do so
1241     {
1242         aHeader.nV5CSType = 0x57696E20; // LCS_WINDOWS_COLOR_SPACE
1243         aHeader.nV5Intent = 0x00000008; // LCS_GM_ABS_COLORIMETRIC
1244 
1245         rOStm << aHeader.nV5RedMask;
1246         rOStm << aHeader.nV5GreenMask;
1247         rOStm << aHeader.nV5BlueMask;
1248         rOStm << aHeader.nV5AlphaMask;
1249         rOStm << aHeader.nV5CSType;
1250 
1251         rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzX;
1252         rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzY;
1253         rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzZ;
1254         rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzX;
1255         rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzY;
1256         rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzZ;
1257         rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzX;
1258         rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzY;
1259         rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzZ;
1260 
1261         rOStm << aHeader.nV5GammaRed;
1262         rOStm << aHeader.nV5GammaGreen;
1263         rOStm << aHeader.nV5GammaBlue;
1264         rOStm << aHeader.nV5Intent;
1265         rOStm << aHeader.nV5ProfileData;
1266         rOStm << aHeader.nV5ProfileSize;
1267         rOStm << aHeader.nV5Reserved;
1268     }
1269 
1270     if(ZCOMPRESS == aHeader.nCompression)
1271     {
1272         ZCodec aCodec;
1273         SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535);
1274         sal_uLong nCodedPos(rOStm.Tell());
1275         sal_uLong nLastPos(0);
1276         sal_uInt32 nCodedSize(0);
1277         sal_uInt32 nUncodedSize(0);
1278 
1279         // write uncoded data palette
1280         if(aHeader.nColsUsed)
1281         {
1282             ImplWriteDIBPalette(aMemStm, rAcc);
1283         }
1284 
1285         // write uncoded bits
1286         bRet = ImplWriteDIBBits(aMemStm, rAcc, pAccAlpha, nCompression, aHeader.nSizeImage);
1287 
1288         // get uncoded size
1289         nUncodedSize = aMemStm.Tell();
1290 
1291         // seek over compress info
1292         rOStm.SeekRel(12);
1293 
1294         // write compressed data
1295         aCodec.BeginCompression(3);
1296         aCodec.Write(rOStm, (sal_uInt8*)aMemStm.GetData(), nUncodedSize);
1297         aCodec.EndCompression();
1298 
1299         // update compress info ( coded size, uncoded size, uncoded compression )
1300         nLastPos = rOStm.Tell();
1301         nCodedSize = nLastPos - nCodedPos - 12;
1302         rOStm.Seek(nCodedPos);
1303         rOStm << nCodedSize << nUncodedSize << nCompression;
1304         rOStm.Seek(nLastPos);
1305 
1306         if(bRet)
1307         {
1308             bRet = (ERRCODE_NONE == rOStm.GetError());
1309         }
1310     }
1311     else
1312     {
1313         if(aHeader.nColsUsed)
1314         {
1315             ImplWriteDIBPalette(rOStm, rAcc);
1316         }
1317 
1318         bRet = ImplWriteDIBBits(rOStm, rAcc, pAccAlpha, aHeader.nCompression, aHeader.nSizeImage);
1319     }
1320 
1321     nEndPos = rOStm.Tell();
1322     rOStm.Seek(nImageSizePos);
1323     rOStm << aHeader.nSizeImage;
1324     rOStm.Seek(nEndPos);
1325 
1326     return bRet;
1327 }
1328 
1329 bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess& rAcc, bool bUseDIBV5)
1330 {
1331     const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : isBitfieldCompression(rAcc.GetScanlineFormat()) ? 3UL : 0UL));
1332     const sal_uInt32 nOffset(14 + (bUseDIBV5 ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE) + nPalCount * 4UL);
1333 
1334     rOStm << (sal_uInt16)0x4D42; // 'MB' from BITMAPFILEHEADER
1335     rOStm << (sal_uInt32)(nOffset + (rAcc.Height() * rAcc.GetScanlineSize()));
1336     rOStm << (sal_uInt16)0;
1337     rOStm << (sal_uInt16)0;
1338     rOStm << nOffset;
1339 
1340     return( rOStm.GetError() == 0UL );
1341 }
1342 
1343 //////////////////////////////////////////////////////////////////////////////
1344 
1345 bool ImplReadDIB(
1346     Bitmap& rTarget, Bitmap*
1347     pTargetAlpha,
1348     SvStream& rIStm,
1349     bool bFileHeader)
1350 {
1351     const sal_uInt16 nOldFormat(rIStm.GetNumberFormatInt());
1352     const sal_uLong nOldPos(rIStm.Tell());
1353     sal_uLong nOffset(0UL);
1354     bool bRet(false);
1355 
1356     rIStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
1357 
1358     if(bFileHeader)
1359     {
1360         if(ImplReadDIBFileHeader(rIStm, nOffset))
1361         {
1362             bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : 0, nOffset);
1363         }
1364     }
1365     else
1366     {
1367         bRet = ImplReadDIBBody(rIStm, rTarget, 0, nOffset);
1368     }
1369 
1370     if(!bRet)
1371     {
1372         if(!rIStm.GetError())
1373         {
1374             rIStm.SetError(SVSTREAM_GENERALERROR);
1375         }
1376 
1377         rIStm.Seek(nOldPos);
1378     }
1379 
1380     rIStm.SetNumberFormatInt(nOldFormat);
1381 
1382     return bRet;
1383 }
1384 
1385 bool ImplWriteDIB(
1386     const Bitmap& rSource,
1387     const Bitmap* pSourceAlpha,
1388     SvStream& rOStm,
1389     bool bCompressed,
1390     bool bFileHeader)
1391 {
1392     const Size aSizePix(rSource.GetSizePixel());
1393     bool bRet(false);
1394 
1395     if(aSizePix.Width() && aSizePix.Height())
1396     {
1397         BitmapReadAccess* pAcc = const_cast< Bitmap& >(rSource).AcquireReadAccess();
1398         BitmapReadAccess* pAccAlpha = 0;
1399         const sal_uInt16 nOldFormat(rOStm.GetNumberFormatInt());
1400         const sal_uLong nOldPos(rOStm.Tell());
1401 
1402         if(pSourceAlpha)
1403         {
1404             const Size aSizePixAlpha(pSourceAlpha->GetSizePixel());
1405 
1406             if(aSizePixAlpha == aSizePix)
1407             {
1408                 pAccAlpha = const_cast< Bitmap* >(pSourceAlpha)->AcquireReadAccess();
1409             }
1410             else
1411             {
1412                 OSL_ENSURE(false, "WriteDIB got an alpha channel, but it's pixel size differs from the base bitmap (!)");
1413             }
1414         }
1415 
1416         rOStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
1417 
1418         if(pAcc)
1419         {
1420             if(bFileHeader)
1421             {
1422                 if(ImplWriteDIBFileHeader(rOStm, *pAcc, 0 != pSourceAlpha))
1423                 {
1424                     bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed);
1425                 }
1426             }
1427             else
1428             {
1429                 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed);
1430             }
1431 
1432             const_cast< Bitmap& >(rSource).ReleaseAccess(pAcc);
1433 
1434             if(pAccAlpha)
1435             {
1436                 const_cast< Bitmap* >(pSourceAlpha)->ReleaseAccess(pAccAlpha);
1437             }
1438         }
1439 
1440         if(!bRet)
1441         {
1442             rOStm.SetError(SVSTREAM_GENERALERROR);
1443             rOStm.Seek(nOldPos);
1444         }
1445 
1446         rOStm.SetNumberFormatInt(nOldFormat);
1447     }
1448 
1449     return bRet;
1450 }
1451 
1452 //////////////////////////////////////////////////////////////////////////////
1453 
1454 bool ReadDIB(
1455     Bitmap& rTarget,
1456     SvStream& rIStm,
1457     bool bFileHeader)
1458 {
1459     return ImplReadDIB(rTarget, 0, rIStm, bFileHeader);
1460 }
1461 
1462 bool ReadDIBBitmapEx(
1463     BitmapEx& rTarget,
1464     SvStream& rIStm)
1465 {
1466     Bitmap aBmp;
1467     bool bRetval(ImplReadDIB(aBmp, 0, rIStm, true) && !rIStm.GetError());
1468 
1469     if(bRetval)
1470     {
1471         // base bitmap was read, set as return value and try to read alpha extra-data
1472         const sal_uLong nStmPos(rIStm.Tell());
1473         sal_uInt32 nMagic1(0);
1474         sal_uInt32 nMagic2(0);
1475 
1476         rTarget = BitmapEx(aBmp);
1477         rIStm >> nMagic1 >> nMagic2;
1478         bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError();
1479 
1480         if(bRetval)
1481         {
1482             sal_uInt8 bTransparent(false);
1483 
1484             rIStm >> bTransparent;
1485             bRetval = !rIStm.GetError();
1486 
1487             if(bRetval)
1488             {
1489                 if((sal_uInt8)TRANSPARENT_BITMAP == bTransparent)
1490                 {
1491                     Bitmap aMask;
1492 
1493                     bRetval = ImplReadDIB(aMask, 0, rIStm, true);
1494 
1495                     if(bRetval)
1496                     {
1497                         if(!!aMask)
1498                         {
1499                             // do we have an alpha mask?
1500                             if((8 == aMask.GetBitCount()) && aMask.HasGreyPalette())
1501                             {
1502                                 AlphaMask aAlpha;
1503 
1504                                 // create alpha mask quickly (without greyscale conversion)
1505                                 aAlpha.ImplSetBitmap(aMask);
1506                                 rTarget = BitmapEx(aBmp, aAlpha);
1507                             }
1508                             else
1509                             {
1510                                 rTarget = BitmapEx(aBmp, aMask);
1511                             }
1512                         }
1513                     }
1514                 }
1515                 else if((sal_uInt8)TRANSPARENT_COLOR == bTransparent)
1516                 {
1517                     Color aTransparentColor;
1518 
1519                     rIStm >> aTransparentColor;
1520                     bRetval = !rIStm.GetError();
1521 
1522                     if(bRetval)
1523                     {
1524                         rTarget = BitmapEx(aBmp, aTransparentColor);
1525                     }
1526                 }
1527             }
1528         }
1529 
1530         if(!bRetval)
1531         {
1532             // alpha extra data could not be read; reset, but use base bitmap as result
1533             rIStm.ResetError();
1534             rIStm.Seek(nStmPos);
1535             bRetval = true;
1536         }
1537     }
1538 
1539     return bRetval;
1540 }
1541 
1542 bool ReadDIBV5(
1543     Bitmap& rTarget,
1544     Bitmap& rTargetAlpha,
1545     SvStream& rIStm)
1546 {
1547     return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
1548 }
1549 
1550 //////////////////////////////////////////////////////////////////////////////
1551 
1552 bool WriteDIB(
1553     const Bitmap& rSource,
1554     SvStream& rOStm,
1555     bool bCompressed,
1556     bool bFileHeader)
1557 {
1558     return ImplWriteDIB(rSource, 0, rOStm, bCompressed, bFileHeader);
1559 }
1560 
1561 bool WriteDIBBitmapEx(
1562     const BitmapEx& rSource,
1563     SvStream& rOStm)
1564 {
1565     if(ImplWriteDIB(rSource.GetBitmap(), 0, rOStm, true, true))
1566     {
1567         rOStm << (sal_uInt32)0x25091962;
1568         rOStm << (sal_uInt32)0xACB20201;
1569         rOStm << (sal_uInt8)rSource.eTransparent;
1570 
1571         if(TRANSPARENT_BITMAP == rSource.eTransparent)
1572         {
1573             return ImplWriteDIB(rSource.aMask, 0, rOStm, true, true);
1574         }
1575         else if(TRANSPARENT_COLOR == rSource.eTransparent)
1576         {
1577             rOStm << rSource.aTransparentColor;
1578             return true;
1579         }
1580     }
1581 
1582     return false;
1583 }
1584 
1585 bool WriteDIBV5(
1586     const Bitmap& rSource,
1587     const Bitmap& rSourceAlpha,
1588     SvStream& rOStm)
1589 {
1590     return ImplWriteDIB(rSource, &rSourceAlpha, rOStm, false, true);
1591 }
1592 
1593 //////////////////////////////////////////////////////////////////////////////
1594 // eof
1595