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