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