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