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