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