LibreOffice Module vcl (master)  1
bitmap/bitmap.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 <config_features.h>
21 
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/helpers.hxx>
25 
26 #include <vcl/bitmap.hxx>
27 #include <vcl/bitmapex.hxx>
28 #include <vcl/outdev.hxx>
29 
30 #include <svdata.hxx>
31 #include <salinst.hxx>
32 #include <salbmp.hxx>
33 #if HAVE_FEATURE_SKIA
34 #include <vcl/skia/SkiaHelper.hxx>
35 #endif
37 
43 #include <bitmap/impoctree.hxx>
44 #include <bitmap/Octree.hxx>
45 
46 #include "impvect.hxx"
47 #include "floyd.hxx"
48 
49 #include <math.h>
50 #include <algorithm>
51 #include <memory>
52 
53 #ifdef DBG_UTIL
54 #include <cstdlib>
55 #include <tools/stream.hxx>
56 #include <vcl/graphicfilter.hxx>
57 #endif
58 
60 {
61 }
62 
63 Bitmap::Bitmap(const Bitmap& rBitmap)
64  : mxSalBmp(rBitmap.mxSalBmp)
65  , maPrefMapMode(rBitmap.maPrefMapMode)
66  , maPrefSize(rBitmap.maPrefSize)
67 {
68 }
69 
70 Bitmap::Bitmap(std::shared_ptr<SalBitmap> const & pSalBitmap)
71  : mxSalBmp(pSalBitmap)
72  , maPrefMapMode(MapMode(MapUnit::MapPixel))
73  , maPrefSize(mxSalBmp->GetSize())
74 {
75 }
76 
77 Bitmap::Bitmap( const Size& rSizePixel, vcl::PixelFormat ePixelFormat, const BitmapPalette* pPal )
78 {
79  if (!(rSizePixel.Width() && rSizePixel.Height()))
80  return;
81 
82  BitmapPalette aPal;
83  BitmapPalette* pRealPal = nullptr;
84 
85  if (vcl::isPalettePixelFormat(ePixelFormat))
86  {
87  if( !pPal )
88  {
89  if (ePixelFormat == vcl::PixelFormat::N1_BPP)
90  {
91  aPal.SetEntryCount( 2 );
92  aPal[ 0 ] = COL_BLACK;
93  aPal[ 1 ] = COL_WHITE;
94  }
95  else if (ePixelFormat == vcl::PixelFormat::N8_BPP)
96  {
97  aPal.SetEntryCount(1 << sal_uInt16(ePixelFormat));
98  aPal[ 0 ] = COL_BLACK;
99  aPal[ 1 ] = COL_BLUE;
100  aPal[ 2 ] = COL_GREEN;
101  aPal[ 3 ] = COL_CYAN;
102  aPal[ 4 ] = COL_RED;
103  aPal[ 5 ] = COL_MAGENTA;
104  aPal[ 6 ] = COL_BROWN;
105  aPal[ 7 ] = COL_GRAY;
106  aPal[ 8 ] = COL_LIGHTGRAY;
107  aPal[ 9 ] = COL_LIGHTBLUE;
108  aPal[ 10 ] = COL_LIGHTGREEN;
109  aPal[ 11 ] = COL_LIGHTCYAN;
110  aPal[ 12 ] = COL_LIGHTRED;
111  aPal[ 13 ] = COL_LIGHTMAGENTA;
112  aPal[ 14 ] = COL_YELLOW;
113  aPal[ 15 ] = COL_WHITE;
114 
115  // Create dither palette
116  if (ePixelFormat == vcl::PixelFormat::N8_BPP)
117  {
118  sal_uInt16 nActCol = 16;
119 
120  for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
121  for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
122  for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
123  aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
124 
125  // Set standard Office colors
126  aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
127  }
128  }
129  }
130  else
131  pRealPal = const_cast<BitmapPalette*>(pPal);
132  }
133 
135  mxSalBmp->Create(rSizePixel, ePixelFormat, pRealPal ? *pRealPal : aPal);
136 }
137 
138 #ifdef DBG_UTIL
139 
140 namespace
141 {
142 void savePNG(const OUString& sWhere, const Bitmap& rBmp)
143 {
144  SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC);
146  rFilter.compressAsPNG(BitmapEx(rBmp), aStream);
147 }
148 }
149 
150 #endif
151 
153 {
154 #ifdef DBG_UTIL
155  // VCL_DUMP_BMP_PATH should be like C:/bmpDump.png or ~/bmpDump.png
156  static const OUString sDumpPath(OUString::createFromAscii(std::getenv("VCL_DUMP_BMP_PATH")));
157  // Stepping into the dtor of a bitmap you need, and setting the volatile variable to true in
158  // debugger, would dump the bitmap in question
159  static volatile bool save(false);
160  if (!sDumpPath.isEmpty() && save)
161  {
162  save = false;
163  savePNG(sDumpPath, *this);
164  }
165 #endif
166 }
167 
168 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
169 {
170  // Create greyscale palette with 2, 4, 16 or 256 entries
171  switch (nEntries)
172  {
173  case 2:
174  {
175  static const BitmapPalette aGreyPalette2 = [] {
176  BitmapPalette aPalette(2);
177  aPalette[0] = BitmapColor(0, 0, 0);
178  aPalette[1] = BitmapColor(255, 255, 255);
179  return aPalette;
180  }();
181 
182  return aGreyPalette2;
183  }
184  case 4:
185  {
186  static const BitmapPalette aGreyPalette4 = [] {
187  BitmapPalette aPalette(4);
188  aPalette[0] = BitmapColor(0, 0, 0);
189  aPalette[1] = BitmapColor(85, 85, 85);
190  aPalette[2] = BitmapColor(170, 170, 170);
191  aPalette[3] = BitmapColor(255, 255, 255);
192  return aPalette;
193  }();
194 
195  return aGreyPalette4;
196  }
197  case 16:
198  {
199  static const BitmapPalette aGreyPalette16 = [] {
200  sal_uInt8 cGrey = 0;
201  sal_uInt8 const cGreyInc = 17;
202 
203  BitmapPalette aPalette(16);
204 
205  for (sal_uInt16 i = 0; i < 16; ++i, cGrey += cGreyInc)
206  aPalette[i] = BitmapColor(cGrey, cGrey, cGrey);
207 
208  return aPalette;
209  }();
210 
211  return aGreyPalette16;
212  }
213  case 256:
214  {
215  static const BitmapPalette aGreyPalette256 = [] {
216  BitmapPalette aPalette(256);
217 
218  for (sal_uInt16 i = 0; i < 256; ++i)
219  aPalette[i] = BitmapColor(static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i),
220  static_cast<sal_uInt8>(i));
221 
222  return aPalette;
223  }();
224 
225  return aGreyPalette256;
226  }
227  }
228  OSL_FAIL("Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)");
229  return GetGreyPalette(2);
230 }
231 
233 {
234  const int nEntryCount = GetEntryCount();
235  if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
236  return true;
237  // See above: only certain entry values will result in a valid call to GetGreyPalette
238  if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
239  {
240  const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
241  if( rGreyPalette == *this )
242  return true;
243  }
244 
245  bool bRet = false;
246  // TODO: is it worth to compare the entries for the general case?
247  if (nEntryCount == 2)
248  {
249  const BitmapColor& rCol0(maBitmapColor[0]);
250  const BitmapColor& rCol1(maBitmapColor[1]);
251  bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
252  rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
253  }
254  return bRet;
255 }
256 
258 {
259  const int nEntryCount = GetEntryCount();
260  if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
261  return true;
262  if( nEntryCount != 256 )
263  return false;
264  for (sal_uInt16 i = 0; i < 256; ++i)
265  {
266  if( maBitmapColor[i] != BitmapColor(i, i, i))
267  return false;
268  }
269  return true;
270 }
271 
272 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
273 {
274  if (this == &rBitmap)
275  return *this;
276 
277  maPrefSize = rBitmap.maPrefSize;
278  maPrefMapMode = rBitmap.maPrefMapMode;
279  mxSalBmp = rBitmap.mxSalBmp;
280 
281  return *this;
282 }
283 
284 Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept
285 {
286  maPrefSize = std::move(rBitmap.maPrefSize);
287  maPrefMapMode = std::move(rBitmap.maPrefMapMode);
288  mxSalBmp = std::move(rBitmap.mxSalBmp);
289 
290  return *this;
291 }
292 
293 bool Bitmap::operator==( const Bitmap& rBmp ) const
294 {
295  if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr
296  return true;
297  if (!rBmp.mxSalBmp || !mxSalBmp)
298  return false;
299  if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() ||
300  rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount())
301  return false;
302  BitmapChecksum aChecksum1, aChecksum2;
303  rBmp.mxSalBmp->GetChecksum(aChecksum1);
304  mxSalBmp->GetChecksum(aChecksum2);
305  // If the bitmaps can't calculate a checksum, best to regard them as different.
306  if (aChecksum1 == 0 || aChecksum2 == 0)
307  return false;
308  return aChecksum1 == aChecksum2;
309 }
310 
312 {
314  maPrefSize = Size();
315  mxSalBmp.reset();
316 }
317 
319 {
320  return( mxSalBmp ? mxSalBmp->GetSize() : Size() );
321 }
322 
324 {
325  if (!mxSalBmp)
327 
328  sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
329  if (nBitCount <= 1)
331  if (nBitCount <= 8)
333  if (nBitCount <= 24)
335  if (nBitCount <= 32)
337 
339 }
340 
342 {
343  bool bRet = getPixelFormat() == vcl::PixelFormat::N1_BPP;
344 
345  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
346 
347  if( pIAcc )
348  {
349  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPaletteAny();
350  }
351 
352  return bRet;
353 }
354 
356 {
357  bool bRet = false;
358  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
359 
360  if( pIAcc )
361  {
362  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette8Bit();
363  }
364 
365  return bRet;
366 }
367 
369 {
370  BitmapChecksum nRet = 0;
371 
372  if( mxSalBmp )
373  {
374  mxSalBmp->GetChecksum(nRet);
375 
376  if (!nRet)
377  {
378  // nRet == 0 => probably, we were not able to acquire
379  // the buffer in SalBitmap::updateChecksum;
380  // so, we need to update the imp bitmap for this bitmap instance
381  // as we do in BitmapInfoAccess::ImplCreate
382  std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
383  if (xNewImpBmp->Create(*mxSalBmp, getPixelFormat()))
384  {
385  Bitmap* pThis = const_cast<Bitmap*>(this);
386  pThis->mxSalBmp = xNewImpBmp;
387  mxSalBmp->GetChecksum(nRet);
388  }
389  }
390  }
391 
392  return nRet;
393 }
394 
396 {
397  if (mxSalBmp && mxSalBmp.use_count() > 1)
398  {
399  std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp;
401  (void)mxSalBmp->Create(*xOldImpBmp);
402  }
403 }
404 
405 void Bitmap::ReassignWithSize(const Bitmap& rBitmap)
406 {
407  const Size aOldSizePix(GetSizePixel());
408  const Size aNewSizePix(rBitmap.GetSizePixel());
409  const MapMode aOldMapMode(maPrefMapMode);
410  Size aNewPrefSize;
411 
412  if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height())
413  {
414  aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width()));
415  aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height()));
416  }
417  else
418  {
419  aNewPrefSize = maPrefSize;
420  }
421 
422  *this = rBitmap;
423 
424  maPrefSize = aNewPrefSize;
425  maPrefMapMode = aOldMapMode;
426 }
427 
428 void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp)
429 {
430  mxSalBmp = xImpBmp;
431 }
432 
434 {
435  std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this ));
436 
437  if( !*pInfoAccess )
438  {
439  return nullptr;
440  }
441 
442  return pInfoAccess.release();
443 }
444 
446 {
447  std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this ));
448 
449  if( !*pReadAccess )
450  {
451  return nullptr;
452  }
453 
454  return pReadAccess.release();
455 }
456 
458 {
459  std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this ));
460 
461  if( !*pWriteAccess )
462  {
463  return nullptr;
464  }
465 
466  return pWriteAccess.release();
467 }
468 
470 {
471  delete pBitmapAccess;
472 }
473 
474 bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
475 {
476  const Size aSizePix( GetSizePixel() );
477  tools::Rectangle aRect( rRectPixel );
478  bool bRet = false;
479 
480  aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
481 
482  if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
483  {
484  ScopedReadAccess pReadAcc(*this);
485 
486  if( pReadAcc )
487  {
488  const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
489  Bitmap aNewBmp(aNewRect.GetSize(), getPixelFormat(), &pReadAcc->GetPalette());
490  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
491 
492  if( pWriteAcc )
493  {
494  const tools::Long nOldX = aRect.Left();
495  const tools::Long nOldY = aRect.Top();
496  const tools::Long nNewWidth = aNewRect.GetWidth();
497  const tools::Long nNewHeight = aNewRect.GetHeight();
498 
499  for( tools::Long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
500  {
501  Scanline pScanline = pWriteAcc->GetScanline(nY);
502  Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
503  for( tools::Long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
504  pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
505  }
506 
507  pWriteAcc.reset();
508  bRet = true;
509  }
510 
511  pReadAcc.reset();
512 
513  if( bRet )
514  ReassignWithSize( aNewBmp );
515  }
516  }
517 
518  return bRet;
519 };
520 
521 bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
522  const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
523 {
524  const Size aSizePix( GetSizePixel() );
525  tools::Rectangle aRectDst( rRectDst );
526  bool bRet = false;
527 
528  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
529 
530  if( !aRectDst.IsEmpty() )
531  {
532  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
533  {
534  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
535  const Size aCopySizePix( pSrc->GetSizePixel() );
536  tools::Rectangle aRectSrc( rRectSrc );
537  const sal_uInt16 nSrcBitCount = vcl::pixelFormatBitCount(pBmpSrc->getPixelFormat());
538  const sal_uInt16 nDstBitCount = vcl::pixelFormatBitCount(getPixelFormat());
539 
540  if( nSrcBitCount > nDstBitCount )
541  {
542  int nNextIndex = 0;
543 
544  if (nSrcBitCount == 24)
546  else if (nSrcBitCount == 8)
547  {
549  nNextIndex = 16;
550  }
551  else if (nSrcBitCount == 4)
552  {
553  assert(false);
554  }
555 
556  if( nNextIndex )
557  {
558  ScopedReadAccess pSrcAcc(*pSrc);
559  BitmapScopedWriteAccess pDstAcc(*this);
560 
561  if( pSrcAcc && pDstAcc )
562  {
563  const int nSrcCount = pSrcAcc->GetPaletteEntryCount();
564  const int nDstCount = 1 << nDstBitCount;
565 
566  for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nDstCount ); ++i)
567  {
568  const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
569 
570  bool bFound = false;
571 
572  for (int j = 0; j < nDstCount; ++j)
573  {
574  if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
575  {
576  bFound = true;
577  break;
578  }
579  }
580 
581  if( !bFound )
582  pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
583  }
584  }
585  }
586  }
587 
588  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
589 
590  if( !aRectSrc.IsEmpty() )
591  {
592  ScopedReadAccess pReadAcc(*pSrc);
593 
594  if( pReadAcc )
595  {
596  BitmapScopedWriteAccess pWriteAcc(*this);
597 
598  if( pWriteAcc )
599  {
600  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
601  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
602  const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
603  const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
604  tools::Long nDstY = aRectDst.Top();
605 
606  if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
607  {
608  const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
609  std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
610 
611  // Create index map for the color table, as the bitmap should be copied
612  // retaining it's color information relatively well
613  for( sal_uInt16 i = 0; i < nCount; i++ )
614  pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
615 
616  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
617  {
618  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
619  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
620  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
621  pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
622  }
623  }
624  else if( pReadAcc->HasPalette() )
625  {
626  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
627  {
628  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
629  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
630  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
631  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
632  }
633  }
634  else
635  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
636  {
637  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
638  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
639  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
640  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
641  }
642 
643  pWriteAcc.reset();
644  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
645  }
646 
647  pReadAcc.reset();
648  }
649  }
650  }
651  else
652  {
653  tools::Rectangle aRectSrc( rRectSrc );
654 
655  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
656 
657  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
658  {
659  BitmapScopedWriteAccess pWriteAcc(*this);
660 
661  if( pWriteAcc )
662  {
663  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
664  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
665  const tools::Long nSrcX = aRectSrc.Left();
666  const tools::Long nSrcY = aRectSrc.Top();
667  const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
668  const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
669  const tools::Long nDstX = aRectDst.Left();
670  const tools::Long nDstY = aRectDst.Top();
671  const tools::Long nDstEndX1 = nDstX + nWidth - 1;
672  const tools::Long nDstEndY1 = nDstY + nHeight - 1;
673 
674  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
675  {
676  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
677  {
678  Scanline pScanline = pWriteAcc->GetScanline(nYN);
679  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
680  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
681  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
682  }
683  }
684  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
685  {
686  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
687  {
688  Scanline pScanline = pWriteAcc->GetScanline(nYN);
689  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
690  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
691  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
692  }
693  }
694  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
695  {
696  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
697  {
698  Scanline pScanline = pWriteAcc->GetScanline(nYN);
699  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
700  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
701  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
702  }
703  }
704  else
705  {
706  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
707  {
708  Scanline pScanline = pWriteAcc->GetScanline(nYN);
709  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
710  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
711  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
712  }
713  }
714 
715  pWriteAcc.reset();
716  bRet = true;
717  }
718  }
719  }
720  }
721 
722  return bRet;
723 }
724 
726  const Bitmap* pBmpSrc )
727 {
728  // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
729  // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
730  const Size aSizePix( GetSizePixel() );
731  tools::Rectangle aRectDst( rRectDst );
732  bool bRet = false;
733 
734  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
735 
736  if( !aRectDst.IsEmpty() )
737  {
738  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
739  {
740  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
741  const Size aCopySizePix( pSrc->GetSizePixel() );
742  tools::Rectangle aRectSrc( rRectSrc );
743 
744  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
745 
746  if( !aRectSrc.IsEmpty() )
747  {
748  ScopedReadAccess pReadAcc(*pSrc);
749 
750  if( pReadAcc )
751  {
752  BitmapScopedWriteAccess pWriteAcc(*this);
753 
754  if( pWriteAcc )
755  {
756  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
757  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
758  const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
759  const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
760  tools::Long nDstY = aRectDst.Top();
761 
762  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
763  {
764  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
765  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
766  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
767  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
768  }
769 
770  pWriteAcc.reset();
771  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
772  }
773 
774  pReadAcc.reset();
775  }
776  }
777  }
778  else
779  {
780  tools::Rectangle aRectSrc( rRectSrc );
781 
782  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
783 
784  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
785  {
786  BitmapScopedWriteAccess pWriteAcc(*this);
787 
788  if( pWriteAcc )
789  {
790  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
791  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
792  const tools::Long nSrcX = aRectSrc.Left();
793  const tools::Long nSrcY = aRectSrc.Top();
794  const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
795  const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
796  const tools::Long nDstX = aRectDst.Left();
797  const tools::Long nDstY = aRectDst.Top();
798  const tools::Long nDstEndX1 = nDstX + nWidth - 1;
799  const tools::Long nDstEndY1 = nDstY + nHeight - 1;
800 
801  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
802  {
803  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
804  {
805  Scanline pScanline = pWriteAcc->GetScanline(nYN);
806  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
807  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
808  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
809  }
810  }
811  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
812  {
813  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
814  {
815  Scanline pScanline = pWriteAcc->GetScanline(nYN);
816  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
817  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
818  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
819  }
820  }
821  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
822  {
823  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
824  {
825  Scanline pScanline = pWriteAcc->GetScanline(nYN);
826  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
827  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
828  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
829  }
830  }
831  else
832  {
833  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
834  {
835  Scanline pScanline = pWriteAcc->GetScanline(nYN);
836  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
837  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
838  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
839  }
840  }
841 
842  pWriteAcc.reset();
843  bRet = true;
844  }
845  }
846  }
847  }
848 
849  return bRet;
850 
851 }
852 
853 bool Bitmap::Expand( sal_Int32 nDX, sal_Int32 nDY, const Color* pInitColor )
854 {
855  bool bRet = false;
856 
857  if( nDX || nDY )
858  {
859  const Size aSizePixel( GetSizePixel() );
860  const tools::Long nWidth = aSizePixel.Width();
861  const tools::Long nHeight = aSizePixel.Height();
862  const Size aNewSize( nWidth + nDX, nHeight + nDY );
863  ScopedReadAccess pReadAcc(*this);
864 
865  if( pReadAcc )
866  {
867  BitmapPalette aBmpPal( pReadAcc->GetPalette() );
868  Bitmap aNewBmp(aNewSize, getPixelFormat(), &aBmpPal);
869  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
870 
871  if( pWriteAcc )
872  {
873  BitmapColor aColor;
874  const tools::Long nNewX = nWidth;
875  const tools::Long nNewY = nHeight;
876  const tools::Long nNewWidth = pWriteAcc->Width();
877  const tools::Long nNewHeight = pWriteAcc->Height();
878  tools::Long nX;
879  tools::Long nY;
880 
881  if( pInitColor )
882  aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
883 
884  for( nY = 0; nY < nHeight; nY++ )
885  {
886  pWriteAcc->CopyScanline( nY, *pReadAcc );
887 
888  if( pInitColor && nDX )
889  {
890  Scanline pScanline = pWriteAcc->GetScanline(nY);
891  for( nX = nNewX; nX < nNewWidth; nX++ )
892  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
893  }
894  }
895 
896  if( pInitColor && nDY )
897  for( nY = nNewY; nY < nNewHeight; nY++ )
898  {
899  Scanline pScanline = pWriteAcc->GetScanline(nY);
900  for( nX = 0; nX < nNewWidth; nX++ )
901  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
902  }
903 
904  pWriteAcc.reset();
905  bRet = true;
906  }
907 
908  pReadAcc.reset();
909 
910  if (bRet)
911  ReassignWithSize(aNewBmp);
912  }
913  }
914 
915  return bRet;
916 }
917 
919 {
920  Bitmap aDispBmp( *this );
921 
922  SalGraphics* pDispGraphics = pDisplay->GetGraphics();
923 
924  if( mxSalBmp && pDispGraphics )
925  {
926  std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
927  if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics))
928  aDispBmp.ImplSetSalBitmap(xImpDispBmp);
929  }
930 
931  return aDispBmp;
932 }
933 
935 {
936  return mxSalBmp && mxSalBmp->GetSystemData(rData);
937 }
938 
939 
940 bool Bitmap::Convert( BmpConversion eConversion )
941 {
942  // try to convert in backend
943  if (mxSalBmp)
944  {
945  // avoid large chunk of obsolete and hopefully rarely used conversions.
946  if (eConversion == BmpConversion::N8BitNoConversion)
947  {
948  if (mxSalBmp->GetBitCount() == 8 && HasGreyPalette8Bit())
949  return true;
950  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
951  // frequently used conversion for creating alpha masks
952  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->InterpretAs8Bit())
953  {
954  ImplSetSalBitmap(xImpBmp);
955  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
956  return true;
957  }
958  }
959  if (eConversion == BmpConversion::N8BitGreys)
960  {
961  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
962  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->ConvertToGreyscale())
963  {
964  ImplSetSalBitmap(xImpBmp);
965  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
966  return true;
967  }
968  }
969  }
970 
971  const sal_uInt16 nBitCount = vcl::pixelFormatBitCount(getPixelFormat());
972  bool bRet = false;
973 
974  switch( eConversion )
975  {
977  {
978  BitmapEx aBmpEx(*this);
979  bRet = BitmapFilter::Filter(aBmpEx, BitmapMonochromeFilter(128));
980  *this = aBmpEx.GetBitmap();
981  }
982  break;
983 
986  bRet = ImplMakeGreyscales();
987  break;
988 
990  {
991  if( nBitCount < 8 )
993  else if( nBitCount > 8 )
994  bRet = ImplConvertDown8BPP();
995  else
996  bRet = true;
997  }
998  break;
999 
1001  {
1002  Color aTrans( BMP_COL_TRANS );
1003 
1004  if( nBitCount < 8 )
1005  bRet = ImplConvertUp(vcl::PixelFormat::N8_BPP, &aTrans );
1006  else
1007  bRet = ImplConvertDown8BPP(&aTrans );
1008  }
1009  break;
1010 
1011  case BmpConversion::N24Bit:
1012  {
1013  if( nBitCount < 24 )
1015  else
1016  bRet = true;
1017  }
1018  break;
1019 
1020  case BmpConversion::N32Bit:
1021  {
1022  if( nBitCount < 32 )
1024  else
1025  bRet = true;
1026  }
1027  break;
1028 
1029  default:
1030  OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
1031  break;
1032  }
1033 
1034  return bRet;
1035 }
1036 
1038 {
1039  ScopedReadAccess pReadAcc(*this);
1040  bool bRet = false;
1041 
1042  if( pReadAcc )
1043  {
1044  const BitmapPalette& rPal = GetGreyPalette(256);
1045  sal_uLong nShift = 0;
1046  bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
1047 
1048  if( !bPalDiffers )
1049  bPalDiffers = ( rPal != pReadAcc->GetPalette() );
1050 
1051  if( bPalDiffers )
1052  {
1053  const auto ePixelFormat = vcl::PixelFormat::N8_BPP;
1054  Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &rPal );
1055  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1056 
1057  if( pWriteAcc )
1058  {
1059  const tools::Long nWidth = pWriteAcc->Width();
1060  const tools::Long nHeight = pWriteAcc->Height();
1061 
1062  if( pReadAcc->HasPalette() )
1063  {
1064  for( tools::Long nY = 0; nY < nHeight; nY++ )
1065  {
1066  Scanline pScanline = pWriteAcc->GetScanline(nY);
1067  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1068  for( tools::Long nX = 0; nX < nWidth; nX++ )
1069  {
1070  const sal_uInt8 cIndex = pReadAcc->GetIndexFromData( pScanlineRead, nX );
1071  pWriteAcc->SetPixelOnData( pScanline, nX,
1072  BitmapColor(pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
1073  }
1074  }
1075  }
1076  else if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr &&
1077  pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal )
1078  {
1079  nShift += 8;
1080 
1081  for( tools::Long nY = 0; nY < nHeight; nY++ )
1082  {
1083  Scanline pReadScan = pReadAcc->GetScanline( nY );
1084  Scanline pWriteScan = pWriteAcc->GetScanline( nY );
1085 
1086  for( tools::Long nX = 0; nX < nWidth; nX++ )
1087  {
1088  const sal_uLong nB = *pReadScan++;
1089  const sal_uLong nG = *pReadScan++;
1090  const sal_uLong nR = *pReadScan++;
1091 
1092  *pWriteScan++ = static_cast<sal_uInt8>( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
1093  }
1094  }
1095  }
1096  else if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb &&
1097  pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal )
1098  {
1099  nShift += 8;
1100 
1101  for( tools::Long nY = 0; nY < nHeight; nY++ )
1102  {
1103  Scanline pReadScan = pReadAcc->GetScanline( nY );
1104  Scanline pWriteScan = pWriteAcc->GetScanline( nY );
1105 
1106  for( tools::Long nX = 0; nX < nWidth; nX++ )
1107  {
1108  const sal_uLong nR = *pReadScan++;
1109  const sal_uLong nG = *pReadScan++;
1110  const sal_uLong nB = *pReadScan++;
1111 
1112  *pWriteScan++ = static_cast<sal_uInt8>( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
1113  }
1114  }
1115  }
1116  else
1117  {
1118  for( tools::Long nY = 0; nY < nHeight; nY++ )
1119  {
1120  Scanline pScanline = pWriteAcc->GetScanline(nY);
1121  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1122  for( tools::Long nX = 0; nX < nWidth; nX++ )
1123  pWriteAcc->SetPixelOnData( pScanline, nX, BitmapColor(pReadAcc->GetPixelFromData( pScanlineRead, nX ).GetLuminance() >> nShift) );
1124  }
1125  }
1126 
1127  pWriteAcc.reset();
1128  bRet = true;
1129  }
1130 
1131  pReadAcc.reset();
1132 
1133  if( bRet )
1134  {
1135  const MapMode aMap( maPrefMapMode );
1136  const Size aSize( maPrefSize );
1137 
1138  *this = aNewBmp;
1139 
1140  maPrefMapMode = aMap;
1141  maPrefSize = aSize;
1142  }
1143  }
1144  else
1145  {
1146  pReadAcc.reset();
1147  bRet = true;
1148  }
1149  }
1150 
1151  return bRet;
1152 }
1153 
1154 bool Bitmap::ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const * pExtColor)
1155 {
1156  SAL_WARN_IF(ePixelFormat <= getPixelFormat(), "vcl", "New pixel format must be greater!" );
1157 
1158  Bitmap::ScopedReadAccess pReadAcc(*this);
1159  bool bRet = false;
1160 
1161  if (pReadAcc)
1162  {
1163  BitmapPalette aPalette;
1164  Bitmap aNewBmp(GetSizePixel(), ePixelFormat, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPalette);
1165  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1166 
1167  if (pWriteAcc)
1168  {
1169  const tools::Long nWidth = pWriteAcc->Width();
1170  const tools::Long nHeight = pWriteAcc->Height();
1171 
1172  if (pWriteAcc->HasPalette())
1173  {
1174  const BitmapPalette& rOldPalette = pReadAcc->GetPalette();
1175  const sal_uInt16 nOldCount = rOldPalette.GetEntryCount();
1176  assert(nOldCount <= (1 << vcl::pixelFormatBitCount(getPixelFormat())));
1177 
1178  aPalette.SetEntryCount(1 << vcl::pixelFormatBitCount(ePixelFormat));
1179 
1180  for (sal_uInt16 i = 0; i < nOldCount; i++)
1181  aPalette[i] = rOldPalette[i];
1182 
1183  if (pExtColor)
1184  aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
1185 
1186  pWriteAcc->SetPalette(aPalette);
1187 
1188  for (tools::Long nY = 0; nY < nHeight; nY++)
1189  {
1190  Scanline pScanline = pWriteAcc->GetScanline(nY);
1191  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1192  for (tools::Long nX = 0; nX < nWidth; nX++)
1193  {
1194  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPixelFromData(pScanlineRead, nX));
1195  }
1196  }
1197  }
1198  else
1199  {
1200  if (pReadAcc->HasPalette())
1201  {
1202  for (tools::Long nY = 0; nY < nHeight; nY++)
1203  {
1204  Scanline pScanline = pWriteAcc->GetScanline(nY);
1205  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1206  for (tools::Long nX = 0; nX < nWidth; nX++)
1207  {
1208  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX)));
1209  }
1210  }
1211  }
1212  else
1213  {
1214  for (tools::Long nY = 0; nY < nHeight; nY++)
1215  {
1216  Scanline pScanline = pWriteAcc->GetScanline(nY);
1217  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1218  for (tools::Long nX = 0; nX < nWidth; nX++)
1219  {
1220  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPixelFromData(pScanlineRead, nX));
1221  }
1222  }
1223  }
1224  }
1225  bRet = true;
1226  }
1227 
1228  if (bRet)
1229  {
1230  const MapMode aMap(maPrefMapMode);
1231  const Size aSize(maPrefSize);
1232 
1233  *this = aNewBmp;
1234 
1235  maPrefMapMode = aMap;
1236  maPrefSize = aSize;
1237  }
1238  }
1239 
1240  return bRet;
1241 }
1242 
1243 bool Bitmap::ImplConvertDown8BPP(Color const * pExtColor)
1244 {
1245  SAL_WARN_IF(vcl::PixelFormat::N8_BPP > getPixelFormat(), "vcl", "New pixelformat must be lower ( or equal when pExtColor is set )!");
1246 
1247  Bitmap::ScopedReadAccess pReadAcc(*this);
1248  bool bRet = false;
1249 
1250  if (pReadAcc)
1251  {
1252  BitmapPalette aPalette;
1253  Bitmap aNewBmp(GetSizePixel(), vcl::PixelFormat::N8_BPP, &aPalette);
1254  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1255 
1256  if (pWriteAcc)
1257  {
1258  sal_Int16 nNewBitCount = sal_Int16(vcl::PixelFormat::N8_BPP);
1259  const sal_uInt16 nCount = 1 << nNewBitCount;
1260  const tools::Long nWidth = pWriteAcc->Width();
1261  const tools::Long nWidth1 = nWidth - 1;
1262  const tools::Long nHeight = pWriteAcc->Height();
1263  Octree aOctree(*pReadAcc, pExtColor ? (nCount - 1) : nCount);
1264  aPalette = aOctree.GetPalette();
1265  InverseColorMap aColorMap(aPalette);
1266  BitmapColor aColor;
1267  ImpErrorQuad aErrQuad;
1268  std::vector<ImpErrorQuad> aErrQuad1(nWidth);
1269  std::vector<ImpErrorQuad> aErrQuad2(nWidth);
1270  ImpErrorQuad* pQLine1 = aErrQuad1.data();
1271  ImpErrorQuad* pQLine2 = nullptr;
1272  tools::Long nYTmp = 0;
1273  sal_uInt8 cIndex;
1274  bool bQ1 = true;
1275 
1276  if (pExtColor)
1277  {
1278  aPalette.SetEntryCount(aPalette.GetEntryCount() + 1);
1279  aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
1280  }
1281 
1282  // set Black/White always, if we have enough space
1283  if (aPalette.GetEntryCount() < (nCount - 1))
1284  {
1285  aPalette.SetEntryCount(aPalette.GetEntryCount() + 2);
1286  aPalette[aPalette.GetEntryCount() - 2] = COL_BLACK;
1287  aPalette[aPalette.GetEntryCount() - 1] = COL_WHITE;
1288  }
1289 
1290  pWriteAcc->SetPalette(aPalette);
1291 
1292  for (tools::Long nY = 0; nY < std::min(nHeight, tools::Long(2)); nY++, nYTmp++)
1293  {
1294  pQLine2 = !nY ? aErrQuad1.data() : aErrQuad2.data();
1295  Scanline pScanlineRead = pReadAcc->GetScanline(nYTmp);
1296  for (tools::Long nX = 0; nX < nWidth; nX++)
1297  {
1298  if (pReadAcc->HasPalette())
1299  pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
1300  else
1301  pQLine2[nX] = pReadAcc->GetPixelFromData(pScanlineRead, nX);
1302  }
1303  }
1304 
1305  assert(pQLine2 || nHeight == 0);
1306 
1307  for (tools::Long nY = 0; nY < nHeight; nY++, nYTmp++)
1308  {
1309  // first pixel in the line
1310  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(pQLine1[0].ImplGetColor()));
1311  Scanline pScanline = pWriteAcc->GetScanline(nY);
1312  pWriteAcc->SetPixelOnData(pScanline, 0, BitmapColor(cIndex));
1313 
1314  tools::Long nX;
1315  for (nX = 1; nX < nWidth1; nX++)
1316  {
1317  aColor = pQLine1[nX].ImplGetColor();
1318  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(aColor));
1319  aErrQuad = (ImpErrorQuad(aColor) -= pWriteAcc->GetPaletteColor(cIndex));
1320  pQLine1[++nX].ImplAddColorError7(aErrQuad);
1321  pQLine2[nX--].ImplAddColorError1(aErrQuad);
1322  pQLine2[nX--].ImplAddColorError5(aErrQuad);
1323  pQLine2[nX++].ImplAddColorError3(aErrQuad);
1324  pWriteAcc->SetPixelOnData(pScanline, nX, BitmapColor(cIndex));
1325  }
1326 
1327  // Last RowPixel
1328  if (nX < nWidth)
1329  {
1330  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(pQLine1[nWidth1].ImplGetColor()));
1331  pWriteAcc->SetPixelOnData(pScanline, nX, BitmapColor(cIndex));
1332  }
1333 
1334  // Refill/copy row buffer
1335  pQLine1 = pQLine2;
1336  bQ1 = !bQ1;
1337  pQLine2 = bQ1 ? aErrQuad2.data() : aErrQuad1.data();
1338 
1339  if (nYTmp < nHeight)
1340  {
1341  Scanline pScanlineRead = pReadAcc->GetScanline(nYTmp);
1342  for (nX = 0; nX < nWidth; nX++)
1343  {
1344  if (pReadAcc->HasPalette())
1345  pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
1346  else
1347  pQLine2[nX] = pReadAcc->GetPixelFromData(pScanlineRead, nX);
1348  }
1349  }
1350  }
1351 
1352  bRet = true;
1353  }
1354  pWriteAcc.reset();
1355 
1356  if(bRet)
1357  {
1358  const MapMode aMap(maPrefMapMode);
1359  const Size aSize(maPrefSize);
1360 
1361  *this = aNewBmp;
1362 
1363  maPrefMapMode = aMap;
1364  maPrefSize = aSize;
1365  }
1366  }
1367 
1368  return bRet;
1369 }
1370 
1371 bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag )
1372 {
1374  {
1375  // no scale
1376  return true;
1377  }
1378 
1379  if(basegfx::fTools::equal(rScaleX, 1.0) && basegfx::fTools::equal(rScaleY, 1.0))
1380  {
1381  // no scale
1382  return true;
1383  }
1384 
1385  const auto eStartPixelFormat = getPixelFormat();
1386 
1387  if (mxSalBmp && mxSalBmp->ScalingSupported())
1388  {
1389  // implementation specific scaling
1390  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
1391  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->Scale(rScaleX, rScaleY, nScaleFlag))
1392  {
1393  ImplSetSalBitmap(xImpBmp);
1394  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
1395  maPrefMapMode = MapMode( MapUnit::MapPixel );
1396  maPrefSize = xImpBmp->GetSize();
1397  return true;
1398  }
1399  }
1400 
1401  // fdo#33455
1402  //
1403  // If we start with a 1 bit image, then after scaling it in any mode except
1404  // BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
1405  // are going to down-shift it to mono again and Bitmap::MakeMonochrome just
1406  // has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
1407  // will default to black/white and the colors mapped to which ever is closer
1408  // to black/white
1409  //
1410  // So the easiest thing to do to retain the colors of 1 bit bitmaps is to
1411  // just use the fast scale rather than attempting to count unique colors in
1412  // the other converters and pass all the info down through
1413  // Bitmap::MakeMonochrome
1414  if (eStartPixelFormat == vcl::PixelFormat::N1_BPP)
1415  nScaleFlag = BmpScaleFlag::Fast;
1416 
1417  BitmapEx aBmpEx(*this);
1418  bool bRetval(false);
1419 
1420  switch(nScaleFlag)
1421  {
1422  case BmpScaleFlag::Default:
1423  if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
1424  bRetval = BitmapFilter::Filter(aBmpEx, BitmapFastScaleFilter(rScaleX, rScaleY));
1425  else
1426  bRetval = BitmapFilter::Filter(aBmpEx, BitmapScaleSuperFilter(rScaleX, rScaleY));
1427  break;
1428 
1429  case BmpScaleFlag::Fast:
1431  bRetval = BitmapFilter::Filter(aBmpEx, BitmapFastScaleFilter(rScaleX, rScaleY));
1432  break;
1433 
1435  bRetval = BitmapFilter::Filter(aBmpEx, BitmapInterpolateScaleFilter(rScaleX, rScaleY));
1436  break;
1437 
1439  case BmpScaleFlag::Lanczos:
1440  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleLanczos3Filter(rScaleX, rScaleY));
1441  break;
1442 
1443  case BmpScaleFlag::BiCubic:
1444  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleBicubicFilter(rScaleX, rScaleY));
1445  break;
1446 
1448  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleBilinearFilter(rScaleX, rScaleY));
1449  break;
1450  }
1451 
1452  if (bRetval)
1453  *this = aBmpEx.GetBitmap();
1454 
1455  OSL_ENSURE(!bRetval || eStartPixelFormat == getPixelFormat(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
1456  return bRetval;
1457 }
1458 
1459 bool Bitmap::Scale( const Size& rNewSize, BmpScaleFlag nScaleFlag )
1460 {
1461  const Size aSize( GetSizePixel() );
1462  bool bRet;
1463 
1464  if( aSize.Width() && aSize.Height() )
1465  {
1466  bRet = Scale( static_cast<double>(rNewSize.Width()) / aSize.Width(),
1467  static_cast<double>(rNewSize.Height()) / aSize.Height(),
1468  nScaleFlag );
1469  }
1470  else
1471  bRet = true;
1472 
1473  return bRet;
1474 }
1475 
1477 {
1478 #if HAVE_FEATURE_SKIA
1479  if( SkiaHelper::isVCLSkiaEnabled() && SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster)
1480  return true;
1481 #endif
1482  return false;
1483 }
1484 
1486 {
1487  // aNew is the result of some operation; adapt it's BitCount to the original (this)
1488  if (getPixelFormat() == rNew.getPixelFormat())
1489  return;
1490 
1491  switch (getPixelFormat())
1492  {
1494  {
1496  break;
1497  }
1499  {
1500  if(HasGreyPaletteAny())
1501  {
1503  }
1504  else
1505  {
1507  }
1508  break;
1509  }
1511  {
1513  break;
1514  }
1516  {
1518  break;
1519  }
1521  {
1522  SAL_WARN("vcl", "Can't adapt the pixelformat as it is invalid.");
1523  break;
1524  }
1525  }
1526 }
1527 
1528 static tools::Long* shiftColor(tools::Long* pColorArray, BitmapColor const& rColor)
1529 {
1530  *pColorArray++ = static_cast<tools::Long>(rColor.GetBlue()) << 12;
1531  *pColorArray++ = static_cast<tools::Long>(rColor.GetGreen()) << 12;
1532  *pColorArray++ = static_cast<tools::Long>(rColor.GetRed()) << 12;
1533  return pColorArray;
1534 }
1536 {
1537  Scanline pScanlineRead = pReadAcc->GetScanline(0);
1538  if (pReadAcc->HasPalette())
1539  return pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nZ));
1540  else
1541  return pReadAcc->GetPixelFromData(pScanlineRead, nZ);
1542 }
1543 
1545 {
1546  const Size aSize( GetSizePixel() );
1547  if( aSize.Width() == 1 || aSize.Height() == 1 )
1548  return true;
1549  if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1550  {
1551  ScopedReadAccess pReadAcc(*this);
1553  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1554  if( pReadAcc && pWriteAcc )
1555  {
1556  BitmapColor aColor;
1557  tools::Long nWidth = pReadAcc->Width();
1558  tools::Long nWidth1 = nWidth - 1;
1559  tools::Long nHeight = pReadAcc->Height();
1560  tools::Long nW = nWidth * 3;
1561  tools::Long nW2 = nW - 3;
1562  std::unique_ptr<tools::Long[]> p1(new tools::Long[ nW ]);
1563  std::unique_ptr<tools::Long[]> p2(new tools::Long[ nW ]);
1564  tools::Long* p1T = p1.get();
1565  tools::Long* p2T = p2.get();
1566  tools::Long* pTmp;
1567  pTmp = p2T;
1568  for (tools::Long nZ = 0; nZ < nWidth; nZ++)
1569  {
1570  pTmp = shiftColor(pTmp, getColor(pReadAcc.get(), nZ));
1571  }
1572  tools::Long nRErr, nGErr, nBErr;
1573  tools::Long nRC, nGC, nBC;
1574  for( tools::Long nY = 1, nYAcc = 0; nY <= nHeight; nY++, nYAcc++ )
1575  {
1576  pTmp = p1T;
1577  p1T = p2T;
1578  p2T = pTmp;
1579  if (nY < nHeight)
1580  {
1581  for (tools::Long nZ = 0; nZ < nWidth; nZ++)
1582  {
1583  pTmp = shiftColor(pTmp, getColor(pReadAcc.get(), nZ));
1584  }
1585  }
1586  // Examine first Pixel separately
1587  tools::Long nX = 0;
1588  tools::Long nTemp;
1589  CALC_ERRORS;
1590  CALC_TABLES7;
1591  nX -= 5;
1592  CALC_TABLES5;
1593  Scanline pScanline = pWriteAcc->GetScanline(nYAcc);
1594  pWriteAcc->SetPixelOnData( pScanline, 0, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1595  // Get middle Pixels using a loop
1596  tools::Long nXAcc;
1597  for ( nX = 3, nXAcc = 1; nX < nW2; nXAcc++ )
1598  {
1599  CALC_ERRORS;
1600  CALC_TABLES7;
1601  nX -= 8;
1602  CALC_TABLES3;
1603  CALC_TABLES5;
1604  pWriteAcc->SetPixelOnData( pScanline, nXAcc, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1605  }
1606  // Treat last Pixel separately
1607  CALC_ERRORS;
1608  nX -= 5;
1609  CALC_TABLES3;
1610  CALC_TABLES5;
1611  pWriteAcc->SetPixelOnData( pScanline, nWidth1, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1612  }
1613  pReadAcc.reset();
1614  pWriteAcc.reset();
1615  const MapMode aMap( maPrefMapMode );
1616  const Size aPrefSize( maPrefSize );
1617  *this = aNewBmp;
1618  maPrefMapMode = aMap;
1619  maPrefSize = aPrefSize;
1620  return true;
1621  }
1622  pReadAcc.reset();
1623  pWriteAcc.reset();
1624  }
1625  return false;
1626 }
1627 
1628 void Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, const Link<tools::Long,void>* pProgress )
1629 {
1630  ImplVectorizer::ImplVectorize( *this, rMtf, cReduce, pProgress );
1631 }
1632 
1633 bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
1634  short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
1635  double fGamma, bool bInvert, bool msoBrightness )
1636 {
1637  bool bRet = false;
1638 
1639  // nothing to do => return quickly
1640  if( !nLuminancePercent && !nContrastPercent &&
1641  !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
1642  ( fGamma == 1.0 ) && !bInvert )
1643  {
1644  bRet = true;
1645  }
1646  else
1647  {
1648  BitmapScopedWriteAccess pAcc(*this);
1649 
1650  if( pAcc )
1651  {
1652  BitmapColor aCol;
1653  const tools::Long nW = pAcc->Width();
1654  const tools::Long nH = pAcc->Height();
1655  std::unique_ptr<sal_uInt8[]> cMapR(new sal_uInt8[ 256 ]);
1656  std::unique_ptr<sal_uInt8[]> cMapG(new sal_uInt8[ 256 ]);
1657  std::unique_ptr<sal_uInt8[]> cMapB(new sal_uInt8[ 256 ]);
1658  double fM, fROff, fGOff, fBOff, fOff;
1659 
1660  // calculate slope
1661  if( nContrastPercent >= 0 )
1662  fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0, 100 ) );
1663  else
1664  fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100, 0 ) ) / 128.0;
1665 
1666  if(!msoBrightness)
1667  // total offset = luminance offset + contrast offset
1668  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55 + 128.0 - fM * 128.0;
1669  else
1670  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55;
1671 
1672  // channel offset = channel offset + total offset
1673  fROff = nChannelRPercent * 2.55 + fOff;
1674  fGOff = nChannelGPercent * 2.55 + fOff;
1675  fBOff = nChannelBPercent * 2.55 + fOff;
1676 
1677  // calculate gamma value
1678  fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
1679  const bool bGamma = ( fGamma != 1.0 );
1680 
1681  // create mapping table
1682  for( tools::Long nX = 0; nX < 256; nX++ )
1683  {
1684  if(!msoBrightness)
1685  {
1686  cMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fROff ), 0, 255 ));
1687  cMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fGOff ), 0, 255 ));
1688  cMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fBOff ), 0, 255 ));
1689  }
1690  else
1691  {
1692  // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
1693  // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
1694  // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
1695  cMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0, 255 ));
1696  cMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0, 255 ));
1697  cMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0, 255 ));
1698  }
1699  if( bGamma )
1700  {
1701  cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
1702  cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
1703  cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
1704  }
1705 
1706  if( bInvert )
1707  {
1708  cMapR[ nX ] = ~cMapR[ nX ];
1709  cMapG[ nX ] = ~cMapG[ nX ];
1710  cMapB[ nX ] = ~cMapB[ nX ];
1711  }
1712  }
1713 
1714  // do modifying
1715  if( pAcc->HasPalette() )
1716  {
1717  BitmapColor aNewCol;
1718 
1719  for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
1720  {
1721  const BitmapColor& rCol = pAcc->GetPaletteColor( i );
1722  aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
1723  aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
1724  aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
1725  pAcc->SetPaletteColor( i, aNewCol );
1726  }
1727  }
1728  else if( pAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr )
1729  {
1730  for( tools::Long nY = 0; nY < nH; nY++ )
1731  {
1732  Scanline pScan = pAcc->GetScanline( nY );
1733 
1734  for( tools::Long nX = 0; nX < nW; nX++ )
1735  {
1736  *pScan = cMapB[ *pScan ]; pScan++;
1737  *pScan = cMapG[ *pScan ]; pScan++;
1738  *pScan = cMapR[ *pScan ]; pScan++;
1739  }
1740  }
1741  }
1742  else if( pAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb )
1743  {
1744  for( tools::Long nY = 0; nY < nH; nY++ )
1745  {
1746  Scanline pScan = pAcc->GetScanline( nY );
1747 
1748  for( tools::Long nX = 0; nX < nW; nX++ )
1749  {
1750  *pScan = cMapR[ *pScan ]; pScan++;
1751  *pScan = cMapG[ *pScan ]; pScan++;
1752  *pScan = cMapB[ *pScan ]; pScan++;
1753  }
1754  }
1755  }
1756  else
1757  {
1758  for( tools::Long nY = 0; nY < nH; nY++ )
1759  {
1760  Scanline pScanline = pAcc->GetScanline(nY);
1761  for( tools::Long nX = 0; nX < nW; nX++ )
1762  {
1763  aCol = pAcc->GetPixelFromData( pScanline, nX );
1764  aCol.SetRed( cMapR[ aCol.GetRed() ] );
1765  aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
1766  aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
1767  pAcc->SetPixelOnData( pScanline, nX, aCol );
1768  }
1769  }
1770  }
1771 
1772  pAcc.reset();
1773  bRet = true;
1774  }
1775  }
1776 
1777  return bRet;
1778 }
1779 
1780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PixelFormat
Pixel format of the bitmap in bits per pixel.
Definition: BitmapTypes.hxx:19
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
static bool HasFastScale()
Returns true if bitmap scaling is considered to be fast.
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
bool Adjust(short nLuminancePercent, short nContrastPercent=0, short nChannelRPercent=0, short nChannelGPercent=0, short nChannelBPercent=0, double fGamma=1.0, bool bInvert=false, bool msoBrightness=false)
Change various global color characteristics.
#define BMP_COL_TRANS
Definition: bitmap.hxx:67
bool IsGreyPalette8Bit() const
Returns true if the palette is 8-bit grey palette.
tools::Long Height() const
sal_uInt8 GetRed() const
void SetBlue(sal_uInt8 nBlue)
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTMAGENTA
void setWidth(tools::Long nWidth)
BitmapInfoAccess * AcquireInfoAccess()
void SetEntryCount(sal_uInt16 nCount)
bool equalZero(const T &rfVal)
constexpr bool isPalettePixelFormat(PixelFormat ePixelFormat)
Is it a pixel format that forces creation of a palette.
Definition: BitmapTypes.hxx:29
#define GAMMA(_def_cVal, _def_InvGamma)
Definition: bitmap.hxx:35
bool operator==(const Bitmap &rBitmap) const
constexpr::Color COL_RED(0x80, 0x00, 0x00)
bool Expand(sal_Int32 nDX, sal_Int32 nDY, const Color *pInitColor=nullptr)
Expand the bitmap by pixel padding.
#define CALC_TABLES5
Definition: floyd.hxx:38
sal_uIntPtr sal_uLong
ErrCode compressAsPNG(const Graphic &rGraphic, SvStream &rOutputStream)
long Long
Size maPrefSize
Definition: bitmap.hxx:532
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, tools::Long nMin, tools::Long nMax)
sal_uInt8 GetLuminance() const
static tools::Long * shiftColor(tools::Long *pColorArray, BitmapColor const &rColor)
Class to import and export graphic formats.
BitmapReadAccess * AcquireReadAccess()
constexpr::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
This template handles BitmapAccess the RAII way.
Size GetSizePixel() const
void ImplAddColorError1(const ImpErrorQuad &rErrQuad)
Definition: impoctree.hxx:73
constexpr::Color COL_MAGENTA(0x80, 0x00, 0x80)
constexpr tools::Long Width() const
HashMap_OWString_Interface aMap
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
tools::Long Left() const
#define CALC_ERRORS
Definition: floyd.hxx:22
bool HasGreyPalette8Bit() const
Scanline GetScanline(tools::Long nY) const
constexpr::Color COL_CYAN(0x00, 0x80, 0x80)
int nCount
static bool Filter(BitmapEx &rBmpEx, BitmapFilter const &rFilter)
constexpr tools::Long GetWidth() const
sal_uInt8 GetBlue() const
#define CALC_TABLES3
Definition: floyd.hxx:33
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTRED
Bitmap & operator=(const Bitmap &rBitmap)
bool Dither()
Apply a Floyd dither algorithm to the bitmap.
constexpr bool IsEmpty() const
SAL_DLLPRIVATE bool ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const *pExtColor=nullptr)
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:75
sal_uInt16 GetEntryCount() const
BitmapColor ImplGetColor()
Definition: impoctree.hxx:101
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
const sal_uLong nVCLBLut[6]
vcl::PixelFormat getPixelFormat() const
Bitmap CreateDisplayBitmap(OutputDevice *pDisplay) const
int i
bool HasPalette() const
ScanlineFormat GetScanlineFormat() const
bool equal(T const &rfValA, T const &rfValB)
tools::Long FRound(double fVal)
void ImplAddColorError5(const ImpErrorQuad &rErrQuad)
Definition: impoctree.hxx:87
BitmapChecksum GetChecksum() const
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_GRAY
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:162
tools::Long Width() const
void SetRed(sal_uInt8 nRed)
bool GetSystemData(BitmapSystemData &rData) const
get system dependent bitmap data
BmpScaleFlag
Definition: bitmap.hxx:53
static BitmapColor getColor(BitmapReadAccess *pReadAcc, tools::Long nZ)
static void ReleaseAccess(BitmapInfoAccess *pAccess)
bool ImplVectorize(const Bitmap &rColorBmp, GDIMetaFile &rMtf, sal_uInt8 cReduce, const Link< tools::Long, void > *pProgress)
Definition: impvect.cxx:644
BmpConversion
Definition: bitmap.hxx:69
tools::Long Top() const
bool CopyPixel_AlphaOptimized(const tools::Rectangle &rRectDst, const tools::Rectangle &rRectSrc, const Bitmap *pBmpSrc)
short nBitCount
Definition: ipict.cxx:80
sal_uInt16 GetPaletteEntryCount() const
void SetEmpty()
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
void ImplAddColorError3(const ImpErrorQuad &rErrQuad)
Definition: impoctree.hxx:80
const sal_uLong nVCLGLut[6]
sal_uInt8 GetGreen() const
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTCYAN
constexpr Size GetSize() const
virtual std::shared_ptr< SalBitmap > CreateSalBitmap()=0
VCL_DLLPUBLIC bool isVCLSkiaEnabled()
#define CALC_TABLES7
Definition: floyd.hxx:43
#define SAL_WARN_IF(condition, area, stream)
constexpr tools::Long Height() const
unsigned char sal_uInt8
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
constexpr::Color COL_GREEN(0x00, 0x80, 0x00)
bool Convert(BmpConversion eConversion)
Convert bitmap format.
void Vectorize(GDIMetaFile &rMtf, sal_uInt8 cReduce, const Link< tools::Long, void > *pProgress)
Convert the bitmap to a meta file.
bool HasGreyPaletteAny() const
void SetGreen(sal_uInt8 nGreen)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
const BitmapPalette & GetPalette() const
#define SAL_INFO(area, stream)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BROWN
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTGREEN
SAL_DLLPRIVATE bool ImplMakeGreyscales()
SalGraphics const * GetGraphics() const
Get the graphic context that the output device uses to draw on.
Definition: outdev.cxx:202
BitmapWriteAccess * AcquireWriteAccess()
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_YELLOW
constexpr sal_uInt16 pixelFormatBitCount(PixelFormat ePixelFormat)
Definition: BitmapTypes.hxx:35
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
std::vector< BitmapColor > maBitmapColor
void AdaptBitCount(Bitmap &rNew) const
SAL_DLLPRIVATE void ImplMakeUnique()
void ImplAddColorError7(const ImpErrorQuad &rErrQuad)
Definition: impoctree.hxx:94
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTBLUE
void setHeight(tools::Long nHeight)
static GraphicFilter & GetGraphicFilter()
SAL_DLLPRIVATE bool ImplConvertDown8BPP(Color const *pExtColor=nullptr)
MapUnit
const sal_uLong nVCLRLut[6]
#define SAL_WARN(area, stream)
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
constexpr::Color COL_BLUE(0x00, 0x00, 0x80)
SAL_DLLPRIVATE void ReassignWithSize(const Bitmap &rBitmap)
ReassignWithSize and recalculate bitmap.
bool CopyPixel(const tools::Rectangle &rRectDst, const tools::Rectangle &rRectSrc, const Bitmap *pBmpSrc=nullptr)
Copy a rectangular area from another bitmap.
MapMode maPrefMapMode
Definition: bitmap.hxx:531
sal_uInt16 GetBestPaletteIndex(const BitmapColor &rColor)
Definition: Octree.cxx:281
virtual ~Bitmap()
std::shared_ptr< SalBitmap > mxSalBmp
Definition: bitmap.hxx:530
SalInstance * mpDefInst
Definition: svdata.hxx:383
static const BitmapPalette & GetGreyPalette(int nEntries)
bool IsGreyPaletteAny() const
Returns true if the palette is a grey palette (may not be 8-bit).
const BitmapPalette & GetPalette()
Definition: Octree.cxx:204
constexpr tools::Long GetHeight() const
SAL_DLLPRIVATE void ImplSetSalBitmap(const std::shared_ptr< SalBitmap > &xImpBmp)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo