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