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