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 
232 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
233 {
234  if (this == &rBitmap)
235  return *this;
236 
237  maPrefSize = rBitmap.maPrefSize;
238  maPrefMapMode = rBitmap.maPrefMapMode;
239  mxSalBmp = rBitmap.mxSalBmp;
240 
241  return *this;
242 }
243 
244 Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept
245 {
246  maPrefSize = std::move(rBitmap.maPrefSize);
247  maPrefMapMode = std::move(rBitmap.maPrefMapMode);
248  mxSalBmp = std::move(rBitmap.mxSalBmp);
249 
250  return *this;
251 }
252 
253 bool Bitmap::operator==( const Bitmap& rBmp ) const
254 {
255  if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr
256  return true;
257  if (!rBmp.mxSalBmp || !mxSalBmp)
258  return false;
259  if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() ||
260  rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount())
261  return false;
262  BitmapChecksum aChecksum1, aChecksum2;
263  rBmp.mxSalBmp->GetChecksum(aChecksum1);
264  mxSalBmp->GetChecksum(aChecksum2);
265  // If the bitmaps can't calculate a checksum, best to regard them as different.
266  if (aChecksum1 == 0 || aChecksum2 == 0)
267  return false;
268  return aChecksum1 == aChecksum2;
269 }
270 
272 {
274  maPrefSize = Size();
275  mxSalBmp.reset();
276 }
277 
279 {
280  return( mxSalBmp ? mxSalBmp->GetSize() : Size() );
281 }
282 
284 {
285  if (!mxSalBmp)
287 
288  sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
289  if (nBitCount <= 1)
291  if (nBitCount <= 8)
293  if (nBitCount <= 24)
295  if (nBitCount <= 32)
297 
299 }
300 
302 {
303  bool bRet = getPixelFormat() == vcl::PixelFormat::N1_BPP;
304 
305  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
306 
307  if( pIAcc )
308  {
309  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPaletteAny();
310  }
311 
312  return bRet;
313 }
314 
316 {
317  bool bRet = false;
318  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
319 
320  if( pIAcc )
321  {
322  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette8Bit();
323  }
324 
325  return bRet;
326 }
327 
329 {
330  BitmapChecksum nRet = 0;
331 
332  if( mxSalBmp )
333  {
334  mxSalBmp->GetChecksum(nRet);
335 
336  if (!nRet)
337  {
338  // nRet == 0 => probably, we were not able to acquire
339  // the buffer in SalBitmap::updateChecksum;
340  // so, we need to update the imp bitmap for this bitmap instance
341  // as we do in BitmapInfoAccess::ImplCreate
342  std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
343  if (xNewImpBmp->Create(*mxSalBmp, getPixelFormat()))
344  {
345  Bitmap* pThis = const_cast<Bitmap*>(this);
346  pThis->mxSalBmp = xNewImpBmp;
347  mxSalBmp->GetChecksum(nRet);
348  }
349  }
350  }
351 
352  return nRet;
353 }
354 
356 {
357  if (mxSalBmp && mxSalBmp.use_count() > 1)
358  {
359  std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp;
361  (void)mxSalBmp->Create(*xOldImpBmp);
362  }
363 }
364 
365 void Bitmap::ReassignWithSize(const Bitmap& rBitmap)
366 {
367  const Size aOldSizePix(GetSizePixel());
368  const Size aNewSizePix(rBitmap.GetSizePixel());
369  const MapMode aOldMapMode(maPrefMapMode);
370  Size aNewPrefSize;
371 
372  if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height())
373  {
374  aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width()));
375  aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height()));
376  }
377  else
378  {
379  aNewPrefSize = maPrefSize;
380  }
381 
382  *this = rBitmap;
383 
384  maPrefSize = aNewPrefSize;
385  maPrefMapMode = aOldMapMode;
386 }
387 
388 void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp)
389 {
390  mxSalBmp = xImpBmp;
391 }
392 
394 {
395  std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this ));
396 
397  if( !*pInfoAccess )
398  {
399  return nullptr;
400  }
401 
402  return pInfoAccess.release();
403 }
404 
406 {
407  std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this ));
408 
409  if( !*pReadAccess )
410  {
411  return nullptr;
412  }
413 
414  return pReadAccess.release();
415 }
416 
418 {
419  std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this ));
420 
421  if( !*pWriteAccess )
422  {
423  return nullptr;
424  }
425 
426  return pWriteAccess.release();
427 }
428 
430 {
431  delete pBitmapAccess;
432 }
433 
434 bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
435 {
436  const Size aSizePix( GetSizePixel() );
437  tools::Rectangle aRect( rRectPixel );
438  bool bRet = false;
439 
440  aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
441 
442  if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
443  {
444  ScopedReadAccess pReadAcc(*this);
445 
446  if( pReadAcc )
447  {
448  const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
449  Bitmap aNewBmp(aNewRect.GetSize(), getPixelFormat(), &pReadAcc->GetPalette());
450  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
451 
452  if( pWriteAcc )
453  {
454  const tools::Long nOldX = aRect.Left();
455  const tools::Long nOldY = aRect.Top();
456  const tools::Long nNewWidth = aNewRect.GetWidth();
457  const tools::Long nNewHeight = aNewRect.GetHeight();
458 
459  for( tools::Long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
460  {
461  Scanline pScanline = pWriteAcc->GetScanline(nY);
462  Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
463  for( tools::Long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
464  pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
465  }
466 
467  pWriteAcc.reset();
468  bRet = true;
469  }
470 
471  pReadAcc.reset();
472 
473  if( bRet )
474  ReassignWithSize( aNewBmp );
475  }
476  }
477 
478  return bRet;
479 };
480 
481 bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
482  const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
483 {
484  const Size aSizePix( GetSizePixel() );
485  tools::Rectangle aRectDst( rRectDst );
486  bool bRet = false;
487 
488  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
489 
490  if( !aRectDst.IsEmpty() )
491  {
492  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
493  {
494  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
495  const Size aCopySizePix( pSrc->GetSizePixel() );
496  tools::Rectangle aRectSrc( rRectSrc );
497  const sal_uInt16 nSrcBitCount = vcl::pixelFormatBitCount(pBmpSrc->getPixelFormat());
498  const sal_uInt16 nDstBitCount = vcl::pixelFormatBitCount(getPixelFormat());
499 
500  if( nSrcBitCount > nDstBitCount )
501  {
502  int nNextIndex = 0;
503 
504  if (nSrcBitCount == 24)
506  else if (nSrcBitCount == 8)
507  {
509  nNextIndex = 16;
510  }
511  else if (nSrcBitCount == 4)
512  {
513  assert(false);
514  }
515 
516  if( nNextIndex )
517  {
518  ScopedReadAccess pSrcAcc(*pSrc);
519  BitmapScopedWriteAccess pDstAcc(*this);
520 
521  if( pSrcAcc && pDstAcc )
522  {
523  const int nSrcCount = pSrcAcc->GetPaletteEntryCount();
524  const int nDstCount = 1 << nDstBitCount;
525 
526  for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nDstCount ); ++i)
527  {
528  const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
529 
530  bool bFound = false;
531 
532  for (int j = 0; j < nDstCount; ++j)
533  {
534  if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
535  {
536  bFound = true;
537  break;
538  }
539  }
540 
541  if( !bFound )
542  pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
543  }
544  }
545  }
546  }
547 
548  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
549 
550  if( !aRectSrc.IsEmpty() )
551  {
552  ScopedReadAccess pReadAcc(*pSrc);
553 
554  if( pReadAcc )
555  {
556  BitmapScopedWriteAccess pWriteAcc(*this);
557 
558  if( pWriteAcc )
559  {
560  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
561  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
562  const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
563  const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
564  tools::Long nDstY = aRectDst.Top();
565 
566  if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
567  {
568  const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
569  std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
570 
571  // Create index map for the color table, as the bitmap should be copied
572  // retaining it's color information relatively well
573  for( sal_uInt16 i = 0; i < nCount; i++ )
574  pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
575 
576  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
577  {
578  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
579  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
580  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
581  pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
582  }
583  }
584  else if( pReadAcc->HasPalette() )
585  {
586  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
587  {
588  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
589  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
590  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
591  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
592  }
593  }
594  else
595  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
596  {
597  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
598  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
599  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
600  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
601  }
602 
603  pWriteAcc.reset();
604  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
605  }
606 
607  pReadAcc.reset();
608  }
609  }
610  }
611  else
612  {
613  tools::Rectangle aRectSrc( rRectSrc );
614 
615  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
616 
617  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
618  {
619  BitmapScopedWriteAccess pWriteAcc(*this);
620 
621  if( pWriteAcc )
622  {
623  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
624  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
625  const tools::Long nSrcX = aRectSrc.Left();
626  const tools::Long nSrcY = aRectSrc.Top();
627  const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
628  const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
629  const tools::Long nDstX = aRectDst.Left();
630  const tools::Long nDstY = aRectDst.Top();
631  const tools::Long nDstEndX1 = nDstX + nWidth - 1;
632  const tools::Long nDstEndY1 = nDstY + nHeight - 1;
633 
634  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
635  {
636  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
637  {
638  Scanline pScanline = pWriteAcc->GetScanline(nYN);
639  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
640  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
641  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
642  }
643  }
644  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
645  {
646  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
647  {
648  Scanline pScanline = pWriteAcc->GetScanline(nYN);
649  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
650  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
651  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
652  }
653  }
654  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
655  {
656  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
657  {
658  Scanline pScanline = pWriteAcc->GetScanline(nYN);
659  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
660  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
661  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
662  }
663  }
664  else
665  {
666  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
667  {
668  Scanline pScanline = pWriteAcc->GetScanline(nYN);
669  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
670  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
671  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
672  }
673  }
674 
675  pWriteAcc.reset();
676  bRet = true;
677  }
678  }
679  }
680  }
681 
682  return bRet;
683 }
684 
686  const Bitmap* pBmpSrc )
687 {
688  // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
689  // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
690  const Size aSizePix( GetSizePixel() );
691  tools::Rectangle aRectDst( rRectDst );
692  bool bRet = false;
693 
694  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
695 
696  if( !aRectDst.IsEmpty() )
697  {
698  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
699  {
700  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
701  const Size aCopySizePix( pSrc->GetSizePixel() );
702  tools::Rectangle aRectSrc( rRectSrc );
703 
704  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
705 
706  if( !aRectSrc.IsEmpty() )
707  {
708  ScopedReadAccess pReadAcc(*pSrc);
709 
710  if( pReadAcc )
711  {
712  BitmapScopedWriteAccess pWriteAcc(*this);
713 
714  if( pWriteAcc )
715  {
716  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
717  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
718  const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
719  const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
720  tools::Long nDstY = aRectDst.Top();
721 
722  for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
723  {
724  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
725  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
726  for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
727  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
728  }
729 
730  pWriteAcc.reset();
731  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
732  }
733 
734  pReadAcc.reset();
735  }
736  }
737  }
738  else
739  {
740  tools::Rectangle aRectSrc( rRectSrc );
741 
742  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
743 
744  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
745  {
746  BitmapScopedWriteAccess pWriteAcc(*this);
747 
748  if( pWriteAcc )
749  {
750  const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
751  const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
752  const tools::Long nSrcX = aRectSrc.Left();
753  const tools::Long nSrcY = aRectSrc.Top();
754  const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
755  const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
756  const tools::Long nDstX = aRectDst.Left();
757  const tools::Long nDstY = aRectDst.Top();
758  const tools::Long nDstEndX1 = nDstX + nWidth - 1;
759  const tools::Long nDstEndY1 = nDstY + nHeight - 1;
760 
761  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
762  {
763  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
764  {
765  Scanline pScanline = pWriteAcc->GetScanline(nYN);
766  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
767  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
768  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
769  }
770  }
771  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
772  {
773  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
774  {
775  Scanline pScanline = pWriteAcc->GetScanline(nYN);
776  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
777  for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
778  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
779  }
780  }
781  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
782  {
783  for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
784  {
785  Scanline pScanline = pWriteAcc->GetScanline(nYN);
786  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
787  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
788  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
789  }
790  }
791  else
792  {
793  for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
794  {
795  Scanline pScanline = pWriteAcc->GetScanline(nYN);
796  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
797  for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
798  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
799  }
800  }
801 
802  pWriteAcc.reset();
803  bRet = true;
804  }
805  }
806  }
807  }
808 
809  return bRet;
810 
811 }
812 
813 bool Bitmap::Expand( sal_Int32 nDX, sal_Int32 nDY, const Color* pInitColor )
814 {
815  bool bRet = false;
816 
817  if( nDX || nDY )
818  {
819  const Size aSizePixel( GetSizePixel() );
820  const tools::Long nWidth = aSizePixel.Width();
821  const tools::Long nHeight = aSizePixel.Height();
822  const Size aNewSize( nWidth + nDX, nHeight + nDY );
823  ScopedReadAccess pReadAcc(*this);
824 
825  if( pReadAcc )
826  {
827  BitmapPalette aBmpPal( pReadAcc->GetPalette() );
828  Bitmap aNewBmp(aNewSize, getPixelFormat(), &aBmpPal);
829  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
830 
831  if( pWriteAcc )
832  {
833  BitmapColor aColor;
834  const tools::Long nNewX = nWidth;
835  const tools::Long nNewY = nHeight;
836  const tools::Long nNewWidth = pWriteAcc->Width();
837  const tools::Long nNewHeight = pWriteAcc->Height();
838  tools::Long nX;
839  tools::Long nY;
840 
841  if( pInitColor )
842  aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
843 
844  for( nY = 0; nY < nHeight; nY++ )
845  {
846  pWriteAcc->CopyScanline( nY, *pReadAcc );
847 
848  if( pInitColor && nDX )
849  {
850  Scanline pScanline = pWriteAcc->GetScanline(nY);
851  for( nX = nNewX; nX < nNewWidth; nX++ )
852  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
853  }
854  }
855 
856  if( pInitColor && nDY )
857  for( nY = nNewY; nY < nNewHeight; nY++ )
858  {
859  Scanline pScanline = pWriteAcc->GetScanline(nY);
860  for( nX = 0; nX < nNewWidth; nX++ )
861  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
862  }
863 
864  pWriteAcc.reset();
865  bRet = true;
866  }
867 
868  pReadAcc.reset();
869 
870  if (bRet)
871  ReassignWithSize(aNewBmp);
872  }
873  }
874 
875  return bRet;
876 }
877 
879 {
880  Bitmap aDispBmp( *this );
881 
882  SalGraphics* pDispGraphics = pDisplay->GetGraphics();
883 
884  if( mxSalBmp && pDispGraphics )
885  {
886  std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
887  if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics))
888  aDispBmp.ImplSetSalBitmap(xImpDispBmp);
889  }
890 
891  return aDispBmp;
892 }
893 
895 {
896  return mxSalBmp && mxSalBmp->GetSystemData(rData);
897 }
898 
899 
900 bool Bitmap::Convert( BmpConversion eConversion )
901 {
902  // try to convert in backend
903  if (mxSalBmp)
904  {
905  // avoid large chunk of obsolete and hopefully rarely used conversions.
906  if (eConversion == BmpConversion::N8BitNoConversion)
907  {
908  if (mxSalBmp->GetBitCount() == 8 && HasGreyPalette8Bit())
909  return true;
910  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
911  // frequently used conversion for creating alpha masks
912  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->InterpretAs8Bit())
913  {
914  ImplSetSalBitmap(xImpBmp);
915  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
916  return true;
917  }
918  }
919  if (eConversion == BmpConversion::N8BitGreys)
920  {
921  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
922  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->ConvertToGreyscale())
923  {
924  ImplSetSalBitmap(xImpBmp);
925  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
926  return true;
927  }
928  }
929  }
930 
931  const sal_uInt16 nBitCount = vcl::pixelFormatBitCount(getPixelFormat());
932  bool bRet = false;
933 
934  switch( eConversion )
935  {
937  {
938  BitmapEx aBmpEx(*this);
939  bRet = BitmapFilter::Filter(aBmpEx, BitmapMonochromeFilter(128));
940  *this = aBmpEx.GetBitmap();
941  }
942  break;
943 
946  bRet = ImplMakeGreyscales();
947  break;
948 
950  {
951  if( nBitCount < 8 )
953  else if( nBitCount > 8 )
954  bRet = ImplConvertDown8BPP();
955  else
956  bRet = true;
957  }
958  break;
959 
961  {
962  Color aTrans( BMP_COL_TRANS );
963 
964  if( nBitCount < 8 )
965  bRet = ImplConvertUp(vcl::PixelFormat::N8_BPP, &aTrans );
966  else
967  bRet = ImplConvertDown8BPP(&aTrans );
968  }
969  break;
970 
972  {
973  if( nBitCount < 24 )
975  else
976  bRet = true;
977  }
978  break;
979 
981  {
982  if( nBitCount < 32 )
984  else
985  bRet = true;
986  }
987  break;
988 
989  default:
990  OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
991  break;
992  }
993 
994  return bRet;
995 }
996 
998 {
999  ScopedReadAccess pReadAcc(*this);
1000  bool bRet = false;
1001 
1002  if( pReadAcc )
1003  {
1004  const BitmapPalette& rPal = GetGreyPalette(256);
1005  sal_uLong nShift = 0;
1006  bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
1007 
1008  if( !bPalDiffers )
1009  bPalDiffers = ( rPal != pReadAcc->GetPalette() );
1010 
1011  if( bPalDiffers )
1012  {
1013  const auto ePixelFormat = vcl::PixelFormat::N8_BPP;
1014  Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &rPal );
1015  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1016 
1017  if( pWriteAcc )
1018  {
1019  const tools::Long nWidth = pWriteAcc->Width();
1020  const tools::Long nHeight = pWriteAcc->Height();
1021 
1022  if( pReadAcc->HasPalette() )
1023  {
1024  for( tools::Long nY = 0; nY < nHeight; nY++ )
1025  {
1026  Scanline pScanline = pWriteAcc->GetScanline(nY);
1027  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1028  for( tools::Long nX = 0; nX < nWidth; nX++ )
1029  {
1030  const sal_uInt8 cIndex = pReadAcc->GetIndexFromData( pScanlineRead, nX );
1031  pWriteAcc->SetPixelOnData( pScanline, nX,
1032  BitmapColor(pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
1033  }
1034  }
1035  }
1036  else if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr &&
1037  pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal )
1038  {
1039  nShift += 8;
1040 
1041  for( tools::Long nY = 0; nY < nHeight; nY++ )
1042  {
1043  Scanline pReadScan = pReadAcc->GetScanline( nY );
1044  Scanline pWriteScan = pWriteAcc->GetScanline( nY );
1045 
1046  for( tools::Long nX = 0; nX < nWidth; nX++ )
1047  {
1048  const sal_uLong nB = *pReadScan++;
1049  const sal_uLong nG = *pReadScan++;
1050  const sal_uLong nR = *pReadScan++;
1051 
1052  *pWriteScan++ = static_cast<sal_uInt8>( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
1053  }
1054  }
1055  }
1056  else if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb &&
1057  pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal )
1058  {
1059  nShift += 8;
1060 
1061  for( tools::Long nY = 0; nY < nHeight; nY++ )
1062  {
1063  Scanline pReadScan = pReadAcc->GetScanline( nY );
1064  Scanline pWriteScan = pWriteAcc->GetScanline( nY );
1065 
1066  for( tools::Long nX = 0; nX < nWidth; nX++ )
1067  {
1068  const sal_uLong nR = *pReadScan++;
1069  const sal_uLong nG = *pReadScan++;
1070  const sal_uLong nB = *pReadScan++;
1071 
1072  *pWriteScan++ = static_cast<sal_uInt8>( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
1073  }
1074  }
1075  }
1076  else
1077  {
1078  for( tools::Long nY = 0; nY < nHeight; nY++ )
1079  {
1080  Scanline pScanline = pWriteAcc->GetScanline(nY);
1081  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1082  for( tools::Long nX = 0; nX < nWidth; nX++ )
1083  pWriteAcc->SetPixelOnData( pScanline, nX, BitmapColor(pReadAcc->GetPixelFromData( pScanlineRead, nX ).GetLuminance() >> nShift) );
1084  }
1085  }
1086 
1087  pWriteAcc.reset();
1088  bRet = true;
1089  }
1090 
1091  pReadAcc.reset();
1092 
1093  if( bRet )
1094  {
1095  const MapMode aMap( maPrefMapMode );
1096  const Size aSize( maPrefSize );
1097 
1098  *this = aNewBmp;
1099 
1100  maPrefMapMode = aMap;
1101  maPrefSize = aSize;
1102  }
1103  }
1104  else
1105  {
1106  pReadAcc.reset();
1107  bRet = true;
1108  }
1109  }
1110 
1111  return bRet;
1112 }
1113 
1114 bool Bitmap::ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const * pExtColor)
1115 {
1116  SAL_WARN_IF(ePixelFormat <= getPixelFormat(), "vcl", "New pixel format must be greater!" );
1117 
1118  Bitmap::ScopedReadAccess pReadAcc(*this);
1119  bool bRet = false;
1120 
1121  if (pReadAcc)
1122  {
1123  BitmapPalette aPalette;
1124  Bitmap aNewBmp(GetSizePixel(), ePixelFormat, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPalette);
1125  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1126 
1127  if (pWriteAcc)
1128  {
1129  const tools::Long nWidth = pWriteAcc->Width();
1130  const tools::Long nHeight = pWriteAcc->Height();
1131 
1132  if (pWriteAcc->HasPalette())
1133  {
1134  const BitmapPalette& rOldPalette = pReadAcc->GetPalette();
1135  const sal_uInt16 nOldCount = rOldPalette.GetEntryCount();
1136  assert(nOldCount <= (1 << vcl::pixelFormatBitCount(getPixelFormat())));
1137 
1138  aPalette.SetEntryCount(1 << vcl::pixelFormatBitCount(ePixelFormat));
1139 
1140  for (sal_uInt16 i = 0; i < nOldCount; i++)
1141  aPalette[i] = rOldPalette[i];
1142 
1143  if (pExtColor)
1144  aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
1145 
1146  pWriteAcc->SetPalette(aPalette);
1147 
1148  for (tools::Long nY = 0; nY < nHeight; nY++)
1149  {
1150  Scanline pScanline = pWriteAcc->GetScanline(nY);
1151  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1152  for (tools::Long nX = 0; nX < nWidth; nX++)
1153  {
1154  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPixelFromData(pScanlineRead, nX));
1155  }
1156  }
1157  }
1158  else
1159  {
1160  if (pReadAcc->HasPalette())
1161  {
1162  for (tools::Long nY = 0; nY < nHeight; nY++)
1163  {
1164  Scanline pScanline = pWriteAcc->GetScanline(nY);
1165  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1166  for (tools::Long nX = 0; nX < nWidth; nX++)
1167  {
1168  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX)));
1169  }
1170  }
1171  }
1172  else
1173  {
1174  for (tools::Long nY = 0; nY < nHeight; nY++)
1175  {
1176  Scanline pScanline = pWriteAcc->GetScanline(nY);
1177  Scanline pScanlineRead = pReadAcc->GetScanline(nY);
1178  for (tools::Long nX = 0; nX < nWidth; nX++)
1179  {
1180  pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPixelFromData(pScanlineRead, nX));
1181  }
1182  }
1183  }
1184  }
1185  bRet = true;
1186  }
1187 
1188  if (bRet)
1189  {
1190  const MapMode aMap(maPrefMapMode);
1191  const Size aSize(maPrefSize);
1192 
1193  *this = aNewBmp;
1194 
1195  maPrefMapMode = aMap;
1196  maPrefSize = aSize;
1197  }
1198  }
1199 
1200  return bRet;
1201 }
1202 
1203 bool Bitmap::ImplConvertDown8BPP(Color const * pExtColor)
1204 {
1205  SAL_WARN_IF(vcl::PixelFormat::N8_BPP > getPixelFormat(), "vcl", "New pixelformat must be lower ( or equal when pExtColor is set )!");
1206 
1207  Bitmap::ScopedReadAccess pReadAcc(*this);
1208  bool bRet = false;
1209 
1210  if (pReadAcc)
1211  {
1212  BitmapPalette aPalette;
1213  Bitmap aNewBmp(GetSizePixel(), vcl::PixelFormat::N8_BPP, &aPalette);
1214  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1215 
1216  if (pWriteAcc)
1217  {
1218  sal_Int16 nNewBitCount = sal_Int16(vcl::PixelFormat::N8_BPP);
1219  const sal_uInt16 nCount = 1 << nNewBitCount;
1220  const tools::Long nWidth = pWriteAcc->Width();
1221  const tools::Long nWidth1 = nWidth - 1;
1222  const tools::Long nHeight = pWriteAcc->Height();
1223  Octree aOctree(*pReadAcc, pExtColor ? (nCount - 1) : nCount);
1224  aPalette = aOctree.GetPalette();
1225  InverseColorMap aColorMap(aPalette);
1226  BitmapColor aColor;
1227  ImpErrorQuad aErrQuad;
1228  std::vector<ImpErrorQuad> aErrQuad1(nWidth);
1229  std::vector<ImpErrorQuad> aErrQuad2(nWidth);
1230  ImpErrorQuad* pQLine1 = aErrQuad1.data();
1231  ImpErrorQuad* pQLine2 = nullptr;
1232  tools::Long nYTmp = 0;
1233  sal_uInt8 cIndex;
1234  bool bQ1 = true;
1235 
1236  if (pExtColor)
1237  {
1238  aPalette.SetEntryCount(aPalette.GetEntryCount() + 1);
1239  aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
1240  }
1241 
1242  // set Black/White always, if we have enough space
1243  if (aPalette.GetEntryCount() < (nCount - 1))
1244  {
1245  aPalette.SetEntryCount(aPalette.GetEntryCount() + 2);
1246  aPalette[aPalette.GetEntryCount() - 2] = COL_BLACK;
1247  aPalette[aPalette.GetEntryCount() - 1] = COL_WHITE;
1248  }
1249 
1250  pWriteAcc->SetPalette(aPalette);
1251 
1252  for (tools::Long nY = 0; nY < std::min(nHeight, tools::Long(2)); nY++, nYTmp++)
1253  {
1254  pQLine2 = !nY ? aErrQuad1.data() : aErrQuad2.data();
1255  Scanline pScanlineRead = pReadAcc->GetScanline(nYTmp);
1256  for (tools::Long nX = 0; nX < nWidth; nX++)
1257  {
1258  if (pReadAcc->HasPalette())
1259  pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
1260  else
1261  pQLine2[nX] = pReadAcc->GetPixelFromData(pScanlineRead, nX);
1262  }
1263  }
1264 
1265  assert(pQLine2 || nHeight == 0);
1266 
1267  for (tools::Long nY = 0; nY < nHeight; nY++, nYTmp++)
1268  {
1269  // first pixel in the line
1270  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(pQLine1[0].ImplGetColor()));
1271  Scanline pScanline = pWriteAcc->GetScanline(nY);
1272  pWriteAcc->SetPixelOnData(pScanline, 0, BitmapColor(cIndex));
1273 
1274  tools::Long nX;
1275  for (nX = 1; nX < nWidth1; nX++)
1276  {
1277  aColor = pQLine1[nX].ImplGetColor();
1278  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(aColor));
1279  aErrQuad = (ImpErrorQuad(aColor) -= pWriteAcc->GetPaletteColor(cIndex));
1280  pQLine1[++nX].ImplAddColorError7(aErrQuad);
1281  pQLine2[nX--].ImplAddColorError1(aErrQuad);
1282  pQLine2[nX--].ImplAddColorError5(aErrQuad);
1283  pQLine2[nX++].ImplAddColorError3(aErrQuad);
1284  pWriteAcc->SetPixelOnData(pScanline, nX, BitmapColor(cIndex));
1285  }
1286 
1287  // Last RowPixel
1288  if (nX < nWidth)
1289  {
1290  cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(pQLine1[nWidth1].ImplGetColor()));
1291  pWriteAcc->SetPixelOnData(pScanline, nX, BitmapColor(cIndex));
1292  }
1293 
1294  // Refill/copy row buffer
1295  pQLine1 = pQLine2;
1296  bQ1 = !bQ1;
1297  pQLine2 = bQ1 ? aErrQuad2.data() : aErrQuad1.data();
1298 
1299  if (nYTmp < nHeight)
1300  {
1301  Scanline pScanlineRead = pReadAcc->GetScanline(nYTmp);
1302  for (nX = 0; nX < nWidth; nX++)
1303  {
1304  if (pReadAcc->HasPalette())
1305  pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
1306  else
1307  pQLine2[nX] = pReadAcc->GetPixelFromData(pScanlineRead, nX);
1308  }
1309  }
1310  }
1311 
1312  bRet = true;
1313  }
1314  pWriteAcc.reset();
1315 
1316  if(bRet)
1317  {
1318  const MapMode aMap(maPrefMapMode);
1319  const Size aSize(maPrefSize);
1320 
1321  *this = aNewBmp;
1322 
1323  maPrefMapMode = aMap;
1324  maPrefSize = aSize;
1325  }
1326  }
1327 
1328  return bRet;
1329 }
1330 
1331 bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag )
1332 {
1334  {
1335  // no scale
1336  return true;
1337  }
1338 
1339  if(basegfx::fTools::equal(rScaleX, 1.0) && basegfx::fTools::equal(rScaleY, 1.0))
1340  {
1341  // no scale
1342  return true;
1343  }
1344 
1345  const auto eStartPixelFormat = getPixelFormat();
1346 
1347  if (mxSalBmp && mxSalBmp->ScalingSupported())
1348  {
1349  // implementation specific scaling
1350  std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
1351  if (xImpBmp->Create(*mxSalBmp) && xImpBmp->Scale(rScaleX, rScaleY, nScaleFlag))
1352  {
1353  ImplSetSalBitmap(xImpBmp);
1354  SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp.use_count() );
1355  maPrefMapMode = MapMode( MapUnit::MapPixel );
1356  maPrefSize = xImpBmp->GetSize();
1357  return true;
1358  }
1359  }
1360 
1361  // fdo#33455
1362  //
1363  // If we start with a 1 bit image, then after scaling it in any mode except
1364  // BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
1365  // are going to down-shift it to mono again and Bitmap::MakeMonochrome just
1366  // has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
1367  // will default to black/white and the colors mapped to which ever is closer
1368  // to black/white
1369  //
1370  // So the easiest thing to do to retain the colors of 1 bit bitmaps is to
1371  // just use the fast scale rather than attempting to count unique colors in
1372  // the other converters and pass all the info down through
1373  // Bitmap::MakeMonochrome
1374  if (eStartPixelFormat == vcl::PixelFormat::N1_BPP)
1375  nScaleFlag = BmpScaleFlag::Fast;
1376 
1377  BitmapEx aBmpEx(*this);
1378  bool bRetval(false);
1379 
1380  switch(nScaleFlag)
1381  {
1382  case BmpScaleFlag::Default:
1383  if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
1384  bRetval = BitmapFilter::Filter(aBmpEx, BitmapFastScaleFilter(rScaleX, rScaleY));
1385  else
1386  bRetval = BitmapFilter::Filter(aBmpEx, BitmapScaleSuperFilter(rScaleX, rScaleY));
1387  break;
1388 
1389  case BmpScaleFlag::Fast:
1391  bRetval = BitmapFilter::Filter(aBmpEx, BitmapFastScaleFilter(rScaleX, rScaleY));
1392  break;
1393 
1395  bRetval = BitmapFilter::Filter(aBmpEx, BitmapInterpolateScaleFilter(rScaleX, rScaleY));
1396  break;
1397 
1399  case BmpScaleFlag::Lanczos:
1400  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleLanczos3Filter(rScaleX, rScaleY));
1401  break;
1402 
1403  case BmpScaleFlag::BiCubic:
1404  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleBicubicFilter(rScaleX, rScaleY));
1405  break;
1406 
1408  bRetval = BitmapFilter::Filter(aBmpEx, vcl::BitmapScaleBilinearFilter(rScaleX, rScaleY));
1409  break;
1410  }
1411 
1412  if (bRetval)
1413  *this = aBmpEx.GetBitmap();
1414 
1415  OSL_ENSURE(!bRetval || eStartPixelFormat == getPixelFormat(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
1416  return bRetval;
1417 }
1418 
1419 bool Bitmap::Scale( const Size& rNewSize, BmpScaleFlag nScaleFlag )
1420 {
1421  const Size aSize( GetSizePixel() );
1422  bool bRet;
1423 
1424  if( aSize.Width() && aSize.Height() )
1425  {
1426  bRet = Scale( static_cast<double>(rNewSize.Width()) / aSize.Width(),
1427  static_cast<double>(rNewSize.Height()) / aSize.Height(),
1428  nScaleFlag );
1429  }
1430  else
1431  bRet = true;
1432 
1433  return bRet;
1434 }
1435 
1437 {
1438 #if HAVE_FEATURE_SKIA
1439  if( SkiaHelper::isVCLSkiaEnabled() && SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster)
1440  return true;
1441 #endif
1442  return false;
1443 }
1444 
1446 {
1447  // aNew is the result of some operation; adapt it's BitCount to the original (this)
1448  if (getPixelFormat() == rNew.getPixelFormat())
1449  return;
1450 
1451  switch (getPixelFormat())
1452  {
1454  {
1456  break;
1457  }
1459  {
1460  if(HasGreyPaletteAny())
1461  {
1463  }
1464  else
1465  {
1467  }
1468  break;
1469  }
1471  {
1473  break;
1474  }
1476  {
1478  break;
1479  }
1481  {
1482  SAL_WARN("vcl", "Can't adapt the pixelformat as it is invalid.");
1483  break;
1484  }
1485  }
1486 }
1487 
1488 static tools::Long* shiftColor(tools::Long* pColorArray, BitmapColor const& rColor)
1489 {
1490  *pColorArray++ = static_cast<tools::Long>(rColor.GetBlue()) << 12;
1491  *pColorArray++ = static_cast<tools::Long>(rColor.GetGreen()) << 12;
1492  *pColorArray++ = static_cast<tools::Long>(rColor.GetRed()) << 12;
1493  return pColorArray;
1494 }
1496 {
1497  Scanline pScanlineRead = pReadAcc->GetScanline(0);
1498  if (pReadAcc->HasPalette())
1499  return pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nZ));
1500  else
1501  return pReadAcc->GetPixelFromData(pScanlineRead, nZ);
1502 }
1503 
1505 {
1506  const Size aSize( GetSizePixel() );
1507  if( aSize.Width() == 1 || aSize.Height() == 1 )
1508  return true;
1509  if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1510  {
1511  ScopedReadAccess pReadAcc(*this);
1513  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
1514  if( pReadAcc && pWriteAcc )
1515  {
1516  BitmapColor aColor;
1517  tools::Long nWidth = pReadAcc->Width();
1518  tools::Long nWidth1 = nWidth - 1;
1519  tools::Long nHeight = pReadAcc->Height();
1520  tools::Long nW = nWidth * 3;
1521  tools::Long nW2 = nW - 3;
1522  std::unique_ptr<tools::Long[]> p1(new tools::Long[ nW ]);
1523  std::unique_ptr<tools::Long[]> p2(new tools::Long[ nW ]);
1524  tools::Long* p1T = p1.get();
1525  tools::Long* p2T = p2.get();
1526  tools::Long* pTmp;
1527  pTmp = p2T;
1528  for (tools::Long nZ = 0; nZ < nWidth; nZ++)
1529  {
1530  pTmp = shiftColor(pTmp, getColor(pReadAcc.get(), nZ));
1531  }
1532  tools::Long nRErr, nGErr, nBErr;
1533  tools::Long nRC, nGC, nBC;
1534  for( tools::Long nY = 1, nYAcc = 0; nY <= nHeight; nY++, nYAcc++ )
1535  {
1536  pTmp = p1T;
1537  p1T = p2T;
1538  p2T = pTmp;
1539  if (nY < nHeight)
1540  {
1541  for (tools::Long nZ = 0; nZ < nWidth; nZ++)
1542  {
1543  pTmp = shiftColor(pTmp, getColor(pReadAcc.get(), nZ));
1544  }
1545  }
1546  // Examine first Pixel separately
1547  tools::Long nX = 0;
1548  tools::Long nTemp;
1549  CALC_ERRORS;
1550  CALC_TABLES7;
1551  nX -= 5;
1552  CALC_TABLES5;
1553  Scanline pScanline = pWriteAcc->GetScanline(nYAcc);
1554  pWriteAcc->SetPixelOnData( pScanline, 0, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1555  // Get middle Pixels using a loop
1556  tools::Long nXAcc;
1557  for ( nX = 3, nXAcc = 1; nX < nW2; nXAcc++ )
1558  {
1559  CALC_ERRORS;
1560  CALC_TABLES7;
1561  nX -= 8;
1562  CALC_TABLES3;
1563  CALC_TABLES5;
1564  pWriteAcc->SetPixelOnData( pScanline, nXAcc, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1565  }
1566  // Treat last Pixel separately
1567  CALC_ERRORS;
1568  nX -= 5;
1569  CALC_TABLES3;
1570  CALC_TABLES5;
1571  pWriteAcc->SetPixelOnData( pScanline, nWidth1, BitmapColor(static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ])) );
1572  }
1573  pReadAcc.reset();
1574  pWriteAcc.reset();
1575  const MapMode aMap( maPrefMapMode );
1576  const Size aPrefSize( maPrefSize );
1577  *this = aNewBmp;
1578  maPrefMapMode = aMap;
1579  maPrefSize = aPrefSize;
1580  return true;
1581  }
1582  pReadAcc.reset();
1583  pWriteAcc.reset();
1584  }
1585  return false;
1586 }
1587 
1588 void Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, const Link<tools::Long,void>* pProgress )
1589 {
1590  ImplVectorizer::ImplVectorize( *this, rMtf, cReduce, pProgress );
1591 }
1592 
1593 bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
1594  short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
1595  double fGamma, bool bInvert, bool msoBrightness )
1596 {
1597  bool bRet = false;
1598 
1599  // nothing to do => return quickly
1600  if( !nLuminancePercent && !nContrastPercent &&
1601  !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
1602  ( fGamma == 1.0 ) && !bInvert )
1603  {
1604  bRet = true;
1605  }
1606  else
1607  {
1608  BitmapScopedWriteAccess pAcc(*this);
1609 
1610  if( pAcc )
1611  {
1612  BitmapColor aCol;
1613  const tools::Long nW = pAcc->Width();
1614  const tools::Long nH = pAcc->Height();
1615  std::unique_ptr<sal_uInt8[]> cMapR(new sal_uInt8[ 256 ]);
1616  std::unique_ptr<sal_uInt8[]> cMapG(new sal_uInt8[ 256 ]);
1617  std::unique_ptr<sal_uInt8[]> cMapB(new sal_uInt8[ 256 ]);
1618  double fM, fROff, fGOff, fBOff, fOff;
1619 
1620  // calculate slope
1621  if( nContrastPercent >= 0 )
1622  fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0, 100 ) );
1623  else
1624  fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100, 0 ) ) / 128.0;
1625 
1626  if(!msoBrightness)
1627  // total offset = luminance offset + contrast offset
1628  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55 + 128.0 - fM * 128.0;
1629  else
1630  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55;
1631 
1632  // channel offset = channel offset + total offset
1633  fROff = nChannelRPercent * 2.55 + fOff;
1634  fGOff = nChannelGPercent * 2.55 + fOff;
1635  fBOff = nChannelBPercent * 2.55 + fOff;
1636 
1637  // calculate gamma value
1638  fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
1639  const bool bGamma = ( fGamma != 1.0 );
1640 
1641  // create mapping table
1642  for( tools::Long nX = 0; nX < 256; nX++ )
1643  {
1644  if(!msoBrightness)
1645  {
1646  cMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fROff ), 0, 255 ));
1647  cMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fGOff ), 0, 255 ));
1648  cMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fBOff ), 0, 255 ));
1649  }
1650  else
1651  {
1652  // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
1653  // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
1654  // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
1655  cMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0, 255 ));
1656  cMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0, 255 ));
1657  cMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0, 255 ));
1658  }
1659  if( bGamma )
1660  {
1661  cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
1662  cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
1663  cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
1664  }
1665 
1666  if( bInvert )
1667  {
1668  cMapR[ nX ] = ~cMapR[ nX ];
1669  cMapG[ nX ] = ~cMapG[ nX ];
1670  cMapB[ nX ] = ~cMapB[ nX ];
1671  }
1672  }
1673 
1674  // do modifying
1675  if( pAcc->HasPalette() )
1676  {
1677  BitmapColor aNewCol;
1678 
1679  for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
1680  {
1681  const BitmapColor& rCol = pAcc->GetPaletteColor( i );
1682  aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
1683  aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
1684  aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
1685  pAcc->SetPaletteColor( i, aNewCol );
1686  }
1687  }
1688  else if( pAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr )
1689  {
1690  for( tools::Long nY = 0; nY < nH; nY++ )
1691  {
1692  Scanline pScan = pAcc->GetScanline( nY );
1693 
1694  for( tools::Long nX = 0; nX < nW; nX++ )
1695  {
1696  *pScan = cMapB[ *pScan ]; pScan++;
1697  *pScan = cMapG[ *pScan ]; pScan++;
1698  *pScan = cMapR[ *pScan ]; pScan++;
1699  }
1700  }
1701  }
1702  else if( pAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb )
1703  {
1704  for( tools::Long nY = 0; nY < nH; nY++ )
1705  {
1706  Scanline pScan = pAcc->GetScanline( nY );
1707 
1708  for( tools::Long nX = 0; nX < nW; nX++ )
1709  {
1710  *pScan = cMapR[ *pScan ]; pScan++;
1711  *pScan = cMapG[ *pScan ]; pScan++;
1712  *pScan = cMapB[ *pScan ]; pScan++;
1713  }
1714  }
1715  }
1716  else
1717  {
1718  for( tools::Long nY = 0; nY < nH; nY++ )
1719  {
1720  Scanline pScanline = pAcc->GetScanline(nY);
1721  for( tools::Long nX = 0; nX < nW; nX++ )
1722  {
1723  aCol = pAcc->GetPixelFromData( pScanline, nX );
1724  aCol.SetRed( cMapR[ aCol.GetRed() ] );
1725  aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
1726  aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
1727  pAcc->SetPixelOnData( pScanline, nX, aCol );
1728  }
1729  }
1730  }
1731 
1732  pAcc.reset();
1733  bRet = true;
1734  }
1735  }
1736 
1737  return bRet;
1738 }
1739 
1740 /* 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.
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
constexpr tools::Long Left() const
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
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
static BitmapColor getColor(const BitmapReadAccess *pReadAcc, tools::Long nZ)
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.
#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)
#define GAMMA(_def_cVal, _def_InvGamma)
#define BMP_COL_TRANS
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
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:167
tools::Long Width() const
void SetRed(sal_uInt8 nRed)
bool GetSystemData(BitmapSystemData &rData) const
get system dependent bitmap data
constexpr tools::Long Top() const
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
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:201
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
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
sal_uInt16 GetBestPaletteIndex(const BitmapColor &rColor)
Definition: Octree.cxx:281
virtual ~Bitmap()
std::shared_ptr< SalBitmap > mxSalBmp
BitmapColor ImplGetColor() const
Definition: impoctree.hxx:101
SalInstance * mpDefInst
Definition: svdata.hxx:388
static const BitmapPalette & GetGreyPalette(int nEntries)
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