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