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