LibreOffice Module vcl (master) 1
dibtools.cxx
Go to the documentation of this file.
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#include <sal/log.hxx>
22
23#include <cassert>
24
25#include <o3tl/safeint.hxx>
26#include <vcl/dibtools.hxx>
28#include <tools/zcodec.hxx>
29#include <tools/stream.hxx>
30#include <tools/fract.hxx>
31#include <tools/helpers.hxx>
34#include <vcl/bitmapex.hxx>
35#include <vcl/outdev.hxx>
37#include <memory>
38
39#define DIBCOREHEADERSIZE ( 12UL )
40#define DIBINFOHEADERSIZE ( sizeof(DIBInfoHeader) )
41#define DIBV5HEADERSIZE ( sizeof(DIBV5Header) )
42
43// - DIBInfoHeader and DIBV5Header
44
45typedef sal_Int32 FXPT2DOT30;
46
47namespace
48{
49
50struct CIEXYZ
51{
52 FXPT2DOT30 aXyzX;
53 FXPT2DOT30 aXyzY;
54 FXPT2DOT30 aXyzZ;
55
56 CIEXYZ()
57 : aXyzX(0),
58 aXyzY(0),
59 aXyzZ(0)
60 {}
61};
62
63struct CIEXYZTriple
64{
65 CIEXYZ aXyzRed;
66 CIEXYZ aXyzGreen;
67 CIEXYZ aXyzBlue;
68
69 CIEXYZTriple()
70 {}
71};
72
73struct DIBInfoHeader
74{
75 sal_uInt32 nSize;
76 sal_Int32 nWidth;
77 sal_Int32 nHeight;
78 sal_uInt16 nPlanes;
79 sal_uInt16 nBitCount;
80 sal_uInt32 nCompression;
81 sal_uInt32 nSizeImage;
82 sal_Int32 nXPelsPerMeter;
83 sal_Int32 nYPelsPerMeter;
84 sal_uInt32 nColsUsed;
85 sal_uInt32 nColsImportant;
86
87 DIBInfoHeader()
88 : nSize(0),
89 nWidth(0),
90 nHeight(0),
91 nPlanes(0),
92 nBitCount(0),
93 nCompression(0),
94 nSizeImage(0),
95 nXPelsPerMeter(0),
96 nYPelsPerMeter(0),
97 nColsUsed(0),
98 nColsImportant(0)
99 {}
100};
101
102struct DIBV5Header : public DIBInfoHeader
103{
104 sal_uInt32 nV5RedMask;
105 sal_uInt32 nV5GreenMask;
106 sal_uInt32 nV5BlueMask;
107 sal_uInt32 nV5AlphaMask;
108 sal_uInt32 nV5CSType;
109 CIEXYZTriple aV5Endpoints;
110 sal_uInt32 nV5GammaRed;
111 sal_uInt32 nV5GammaGreen;
112 sal_uInt32 nV5GammaBlue;
113 sal_uInt32 nV5Intent;
114 sal_uInt32 nV5ProfileData;
115 sal_uInt32 nV5ProfileSize;
116 sal_uInt32 nV5Reserved;
117
118 DIBV5Header()
119 : nV5RedMask(0),
120 nV5GreenMask(0),
121 nV5BlueMask(0),
122 nV5AlphaMask(0),
123 nV5CSType(0),
124 nV5GammaRed(0),
125 nV5GammaGreen(0),
126 nV5GammaBlue(0),
127 nV5Intent(0),
128 nV5ProfileData(0),
129 nV5ProfileSize(0),
130 nV5Reserved(0)
131 {}
132};
133
134vcl::PixelFormat convertToBPP(sal_uInt16 nCount)
135{
136 return (nCount <= 1) ? vcl::PixelFormat::N1_BPP :
139}
140
141bool isBitfieldCompression( ScanlineFormat nScanlineFormat )
142{
143 return ScanlineFormat::N32BitTcMask == nScanlineFormat;
144}
145
146bool ImplReadDIBInfoHeader(SvStream& rIStm, DIBV5Header& rHeader, bool& bTopDown, bool bMSOFormat)
147{
148 if (rIStm.remainingSize() <= 4)
149 return false;
150 // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER
151 sal_uInt64 const aStartPos(rIStm.Tell());
152 rIStm.ReadUInt32( rHeader.nSize );
153
154 // BITMAPCOREHEADER
155 if ( rHeader.nSize == DIBCOREHEADERSIZE )
156 {
157 sal_Int16 nTmp16;
158
159 rIStm.ReadInt16( nTmp16 ); rHeader.nWidth = nTmp16;
160 rIStm.ReadInt16( nTmp16 ); rHeader.nHeight = nTmp16;
161 rIStm.ReadUInt16( rHeader.nPlanes );
162 rIStm.ReadUInt16( rHeader.nBitCount );
163 }
164 else if ( bMSOFormat && rHeader.nSize == DIBINFOHEADERSIZE )
165 {
166 sal_Int16 nTmp16(0);
167 rIStm.ReadInt16(nTmp16);
168 rHeader.nWidth = nTmp16;
169 rIStm.ReadInt16(nTmp16);
170 rHeader.nHeight = nTmp16;
171 sal_uInt8 nTmp8(0);
172 rIStm.ReadUChar(nTmp8);
173 rHeader.nPlanes = nTmp8;
174 rIStm.ReadUChar(nTmp8);
175 rHeader.nBitCount = nTmp8;
176 rIStm.ReadInt16(nTmp16);
177 rHeader.nSizeImage = nTmp16;
178 rIStm.ReadInt16(nTmp16);
179 rHeader.nCompression = nTmp16;
180 if ( !rHeader.nSizeImage ) // uncompressed?
181 rHeader.nSizeImage = ((rHeader.nWidth * rHeader.nBitCount + 31) & ~31) / 8 * rHeader.nHeight;
182 rIStm.ReadInt32( rHeader.nXPelsPerMeter );
183 rIStm.ReadInt32( rHeader.nYPelsPerMeter );
184 rIStm.ReadUInt32( rHeader.nColsUsed );
185 rIStm.ReadUInt32( rHeader.nColsImportant );
186 }
187 else
188 {
189 // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible
190 std::size_t nUsed(sizeof(rHeader.nSize));
191
192 auto readUInt16 = [&nUsed, &rHeader, &rIStm](sal_uInt16 & v) {
193 if (nUsed < rHeader.nSize) {
194 rIStm.ReadUInt16(v);
195 nUsed += sizeof(v);
196 }
197 };
198 auto readInt32 = [&nUsed, &rHeader, &rIStm](sal_Int32 & v) {
199 if (nUsed < rHeader.nSize) {
200 rIStm.ReadInt32(v);
201 nUsed += sizeof(v);
202 }
203 };
204 auto readUInt32 = [&nUsed, &rHeader, &rIStm](sal_uInt32 & v) {
205 if (nUsed < rHeader.nSize) {
206 rIStm.ReadUInt32(v);
207 nUsed += sizeof(v);
208 }
209 };
210
211 // read DIBInfoHeader entries
212 readInt32( rHeader.nWidth );
213 readInt32( rHeader.nHeight );
214 readUInt16( rHeader.nPlanes );
215 readUInt16( rHeader.nBitCount );
216 readUInt32( rHeader.nCompression );
217 readUInt32( rHeader.nSizeImage );
218 readInt32( rHeader.nXPelsPerMeter );
219 readInt32( rHeader.nYPelsPerMeter );
220 readUInt32( rHeader.nColsUsed );
221 readUInt32( rHeader.nColsImportant );
222
223 // read DIBV5HEADER members
224 readUInt32( rHeader.nV5RedMask );
225 readUInt32( rHeader.nV5GreenMask );
226 readUInt32( rHeader.nV5BlueMask );
227 readUInt32( rHeader.nV5AlphaMask );
228 readUInt32( rHeader.nV5CSType );
229
230 // read contained CIEXYZTriple's
231 readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzX );
232 readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzY );
233 readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzZ );
234 readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzX );
235 readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzY );
236 readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzZ );
237 readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzX );
238 readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzY );
239 readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzZ );
240
241 readUInt32( rHeader.nV5GammaRed );
242 readUInt32( rHeader.nV5GammaGreen );
243 readUInt32( rHeader.nV5GammaBlue );
244 readUInt32( rHeader.nV5Intent );
245 readUInt32( rHeader.nV5ProfileData );
246 readUInt32( rHeader.nV5ProfileSize );
247 readUInt32( rHeader.nV5Reserved );
248
249 // Read color mask. An additional 12 bytes of color bitfields follow the info header (WinBMPv3-NT)
250 sal_uInt32 nColorMask = 0;
251 if (BITFIELDS == rHeader.nCompression && DIBINFOHEADERSIZE == rHeader.nSize)
252 {
253 rIStm.ReadUInt32( rHeader.nV5RedMask );
254 rIStm.ReadUInt32( rHeader.nV5GreenMask );
255 rIStm.ReadUInt32( rHeader.nV5BlueMask );
256 nColorMask = 12;
257 }
258
259 // seek to EndPos
260 if (!checkSeek(rIStm, aStartPos + rHeader.nSize + nColorMask))
261 return false;
262 }
263
264 if (!rIStm.good() || rHeader.nHeight == SAL_MIN_INT32)
265 return false;
266
267 if ( rHeader.nHeight < 0 )
268 {
269 bTopDown = true;
270 rHeader.nHeight *= -1;
271 }
272 else
273 {
274 bTopDown = false;
275 }
276
277 if ( rHeader.nWidth < 0 || rHeader.nXPelsPerMeter < 0 || rHeader.nYPelsPerMeter < 0 )
278 {
279 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
280 }
281
282 // #144105# protect a little against damaged files
283 assert(rHeader.nHeight >= 0);
284 if (rHeader.nHeight != 0 && rHeader.nWidth >= 0
285 && (rHeader.nSizeImage / 16 / static_cast<sal_uInt32>(rHeader.nHeight)
286 > o3tl::make_unsigned(rHeader.nWidth)))
287 {
288 rHeader.nSizeImage = 0;
289 }
290
291
292 if (rHeader.nPlanes != 1)
293 return false;
294
295 if (rHeader.nBitCount != 0 && rHeader.nBitCount != 1 &&
296 rHeader.nBitCount != 4 && rHeader.nBitCount != 8 &&
297 rHeader.nBitCount != 16 && rHeader.nBitCount != 24 &&
298 rHeader.nBitCount != 32)
299 {
300 return false;
301 }
302
303 return rIStm.good();
304}
305
306bool ImplReadDIBPalette(SvStream& rIStm, BitmapPalette& rPal, bool bQuad)
307{
308 const sal_uInt16 nColors = rPal.GetEntryCount();
309 const sal_uLong nPalSize = nColors * ( bQuad ? 4UL : 3UL );
310 BitmapColor aPalColor;
311
312 std::unique_ptr<sal_uInt8[]> pEntries(new sal_uInt8[ nPalSize ]);
313 if (rIStm.ReadBytes(pEntries.get(), nPalSize) != nPalSize)
314 {
315 return false;
316 }
317
318 sal_uInt8* pTmpEntry = pEntries.get();
319 for( sal_uInt16 i = 0; i < nColors; i++ )
320 {
321 aPalColor.SetBlue( *pTmpEntry++ );
322 aPalColor.SetGreen( *pTmpEntry++ );
323 aPalColor.SetRed( *pTmpEntry++ );
324
325 if( bQuad )
326 pTmpEntry++;
327
328 rPal[i] = aPalColor;
329 }
330
331 return rIStm.GetError() == ERRCODE_NONE;
332}
333
334BitmapColor SanitizePaletteIndex(sal_uInt8 nIndex, BitmapPalette& rPalette, bool bForceToMonoWhileReading)
335{
336 const sal_uInt16 nPaletteEntryCount = rPalette.GetEntryCount();
337 if (nPaletteEntryCount && nIndex >= nPaletteEntryCount)
338 {
339 auto nSanitizedIndex = nIndex % nPaletteEntryCount;
340 SAL_WARN_IF(nIndex != nSanitizedIndex, "vcl", "invalid colormap index: "
341 << static_cast<unsigned int>(nIndex) << ", colormap len is: "
342 << nPaletteEntryCount);
343 nIndex = nSanitizedIndex;
344 }
345
346 if (nPaletteEntryCount && bForceToMonoWhileReading)
347 {
348 return BitmapColor(static_cast<sal_uInt8>(rPalette[nIndex].GetLuminance() >= 255));
349 }
350
351 return BitmapColor(nIndex);
352}
353
354BitmapColor SanitizeColor(const BitmapColor &rColor, bool bForceToMonoWhileReading)
355{
356 if (!bForceToMonoWhileReading)
357 return rColor;
358 return BitmapColor(static_cast<sal_uInt8>(rColor.GetLuminance() >= 255));
359}
360
361bool ImplDecodeRLE(sal_uInt8* pBuffer, DIBV5Header const & rHeader, BitmapWriteAccess& rAcc, BitmapPalette& rPalette, bool bForceToMonoWhileReading, bool bRLE4)
362{
363 Scanline pRLE = pBuffer;
364 Scanline pEndRLE = pBuffer + rHeader.nSizeImage;
365 tools::Long nY = rHeader.nHeight - 1;
366 const sal_uLong nWidth = rAcc.Width();
367 sal_uLong nCountByte;
368 sal_uLong nRunByte;
369 sal_uLong nX = 0;
370 sal_uInt8 cTmp;
371 bool bEndDecoding = false;
372
373 do
374 {
375 if (pRLE == pEndRLE)
376 return false;
377 if( ( nCountByte = *pRLE++ ) == 0 )
378 {
379 if (pRLE == pEndRLE)
380 return false;
381 nRunByte = *pRLE++;
382
383 if( nRunByte > 2 )
384 {
385 Scanline pScanline = rAcc.GetScanline(nY);
386 if( bRLE4 )
387 {
388 nCountByte = nRunByte >> 1;
389
390 for( sal_uLong i = 0; i < nCountByte; i++ )
391 {
392 if (pRLE == pEndRLE)
393 return false;
394
395 cTmp = *pRLE++;
396
397 if( nX < nWidth )
398 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette, bForceToMonoWhileReading));
399
400 if( nX < nWidth )
401 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp & 0x0f, rPalette, bForceToMonoWhileReading));
402 }
403
404 if( nRunByte & 1 )
405 {
406 if (pRLE == pEndRLE)
407 return false;
408
409 if( nX < nWidth )
410 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(*pRLE >> 4, rPalette, bForceToMonoWhileReading));
411
412 pRLE++;
413 }
414
415 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
416 {
417 if (pRLE == pEndRLE)
418 return false;
419
420 pRLE++;
421 }
422 }
423 else
424 {
425 for( sal_uLong i = 0; i < nRunByte; i++ )
426 {
427 if (pRLE == pEndRLE)
428 return false;
429
430 if( nX < nWidth )
431 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(*pRLE, rPalette, bForceToMonoWhileReading));
432
433 pRLE++;
434 }
435
436 if( nRunByte & 1 )
437 {
438 if (pRLE == pEndRLE)
439 return false;
440
441 pRLE++;
442 }
443 }
444 }
445 else if( !nRunByte )
446 {
447 nY--;
448 nX = 0;
449 }
450 else if( nRunByte == 1 )
451 bEndDecoding = true;
452 else
453 {
454 if (pRLE == pEndRLE)
455 return false;
457 nX += *pRLE++;
458
459 if (pRLE == pEndRLE)
460 return false;
461
462 nY -= *pRLE++;
463 }
464 }
465 else
466 {
467 if (pRLE == pEndRLE)
468 return false;
469 cTmp = *pRLE++;
470
471 Scanline pScanline = rAcc.GetScanline(nY);
472 if( bRLE4 )
473 {
474 nRunByte = nCountByte >> 1;
475
476 for (sal_uLong i = 0; i < nRunByte && nX < nWidth; ++i)
477 {
478 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette, bForceToMonoWhileReading));
479 if( nX < nWidth )
480 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp & 0x0f, rPalette, bForceToMonoWhileReading));
481 }
482
483 if( ( nCountByte & 1 ) && ( nX < nWidth ) )
484 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette, bForceToMonoWhileReading));
485 }
486 else
487 {
488 for (sal_uLong i = 0; i < nCountByte && nX < nWidth; ++i)
489 rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp, rPalette, bForceToMonoWhileReading));
490 }
491 }
492 }
493 while (!bEndDecoding && (nY >= 0));
494
495 return true;
496}
497
498bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, BitmapPalette& rPalette, BitmapWriteAccess* pAccAlpha,
499 bool bTopDown, bool& rAlphaUsed, const sal_uInt64 nAlignedWidth,
500 const bool bForceToMonoWhileReading)
501{
502 sal_uInt32 nRMask(( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL);
503 sal_uInt32 nGMask(( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL);
504 sal_uInt32 nBMask(( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL);
505 bool bNative(false);
506 bool bTCMask(!pAccAlpha && ((16 == rHeader.nBitCount) || (32 == rHeader.nBitCount)));
507 bool bRLE((RLE_8 == rHeader.nCompression && 8 == rHeader.nBitCount) || (RLE_4 == rHeader.nCompression && 4 == rHeader.nBitCount));
508
509 // Is native format?
510 switch(rAcc.GetScanlineFormat())
511 {
514 {
515 // we can't trust arbitrary-sourced index based formats to have correct indexes, so we exclude the pal formats
516 // from raw read and force checking their colormap indexes
517 bNative = ( ( rAcc.IsBottomUp() != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) );
518 break;
519 }
520
521 default:
522 {
523 break;
524 }
525 }
526
527 // Read data
528 if (bNative)
529 {
530 if (nAlignedWidth
531 > std::numeric_limits<std::size_t>::max() / rHeader.nHeight)
532 {
533 return false;
534 }
535 std::size_t n = nAlignedWidth * rHeader.nHeight;
536 if (rIStm.ReadBytes(rAcc.GetBuffer(), n) != n)
537 {
538 return false;
539 }
540 }
541 else
542 {
543 if (rHeader.nV5RedMask > 0)
544 nRMask = rHeader.nV5RedMask;
545 if (rHeader.nV5GreenMask > 0)
546 nGMask = rHeader.nV5GreenMask;
547 if (rHeader.nV5BlueMask > 0)
548 nBMask = rHeader.nV5BlueMask;
549
550 const tools::Long nWidth(rHeader.nWidth);
551 const tools::Long nHeight(rHeader.nHeight);
552 tools::Long nResult = 0;
553 if (utl::ConfigManager::IsFuzzing() && (o3tl::checked_multiply(nWidth, nHeight, nResult) || nResult > 4000000))
554 return false;
555
556 if (bRLE)
557 {
558 if(!rHeader.nSizeImage)
559 {
560 rHeader.nSizeImage = rIStm.remainingSize();
561 }
562
563 if (rHeader.nSizeImage > rIStm.remainingSize())
564 return false;
565 std::vector<sal_uInt8> aBuffer(rHeader.nSizeImage);
566 if (rIStm.ReadBytes(aBuffer.data(), rHeader.nSizeImage) != rHeader.nSizeImage)
567 return false;
568 if (!ImplDecodeRLE(aBuffer.data(), rHeader, rAcc, rPalette, bForceToMonoWhileReading, RLE_4 == rHeader.nCompression))
569 return false;
570 }
571 else
572 {
573 if (nAlignedWidth > rIStm.remainingSize())
574 {
575 // ofz#11188 avoid timeout
576 // all following paths will enter a case statement, and nCount
577 // is always at least 1, so we can check here before allocation
578 // if at least one row can be read
579 return false;
580 }
581 std::vector<sal_uInt8> aBuf(nAlignedWidth);
582
583 const tools::Long nI(bTopDown ? 1 : -1);
584 tools::Long nY(bTopDown ? 0 : nHeight - 1);
585 tools::Long nCount(nHeight);
586
587 switch(rHeader.nBitCount)
588 {
589 case 1:
590 {
591 for( ; nCount--; nY += nI )
592 {
593 sal_uInt8 * pTmp = aBuf.data();
594 if (rIStm.ReadBytes(pTmp, nAlignedWidth)
595 != nAlignedWidth)
596 {
597 return false;
598 }
599 sal_uInt8 cTmp = *pTmp++;
600 Scanline pScanline = rAcc.GetScanline(nY);
601 for( tools::Long nX = 0, nShift = 8; nX < nWidth; nX++ )
602 {
603 if( !nShift )
604 {
605 nShift = 8;
606 cTmp = *pTmp++;
607 }
608
609 auto nIndex = (cTmp >> --nShift) & 1;
610 rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette, bForceToMonoWhileReading));
611 }
612 }
613 }
614 break;
615
616 case 4:
617 {
618 for( ; nCount--; nY += nI )
619 {
620 sal_uInt8 * pTmp = aBuf.data();
621 if (rIStm.ReadBytes(pTmp, nAlignedWidth)
622 != nAlignedWidth)
623 {
624 return false;
625 }
626 sal_uInt8 cTmp = *pTmp++;
627 Scanline pScanline = rAcc.GetScanline(nY);
628 for( tools::Long nX = 0, nShift = 2; nX < nWidth; nX++ )
629 {
630 if( !nShift )
631 {
632 nShift = 2;
633 cTmp = *pTmp++;
634 }
635
636 auto nIndex = (cTmp >> ( --nShift << 2 ) ) & 0x0f;
637 rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette, bForceToMonoWhileReading));
638 }
639 }
640 }
641 break;
642
643 case 8:
644 {
645 for( ; nCount--; nY += nI )
646 {
647 sal_uInt8 * pTmp = aBuf.data();
648 if (rIStm.ReadBytes(pTmp, nAlignedWidth)
649 != nAlignedWidth)
650 {
651 return false;
652 }
653
654 Scanline pScanline = rAcc.GetScanline(nY);
655 for( tools::Long nX = 0; nX < nWidth; nX++ )
656 {
657 auto nIndex = *pTmp++;
658 rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette, bForceToMonoWhileReading));
659 }
660 }
661 }
662 break;
663
664 case 16:
665 {
666 ColorMaskElement aRedMask(nRMask);
667 if (!aRedMask.CalcMaskShift())
668 return false;
669 ColorMaskElement aGreenMask(nGMask);
670 if (!aGreenMask.CalcMaskShift())
671 return false;
672 ColorMaskElement aBlueMask(nBMask);
673 if (!aBlueMask.CalcMaskShift())
674 return false;
675
676 ColorMask aMask(aRedMask, aGreenMask, aBlueMask);
677 BitmapColor aColor;
678
679 for( ; nCount--; nY += nI )
680 {
681 sal_uInt16 * pTmp16 = reinterpret_cast<sal_uInt16*>(aBuf.data());
682 if (rIStm.ReadBytes(pTmp16, nAlignedWidth)
683 != nAlignedWidth)
684 {
685 return false;
686 }
687
688 Scanline pScanline = rAcc.GetScanline(nY);
689 for( tools::Long nX = 0; nX < nWidth; nX++ )
690 {
691 aMask.GetColorFor16BitLSB( aColor, reinterpret_cast<sal_uInt8*>(pTmp16++) );
692 rAcc.SetPixelOnData(pScanline, nX, SanitizeColor(aColor, bForceToMonoWhileReading));
693 }
694 }
695 }
696 break;
697
698 case 24:
699 {
700 BitmapColor aPixelColor;
701
702 for( ; nCount--; nY += nI )
703 {
704 sal_uInt8* pTmp = aBuf.data();
705 if (rIStm.ReadBytes(pTmp, nAlignedWidth)
706 != nAlignedWidth)
707 {
708 return false;
709 }
710
711 Scanline pScanline = rAcc.GetScanline(nY);
712 for( tools::Long nX = 0; nX < nWidth; nX++ )
713 {
714 aPixelColor.SetBlue( *pTmp++ );
715 aPixelColor.SetGreen( *pTmp++ );
716 aPixelColor.SetRed( *pTmp++ );
717 rAcc.SetPixelOnData(pScanline, nX, SanitizeColor(aPixelColor, bForceToMonoWhileReading));
718 }
719 }
720 }
721 break;
722
723 case 32:
724 {
725 ColorMaskElement aRedMask(nRMask);
726 if (!aRedMask.CalcMaskShift())
727 return false;
728 ColorMaskElement aGreenMask(nGMask);
729 if (!aGreenMask.CalcMaskShift())
730 return false;
731 ColorMaskElement aBlueMask(nBMask);
732 if (!aBlueMask.CalcMaskShift())
733 return false;
734 ColorMask aMask(aRedMask, aGreenMask, aBlueMask);
735
736 BitmapColor aColor;
737 sal_uInt32* pTmp32;
738
739 if(pAccAlpha)
740 {
741 sal_uInt8 aAlpha;
742
743 for( ; nCount--; nY += nI )
744 {
745 pTmp32 = reinterpret_cast<sal_uInt32*>(aBuf.data());
746 if (rIStm.ReadBytes(pTmp32, nAlignedWidth)
747 != nAlignedWidth)
748 {
749 return false;
750 }
751
752 Scanline pScanline = rAcc.GetScanline(nY);
753 Scanline pAlphaScanline = pAccAlpha->GetScanline(nY);
754 for( tools::Long nX = 0; nX < nWidth; nX++ )
755 {
756 aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, reinterpret_cast<sal_uInt8*>(pTmp32++) );
757 rAcc.SetPixelOnData(pScanline, nX, SanitizeColor(aColor, bForceToMonoWhileReading));
758 pAccAlpha->SetPixelOnData(pAlphaScanline, nX, BitmapColor(sal_uInt8(0xff) - aAlpha));
759 rAlphaUsed |= 0xff != aAlpha;
760 }
761 }
762 }
763 else
764 {
765 for( ; nCount--; nY += nI )
766 {
767 pTmp32 = reinterpret_cast<sal_uInt32*>(aBuf.data());
768 if (rIStm.ReadBytes(pTmp32, nAlignedWidth)
769 != nAlignedWidth)
770 {
771 return false;
772 }
773
774 Scanline pScanline = rAcc.GetScanline(nY);
775 for( tools::Long nX = 0; nX < nWidth; nX++ )
776 {
777 aMask.GetColorFor32Bit( aColor, reinterpret_cast<sal_uInt8*>(pTmp32++) );
778 rAcc.SetPixelOnData(pScanline, nX, SanitizeColor(aColor, bForceToMonoWhileReading));
779 }
780 }
781 }
782 }
783 }
784 }
785 }
786
787 return rIStm.GetError() == ERRCODE_NONE;
788}
789
790bool ImplReadDIBBody(SvStream& rIStm, Bitmap& rBmp, AlphaMask* pBmpAlpha, sal_uInt64 nOffset, bool bIsMask, bool bMSOFormat)
791{
792 DIBV5Header aHeader;
793 const sal_uInt64 nStmPos = rIStm.Tell();
794 bool bTopDown(false);
795
796 if (!ImplReadDIBInfoHeader(rIStm, aHeader, bTopDown, bMSOFormat))
797 return false;
798
799 //BI_BITCOUNT_0 jpeg/png is unsupported
800 if (aHeader.nBitCount == 0)
801 return false;
802
803 if (aHeader.nWidth <= 0 || aHeader.nHeight <= 0)
804 return false;
805
806 // In case ImplReadDIB() didn't call ImplReadDIBFileHeader() before
807 // this method, nOffset is 0, that's OK.
808 if (nOffset && aHeader.nSize > nOffset)
809 {
810 // Header size claims to extend into the image data.
811 // Looks like an error.
812 return false;
813 }
814
815 sal_uInt16 nColors(0);
816 SvStream* pIStm;
817 std::unique_ptr<SvMemoryStream> pMemStm;
818 std::vector<sal_uInt8> aData;
819
820 if (aHeader.nBitCount <= 8)
821 {
822 if(aHeader.nColsUsed)
823 {
824 nColors = static_cast<sal_uInt16>(aHeader.nColsUsed);
825 }
826 else
827 {
828 nColors = ( 1 << aHeader.nBitCount );
829 }
830 }
831
832 if (ZCOMPRESS == aHeader.nCompression)
833 {
834 sal_uInt32 nCodedSize(0);
835 sal_uInt32 nUncodedSize(0);
836
837 // read coding information
838 rIStm.ReadUInt32( nCodedSize ).ReadUInt32( nUncodedSize ).ReadUInt32( aHeader.nCompression );
839 if (nCodedSize > rIStm.remainingSize())
840 nCodedSize = sal_uInt32(rIStm.remainingSize());
841
842 pMemStm.reset(new SvMemoryStream);
843 // There may be bytes left over or the codec might read more than
844 // necessary. So to preserve the correctness of the source stream copy
845 // the encoded block
846 pMemStm->WriteStream(rIStm, nCodedSize);
847 pMemStm->Seek(0);
848
849 size_t nSizeInc(4 * pMemStm->remainingSize());
850 if (nUncodedSize < nSizeInc)
851 nSizeInc = nUncodedSize;
852
853 if (nSizeInc > 0)
854 {
855 // decode buffer
856 ZCodec aCodec;
857 aCodec.BeginCompression();
858 aData.resize(nSizeInc);
859 size_t nDataPos(0);
860 while (nUncodedSize > nDataPos)
861 {
862 assert(aData.size() > nDataPos);
863 const size_t nToRead(std::min<size_t>(nUncodedSize - nDataPos, aData.size() - nDataPos));
864 assert(nToRead > 0);
865 assert(!aData.empty());
866 const tools::Long nRead = aCodec.Read(*pMemStm, aData.data() + nDataPos, sal_uInt32(nToRead));
867 if (nRead > 0)
868 {
869 nDataPos += static_cast<tools::ULong>(nRead);
870 // we haven't read everything yet: resize buffer and continue
871 if (nDataPos < nUncodedSize)
872 aData.resize(aData.size() + nSizeInc);
873 }
874 else
875 {
876 break;
877 }
878 }
879 // truncate the data buffer to actually read size
880 aData.resize(nDataPos);
881 // set the real uncoded size
882 nUncodedSize = sal_uInt32(aData.size());
883 aCodec.EndCompression();
884 }
885
886 if (aData.empty())
887 {
888 // add something so we can take address of the first element
889 aData.resize(1);
890 nUncodedSize = 0;
891 }
892
893 // set decoded bytes to memory stream,
894 // from which we will read the bitmap data
895 pMemStm.reset(new SvMemoryStream);
896 pIStm = pMemStm.get();
897 assert(!aData.empty());
898 pMemStm->SetBuffer(aData.data(), nUncodedSize, nUncodedSize);
899 nOffset = 0;
900 }
901 else
902 {
903 pIStm = &rIStm;
904 }
905
906 // read palette
907 BitmapPalette aPalette;
908 if (nColors)
909 {
910 aPalette.SetEntryCount(nColors);
911 ImplReadDIBPalette(*pIStm, aPalette, aHeader.nSize != DIBCOREHEADERSIZE);
912 }
913
914 if (pIStm->GetError())
915 return false;
916
917 if (nOffset)
918 {
919 // It is problematic to seek backwards. We are at the
920 // end of BITMAPINFOHEADER or 12 bytes further in case
921 // of WinBMPv3-NT format. It is possible to seek forward
922 // though because a gap may be there.
923 sal_Int32 nSeekRel = nOffset - (pIStm->Tell() - nStmPos);
924 if (nSeekRel > 0)
925 pIStm->SeekRel(nSeekRel);
926 }
927
928 const sal_Int64 nBitsPerLine (static_cast<sal_Int64>(aHeader.nWidth) * static_cast<sal_Int64>(aHeader.nBitCount));
929 if (nBitsPerLine > SAL_MAX_UINT32)
930 return false;
931 const sal_uInt64 nAlignedWidth(AlignedWidth4Bytes(static_cast<sal_uLong>(nBitsPerLine)));
932
933 switch (aHeader.nCompression)
934 {
935 case RLE_8:
936 {
937 if (aHeader.nBitCount != 8)
938 return false;
939 // (partially) check the image dimensions to avoid potential large bitmap allocation if the input is damaged
940 sal_uInt64 nMaxWidth = pIStm->remainingSize();
941 nMaxWidth *= 256; //assume generous compression ratio
942 nMaxWidth /= aHeader.nHeight;
943 if (nMaxWidth < o3tl::make_unsigned(aHeader.nWidth))
944 return false;
945 break;
946 }
947 case RLE_4:
948 {
949 if (aHeader.nBitCount != 4)
950 return false;
951 sal_uInt64 nMaxWidth = pIStm->remainingSize();
952 nMaxWidth *= 512; //assume generous compression ratio
953 nMaxWidth /= aHeader.nHeight;
954 if (nMaxWidth < o3tl::make_unsigned(aHeader.nWidth))
955 return false;
956 break;
957 }
958 default:
959 // tdf#122958 invalid compression value used
960 if (aHeader.nCompression & 0x000F)
961 {
962 // lets assume that there was an error in the generating application
963 // and allow through as COMPRESS_NONE if the bottom byte is 0
964 SAL_WARN( "vcl", "bad bmp compression scheme: " << aHeader.nCompression << ", rejecting bmp");
965 return false;
966 }
967 else
968 SAL_WARN( "vcl", "bad bmp compression scheme: " << aHeader.nCompression << ", assuming meant to be COMPRESS_NONE");
969 [[fallthrough]];
970 case BITFIELDS:
971 case ZCOMPRESS:
972 case COMPRESS_NONE:
973 {
974 // (partially) check the image dimensions to avoid potential large bitmap allocation if the input is damaged
975 sal_uInt64 nMaxWidth = pIStm->remainingSize();
976 nMaxWidth /= aHeader.nHeight;
977 if (nMaxWidth < nAlignedWidth)
978 return false;
979 break;
980 }
981 }
982
983 const Size aSizePixel(aHeader.nWidth, aHeader.nHeight);
984 AlphaMask aNewBmpAlpha;
985 AlphaScopedWriteAccess pAccAlpha;
986 bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32);
987
988 if (bAlphaPossible)
989 {
990 const bool bRedSet(0 != aHeader.nV5RedMask);
991 const bool bGreenSet(0 != aHeader.nV5GreenMask);
992 const bool bBlueSet(0 != aHeader.nV5BlueMask);
993
994 // some clipboard entries have alpha mask on zero to say that there is
995 // no alpha; do only use this when the other masks are set. The MS docu
996 // says that masks are only to be set when bV5Compression is set to
997 // BI_BITFIELDS, but there seem to exist a wild variety of usages...
998 if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask))
999 {
1000 bAlphaPossible = false;
1001 }
1002 }
1003
1004 if (bAlphaPossible)
1005 {
1006 aNewBmpAlpha = AlphaMask(aSizePixel);
1007 pAccAlpha = AlphaScopedWriteAccess(aNewBmpAlpha);
1008 }
1009
1010 vcl::PixelFormat ePixelFormat(convertToBPP(aHeader.nBitCount));
1011 const BitmapPalette* pPal = &aPalette;
1012 //ofz#948 match the surrounding logic of case TransparentType::Bitmap of
1013 //ReadDIBBitmapEx but do it while reading for performance
1014 const bool bIsAlpha = (ePixelFormat == vcl::PixelFormat::N8_BPP &&
1015 !!aPalette && aPalette.IsGreyPalette8Bit());
1016 const bool bForceToMonoWhileReading = (bIsMask && !bIsAlpha && ePixelFormat != vcl::PixelFormat::N1_BPP);
1017 if (bForceToMonoWhileReading)
1018 {
1019 pPal = nullptr;
1020 ePixelFormat = vcl::PixelFormat::N1_BPP;
1021 SAL_WARN( "vcl", "forcing mask to monochrome");
1022 }
1023
1024 Bitmap aNewBmp(aSizePixel, ePixelFormat, pPal);
1025 BitmapScopedWriteAccess pAcc(aNewBmp);
1026 if (!pAcc)
1027 return false;
1028 if (pAcc->Width() != aHeader.nWidth || pAcc->Height() != aHeader.nHeight)
1029 {
1030 return false;
1031 }
1032
1033 // read bits
1034 bool bAlphaUsed(false);
1035 bool bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, aPalette, pAccAlpha.get(), bTopDown, bAlphaUsed, nAlignedWidth, bForceToMonoWhileReading);
1036
1037 if (bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter)
1038 {
1039 MapMode aMapMode(
1040 MapUnit::MapMM,
1041 Point(),
1042 Fraction(1000, aHeader.nXPelsPerMeter),
1043 Fraction(1000, aHeader.nYPelsPerMeter));
1044
1045 aNewBmp.SetPrefMapMode(aMapMode);
1046 aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight));
1047 }
1048
1049 pAcc.reset();
1050
1051 if (bAlphaPossible)
1052 {
1053 pAccAlpha.reset();
1054
1055 if(!bAlphaUsed)
1056 {
1057 bAlphaPossible = false;
1058 }
1059 }
1060
1061 if (bRet)
1062 {
1063 rBmp = aNewBmp;
1064
1065 if(bAlphaPossible)
1066 {
1067 *pBmpAlpha = aNewBmpAlpha;
1068 }
1069 }
1070
1071 return bRet;
1072}
1073
1074bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset )
1075{
1076 bool bRet = false;
1077
1078 const sal_uInt64 nStreamLength = rIStm.TellEnd();
1079
1080 sal_uInt16 nTmp16 = 0;
1081 rIStm.ReadUInt16( nTmp16 );
1082
1083 if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
1084 {
1085 sal_uInt32 nTmp32(0);
1086 if ( 0x4142 == nTmp16 )
1087 {
1088 rIStm.SeekRel( 12 );
1089 rIStm.ReadUInt16( nTmp16 );
1090 rIStm.SeekRel( 8 );
1091 rIStm.ReadUInt32( nTmp32 );
1092 rOffset = nTmp32 - 28;
1093 bRet = ( 0x4D42 == nTmp16 );
1094 }
1095 else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER
1096 {
1097 rIStm.SeekRel( 8 ); // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits
1098 rIStm.ReadUInt32( nTmp32 ); // read bfOffBits
1099 rOffset = nTmp32 - 14; // adapt offset by sizeof(BITMAPFILEHEADER)
1100 bRet = rIStm.GetError() == ERRCODE_NONE;
1101 }
1102
1103 if ( rOffset >= nStreamLength )
1104 {
1105 // Offset claims that image starts past the end of the
1106 // stream. Unlikely.
1107 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
1108 bRet = false;
1109 }
1110 }
1111 else
1112 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
1113
1114 return bRet;
1115}
1116
1117bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess const & rAcc )
1118{
1119 const sal_uInt16 nColors = rAcc.GetPaletteEntryCount();
1120 const sal_uLong nPalSize = nColors * 4UL;
1121 std::unique_ptr<sal_uInt8[]> pEntries(new sal_uInt8[ nPalSize ]);
1122 sal_uInt8* pTmpEntry = pEntries.get();
1123
1124 for( sal_uInt16 i = 0; i < nColors; i++ )
1125 {
1126 const BitmapColor& rPalColor = rAcc.GetPaletteColor( i );
1127
1128 *pTmpEntry++ = rPalColor.GetBlue();
1129 *pTmpEntry++ = rPalColor.GetGreen();
1130 *pTmpEntry++ = rPalColor.GetRed();
1131 *pTmpEntry++ = 0;
1132 }
1133
1134 rOStm.WriteBytes( pEntries.get(), nPalSize );
1135
1136 return rOStm.GetError() == ERRCODE_NONE;
1137}
1138
1139bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess const & rAcc, bool bRLE4 )
1140{
1141 const sal_uLong nWidth = rAcc.Width();
1142 const sal_uLong nHeight = rAcc.Height();
1143 sal_uLong nX;
1144 sal_uLong nSaveIndex;
1146 sal_uLong nBufCount;
1147 std::vector<sal_uInt8> aBuf(( nWidth << 1 ) + 2);
1148 sal_uInt8 cPix;
1149 sal_uInt8 cLast;
1150 bool bFound;
1151
1152 for ( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1153 {
1154 sal_uInt8* pTmp = aBuf.data();
1155 nX = nBufCount = 0;
1156 Scanline pScanline = rAcc.GetScanline( nY );
1157
1158 while( nX < nWidth )
1159 {
1160 nCount = 1;
1161 cPix = rAcc.GetIndexFromData( pScanline, nX++ );
1162
1163 while( ( nX < nWidth ) && ( nCount < 255 )
1164 && ( cPix == rAcc.GetIndexFromData( pScanline, nX ) ) )
1165 {
1166 nX++;
1167 nCount++;
1168 }
1169
1170 if ( nCount > 1 )
1171 {
1172 *pTmp++ = static_cast<sal_uInt8>(nCount);
1173 *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
1174 nBufCount += 2;
1175 }
1176 else
1177 {
1178 cLast = cPix;
1179 nSaveIndex = nX - 1;
1180 bFound = false;
1181
1182 while( ( nX < nWidth ) && ( nCount < 256 ) )
1183 {
1184 cPix = rAcc.GetIndexFromData( pScanline, nX );
1185 if (cPix == cLast)
1186 break;
1187 nX++; nCount++;
1188 cLast = cPix;
1189 bFound = true;
1190 }
1191
1192 if ( bFound )
1193 nX--;
1194
1195 if ( nCount > 3 )
1196 {
1197 *pTmp++ = 0;
1198 *pTmp++ = static_cast<sal_uInt8>(--nCount);
1199
1200 if( bRLE4 )
1201 {
1202 for ( sal_uLong i = 0; i < nCount; i++, pTmp++ )
1203 {
1204 *pTmp = rAcc.GetIndexFromData( pScanline, nSaveIndex++ ) << 4;
1205
1206 if ( ++i < nCount )
1207 *pTmp |= rAcc.GetIndexFromData( pScanline, nSaveIndex++ );
1208 }
1209
1210 nCount = ( nCount + 1 ) >> 1;
1211 }
1212 else
1213 {
1214 for( sal_uLong i = 0; i < nCount; i++ )
1215 *pTmp++ = rAcc.GetIndexFromData( pScanline, nSaveIndex++ );
1216 }
1217
1218 if ( nCount & 1 )
1219 {
1220 *pTmp++ = 0;
1221 nBufCount += ( nCount + 3 );
1222 }
1223 else
1224 nBufCount += ( nCount + 2 );
1225 }
1226 else
1227 {
1228 *pTmp++ = 1;
1229 *pTmp++ = rAcc.GetIndexFromData( pScanline, nSaveIndex ) << (bRLE4 ? 4 : 0);
1230
1231 if ( nCount == 3 )
1232 {
1233 *pTmp++ = 1;
1234 *pTmp++ = rAcc.GetIndexFromData( pScanline, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1235 nBufCount += 4;
1236 }
1237 else
1238 nBufCount += 2;
1239 }
1240 }
1241 }
1242
1243 aBuf[ nBufCount++ ] = 0;
1244 aBuf[ nBufCount++ ] = 0;
1245
1246 rOStm.WriteBytes(aBuf.data(), nBufCount);
1247 }
1248
1249 rOStm.WriteUChar( 0 );
1250 rOStm.WriteUChar( 1 );
1251
1252 return rOStm.GetError() == ERRCODE_NONE;
1253}
1254
1255bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess const & rAcc, BitmapReadAccess const * pAccAlpha, sal_uLong nCompression, sal_uInt32& rImageSize)
1256{
1257 if(!pAccAlpha && BITFIELDS == nCompression)
1258 {
1259 const ColorMask& rMask = rAcc.GetColorMask();
1260 SVBT32 aVal32;
1261
1262 UInt32ToSVBT32( rMask.GetRedMask(), aVal32 );
1263 rOStm.WriteBytes( aVal32, 4UL );
1264
1265 UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 );
1266 rOStm.WriteBytes( aVal32, 4UL );
1267
1268 UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 );
1269 rOStm.WriteBytes( aVal32, 4UL );
1270
1271 rImageSize = rOStm.Tell();
1272
1273 if( rAcc.IsBottomUp() )
1274 rOStm.WriteBytes(rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize());
1275 else
1276 {
1277 for( tools::Long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0; nY-- )
1278 rOStm.WriteBytes( rAcc.GetScanline(nY), nScanlineSize );
1279 }
1280 }
1281 else if(!pAccAlpha && ((RLE_4 == nCompression) || (RLE_8 == nCompression)))
1282 {
1283 rImageSize = rOStm.Tell();
1284 ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression );
1285 }
1286 else if(!nCompression)
1287 {
1288 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
1289 // handled properly below (would have to set color masks, and
1290 // nCompression=BITFIELDS - but color mask is not set for
1291 // formats != *_TC_*). Note that this very problem might cause
1292 // trouble at other places - the introduction of 32 bit RGBA
1293 // bitmaps is relatively recent.
1294 // #i59239# discretize bitcount for aligned width to 1,8,24
1295 // (other cases are not written below)
1296 const auto ePixelFormat(pAccAlpha ? vcl::PixelFormat::N32_BPP : convertToBPP(rAcc.GetBitCount()));
1297 const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * sal_Int32(ePixelFormat)));
1298 bool bNative(false);
1299
1300 switch(rAcc.GetScanlineFormat())
1301 {
1305 {
1306 if(!pAccAlpha && rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth))
1307 {
1308 bNative = true;
1309 }
1310
1311 break;
1312 }
1313
1314 default:
1315 {
1316 break;
1317 }
1318 }
1319
1320 rImageSize = rOStm.Tell();
1321
1322 if(bNative)
1323 {
1324 rOStm.WriteBytes(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height());
1325 }
1326 else
1327 {
1328 const tools::Long nWidth(rAcc.Width());
1329 const tools::Long nHeight(rAcc.Height());
1330 std::vector<sal_uInt8> aBuf(nAlignedWidth);
1331 switch(ePixelFormat)
1332 {
1334 {
1335 //valgrind, zero out the trailing unused alignment bytes
1336 size_t nUnusedBytes = nAlignedWidth - ((nWidth+7) / 8);
1337 memset(aBuf.data() + nAlignedWidth - nUnusedBytes, 0, nUnusedBytes);
1338
1339 for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1340 {
1341 sal_uInt8* pTmp = aBuf.data();
1342 sal_uInt8 cTmp = 0;
1343 Scanline pScanline = rAcc.GetScanline( nY );
1344
1345 for( tools::Long nX = 0, nShift = 8; nX < nWidth; nX++ )
1346 {
1347 if( !nShift )
1348 {
1349 nShift = 8;
1350 *pTmp++ = cTmp;
1351 cTmp = 0;
1352 }
1353
1354 cTmp |= rAcc.GetIndexFromData( pScanline, nX ) << --nShift;
1355 }
1356
1357 *pTmp = cTmp;
1358 rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
1359 }
1360 }
1361 break;
1362
1364 {
1365 for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1366 {
1367 sal_uInt8* pTmp = aBuf.data();
1368 Scanline pScanline = rAcc.GetScanline( nY );
1369
1370 for( tools::Long nX = 0; nX < nWidth; nX++ )
1371 *pTmp++ = rAcc.GetIndexFromData( pScanline, nX );
1372
1373 rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
1374 }
1375 }
1376 break;
1377
1379 {
1380 //valgrind, zero out the trailing unused alignment bytes
1381 size_t nUnusedBytes = nAlignedWidth - nWidth * 3;
1382 memset(aBuf.data() + nAlignedWidth - nUnusedBytes, 0, nUnusedBytes);
1383 }
1384 [[fallthrough]];
1385 // #i59239# fallback to 24 bit format, if bitcount is non-default
1386 default:
1387 {
1388 BitmapColor aPixelColor;
1389 const bool bWriteAlpha(ePixelFormat == vcl::PixelFormat::N32_BPP && pAccAlpha);
1390
1391 for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1392 {
1393 sal_uInt8* pTmp = aBuf.data();
1394 Scanline pScanlineAlpha = bWriteAlpha ? pAccAlpha->GetScanline( nY ) : nullptr;
1395
1396 for( tools::Long nX = 0; nX < nWidth; nX++ )
1397 {
1398 // when alpha is used, this may be non-24bit main bitmap, so use GetColor
1399 // instead of GetPixel to ensure RGB value
1400 aPixelColor = rAcc.GetColor( nY, nX );
1401
1402 *pTmp++ = aPixelColor.GetBlue();
1403 *pTmp++ = aPixelColor.GetGreen();
1404 *pTmp++ = aPixelColor.GetRed();
1405
1406 if(bWriteAlpha)
1407 {
1408 *pTmp++ = sal_uInt8(0xff) - pAccAlpha->GetIndexFromData( pScanlineAlpha, nX );
1409 }
1410 }
1411
1412 rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
1413 }
1414 }
1415 break;
1416 }
1417 }
1418 }
1419
1420 rImageSize = rOStm.Tell() - rImageSize;
1421
1422 return (!rOStm.GetError());
1423}
1424
1425bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess const & rAcc, BitmapReadAccess const * pAccAlpha, bool bCompressed)
1426{
1427 const MapMode aMapPixel(MapUnit::MapPixel);
1428 DIBV5Header aHeader;
1429 sal_uInt64 nImageSizePos(0);
1430 sal_uInt64 nEndPos(0);
1431 sal_uInt32 nCompression(COMPRESS_NONE);
1432 bool bRet(false);
1433
1434 aHeader.nSize = pAccAlpha ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use
1435 aHeader.nWidth = rAcc.Width();
1436 aHeader.nHeight = rAcc.Height();
1437 aHeader.nPlanes = 1;
1438
1439 if(!pAccAlpha && isBitfieldCompression(rAcc.GetScanlineFormat()))
1440 {
1441 aHeader.nBitCount = 32;
1442 aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize();
1443 nCompression = BITFIELDS;
1444 }
1445 else
1446 {
1447 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
1448 // not handled properly below (would have to set color
1449 // masks, and nCompression=BITFIELDS - but color mask is
1450 // not set for formats != *_TC_*). Note that this very
1451 // problem might cause trouble at other places - the
1452 // introduction of 32 bit RGBA bitmaps is relatively
1453 // recent.
1454 // #i59239# discretize bitcount to 1,8,24 (other cases
1455 // are not written below)
1456 const auto ePixelFormat(pAccAlpha ? vcl::PixelFormat::N32_BPP : convertToBPP(rAcc.GetBitCount()));
1457 aHeader.nBitCount = sal_uInt16(ePixelFormat);
1458 aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount);
1459
1460 if (bCompressed)
1461 {
1462 if (ePixelFormat == vcl::PixelFormat::N8_BPP)
1463 nCompression = RLE_8;
1464 }
1465 }
1466
1467 if((rOStm.GetCompressMode() & SvStreamCompressFlags::ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40))
1468 {
1469 aHeader.nCompression = ZCOMPRESS;
1470 }
1471 else
1472 {
1473 aHeader.nCompression = nCompression;
1474 }
1475
1476 if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel))
1477 {
1478 // #i48108# Try to recover xpels/ypels as previously stored on
1479 // disk. The problem with just converting maPrefSize to 100th
1480 // mm and then relating that to the bitmap pixel size is that
1481 // MapMode is integer-based, and suffers from roundoffs,
1482 // especially if maPrefSize is small. Trying to circumvent
1483 // that by performing part of the math in floating point.
1484 const Size aScale100000(OutputDevice::LogicToLogic(Size(100000, 100000), MapMode(MapUnit::Map100thMM), rBitmap.GetPrefMapMode()));
1485 const double fBmpWidthM(static_cast<double>(rBitmap.GetPrefSize().Width()) / aScale100000.Width());
1486 const double fBmpHeightM(static_cast<double>(rBitmap.GetPrefSize().Height()) / aScale100000.Height());
1487
1488 if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM))
1489 {
1490 aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM));
1491 aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM));
1492 }
1493 }
1494
1495 aHeader.nColsUsed = ((!pAccAlpha && aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0);
1496 aHeader.nColsImportant = 0;
1497
1498 rOStm.WriteUInt32( aHeader.nSize );
1499 rOStm.WriteInt32( aHeader.nWidth );
1500 rOStm.WriteInt32( aHeader.nHeight );
1501 rOStm.WriteUInt16( aHeader.nPlanes );
1502 rOStm.WriteUInt16( aHeader.nBitCount );
1503 rOStm.WriteUInt32( aHeader.nCompression );
1504
1505 nImageSizePos = rOStm.Tell();
1506 rOStm.SeekRel( sizeof( aHeader.nSizeImage ) );
1507
1508 rOStm.WriteInt32( aHeader.nXPelsPerMeter );
1509 rOStm.WriteInt32( aHeader.nYPelsPerMeter );
1510 rOStm.WriteUInt32( aHeader.nColsUsed );
1511 rOStm.WriteUInt32( aHeader.nColsImportant );
1512
1513 if(pAccAlpha) // only write DIBV5 when asked to do so
1514 {
1515 aHeader.nV5CSType = 0x57696E20; // LCS_WINDOWS_COLOR_SPACE
1516 aHeader.nV5Intent = 0x00000004; // LCS_GM_IMAGES
1517
1518 rOStm.WriteUInt32( aHeader.nV5RedMask );
1519 rOStm.WriteUInt32( aHeader.nV5GreenMask );
1520 rOStm.WriteUInt32( aHeader.nV5BlueMask );
1521 rOStm.WriteUInt32( aHeader.nV5AlphaMask );
1522 rOStm.WriteUInt32( aHeader.nV5CSType );
1523
1524 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzRed.aXyzX );
1525 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzRed.aXyzY );
1526 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzRed.aXyzZ );
1527 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzGreen.aXyzX );
1528 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzGreen.aXyzY );
1529 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzGreen.aXyzZ );
1530 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzBlue.aXyzX );
1531 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzBlue.aXyzY );
1532 rOStm.WriteInt32( aHeader.aV5Endpoints.aXyzBlue.aXyzZ );
1533
1534 rOStm.WriteUInt32( aHeader.nV5GammaRed );
1535 rOStm.WriteUInt32( aHeader.nV5GammaGreen );
1536 rOStm.WriteUInt32( aHeader.nV5GammaBlue );
1537 rOStm.WriteUInt32( aHeader.nV5Intent );
1538 rOStm.WriteUInt32( aHeader.nV5ProfileData );
1539 rOStm.WriteUInt32( aHeader.nV5ProfileSize );
1540 rOStm.WriteUInt32( aHeader.nV5Reserved );
1541 }
1542
1543 if(ZCOMPRESS == aHeader.nCompression)
1544 {
1545 ZCodec aCodec;
1546 SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535);
1547 sal_uInt64 nCodedPos(rOStm.Tell());
1548 sal_uInt64 nLastPos(0);
1549 sal_uInt32 nCodedSize(0);
1550 sal_uInt32 nUncodedSize(0);
1551
1552 // write uncoded data palette
1553 if(aHeader.nColsUsed)
1554 {
1555 ImplWriteDIBPalette(aMemStm, rAcc);
1556 }
1557
1558 // write uncoded bits
1559 bRet = ImplWriteDIBBits(aMemStm, rAcc, pAccAlpha, nCompression, aHeader.nSizeImage);
1560
1561 // get uncoded size
1562 nUncodedSize = aMemStm.Tell();
1563
1564 // seek over compress info
1565 rOStm.SeekRel(12);
1566
1567 // write compressed data
1568 aCodec.BeginCompression(3);
1569 aCodec.Write(rOStm, static_cast<sal_uInt8 const *>(aMemStm.GetData()), nUncodedSize);
1570 aCodec.EndCompression();
1571
1572 // update compress info ( coded size, uncoded size, uncoded compression )
1573 nLastPos = rOStm.Tell();
1574 nCodedSize = nLastPos - nCodedPos - 12;
1575 rOStm.Seek(nCodedPos);
1576 rOStm.WriteUInt32( nCodedSize ).WriteUInt32( nUncodedSize ).WriteUInt32( nCompression );
1577 rOStm.Seek(nLastPos);
1578
1579 if(bRet)
1580 {
1581 bRet = (ERRCODE_NONE == rOStm.GetError());
1582 }
1583 }
1584 else
1585 {
1586 if(aHeader.nColsUsed)
1587 {
1588 ImplWriteDIBPalette(rOStm, rAcc);
1589 }
1590
1591 bRet = ImplWriteDIBBits(rOStm, rAcc, pAccAlpha, aHeader.nCompression, aHeader.nSizeImage);
1592 }
1593
1594 nEndPos = rOStm.Tell();
1595 rOStm.Seek(nImageSizePos);
1596 rOStm.WriteUInt32( aHeader.nSizeImage );
1597 rOStm.Seek(nEndPos);
1598
1599 return bRet;
1600}
1601
1602bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess const & rAcc)
1603{
1604 const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : isBitfieldCompression(rAcc.GetScanlineFormat()) ? 3UL : 0UL));
1605 const sal_uInt32 nOffset(14 + DIBINFOHEADERSIZE + nPalCount * 4UL);
1606
1607 rOStm.WriteUInt16( 0x4D42 ); // 'MB' from BITMAPFILEHEADER
1608 rOStm.WriteUInt32( nOffset + (rAcc.Height() * rAcc.GetScanlineSize()) );
1609 rOStm.WriteUInt16( 0 );
1610 rOStm.WriteUInt16( 0 );
1611 rOStm.WriteUInt32( nOffset );
1612
1613 return rOStm.GetError() == ERRCODE_NONE;
1614}
1615
1616bool ImplReadDIB(
1617 Bitmap& rTarget,
1618 AlphaMask* pTargetAlpha,
1619 SvStream& rIStm,
1620 bool bFileHeader,
1621 bool bIsMask=false,
1622 bool bMSOFormat=false)
1623{
1624 const SvStreamEndian nOldFormat(rIStm.GetEndian());
1625 const auto nOldPos(rIStm.Tell());
1626 sal_uLong nOffset(0);
1627 bool bRet(false);
1628
1629 rIStm.SetEndian(SvStreamEndian::LITTLE);
1630
1631 if(bFileHeader)
1632 {
1633 if(ImplReadDIBFileHeader(rIStm, nOffset))
1634 {
1635 bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : nullptr, nOffset, bIsMask, bMSOFormat);
1636 }
1637 }
1638 else
1639 {
1640 bRet = ImplReadDIBBody(rIStm, rTarget, nullptr, nOffset, bIsMask, bMSOFormat);
1641 }
1642
1643 if(!bRet)
1644 {
1645 if(!rIStm.GetError()) // Set error and stop processing whole stream due to security reason
1646 {
1647 rIStm.SetError(SVSTREAM_GENERALERROR);
1648 }
1649
1650 rIStm.Seek(nOldPos);
1651 }
1652
1653 rIStm.SetEndian(nOldFormat);
1654
1655 return bRet;
1656}
1657
1658bool ImplWriteDIB(
1659 const Bitmap& rSource,
1660 SvStream& rOStm,
1661 bool bCompressed,
1662 bool bFileHeader)
1663{
1664 const Size aSizePix(rSource.GetSizePixel());
1665 bool bRet(false);
1666
1667 if(aSizePix.Width() && aSizePix.Height())
1668 {
1669 Bitmap::ScopedReadAccess pAcc(const_cast< Bitmap& >(rSource));
1670 Bitmap::ScopedReadAccess pAccAlpha;
1671 const SvStreamEndian nOldFormat(rOStm.GetEndian());
1672 const sal_uInt64 nOldPos(rOStm.Tell());
1673
1674 rOStm.SetEndian(SvStreamEndian::LITTLE);
1675
1676 if (pAcc)
1677 {
1678 if(bFileHeader)
1679 {
1680 if(ImplWriteDIBFileHeader(rOStm, *pAcc))
1681 {
1682 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha.get(), bCompressed);
1683 }
1684 }
1685 else
1686 {
1687 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha.get(), bCompressed);
1688 }
1689
1690 pAcc.reset();
1691 }
1692
1693 pAccAlpha.reset();
1694
1695 if(!bRet)
1696 {
1697 rOStm.SetError(SVSTREAM_GENERALERROR);
1698 rOStm.Seek(nOldPos);
1699 }
1700
1701 rOStm.SetEndian(nOldFormat);
1702 }
1703
1704 return bRet;
1705}
1706
1707} // unnamed namespace
1708
1710 Bitmap& rTarget,
1711 SvStream& rIStm,
1712 bool bFileHeader,
1713 bool bMSOFormat)
1714{
1715 return ImplReadDIB(rTarget, nullptr, rIStm, bFileHeader, false, bMSOFormat);
1716}
1717
1719 BitmapEx& rTarget,
1720 SvStream& rIStm,
1721 bool bFileHeader,
1722 bool bMSOFormat)
1723{
1724 Bitmap aBmp;
1725 bool bRetval(ImplReadDIB(aBmp, nullptr, rIStm, bFileHeader, /*bMask*/false, bMSOFormat) && !rIStm.GetError());
1726
1727 if(bRetval)
1728 {
1729 // base bitmap was read, set as return value and try to read alpha extra-data
1730 const sal_uInt64 nStmPos(rIStm.Tell());
1731 sal_uInt32 nMagic1(0);
1732 sal_uInt32 nMagic2(0);
1733
1734 rTarget = BitmapEx(aBmp);
1735 if (rIStm.remainingSize() >= 4)
1736 rIStm.ReadUInt32( nMagic1 ).ReadUInt32( nMagic2 );
1737 bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError();
1738
1739 if(bRetval)
1740 {
1741 sal_uInt8 tmp = 0;
1742 rIStm.ReadUChar( tmp );
1743 bRetval = !rIStm.GetError();
1744
1745 if(bRetval)
1746 {
1747 switch (tmp)
1748 {
1749 case 2: // TransparentType::Bitmap
1750 {
1751 Bitmap aMask;
1752
1753 bRetval = ImplReadDIB(aMask, nullptr, rIStm, true, true);
1754
1755 if(bRetval)
1756 {
1757 if(!aMask.IsEmpty())
1758 {
1759 // do we have an alpha mask?
1761 {
1762 AlphaMask aAlpha;
1763
1764 // create alpha mask quickly (without greyscale conversion)
1765 aAlpha.ImplSetBitmap(aMask);
1766 rTarget = BitmapEx(aBmp, aAlpha);
1767 }
1768 else
1769 {
1770 rTarget = BitmapEx(aBmp, aMask);
1771 }
1772 }
1773 }
1774 break;
1775 }
1776 case 1: // backwards compat for old option TransparentType::Color
1777 {
1778 Color aTransparentColor;
1779
1780 tools::GenericTypeSerializer aSerializer(rIStm);
1781 aSerializer.readColor(aTransparentColor);
1782
1783 bRetval = rIStm.good();
1784
1785 if(bRetval)
1786 {
1787 rTarget = BitmapEx(aBmp, aTransparentColor);
1788 }
1789 break;
1790 }
1791 default: break;
1792 }
1793 }
1794 }
1795
1796 if(!bRetval)
1797 {
1798 // alpha extra data could not be read; reset, but use base bitmap as result
1799 rIStm.ResetError();
1800 rIStm.Seek(nStmPos);
1801 bRetval = true;
1802 }
1803 }
1804
1805 return bRetval;
1806}
1807
1809 Bitmap& rTarget,
1810 AlphaMask& rTargetAlpha,
1811 SvStream& rIStm)
1812{
1813 return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
1814}
1815
1817 BitmapEx& rTarget,
1818 const unsigned char* pBuf,
1819 const ScanlineFormat nFormat,
1820 const int nHeight,
1821 const int nStride)
1822{
1823 BitmapScopedWriteAccess pWriteAccess(rTarget.maBitmap.AcquireWriteAccess(), rTarget.maBitmap);
1824 for (int nRow = 0; nRow < nHeight; ++nRow)
1825 {
1826 pWriteAccess->CopyScanline(nRow, pBuf + (nStride * nRow), nFormat, nStride);
1827 }
1828
1829 return true;
1830}
1831
1833 const Bitmap& rSource,
1834 SvStream& rOStm,
1835 bool bCompressed,
1836 bool bFileHeader)
1837{
1838 return ImplWriteDIB(rSource, rOStm, bCompressed, bFileHeader);
1839}
1840
1842 const BitmapEx& rSource,
1843 SvStream& rOStm,
1844 bool bCompressed)
1845{
1846 return ImplWriteDIB(rSource.GetBitmap(), rOStm, bCompressed, /*bFileHeader*/true);
1847}
1848
1850 const BitmapEx& rSource,
1851 SvStream& rOStm)
1852{
1853 if(ImplWriteDIB(rSource.GetBitmap(), rOStm, true, true))
1854 {
1855 rOStm.WriteUInt32( 0x25091962 );
1856 rOStm.WriteUInt32( 0xACB20201 );
1857 rOStm.WriteUChar( rSource.IsAlpha() ? 2 : 0 ); // Used to be TransparentType enum
1858
1859 if(rSource.IsAlpha())
1860 {
1861 return ImplWriteDIB(rSource.maAlphaMask, rOStm, true, true);
1862 }
1863 }
1864
1865 return false;
1866}
1867
1869{
1870 return DIBV5HEADERSIZE;
1871}
1872
1873/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::ScopedBitmapAccess< BitmapWriteAccess, AlphaMask, &AlphaMask::AcquireAlphaWriteAccess > AlphaScopedWriteAccess
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
ScanlineFormat
Definition: Scanline.hxx:29
SAL_DLLPRIVATE void ImplSetBitmap(const Bitmap &rBitmap)
Definition: alpha.cxx:66
bool IsAlpha() const
Definition: BitmapEx.cxx:193
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
Bitmap maAlphaMask
Definition: bitmapex.hxx:465
tools::Long Height() const
tools::Long Width() const
bool IsBottomUp() const
bool HasPalette() const
ScanlineFormat GetScanlineFormat() const
sal_uInt16 GetPaletteEntryCount() const
sal_uInt16 GetBitCount() const
const ColorMask & GetColorMask() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
sal_uInt32 GetScanlineSize() const
sal_uInt16 GetEntryCount() const
void SetEntryCount(sal_uInt16 nCount)
bool IsGreyPalette8Bit() const
Returns true if the palette is 8-bit grey palette.
Scanline GetBuffer() const
BitmapColor GetColor(tools::Long nY, tools::Long nX) const
void SetPixelOnData(sal_uInt8 *pData, tools::Long nX, const BitmapColor &rBitmapColor)
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
bool HasGreyPalette8Bit() const
const MapMode & GetPrefMapMode() const
Size GetSizePixel() const
bool IsEmpty() const
const Size & GetPrefSize() const
vcl::PixelFormat getPixelFormat() const
sal_uInt32 GetRedMask() const
Definition: ColorMask.hxx:120
sal_uInt32 GetGreenMask() const
Definition: ColorMask.hxx:125
sal_uInt32 GetBlueMask() const
Definition: ColorMask.hxx:130
sal_uInt8 GetLuminance() const
sal_uInt8 GetBlue() const
void SetGreen(sal_uInt8 nGreen)
void SetRed(sal_uInt8 nRed)
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
void SetBlue(sal_uInt8 nBlue)
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1639
constexpr tools::Long Height() const
constexpr tools::Long Width() const
virtual void ResetError()
SvStream & WriteInt32(sal_Int32 nInt32)
sal_uInt64 Tell() const
void SetEndian(SvStreamEndian SvStreamEndian)
bool good() const
virtual sal_uInt64 TellEnd()
SvStream & ReadInt16(sal_Int16 &rInt16)
SvStreamCompressFlags GetCompressMode() const
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
sal_Int32 GetVersion() const
SvStream & WriteUInt32(sal_uInt32 nUInt32)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
SvStreamEndian GetEndian() const
void SetError(ErrCode nErrorCode)
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & ReadInt32(sal_Int32 &rInt32)
std::size_t ReadBytes(void *pData, std::size_t nSize)
sal_uInt64 SeekRel(sal_Int64 nPos)
ErrCode GetError() const
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_uInt64 remainingSize()
SvStream & ReadUChar(unsigned char &rChar)
tools::Long Read(SvStream &rIStm, sal_uInt8 *pData, sal_uInt32 nSize)
tools::Long EndCompression()
void BeginCompression(int nCompressLevel=ZCODEC_DEFAULT_COMPRESSION, bool gzLib=false)
void Write(SvStream &rOStm, const sal_uInt8 *pData, sal_uInt32 nSize)
void readColor(Color &rColor)
static bool IsFuzzing()
This template handles BitmapAccess the RAII way.
int nCount
bool WriteDIBBitmapEx(const BitmapEx &rSource, SvStream &rOStm)
Definition: dibtools.cxx:1849
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1832
sal_Int32 FXPT2DOT30
Definition: dibtools.cxx:45
sal_uInt32 getDIBV5HeaderSize()
Definition: dibtools.cxx:1868
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1808
#define DIBV5HEADERSIZE
Definition: dibtools.cxx:41
#define DIBINFOHEADERSIZE
Definition: dibtools.cxx:40
bool ReadDIBBitmapEx(BitmapEx &rTarget, SvStream &rIStm, bool bFileHeader, bool bMSOFormat)
Definition: dibtools.cxx:1718
#define DIBCOREHEADERSIZE
Definition: dibtools.cxx:39
bool ReadDIB(Bitmap &rTarget, SvStream &rIStm, bool bFileHeader, bool bMSOFormat)
Definition: dibtools.cxx:1709
bool ReadRawDIB(BitmapEx &rTarget, const unsigned char *pBuf, const ScanlineFormat nFormat, const int nHeight, const int nStride)
Definition: dibtools.cxx:1816
#define BITFIELDS
Definition: dibtools.hxx:37
#define COMPRESS_NONE
Definition: dibtools.hxx:34
#define RLE_8
Definition: dibtools.hxx:35
#define RLE_4
Definition: dibtools.hxx:36
#define ZCOMPRESS
Definition: dibtools.hxx:38
float v
#define ERRCODE_NONE
FilterGroup & rTarget
sal_uInt32 AlignedWidth4Bytes(sal_uInt32 nWidthBits)
sal_Int32 nIndex
short nBitCount
Definition: ipict.cxx:80
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
aBuf
constexpr OUStringLiteral aData
bool equalZero(const T &rfVal)
B2IRange fround(const B2DRange &rRange)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
unsigned long ULong
long Long
PixelFormat
Pixel format of the bitmap in bits per pixel.
Definition: BitmapTypes.hxx:20
sal_uInt8 SVBT32[4]
sal_uIntPtr sal_uLong
SvStreamEndian
TOOLS_DLLPUBLIC bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
unsigned char sal_uInt8
std::unique_ptr< char[]> aBuffer