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