Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <tools/zcodec.hxx>
31 : : #include <tools/stream.hxx>
32 : : #include <vcl/salbtype.hxx>
33 : : #include <vcl/bmpacc.hxx>
34 : : #include <vcl/outdev.hxx>
35 : : #include <vcl/bitmap.hxx>
36 : :
37 : : #include <utility>
38 : :
39 : : #if defined(HAVE_MEMCHECK_H)
40 : : #include <memcheck.h>
41 : : #endif
42 : :
43 : :
44 : : // -----------
45 : : // - Defines -
46 : : // -----------
47 : :
48 : : #define DIBCOREHEADERSIZE ( 12UL )
49 : : #define DIBINFOHEADERSIZE ( sizeof( DIBInfoHeader ) )
50 : : #define BITMAPINFOHEADER 0x28
51 : :
52 : : // ----------------------
53 : : // - Compression defines
54 : : // ----------------------
55 : :
56 : : #define COMPRESS_OWN ('S'|('D'<<8UL))
57 : : #define COMPRESS_NONE ( 0UL )
58 : : #define RLE_8 ( 1UL )
59 : : #define RLE_4 ( 2UL )
60 : : #define BITFIELDS ( 3UL )
61 : : #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
62 : :
63 : : // -----------------
64 : : // - DIBInfoHeader -
65 : : // -----------------
66 : :
67 : : struct DIBInfoHeader
68 : : {
69 : : sal_uInt32 nSize;
70 : : sal_Int32 nWidth;
71 : : sal_Int32 nHeight;
72 : : sal_uInt16 nPlanes;
73 : : sal_uInt16 nBitCount;
74 : : sal_uInt32 nCompression;
75 : : sal_uInt32 nSizeImage;
76 : : sal_Int32 nXPelsPerMeter;
77 : : sal_Int32 nYPelsPerMeter;
78 : : sal_uInt32 nColsUsed;
79 : : sal_uInt32 nColsImportant;
80 : :
81 : 197 : DIBInfoHeader() :
82 : : nSize( 0UL ),
83 : : nWidth( 0UL ),
84 : : nHeight( 0UL ),
85 : : nPlanes( 0 ),
86 : : nBitCount( 0 ),
87 : : nCompression( 0 ),
88 : : nSizeImage( 0 ),
89 : : nXPelsPerMeter( 0UL ),
90 : : nYPelsPerMeter( 0UL ),
91 : : nColsUsed( 0UL ),
92 : 197 : nColsImportant( 0UL ) {}
93 : :
94 : 197 : ~DIBInfoHeader() {}
95 : : };
96 : :
97 : : namespace
98 : : {
99 : 109 : inline sal_uInt16 discretizeBitcount( sal_uInt16 nInputCount )
100 : : {
101 : : return ( nInputCount <= 1 ) ? 1 :
102 : : ( nInputCount <= 4 ) ? 4 :
103 [ + + ][ + + ]: 109 : ( nInputCount <= 8 ) ? 8 : 24;
[ + + ]
104 : : }
105 : :
106 : 51 : inline bool isBitfieldCompression( sal_uLong nScanlineFormat )
107 : : {
108 : : return nScanlineFormat == BMP_FORMAT_16BIT_TC_LSB_MASK ||
109 [ + - ][ - + ]: 51 : nScanlineFormat == BMP_FORMAT_32BIT_TC_MASK;
110 : : }
111 : : }
112 : :
113 : : // ----------
114 : : // - Bitmap -
115 : : // ----------
116 : :
117 : 6939 : SvStream& operator>>( SvStream& rIStm, Bitmap& rBitmap )
118 : : {
119 : 6939 : rBitmap.Read( rIStm, sal_True );
120 : 6939 : return rIStm;
121 : : }
122 : :
123 : : // ------------------------------------------------------------------
124 : :
125 : 0 : SvStream& operator<<( SvStream& rOStm, const Bitmap& rBitmap )
126 : : {
127 : 0 : rBitmap.Write( rOStm, sal_False, sal_True );
128 : 0 : return rOStm;
129 : : }
130 : :
131 : : // ------------------------------------------------------------------
132 : :
133 : 7064 : sal_Bool Bitmap::Read( SvStream& rIStm, sal_Bool bFileHeader, sal_Bool bIsMSOFormat )
134 : : {
135 : 7064 : const sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt();
136 : 7064 : const sal_uLong nOldPos = rIStm.Tell();
137 : 7064 : sal_uLong nOffset = 0UL;
138 : 7064 : sal_Bool bRet = sal_False;
139 : :
140 [ + - ]: 7064 : rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
141 : :
142 [ + - ]: 7064 : if( bFileHeader )
143 : : {
144 [ + - ][ + + ]: 7064 : if( ImplReadDIBFileHeader( rIStm, nOffset ) )
145 [ + - ]: 159 : bRet = ImplReadDIB( rIStm, *this, nOffset );
146 : : }
147 : : else
148 [ # # ]: 0 : bRet = ImplReadDIB( rIStm, *this, nOffset, bIsMSOFormat );
149 : :
150 [ + + ]: 7064 : if( !bRet )
151 : : {
152 [ + + ]: 7018 : if( !rIStm.GetError() )
153 [ + - ]: 113 : rIStm.SetError( SVSTREAM_GENERALERROR );
154 : :
155 [ + - ]: 7018 : rIStm.Seek( nOldPos );
156 : : }
157 : :
158 [ + - ]: 7064 : rIStm.SetNumberFormatInt( nOldFormat );
159 : :
160 : 7064 : return bRet;
161 : : }
162 : :
163 : : // ------------------------------------------------------------------
164 : :
165 : 159 : sal_Bool Bitmap::ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, sal_uLong nOffset, sal_Bool bIsMSOFormat )
166 : : {
167 : 159 : DIBInfoHeader aHeader;
168 : 159 : const sal_uLong nStmPos = rIStm.Tell();
169 : 159 : sal_Bool bRet = sal_False;
170 : 159 : sal_Bool bTopDown = sal_False;
171 : :
172 [ + + ][ + - ]: 159 : if( ImplReadDIBInfoHeader( rIStm, aHeader, bTopDown, bIsMSOFormat ) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount )
[ + - ][ + - ]
[ + + ][ + - ]
173 : : {
174 : 46 : const sal_uInt16 nBitCount( discretizeBitcount(aHeader.nBitCount) );
175 : :
176 : 46 : const Size aSizePixel( aHeader.nWidth, abs(aHeader.nHeight) );
177 : 46 : BitmapPalette aDummyPal;
178 [ + - ]: 46 : Bitmap aNewBmp( aSizePixel, nBitCount, &aDummyPal );
179 [ + - ]: 46 : BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess();
180 : :
181 [ + - ]: 46 : if( pAcc )
182 : : {
183 : : sal_uInt16 nColors;
184 : : SvStream* pIStm;
185 : 46 : SvMemoryStream* pMemStm = NULL;
186 : 46 : sal_uInt8* pData = NULL;
187 : :
188 [ + + ]: 46 : if( nBitCount <= 8 )
189 : : {
190 [ + - ]: 27 : if( aHeader.nColsUsed )
191 : 27 : nColors = (sal_uInt16) aHeader.nColsUsed;
192 : : else
193 : 0 : nColors = ( 1 << aHeader.nBitCount );
194 : : }
195 : : else
196 : 19 : nColors = 0;
197 : :
198 [ - + ]: 46 : if( ZCOMPRESS == aHeader.nCompression )
199 : : {
200 [ # # ]: 0 : ZCodec aCodec;
201 : : sal_uInt32 nCodedSize, nUncodedSize;
202 : : sal_uLong nCodedPos;
203 : :
204 : : // read coding information
205 [ # # ][ # # ]: 0 : rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression;
[ # # ]
206 : 0 : pData = (sal_uInt8*) rtl_allocateMemory( nUncodedSize );
207 : :
208 : : // decode buffer
209 : 0 : nCodedPos = rIStm.Tell();
210 [ # # ]: 0 : aCodec.BeginCompression();
211 [ # # ]: 0 : aCodec.Read( rIStm, pData, nUncodedSize );
212 [ # # ]: 0 : aCodec.EndCompression();
213 : :
214 : : // skip unread bytes from coded buffer
215 [ # # ]: 0 : rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) );
216 : :
217 : : // set decoded bytes to memory stream,
218 : : // from which we will read the bitmap data
219 [ # # ][ # # ]: 0 : pMemStm = new SvMemoryStream;
220 : 0 : pIStm = pMemStm;
221 [ # # ]: 0 : pMemStm->SetBuffer( (char*) pData, nUncodedSize, sal_False, nUncodedSize );
222 [ # # ]: 0 : nOffset = 0;
223 : : }
224 : : else
225 : 46 : pIStm = &rIStm;
226 : :
227 : : // read palette
228 [ + + ]: 46 : if( nColors )
229 : : {
230 [ + - ]: 27 : pAcc->SetPaletteEntryCount( nColors );
231 [ + - ]: 27 : ImplReadDIBPalette( *pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE );
232 : : }
233 : :
234 : : // read bits
235 [ + - ]: 46 : if( !pIStm->GetError() )
236 : : {
237 [ + - ]: 46 : if( nOffset )
238 [ + - ]: 46 : pIStm->SeekRel( nOffset - ( pIStm->Tell() - nStmPos ) );
239 : :
240 [ + - ]: 46 : bRet = ImplReadDIBBits( *pIStm, aHeader, *pAcc, bTopDown );
241 : :
242 [ + - ][ + + ]: 46 : if( bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter )
[ + - ]
243 : : {
244 : : MapMode aMapMode( MAP_MM, Point(),
245 : : Fraction( 1000, aHeader.nXPelsPerMeter ),
246 [ + - ][ + - ]: 21 : Fraction( 1000, aHeader.nYPelsPerMeter ) );
[ + - ]
247 : :
248 [ + - ]: 21 : aNewBmp.SetPrefMapMode( aMapMode );
249 [ + - ]: 21 : aNewBmp.SetPrefSize( Size( aHeader.nWidth, abs(aHeader.nHeight) ) );
250 : : }
251 : : }
252 : :
253 [ - + ]: 46 : if( pData )
254 : 0 : rtl_freeMemory( pData );
255 : :
256 [ - + ][ # # ]: 46 : delete pMemStm;
257 [ + - ]: 46 : aNewBmp.ReleaseAccess( pAcc );
258 : :
259 [ + - ]: 46 : if( bRet )
260 [ + - ]: 46 : rBmp = aNewBmp;
261 [ + - ]: 46 : }
262 : : }
263 : :
264 : 159 : return bRet;
265 : : }
266 : :
267 : : // ------------------------------------------------------------------
268 : :
269 : 7064 : sal_Bool Bitmap::ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset )
270 : : {
271 : : sal_uInt32 nTmp32;
272 : 7064 : sal_uInt16 nTmp16 = 0;
273 : 7064 : sal_Bool bRet = sal_False;
274 : :
275 [ + - ]: 7064 : rIStm >> nTmp16;
276 : :
277 [ + + ][ - + ]: 7064 : if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
278 : : {
279 [ - + ]: 318 : if ( 0x4142 == nTmp16 )
280 : : {
281 [ # # ]: 0 : rIStm.SeekRel( 12L );
282 [ # # ]: 0 : rIStm >> nTmp16;
283 [ # # ]: 0 : rIStm.SeekRel( 8L );
284 [ # # ]: 0 : rIStm >> nTmp32;
285 : 0 : rOffset = nTmp32 - 28UL;
286 : 0 : bRet = ( 0x4D42 == nTmp16 );
287 : : }
288 : : else
289 : : {
290 [ + - ]: 159 : rIStm.SeekRel( 8L );
291 [ + - ]: 159 : rIStm >> nTmp32;
292 : 159 : rOffset = nTmp32 - 14UL;
293 : 159 : bRet = ( rIStm.GetError() == 0UL );
294 : : }
295 : : }
296 : : else
297 [ + - ]: 6905 : rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
298 : :
299 : 7064 : return bRet;
300 : : }
301 : :
302 : : // ------------------------------------------------------------------
303 : :
304 : 159 : sal_Bool Bitmap::ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown, sal_Bool bIsMSOFormat )
305 : : {
306 : : // BITMAPINFOHEADER or BITMAPCOREHEADER
307 [ + - ]: 159 : rIStm >> rHeader.nSize;
308 : :
309 : : // BITMAPCOREHEADER
310 : 159 : sal_Int16 nTmp16 = 0;
311 [ + + ]: 159 : if ( rHeader.nSize == DIBCOREHEADERSIZE )
312 : : {
313 : :
314 [ + - ]: 3 : rIStm >> nTmp16; rHeader.nWidth = nTmp16;
315 [ + - ]: 3 : rIStm >> nTmp16; rHeader.nHeight = nTmp16;
316 [ + - ]: 3 : rIStm >> rHeader.nPlanes;
317 [ + - ]: 3 : rIStm >> rHeader.nBitCount;
318 : : }
319 [ - + ][ # # ]: 156 : else if ( bIsMSOFormat && ( rHeader.nSize == BITMAPINFOHEADER ) )
320 : : {
321 : 0 : sal_uInt8 nTmp8 = 0;
322 [ # # ]: 0 : rIStm >> nTmp16; rHeader.nWidth = nTmp16;
323 [ # # ]: 0 : rIStm >> nTmp16; rHeader.nHeight = nTmp16;
324 [ # # ]: 0 : rIStm >> nTmp8; rHeader.nPlanes = nTmp8;
325 [ # # ]: 0 : rIStm >> nTmp8; rHeader.nBitCount = nTmp8;
326 [ # # ]: 0 : rIStm >> nTmp16; rHeader.nSizeImage = nTmp16;
327 [ # # ]: 0 : rIStm >> nTmp16; rHeader.nCompression = nTmp16;
328 [ # # ]: 0 : if ( !rHeader.nSizeImage ) // uncompressed?
329 : 0 : rHeader.nSizeImage = ((rHeader.nWidth * rHeader.nBitCount + 31) & ~31) / 8 * rHeader.nHeight;
330 [ # # ]: 0 : rIStm >> rHeader.nXPelsPerMeter;
331 [ # # ]: 0 : rIStm >> rHeader.nYPelsPerMeter;
332 [ # # ]: 0 : rIStm >> rHeader.nColsUsed;
333 [ # # ]: 0 : rIStm >> rHeader.nColsImportant;
334 : : }
335 : : else
336 : : {
337 : : // unknown Header
338 [ + + ]: 156 : if( rHeader.nSize < DIBINFOHEADERSIZE )
339 : : {
340 : 110 : sal_uLong nUnknownSize = sizeof( rHeader.nSize );
341 : :
342 [ + - ]: 110 : rIStm >> rHeader.nWidth; nUnknownSize += sizeof( rHeader.nWidth );
343 [ + - ]: 110 : rIStm >> rHeader.nHeight; nUnknownSize += sizeof( rHeader.nHeight );
344 [ + - ]: 110 : rIStm >> rHeader.nPlanes; nUnknownSize += sizeof( rHeader.nPlanes );
345 [ + - ]: 110 : rIStm >> rHeader.nBitCount; nUnknownSize += sizeof( rHeader.nBitCount );
346 : :
347 [ - + ]: 110 : if( nUnknownSize < rHeader.nSize )
348 : : {
349 [ # # ]: 0 : rIStm >> rHeader.nCompression;
350 : 0 : nUnknownSize += sizeof( rHeader.nCompression );
351 : :
352 [ # # ]: 0 : if( nUnknownSize < rHeader.nSize )
353 : : {
354 [ # # ]: 0 : rIStm >> rHeader.nSizeImage;
355 : 0 : nUnknownSize += sizeof( rHeader.nSizeImage );
356 : :
357 [ # # ]: 0 : if( nUnknownSize < rHeader.nSize )
358 : : {
359 [ # # ]: 0 : rIStm >> rHeader.nXPelsPerMeter;
360 : 0 : nUnknownSize += sizeof( rHeader.nXPelsPerMeter );
361 : :
362 [ # # ]: 0 : if( nUnknownSize < rHeader.nSize )
363 : : {
364 [ # # ]: 0 : rIStm >> rHeader.nYPelsPerMeter;
365 : 0 : nUnknownSize += sizeof( rHeader.nYPelsPerMeter );
366 : : }
367 : :
368 [ # # ]: 0 : if( nUnknownSize < rHeader.nSize )
369 : : {
370 [ # # ]: 0 : rIStm >> rHeader.nColsUsed;
371 : 0 : nUnknownSize += sizeof( rHeader.nColsUsed );
372 : :
373 [ # # ]: 0 : if( nUnknownSize < rHeader.nSize )
374 : : {
375 [ # # ]: 0 : rIStm >> rHeader.nColsImportant;
376 : 0 : nUnknownSize += sizeof( rHeader.nColsImportant );
377 : : }
378 : : }
379 : : }
380 : : }
381 : : }
382 : : }
383 : : else
384 : : {
385 [ + - ]: 46 : rIStm >> rHeader.nWidth;
386 [ + - ]: 46 : rIStm >> rHeader.nHeight; //rHeader.nHeight=abs(rHeader.nHeight);
387 [ + - ]: 46 : rIStm >> rHeader.nPlanes;
388 [ + - ]: 46 : rIStm >> rHeader.nBitCount;
389 [ + - ]: 46 : rIStm >> rHeader.nCompression;
390 [ + - ]: 46 : rIStm >> rHeader.nSizeImage;
391 [ + - ]: 46 : rIStm >> rHeader.nXPelsPerMeter;
392 [ + - ]: 46 : rIStm >> rHeader.nYPelsPerMeter;
393 [ + - ]: 46 : rIStm >> rHeader.nColsUsed;
394 [ + - ]: 46 : rIStm >> rHeader.nColsImportant;
395 : : }
396 : :
397 : : // Eventuell bis zur Palette ueberlesen
398 [ - + ]: 156 : if ( rHeader.nSize > DIBINFOHEADERSIZE )
399 [ # # ]: 0 : rIStm.SeekRel( rHeader.nSize - DIBINFOHEADERSIZE );
400 : : }
401 [ - + ]: 159 : if ( rHeader.nHeight < 0 )
402 : : {
403 : 0 : bTopDown = sal_True;
404 : 0 : rHeader.nHeight *= -1;
405 : : }
406 : : else
407 : 159 : bTopDown = sal_False;
408 : :
409 [ - + ]: 159 : if ( rHeader.nWidth < 0 )
410 [ # # ]: 0 : rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
411 : :
412 : : // #144105# protect a little against damaged files
413 [ - + ]: 159 : if( rHeader.nSizeImage > ( 16 * static_cast< sal_uInt32 >( rHeader.nWidth * rHeader.nHeight ) ) )
414 : 0 : rHeader.nSizeImage = 0;
415 : :
416 [ + + ][ + - ]: 159 : return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) );
417 : : }
418 : :
419 : : // ------------------------------------------------------------------
420 : :
421 : 27 : sal_Bool Bitmap::ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, sal_Bool bQuad )
422 : : {
423 : 27 : const sal_uInt16 nColors = rAcc.GetPaletteEntryCount();
424 [ + - ]: 27 : const sal_uLong nPalSize = nColors * ( bQuad ? 4UL : 3UL );
425 : 27 : BitmapColor aPalColor;
426 : :
427 [ + - ]: 27 : sal_uInt8* pEntries = new sal_uInt8[ nPalSize ];
428 [ + - ]: 27 : rIStm.Read( pEntries, nPalSize );
429 : :
430 : 27 : sal_uInt8* pTmpEntry = pEntries;
431 [ + + ]: 3495 : for( sal_uInt16 i = 0; i < nColors; i++ )
432 : : {
433 : 3468 : aPalColor.SetBlue( *pTmpEntry++ );
434 : 3468 : aPalColor.SetGreen( *pTmpEntry++ );
435 : 3468 : aPalColor.SetRed( *pTmpEntry++ );
436 : :
437 [ + - ]: 3468 : if( bQuad )
438 : 3468 : pTmpEntry++;
439 : :
440 : 3468 : rAcc.SetPaletteColor( i, aPalColor );
441 : : }
442 : :
443 [ + - ]: 27 : delete[] pEntries;
444 : :
445 : 27 : return( rIStm.GetError() == 0UL );
446 : : }
447 : :
448 : : // ------------------------------------------------------------------
449 : :
450 : 46 : sal_Bool Bitmap::ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc, sal_Bool bTopDown )
451 : : {
452 : 46 : const sal_uLong nAlignedWidth = AlignedWidth4Bytes( rHeader.nWidth * rHeader.nBitCount );
453 : 46 : sal_uInt32 nRMask = 0;
454 : 46 : sal_uInt32 nGMask = 0;
455 : 46 : sal_uInt32 nBMask = 0;
456 : : sal_Bool bNative;
457 [ - + ][ + - ]: 46 : sal_Bool bTCMask = ( rHeader.nBitCount == 16 ) || ( rHeader.nBitCount == 32 );
458 : : sal_Bool bRLE = ( RLE_8 == rHeader.nCompression && rHeader.nBitCount == 8 ) ||
459 [ + + ][ - + ]: 46 : ( RLE_4 == rHeader.nCompression && rHeader.nBitCount == 4 );
[ - + ][ # # ]
460 : :
461 : : // Is native format?
462 [ + - ]: 46 : switch( rAcc.GetScanlineFormat() )
463 : : {
464 : : case( BMP_FORMAT_1BIT_MSB_PAL ):
465 : : case( BMP_FORMAT_4BIT_MSN_PAL ):
466 : : case( BMP_FORMAT_8BIT_PAL ):
467 : : case( BMP_FORMAT_24BIT_TC_BGR ):
468 [ + - ][ + - ]: 46 : bNative = ( ( rAcc.IsBottomUp() != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) );
[ + + ][ + - ]
[ + + ]
469 : 46 : break;
470 : :
471 : : default:
472 : 0 : bNative = sal_False;
473 : 0 : break;
474 : : }
475 : : // Read data
476 [ + + ]: 46 : if( bNative )
477 : : {
478 : : // true color DIB's can have a (optimization) palette
479 [ + + ][ - + ]: 25 : if( rHeader.nColsUsed && rHeader.nBitCount > 8 )
480 [ # # ][ # # ]: 0 : rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) );
481 : :
482 [ + - ]: 25 : if ( rHeader.nHeight > 0 )
483 [ + - ]: 25 : rIStm.Read( rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth );
484 : : else
485 : : {
486 [ # # ]: 0 : for( int i = abs(rHeader.nHeight)-1; i >= 0; i-- )
487 [ # # ]: 0 : rIStm.Read( ((char*)rAcc.GetBuffer()) + (nAlignedWidth*i), nAlignedWidth );
488 : : }
489 : : }
490 : : else
491 : : {
492 : : // Read color mask
493 [ - + ]: 21 : if( bTCMask )
494 : : {
495 [ # # ]: 0 : if( rHeader.nCompression == BITFIELDS )
496 : : {
497 [ # # ]: 0 : rIStm.SeekRel( -12L );
498 [ # # ]: 0 : rIStm >> nRMask;
499 [ # # ]: 0 : rIStm >> nGMask;
500 [ # # ]: 0 : rIStm >> nBMask;
501 : : }
502 : : else
503 : : {
504 [ # # ]: 0 : nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL;
505 [ # # ]: 0 : nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL;
506 [ # # ]: 0 : nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL;
507 : : }
508 : : }
509 : :
510 [ + + ]: 21 : if( bRLE )
511 : : {
512 [ - + ]: 13 : if ( !rHeader.nSizeImage )
513 : : {
514 : 0 : const sal_uLong nOldPos = rIStm.Tell();
515 : :
516 [ # # ]: 0 : rIStm.Seek( STREAM_SEEK_TO_END );
517 : 0 : rHeader.nSizeImage = rIStm.Tell() - nOldPos;
518 [ # # ]: 0 : rIStm.Seek( nOldPos );
519 : : }
520 : :
521 : 13 : sal_uInt8* pBuffer = (sal_uInt8*) rtl_allocateMemory( rHeader.nSizeImage );
522 : :
523 [ + - ]: 13 : rIStm.Read( (char*) pBuffer, rHeader.nSizeImage );
524 [ + - ]: 13 : ImplDecodeRLE( pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression );
525 : :
526 : 13 : rtl_freeMemory( pBuffer );
527 : : }
528 : : else
529 : : {
530 : 8 : const long nWidth = rHeader.nWidth;
531 : 8 : const long nHeight = abs(rHeader.nHeight);
532 [ + - ]: 8 : sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ];
533 : :
534 : : // true color DIB's can have a (optimization) palette
535 [ + - ][ - + ]: 8 : if( rHeader.nColsUsed && rHeader.nBitCount > 8 )
536 [ # # ][ # # ]: 0 : rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) );
537 : :
538 [ - + ]: 8 : const long nI = bTopDown ? 1 : -1;
539 [ + - ]: 8 : long nY = bTopDown ? 0 : nHeight - 1;
540 : 8 : long nCount = nHeight;
541 : :
542 [ - + - - : 8 : switch( rHeader.nBitCount )
- - - ]
543 : : {
544 : : case( 1 ):
545 : : {
546 : : sal_uInt8* pTmp;
547 : : sal_uInt8 cTmp;
548 : :
549 [ # # ]: 0 : for( ; nCount--; nY += nI )
550 : : {
551 [ # # ]: 0 : rIStm.Read( pTmp = pBuf, nAlignedWidth );
552 : 0 : cTmp = *pTmp++;
553 : :
554 [ # # ]: 0 : for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
555 : : {
556 [ # # ]: 0 : if( !nShift )
557 : : {
558 : : nShift = 8L,
559 : 0 : cTmp = *pTmp++;
560 : : }
561 : :
562 [ # # ]: 0 : rAcc.SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( cTmp >> --nShift ) & 1) );
563 : : }
564 : : }
565 : : }
566 : 0 : break;
567 : :
568 : : case( 4 ):
569 : : {
570 : : sal_uInt8* pTmp;
571 : : sal_uInt8 cTmp;
572 : :
573 [ + + ]: 112 : for( ; nCount--; nY += nI )
574 : : {
575 [ + - ]: 104 : rIStm.Read( pTmp = pBuf, nAlignedWidth );
576 : 104 : cTmp = *pTmp++;
577 : :
578 [ + + ]: 10244 : for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
579 : : {
580 [ + + ]: 10140 : if( !nShift )
581 : : {
582 : : nShift = 2UL,
583 : 4992 : cTmp = *pTmp++;
584 : : }
585 : :
586 [ + - ]: 10140 : rAcc.SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( cTmp >> ( --nShift << 2UL ) ) & 0x0f) );
587 : : }
588 : : }
589 : : }
590 : 8 : break;
591 : :
592 : : case( 8 ):
593 : : {
594 : : sal_uInt8* pTmp;
595 : :
596 [ # # ]: 0 : for( ; nCount--; nY += nI )
597 : : {
598 [ # # ]: 0 : rIStm.Read( pTmp = pBuf, nAlignedWidth );
599 : :
600 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
601 [ # # ]: 0 : rAcc.SetPixel( nY, nX, *pTmp++ );
602 : : }
603 : : }
604 : 0 : break;
605 : :
606 : : case( 16 ):
607 : : {
608 [ # # ]: 0 : ColorMask aMask( nRMask, nGMask, nBMask );
609 : 0 : BitmapColor aColor;
610 : : sal_uInt16* pTmp16;
611 : :
612 [ # # ]: 0 : for( ; nCount--; nY += nI )
613 : : {
614 [ # # ]: 0 : rIStm.Read( (char*)( pTmp16 = (sal_uInt16*) pBuf ), nAlignedWidth );
615 : :
616 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
617 : : {
618 : 0 : aMask.GetColorFor16BitLSB( aColor, (sal_uInt8*) pTmp16++ );
619 [ # # ]: 0 : rAcc.SetPixel( nY, nX, aColor );
620 : : }
621 : 0 : }
622 : : }
623 : 0 : break;
624 : :
625 : : case( 24 ):
626 : : {
627 : 0 : BitmapColor aPixelColor;
628 : : sal_uInt8* pTmp;
629 : :
630 [ # # ]: 0 : for( ; nCount--; nY += nI )
631 : : {
632 [ # # ]: 0 : rIStm.Read( pTmp = pBuf, nAlignedWidth );
633 : :
634 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
635 : : {
636 : 0 : aPixelColor.SetBlue( *pTmp++ );
637 : 0 : aPixelColor.SetGreen( *pTmp++ );
638 : 0 : aPixelColor.SetRed( *pTmp++ );
639 [ # # ]: 0 : rAcc.SetPixel( nY, nX, aPixelColor );
640 : : }
641 : 0 : }
642 : : }
643 : 0 : break;
644 : :
645 : : case( 32 ):
646 : : {
647 [ # # ]: 0 : ColorMask aMask( nRMask, nGMask, nBMask );
648 : 0 : BitmapColor aColor;
649 : : sal_uInt32* pTmp32;
650 : :
651 [ # # ]: 0 : for( ; nCount--; nY += nI )
652 : : {
653 [ # # ]: 0 : rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth );
654 : :
655 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
656 : : {
657 : 0 : aMask.GetColorFor32Bit( aColor, (sal_uInt8*) pTmp32++ );
658 [ # # ]: 0 : rAcc.SetPixel( nY, nX, aColor );
659 : : }
660 : 0 : }
661 : : }
662 : : }
663 : :
664 [ + - ]: 8 : delete[] pBuf;
665 : : }
666 : : }
667 : :
668 : 46 : return( rIStm.GetError() == 0UL );
669 : : }
670 : :
671 : : // ------------------------------------------------------------------
672 : :
673 : 38 : sal_Bool Bitmap::Write( SvStream& rOStm, sal_Bool bCompressed, sal_Bool bFileHeader ) const
674 : : {
675 : : DBG_ASSERT( mpImpBmp, "Empty Bitmaps can't be saved" );
676 : :
677 [ + - ]: 38 : const Size aSizePix( GetSizePixel() );
678 : 38 : sal_Bool bRet = sal_False;
679 : :
680 [ + - ][ + - ]: 38 : if( mpImpBmp && aSizePix.Width() && aSizePix.Height() )
[ + - ][ + - ]
681 : : {
682 [ + - ]: 38 : BitmapReadAccess* pAcc = ( (Bitmap*) this)->AcquireReadAccess();
683 : 38 : const sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt();
684 : 38 : const sal_uLong nOldPos = rOStm.Tell();
685 : :
686 [ + - ]: 38 : rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
687 : :
688 [ + - ]: 38 : if( pAcc )
689 : : {
690 [ + + ]: 38 : if( bFileHeader )
691 : : {
692 [ + - ][ + - ]: 26 : if( ImplWriteDIBFileHeader( rOStm, *pAcc ) )
693 [ + - ]: 26 : bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
694 : : }
695 : : else
696 [ + - ]: 12 : bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
697 : :
698 [ + - ]: 38 : ( (Bitmap*) this)->ReleaseAccess( pAcc );
699 : : }
700 : :
701 [ - + ]: 38 : if( !bRet )
702 : : {
703 [ # # ]: 0 : rOStm.SetError( SVSTREAM_GENERALERROR );
704 [ # # ]: 0 : rOStm.Seek( nOldPos );
705 : : }
706 : :
707 [ + - ]: 38 : rOStm.SetNumberFormatInt( nOldFormat );
708 : : }
709 : :
710 : 38 : return bRet;
711 : : }
712 : :
713 : : // ------------------------------------------------------------------
714 : :
715 : 38 : sal_Bool Bitmap::ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bCompressed ) const
716 : : {
717 [ + - ]: 38 : const MapMode aMapPixel( MAP_PIXEL );
718 : 38 : DIBInfoHeader aHeader;
719 : : sal_uLong nImageSizePos;
720 : : sal_uLong nEndPos;
721 : 38 : sal_uInt32 nCompression = 0;
722 : 38 : sal_Bool bRet = sal_False;
723 : :
724 : 38 : aHeader.nSize = DIBINFOHEADERSIZE;
725 : 38 : aHeader.nWidth = rAcc.Width();
726 : 38 : aHeader.nHeight = rAcc.Height();
727 : 38 : aHeader.nPlanes = 1;
728 : :
729 [ - + ]: 38 : if( isBitfieldCompression( rAcc.GetScanlineFormat() ) )
730 : : {
731 [ # # ]: 0 : aHeader.nBitCount = ( rAcc.GetScanlineFormat() == BMP_FORMAT_16BIT_TC_LSB_MASK ) ? 16 : 32;
732 : 0 : aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize();
733 : :
734 : 0 : nCompression = BITFIELDS;
735 : : }
736 : : else
737 : : {
738 : : // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
739 : : // not handled properly below (would have to set color
740 : : // masks, and nCompression=BITFIELDS - but color mask is
741 : : // not set for formats != *_TC_*). Note that this very
742 : : // problem might cause trouble at other places - the
743 : : // introduction of 32 bit RGBA bitmaps is relatively
744 : : // recent.
745 : : // #i59239# discretize bitcount to 1,4,8,24 (other cases
746 : : // are not written below)
747 : 38 : const sal_uInt16 nBitCount( sal::static_int_cast<sal_uInt16>(rAcc.GetBitCount()) );
748 : :
749 : 38 : aHeader.nBitCount = discretizeBitcount( nBitCount );
750 : 38 : aHeader.nSizeImage = rAcc.Height() *
751 : 38 : AlignedWidth4Bytes( rAcc.Width()*aHeader.nBitCount );
752 : :
753 [ + - ]: 38 : if( bCompressed )
754 : : {
755 [ - + ]: 38 : if( 4 == nBitCount )
756 : 0 : nCompression = RLE_4;
757 [ + + ]: 38 : else if( 8 == nBitCount )
758 : 13 : nCompression = RLE_8;
759 : : }
760 : : else
761 : 0 : nCompression = COMPRESS_NONE;
762 : : }
763 : :
764 [ - + # # ]: 38 : if( ( rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP ) &&
[ - + ]
765 : 0 : ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40 ) )
766 : : {
767 : 0 : aHeader.nCompression = ZCOMPRESS;
768 : : }
769 : : else
770 : 38 : aHeader.nCompression = nCompression;
771 : :
772 [ + + ][ + - ]: 38 : if( maPrefSize.Width() && maPrefSize.Height() && ( maPrefMapMode != aMapPixel ) )
[ + - ][ + - ]
[ + + ]
773 : : {
774 : : // #i48108# Try to recover xpels/ypels as previously stored on
775 : : // disk. The problem with just converting maPrefSize to 100th
776 : : // mm and then relating that to the bitmap pixel size is that
777 : : // MapMode is integer-based, and suffers from roundoffs,
778 : : // especially if maPrefSize is small. Trying to circumvent
779 : : // that by performing part of the math in floating point.
780 : : const Size aScale100000(
781 : : OutputDevice::LogicToLogic( Size(100000L,
782 : : 100000L),
783 : : MAP_100TH_MM,
784 [ + - ][ + - ]: 13 : maPrefMapMode ) );
[ + - ]
785 : 13 : const double fBmpWidthM((double)maPrefSize.Width() / aScale100000.Width() );
786 : 13 : const double fBmpHeightM((double)maPrefSize.Height() / aScale100000.Height() );
787 [ + - ][ + - ]: 13 : if( fabs(fBmpWidthM) > 0.000000001 &&
788 : 13 : fabs(fBmpHeightM) > 0.000000001 )
789 : : {
790 : 13 : aHeader.nXPelsPerMeter = (sal_uInt32)(rAcc.Width() / fBmpWidthM + .5);
791 : 13 : aHeader.nYPelsPerMeter = (sal_uInt32)(rAcc.Height() / fBmpHeightM + .5);
792 : : }
793 : : }
794 : :
795 [ + + ]: 38 : aHeader.nColsUsed = ( ( aHeader.nBitCount <= 8 ) ? rAcc.GetPaletteEntryCount() : 0 );
796 : 38 : aHeader.nColsImportant = 0;
797 : :
798 [ + - ]: 38 : rOStm << aHeader.nSize;
799 [ + - ]: 38 : rOStm << aHeader.nWidth;
800 [ + - ]: 38 : rOStm << aHeader.nHeight;
801 [ + - ]: 38 : rOStm << aHeader.nPlanes;
802 [ + - ]: 38 : rOStm << aHeader.nBitCount;
803 [ + - ]: 38 : rOStm << aHeader.nCompression;
804 : :
805 : 38 : nImageSizePos = rOStm.Tell();
806 [ + - ]: 38 : rOStm.SeekRel( sizeof( aHeader.nSizeImage ) );
807 : :
808 [ + - ]: 38 : rOStm << aHeader.nXPelsPerMeter;
809 [ + - ]: 38 : rOStm << aHeader.nYPelsPerMeter;
810 [ + - ]: 38 : rOStm << aHeader.nColsUsed;
811 [ + - ]: 38 : rOStm << aHeader.nColsImportant;
812 : :
813 [ - + ]: 38 : if( aHeader.nCompression == ZCOMPRESS )
814 : : {
815 [ # # ]: 0 : ZCodec aCodec;
816 [ # # ]: 0 : SvMemoryStream aMemStm( aHeader.nSizeImage + 4096, 65535 );
817 : 0 : sal_uLong nCodedPos = rOStm.Tell(), nLastPos;
818 : : sal_uInt32 nCodedSize, nUncodedSize;
819 : :
820 : : // write uncoded data palette
821 [ # # ]: 0 : if( aHeader.nColsUsed )
822 [ # # ]: 0 : ImplWriteDIBPalette( aMemStm, rAcc );
823 : :
824 : : // write uncoded bits
825 [ # # ]: 0 : bRet = ImplWriteDIBBits( aMemStm, rAcc, nCompression, aHeader.nSizeImage );
826 : :
827 : : // get uncoded size
828 : 0 : nUncodedSize = aMemStm.Tell();
829 : :
830 : : // seek over compress info
831 [ # # ]: 0 : rOStm.SeekRel( 12 );
832 : :
833 : : // write compressed data
834 [ # # ]: 0 : aCodec.BeginCompression( 3 );
835 [ # # ][ # # ]: 0 : aCodec.Write( rOStm, (sal_uInt8*) aMemStm.GetData(), nUncodedSize );
836 [ # # ]: 0 : aCodec.EndCompression();
837 : :
838 : : // update compress info ( coded size, uncoded size, uncoded compression )
839 : 0 : nCodedSize = ( nLastPos = rOStm.Tell() ) - nCodedPos - 12;
840 [ # # ]: 0 : rOStm.Seek( nCodedPos );
841 [ # # ][ # # ]: 0 : rOStm << nCodedSize << nUncodedSize << nCompression;
[ # # ]
842 [ # # ]: 0 : rOStm.Seek( nLastPos );
843 : :
844 [ # # ]: 0 : if( bRet )
845 [ # # ][ # # ]: 0 : bRet = ( rOStm.GetError() == ERRCODE_NONE );
846 : : }
847 : : else
848 : : {
849 [ + + ]: 38 : if( aHeader.nColsUsed )
850 [ + - ]: 19 : ImplWriteDIBPalette( rOStm, rAcc );
851 : :
852 [ + - ]: 38 : bRet = ImplWriteDIBBits( rOStm, rAcc, aHeader.nCompression, aHeader.nSizeImage );
853 : : }
854 : :
855 : 38 : nEndPos = rOStm.Tell();
856 [ + - ]: 38 : rOStm.Seek( nImageSizePos );
857 [ + - ]: 38 : rOStm << aHeader.nSizeImage;
858 [ + - ]: 38 : rOStm.Seek( nEndPos );
859 : :
860 [ + - ]: 38 : return bRet;
861 : : }
862 : :
863 : : // ------------------------------------------------------------------
864 : :
865 : 26 : sal_Bool Bitmap::ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc )
866 : : {
867 : 39 : sal_uInt32 nPalCount = ( rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() :
868 [ - + ][ + + ]: 39 : isBitfieldCompression( rAcc.GetScanlineFormat() ) ? 3UL : 0UL );
869 : 26 : sal_uInt32 nOffset = 14 + DIBINFOHEADERSIZE + nPalCount * 4UL;
870 : :
871 : 26 : rOStm << (sal_uInt16) 0x4D42;
872 : 26 : rOStm << (sal_uInt32) ( nOffset + ( rAcc.Height() * rAcc.GetScanlineSize() ) );
873 : 26 : rOStm << (sal_uInt16) 0;
874 : 26 : rOStm << (sal_uInt16) 0;
875 : 26 : rOStm << nOffset;
876 : :
877 : 26 : return( rOStm.GetError() == 0UL );
878 : : }
879 : :
880 : : // ------------------------------------------------------------------
881 : :
882 : 19 : sal_Bool Bitmap::ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc )
883 : : {
884 : 19 : const sal_uInt16 nColors = rAcc.GetPaletteEntryCount();
885 : 19 : const sal_uLong nPalSize = nColors * 4UL;
886 [ + - ]: 19 : sal_uInt8* pEntries = new sal_uInt8[ nPalSize ];
887 : 19 : sal_uInt8* pTmpEntry = pEntries;
888 : 19 : BitmapColor aPalColor;
889 : :
890 [ + + ]: 3359 : for( sal_uInt16 i = 0; i < nColors; i++ )
891 : : {
892 : 3340 : const BitmapColor& rPalColor = rAcc.GetPaletteColor( i );
893 : :
894 : 3340 : *pTmpEntry++ = rPalColor.GetBlue();
895 : 3340 : *pTmpEntry++ = rPalColor.GetGreen();
896 : 3340 : *pTmpEntry++ = rPalColor.GetRed();
897 : 3340 : *pTmpEntry++ = 0;
898 : : }
899 : :
900 [ + - ]: 19 : rOStm.Write( pEntries, nPalSize );
901 [ + - ]: 19 : delete[] pEntries;
902 : :
903 : 19 : return( rOStm.GetError() == 0UL );
904 : : }
905 : :
906 : : // ------------------------------------------------------------------
907 : :
908 : : #if defined(HAVE_MEMCHECK_H)
909 : : namespace
910 : : {
911 : : void blankExtraSpace(sal_uInt8 *pBits, long nWidth, long nScanlineSize, int nBitCount)
912 : : {
913 : : size_t nExtraSpaceInScanLine = nScanlineSize - nWidth * nBitCount / 8;
914 : : if (nExtraSpaceInScanLine)
915 : : memset(pBits + (nScanlineSize - nExtraSpaceInScanLine), 0, nExtraSpaceInScanLine);
916 : : }
917 : : }
918 : : #endif
919 : :
920 : 38 : sal_Bool Bitmap::ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc,
921 : : sal_uLong nCompression, sal_uInt32& rImageSize )
922 : : {
923 [ - + ]: 38 : if( BITFIELDS == nCompression )
924 : : {
925 : 0 : const ColorMask& rMask = rAcc.GetColorMask();
926 : : SVBT32 aVal32;
927 : :
928 : 0 : UInt32ToSVBT32( rMask.GetRedMask(), aVal32 );
929 [ # # ]: 0 : rOStm.Write( (sal_uInt8*) aVal32, 4UL );
930 : :
931 : 0 : UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 );
932 [ # # ]: 0 : rOStm.Write( (sal_uInt8*) aVal32, 4UL );
933 : :
934 : 0 : UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 );
935 [ # # ]: 0 : rOStm.Write( (sal_uInt8*) aVal32, 4UL );
936 : :
937 : 0 : rImageSize = rOStm.Tell();
938 : :
939 [ # # ][ # # ]: 0 : if( rAcc.IsBottomUp() )
940 [ # # ]: 0 : rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() );
941 : : else
942 : : {
943 [ # # ]: 0 : for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- )
944 [ # # ]: 0 : rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize );
945 : : }
946 : : }
947 [ + - ][ + + ]: 38 : else if( ( RLE_4 == nCompression ) || ( RLE_8 == nCompression ) )
948 : : {
949 : 13 : rImageSize = rOStm.Tell();
950 : 13 : ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression );
951 : : }
952 [ + - ]: 25 : else if( !nCompression )
953 : : {
954 : : // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
955 : : // handled properly below (would have to set color masks, and
956 : : // nCompression=BITFIELDS - but color mask is not set for
957 : : // formats != *_TC_*). Note that this very problem might cause
958 : : // trouble at other places - the introduction of 32 bit RGBA
959 : : // bitmaps is relatively recent.
960 : : // #i59239# discretize bitcount for aligned width to 1,4,8,24
961 : : // (other cases are not written below)
962 : 25 : const sal_uInt16 nBitCount( sal::static_int_cast<sal_uInt16>(rAcc.GetBitCount()) );
963 : 25 : const sal_uLong nAlignedWidth = AlignedWidth4Bytes( rAcc.Width() *
964 : 25 : discretizeBitcount(nBitCount));
965 : 25 : sal_Bool bNative = sal_False;
966 : :
967 [ + - ]: 25 : switch( rAcc.GetScanlineFormat() )
968 : : {
969 : : case( BMP_FORMAT_1BIT_MSB_PAL ):
970 : : case( BMP_FORMAT_4BIT_MSN_PAL ):
971 : : case( BMP_FORMAT_8BIT_PAL ):
972 : : case( BMP_FORMAT_24BIT_TC_BGR ):
973 : : {
974 [ + - ][ + - ]: 25 : if( rAcc.IsBottomUp() && ( rAcc.GetScanlineSize() == nAlignedWidth ) )
[ + - ]
975 : 25 : bNative = sal_True;
976 : : }
977 : 25 : break;
978 : :
979 : : default:
980 : 0 : break;
981 : : }
982 : :
983 : 25 : rImageSize = rOStm.Tell();
984 : :
985 [ + - ]: 25 : if( bNative )
986 : 25 : rOStm.Write( rAcc.GetBuffer(), nAlignedWidth * rAcc.Height() );
987 : : else
988 : : {
989 : 0 : const long nWidth = rAcc.Width();
990 : 0 : const long nHeight = rAcc.Height();
991 : 0 : sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ];
992 : : #if defined(HAVE_MEMCHECK_H)
993 : : if (RUNNING_ON_VALGRIND)
994 : : blankExtraSpace(pBuf, nWidth, nAlignedWidth, discretizeBitcount(nBitCount));
995 : : #endif
996 : : sal_uInt8* pTmp;
997 : : sal_uInt8 cTmp;
998 : :
999 [ # # # # ]: 0 : switch( nBitCount )
1000 : : {
1001 : : case( 1 ):
1002 : : {
1003 [ # # ]: 0 : for( long nY = nHeight - 1; nY >= 0L; nY-- )
1004 : : {
1005 : 0 : pTmp = pBuf;
1006 : 0 : cTmp = 0;
1007 : :
1008 [ # # ]: 0 : for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
1009 : : {
1010 [ # # ]: 0 : if( !nShift )
1011 : : {
1012 : 0 : nShift = 8L;
1013 : 0 : *pTmp++ = cTmp;
1014 : 0 : cTmp = 0;
1015 : : }
1016 : :
1017 : 0 : cTmp |= ( (sal_uInt8) rAcc.GetPixel( nY, nX ) << --nShift );
1018 : : }
1019 : :
1020 : 0 : *pTmp = cTmp;
1021 : 0 : rOStm.Write( pBuf, nAlignedWidth );
1022 : : }
1023 : : }
1024 : 0 : break;
1025 : :
1026 : : case( 4 ):
1027 : : {
1028 [ # # ]: 0 : for( long nY = nHeight - 1; nY >= 0L; nY-- )
1029 : : {
1030 : 0 : pTmp = pBuf;
1031 : 0 : cTmp = 0;
1032 : :
1033 [ # # ]: 0 : for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
1034 : : {
1035 [ # # ]: 0 : if( !nShift )
1036 : : {
1037 : 0 : nShift = 2L;
1038 : 0 : *pTmp++ = cTmp;
1039 : 0 : cTmp = 0;
1040 : : }
1041 : :
1042 : 0 : cTmp |= ( (sal_uInt8) rAcc.GetPixel( nY, nX ) << ( --nShift << 2L ) );
1043 : : }
1044 : 0 : *pTmp = cTmp;
1045 : 0 : rOStm.Write( pBuf, nAlignedWidth );
1046 : : }
1047 : : }
1048 : 0 : break;
1049 : :
1050 : : case( 8 ):
1051 : : {
1052 [ # # ]: 0 : for( long nY = nHeight - 1; nY >= 0L; nY-- )
1053 : : {
1054 : 0 : pTmp = pBuf;
1055 : :
1056 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
1057 : 0 : *pTmp++ = rAcc.GetPixel( nY, nX );
1058 : :
1059 : 0 : rOStm.Write( pBuf, nAlignedWidth );
1060 : : }
1061 : : }
1062 : 0 : break;
1063 : :
1064 : : // #i59239# fallback to 24 bit format, if bitcount is non-default
1065 : : default:
1066 : : // FALLTHROUGH intended
1067 : : case( 24 ):
1068 : : {
1069 : 0 : BitmapColor aPixelColor;
1070 : :
1071 [ # # ]: 0 : for( long nY = nHeight - 1; nY >= 0L; nY-- )
1072 : : {
1073 : 0 : pTmp = pBuf;
1074 : :
1075 [ # # ]: 0 : for( long nX = 0L; nX < nWidth; nX++ )
1076 : : {
1077 [ # # ]: 0 : aPixelColor = rAcc.GetPixel( nY, nX );
1078 : 0 : *pTmp++ = aPixelColor.GetBlue();
1079 : 0 : *pTmp++ = aPixelColor.GetGreen();
1080 : 0 : *pTmp++ = aPixelColor.GetRed();
1081 : : }
1082 : :
1083 [ # # ]: 0 : rOStm.Write( pBuf, nAlignedWidth );
1084 : 0 : }
1085 : : }
1086 : 0 : break;
1087 : : }
1088 : :
1089 [ # # ]: 0 : delete[] pBuf;
1090 : : }
1091 : : }
1092 : :
1093 : 38 : rImageSize = rOStm.Tell() - rImageSize;
1094 : :
1095 : 38 : return( rOStm.GetError() == 0UL );
1096 : : }
1097 : :
1098 : : // ------------------------------------------------------------------
1099 : :
1100 : 13 : void Bitmap::ImplDecodeRLE( sal_uInt8* pBuffer, DIBInfoHeader& rHeader,
1101 : : BitmapWriteAccess& rAcc, sal_Bool bRLE4 )
1102 : : {
1103 : 13 : Scanline pRLE = pBuffer;
1104 : 13 : long nY = abs(rHeader.nHeight) - 1L;
1105 : 13 : const sal_uLong nWidth = rAcc.Width();
1106 : : sal_uLong nCountByte;
1107 : : sal_uLong nRunByte;
1108 : 13 : sal_uLong nX = 0UL;
1109 : : sal_uInt8 cTmp;
1110 : 13 : sal_Bool bEndDecoding = sal_False;
1111 : :
1112 [ + - ][ + + ]: 45484 : do
[ + + ]
1113 : : {
1114 [ + + ]: 45484 : if( ( nCountByte = *pRLE++ ) == 0 )
1115 : : {
1116 : 4513 : nRunByte = *pRLE++;
1117 : :
1118 [ - + ]: 4513 : if( nRunByte > 2 )
1119 : : {
1120 [ # # ]: 0 : if( bRLE4 )
1121 : : {
1122 : 0 : nCountByte = nRunByte >> 1;
1123 : :
1124 [ # # ]: 0 : for( sal_uLong i = 0UL; i < nCountByte; i++ )
1125 : : {
1126 : 0 : cTmp = *pRLE++;
1127 : :
1128 [ # # ]: 0 : if( nX < nWidth )
1129 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1130 : :
1131 [ # # ]: 0 : if( nX < nWidth )
1132 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
1133 : : }
1134 : :
1135 [ # # ]: 0 : if( nRunByte & 1 )
1136 : : {
1137 [ # # ]: 0 : if( nX < nWidth )
1138 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, *pRLE >> 4 );
1139 : :
1140 : 0 : pRLE++;
1141 : : }
1142 : :
1143 [ # # ]: 0 : if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
1144 : 0 : pRLE++;
1145 : : }
1146 : : else
1147 : : {
1148 [ # # ]: 0 : for( sal_uLong i = 0UL; i < nRunByte; i++ )
1149 : : {
1150 [ # # ]: 0 : if( nX < nWidth )
1151 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, *pRLE );
1152 : :
1153 : 0 : pRLE++;
1154 : : }
1155 : :
1156 [ # # ]: 0 : if( nRunByte & 1 )
1157 : 0 : pRLE++;
1158 : : }
1159 : : }
1160 [ + - ]: 4513 : else if( !nRunByte )
1161 : : {
1162 : 4513 : nY--;
1163 : 4513 : nX = 0UL;
1164 : : }
1165 [ # # ]: 0 : else if( nRunByte == 1 )
1166 : 0 : bEndDecoding = sal_True;
1167 : : else
1168 : : {
1169 : 0 : nX += *pRLE++;
1170 : 0 : nY -= *pRLE++;
1171 : : }
1172 : : }
1173 : : else
1174 : : {
1175 : 40971 : cTmp = *pRLE++;
1176 : :
1177 [ - + ]: 40971 : if( bRLE4 )
1178 : : {
1179 : 0 : nRunByte = nCountByte >> 1;
1180 : :
1181 [ # # ]: 0 : for( sal_uLong i = 0UL; i < nRunByte; i++ )
1182 : : {
1183 [ # # ]: 0 : if( nX < nWidth )
1184 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1185 : :
1186 [ # # ]: 0 : if( nX < nWidth )
1187 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
1188 : : }
1189 : :
1190 [ # # ][ # # ]: 0 : if( ( nCountByte & 1 ) && ( nX < nWidth ) )
1191 [ # # ]: 0 : rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1192 : : }
1193 : : else
1194 : : {
1195 [ + + ][ + - ]: 3506203 : for( sal_uLong i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ )
[ + + ]
1196 [ + - ]: 3465232 : rAcc.SetPixel( nY, nX++, cTmp );
1197 : : }
1198 : : }
1199 : : }
1200 : : while ( !bEndDecoding && ( nY >= 0L ) );
1201 : 13 : }
1202 : :
1203 : : // ------------------------------------------------------------------
1204 : :
1205 : 13 : sal_Bool Bitmap::ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bRLE4 )
1206 : : {
1207 : 13 : const sal_uLong nWidth = rAcc.Width();
1208 : 13 : const sal_uLong nHeight = rAcc.Height();
1209 : : sal_uLong nX;
1210 : : sal_uLong nSaveIndex;
1211 : : sal_uLong nCount;
1212 : : sal_uLong nBufCount;
1213 : 13 : sal_uInt8* pBuf = new sal_uInt8[ ( nWidth << 1 ) + 2 ];
1214 : : sal_uInt8* pTmp;
1215 : : sal_uInt8 cPix;
1216 : : sal_uInt8 cLast;
1217 : : sal_Bool bFound;
1218 : :
1219 [ + + ]: 4526 : for ( long nY = nHeight - 1L; nY >= 0L; nY-- )
1220 : : {
1221 : 4513 : pTmp = pBuf;
1222 : 4513 : nX = nBufCount = 0UL;
1223 : :
1224 [ + + ]: 45440 : while( nX < nWidth )
1225 : : {
1226 : 40927 : nCount = 1L;
1227 : 40927 : cPix = rAcc.GetPixel( nY, nX++ );
1228 : :
1229 [ + + ][ + + ]: 3465188 : while( ( nX < nWidth ) && ( nCount < 255L ) && ( cPix == rAcc.GetPixel( nY, nX ) ) )
[ + - ][ + + ]
[ + + ]
[ + + # # ]
1230 : : {
1231 : 3424261 : nX++;
1232 : 3424261 : nCount++;
1233 : : }
1234 : :
1235 [ + + ]: 40927 : if ( nCount > 1 )
1236 : : {
1237 : 30597 : *pTmp++ = (sal_uInt8) nCount;
1238 [ - + ]: 30597 : *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
1239 : 30597 : nBufCount += 2;
1240 : : }
1241 : : else
1242 : : {
1243 : 10330 : cLast = cPix;
1244 : 10330 : nSaveIndex = nX - 1UL;
1245 : 10330 : bFound = sal_False;
1246 : :
1247 [ + + ][ + - ]: 17025 : while( ( nX < nWidth ) && ( nCount < 256L ) && ( cPix = rAcc.GetPixel( nY, nX ) ) != cLast )
[ + - ][ + + ]
[ + + ]
[ + + # # ]
1248 : : {
1249 : 6695 : nX++; nCount++;
1250 : 6695 : cLast = cPix;
1251 : 6695 : bFound = sal_True;
1252 : : }
1253 : :
1254 [ + + ]: 10330 : if ( bFound )
1255 : 6651 : nX--;
1256 : :
1257 [ - + ]: 10330 : if ( nCount > 3 )
1258 : : {
1259 : 0 : *pTmp++ = 0;
1260 : 0 : *pTmp++ = (sal_uInt8) --nCount;
1261 : :
1262 [ # # ]: 0 : if( bRLE4 )
1263 : : {
1264 [ # # ]: 0 : for ( sal_uLong i = 0; i < nCount; i++, pTmp++ )
1265 : : {
1266 : 0 : *pTmp = (sal_uInt8) rAcc.GetPixel( nY, nSaveIndex++ ) << 4;
1267 : :
1268 [ # # ]: 0 : if ( ++i < nCount )
1269 : 0 : *pTmp |= rAcc.GetPixel( nY, nSaveIndex++ );
1270 : : }
1271 : :
1272 : 0 : nCount = ( nCount + 1 ) >> 1;
1273 : : }
1274 : : else
1275 : : {
1276 [ # # ]: 0 : for( sal_uLong i = 0UL; i < nCount; i++ )
1277 : 0 : *pTmp++ = rAcc.GetPixel( nY, nSaveIndex++ );
1278 : : }
1279 : :
1280 [ # # ]: 0 : if ( nCount & 1 )
1281 : : {
1282 : 0 : *pTmp++ = 0;
1283 : 0 : nBufCount += ( nCount + 3 );
1284 : : }
1285 : : else
1286 : 0 : nBufCount += ( nCount + 2 );
1287 : : }
1288 : : else
1289 : : {
1290 : 10330 : *pTmp++ = 1;
1291 [ - + ]: 10330 : *pTmp++ = (sal_uInt8) rAcc.GetPixel( nY, nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1292 : :
1293 [ + + ]: 10330 : if ( nCount == 3 )
1294 : : {
1295 : 44 : *pTmp++ = 1;
1296 [ - + ]: 44 : *pTmp++ = (sal_uInt8) rAcc.GetPixel( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1297 : 44 : nBufCount += 4;
1298 : : }
1299 : : else
1300 : 10286 : nBufCount += 2;
1301 : : }
1302 : : }
1303 : : }
1304 : :
1305 : 4513 : pBuf[ nBufCount++ ] = 0;
1306 : 4513 : pBuf[ nBufCount++ ] = 0;
1307 : :
1308 : 4513 : rOStm.Write( pBuf, nBufCount );
1309 : : }
1310 : :
1311 : 13 : rOStm << (sal_uInt8) 0;
1312 : 13 : rOStm << (sal_uInt8) 1;
1313 : :
1314 [ + - ]: 13 : delete[] pBuf;
1315 : :
1316 : 13 : return( rOStm.GetError() == 0UL );
1317 : : }
1318 : :
1319 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|