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