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