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 <osl/diagnose.h>
21 #include <tools/helpers.hxx>
22 #include <vcl/bitmap.hxx>
23 #include <vcl/bitmapaccess.hxx>
24 #include <vcl/outdev.hxx>
25 
26 #include <svdata.hxx>
27 #include <salinst.hxx>
28 #include <salbmp.hxx>
29 #include <bitmapwriteaccess.hxx>
30 
31 #include <algorithm>
32 #include <memory>
33 
34 #ifdef DBG_UTIL
35 #include <cstdlib>
36 #include <tools/stream.hxx>
37 #include <vcl/graphicfilter.hxx>
38 #endif
39 
41 {
42 }
43 
44 Bitmap::Bitmap(const Bitmap& rBitmap)
45  : mxSalBmp(rBitmap.mxSalBmp)
46  , maPrefMapMode(rBitmap.maPrefMapMode)
47  , maPrefSize(rBitmap.maPrefSize)
48 {
49 }
50 
51 Bitmap::Bitmap(std::shared_ptr<SalBitmap> const & pSalBitmap)
52  : mxSalBmp(pSalBitmap)
53  , maPrefMapMode(MapMode(MapUnit::MapPixel))
54  , maPrefSize(mxSalBmp->GetSize())
55 {
56 }
57 
58 Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal )
59 {
60  if (rSizePixel.Width() && rSizePixel.Height())
61  {
62  BitmapPalette aPal;
63  BitmapPalette* pRealPal = nullptr;
64 
65  if( nBitCount <= 8 )
66  {
67  if( !pPal )
68  {
69  if( 1 == nBitCount )
70  {
71  aPal.SetEntryCount( 2 );
72  aPal[ 0 ] = COL_BLACK;
73  aPal[ 1 ] = COL_WHITE;
74  }
75  else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
76  {
77  aPal.SetEntryCount( 1 << nBitCount );
78  aPal[ 0 ] = COL_BLACK;
79  aPal[ 1 ] = COL_BLUE;
80  aPal[ 2 ] = COL_GREEN;
81  aPal[ 3 ] = COL_CYAN;
82  aPal[ 4 ] = COL_RED;
83  aPal[ 5 ] = COL_MAGENTA;
84  aPal[ 6 ] = COL_BROWN;
85  aPal[ 7 ] = COL_GRAY;
86  aPal[ 8 ] = COL_LIGHTGRAY;
87  aPal[ 9 ] = COL_LIGHTBLUE;
88  aPal[ 10 ] = COL_LIGHTGREEN;
89  aPal[ 11 ] = COL_LIGHTCYAN;
90  aPal[ 12 ] = COL_LIGHTRED;
91  aPal[ 13 ] = COL_LIGHTMAGENTA;
92  aPal[ 14 ] = COL_YELLOW;
93  aPal[ 15 ] = COL_WHITE;
94 
95  // Create dither palette
96  if( 8 == nBitCount )
97  {
98  sal_uInt16 nActCol = 16;
99 
100  for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
101  for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
102  for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
103  aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
104 
105  // Set standard Office colors
106  aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
107  }
108  }
109  }
110  else
111  pRealPal = const_cast<BitmapPalette*>(pPal);
112  }
113 
115  mxSalBmp->Create( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
116  }
117 }
118 
119 #ifdef DBG_UTIL
120 
121 namespace
122 {
123 void savePNG(const OUString& sWhere, const Bitmap& rBmp)
124 {
125  SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC);
127  rFilter.compressAsPNG(rBmp, aStream);
128 }
129 }
130 
131 #endif
132 
134 {
135 #ifdef DBG_UTIL
136  // VCL_DUMP_BMP_PATH should be like C:/bmpDump.png or ~/bmpDump.png
137  static const OUString sDumpPath(OUString::createFromAscii(std::getenv("VCL_DUMP_BMP_PATH")));
138  static volatile bool save(false);
139  if (!sDumpPath.isEmpty() && save)
140  {
141  save = false;
142  savePNG(sDumpPath, *this);
143  }
144 #endif
145 }
146 
147 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
148 {
149  // Create greyscale palette with 2, 4, 16 or 256 entries
150  switch (nEntries)
151  {
152  case 2:
153  {
154  static const BitmapPalette aGreyPalette2 = [] {
155  BitmapPalette aPalette(2);
156  aPalette[0] = BitmapColor(0, 0, 0);
157  aPalette[1] = BitmapColor(255, 255, 255);
158  return aPalette;
159  }();
160 
161  return aGreyPalette2;
162  }
163  case 4:
164  {
165  static const BitmapPalette aGreyPalette4 = [] {
166  BitmapPalette aPalette(4);
167  aPalette[0] = BitmapColor(0, 0, 0);
168  aPalette[1] = BitmapColor(85, 85, 85);
169  aPalette[2] = BitmapColor(170, 170, 170);
170  aPalette[3] = BitmapColor(255, 255, 255);
171  return aPalette;
172  }();
173 
174  return aGreyPalette4;
175  }
176  case 16:
177  {
178  static const BitmapPalette aGreyPalette16 = [] {
179  sal_uInt8 cGrey = 0;
180  sal_uInt8 const cGreyInc = 17;
181 
182  BitmapPalette aPalette(16);
183 
184  for (sal_uInt16 i = 0; i < 16; ++i, cGrey += cGreyInc)
185  aPalette[i] = BitmapColor(cGrey, cGrey, cGrey);
186 
187  return aPalette;
188  }();
189 
190  return aGreyPalette16;
191  }
192  case 256:
193  {
194  static const BitmapPalette aGreyPalette256 = [] {
195  BitmapPalette aPalette(256);
196 
197  for (sal_uInt16 i = 0; i < 256; ++i)
198  aPalette[i] = BitmapColor(static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i),
199  static_cast<sal_uInt8>(i));
200 
201  return aPalette;
202  }();
203 
204  return aGreyPalette256;
205  }
206  }
207  OSL_FAIL("Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)");
208  return GetGreyPalette(2);
209 }
210 
212 {
213  const int nEntryCount = GetEntryCount();
214  if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
215  return true;
216  // See above: only certain entry values will result in a valid call to GetGreyPalette
217  if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
218  {
219  const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
220  if( rGreyPalette == *this )
221  return true;
222  }
223 
224  bool bRet = false;
225  // TODO: is it worth to compare the entries for the general case?
226  if (nEntryCount == 2)
227  {
228  const BitmapColor& rCol0(maBitmapColor[0]);
229  const BitmapColor& rCol1(maBitmapColor[1]);
230  bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
231  rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
232  }
233  return bRet;
234 }
235 
237 {
238  const int nEntryCount = GetEntryCount();
239  if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
240  return true;
241  if( nEntryCount != 256 )
242  return false;
243  for (sal_uInt16 i = 0; i < 256; ++i)
244  {
245  if( maBitmapColor[i] != BitmapColor(i, i, i))
246  return false;
247  }
248  return true;
249 }
250 
251 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
252 {
253  if (this == &rBitmap)
254  return *this;
255 
256  maPrefSize = rBitmap.maPrefSize;
257  maPrefMapMode = rBitmap.maPrefMapMode;
258  mxSalBmp = rBitmap.mxSalBmp;
259 
260  return *this;
261 }
262 
263 Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept
264 {
265  maPrefSize = std::move(rBitmap.maPrefSize);
266  maPrefMapMode = std::move(rBitmap.maPrefMapMode);
267  mxSalBmp = std::move(rBitmap.mxSalBmp);
268 
269  return *this;
270 }
271 
272 bool Bitmap::operator==( const Bitmap& rBmp ) const
273 {
274  if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr
275  return true;
276  if (!rBmp.mxSalBmp || !mxSalBmp)
277  return false;
278  if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() ||
279  rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount())
280  return false;
281  BitmapChecksum aChecksum1, aChecksum2;
282  rBmp.mxSalBmp->GetChecksum(aChecksum1);
283  mxSalBmp->GetChecksum(aChecksum2);
284  // If the bitmaps can't calculate a checksum, best to regard them as different.
285  if (aChecksum1 == 0 || aChecksum2 == 0)
286  return false;
287  return aChecksum1 == aChecksum2;
288 }
289 
291 {
293  maPrefSize = Size();
294  mxSalBmp.reset();
295 }
296 
298 {
299  return( mxSalBmp ? mxSalBmp->GetSize() : Size() );
300 }
301 
302 sal_uInt16 Bitmap::GetBitCount() const
303 {
304  if (!mxSalBmp)
305  return 0;
306 
307  sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
308  if (nBitCount <= 1)
309  return 1;
310  if (nBitCount <= 4)
311  return 4;
312  if (nBitCount <= 8)
313  return 8;
314  if (nBitCount <= 24)
315  return 24;
316  if (nBitCount <= 32)
317  return 32;
318  return 0;
319 }
320 
322 {
323  const sal_uInt16 nBitCount = GetBitCount();
324  bool bRet = nBitCount == 1;
325 
326  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
327 
328  if( pIAcc )
329  {
330  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPaletteAny();
331  }
332 
333  return bRet;
334 }
335 
337 {
338  bool bRet = false;
339  ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
340 
341  if( pIAcc )
342  {
343  bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette8Bit();
344  }
345 
346  return bRet;
347 }
348 
350 {
351  BitmapChecksum nRet = 0;
352 
353  if( mxSalBmp )
354  {
355  mxSalBmp->GetChecksum(nRet);
356 
357  if (!nRet)
358  {
359  // nRet == 0 => probably, we were not able to acquire
360  // the buffer in SalBitmap::updateChecksum;
361  // so, we need to update the imp bitmap for this bitmap instance
362  // as we do in BitmapInfoAccess::ImplCreate
363  std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
364  if (xNewImpBmp->Create(*mxSalBmp, GetBitCount()))
365  {
366  Bitmap* pThis = const_cast<Bitmap*>(this);
367  pThis->mxSalBmp = xNewImpBmp;
368  mxSalBmp->GetChecksum(nRet);
369  }
370  }
371  }
372 
373  return nRet;
374 }
375 
377 {
378  if (mxSalBmp && mxSalBmp.use_count() > 1)
379  {
380  std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp;
382  (void)mxSalBmp->Create(*xOldImpBmp);
383  }
384 }
385 
386 void Bitmap::ReassignWithSize(const Bitmap& rBitmap)
387 {
388  const Size aOldSizePix(GetSizePixel());
389  const Size aNewSizePix(rBitmap.GetSizePixel());
390  const MapMode aOldMapMode(maPrefMapMode);
391  Size aNewPrefSize;
392 
393  if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height())
394  {
395  aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width()));
396  aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height()));
397  }
398  else
399  {
400  aNewPrefSize = maPrefSize;
401  }
402 
403  *this = rBitmap;
404 
405  maPrefSize = aNewPrefSize;
406  maPrefMapMode = aOldMapMode;
407 }
408 
409 
410 void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp)
411 {
412  mxSalBmp = xImpBmp;
413 }
414 
416 {
417  std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this ));
418 
419  if( !*pInfoAccess )
420  {
421  return nullptr;
422  }
423 
424  return pInfoAccess.release();
425 }
426 
428 {
429  std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this ));
430 
431  if( !*pReadAccess )
432  {
433  return nullptr;
434  }
435 
436  return pReadAccess.release();
437 }
438 
440 {
441  std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this ));
442 
443  if( !*pWriteAccess )
444  {
445  return nullptr;
446  }
447 
448  return pWriteAccess.release();
449 }
450 
452 {
453  delete pBitmapAccess;
454 }
455 
456 bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
457 {
458  const Size aSizePix( GetSizePixel() );
459  tools::Rectangle aRect( rRectPixel );
460  bool bRet = false;
461 
462  aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
463 
464  if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
465  {
466  ScopedReadAccess pReadAcc(*this);
467 
468  if( pReadAcc )
469  {
470  const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
471  Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
472  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
473 
474  if( pWriteAcc )
475  {
476  const long nOldX = aRect.Left();
477  const long nOldY = aRect.Top();
478  const long nNewWidth = aNewRect.GetWidth();
479  const long nNewHeight = aNewRect.GetHeight();
480 
481  for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
482  {
483  Scanline pScanline = pWriteAcc->GetScanline(nY);
484  Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
485  for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
486  pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
487  }
488 
489  pWriteAcc.reset();
490  bRet = true;
491  }
492 
493  pReadAcc.reset();
494 
495  if( bRet )
496  ReassignWithSize( aNewBmp );
497  }
498  }
499 
500  return bRet;
501 };
502 
503 bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
504  const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
505 {
506  const Size aSizePix( GetSizePixel() );
507  tools::Rectangle aRectDst( rRectDst );
508  bool bRet = false;
509 
510  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
511 
512  if( !aRectDst.IsEmpty() )
513  {
514  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
515  {
516  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
517  const Size aCopySizePix( pSrc->GetSizePixel() );
518  tools::Rectangle aRectSrc( rRectSrc );
519  const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
520  const sal_uInt16 nDstBitCount = GetBitCount();
521 
522  if( nSrcBitCount > nDstBitCount )
523  {
524  int nNextIndex = 0;
525 
526  if (nSrcBitCount == 24)
528  else if (nSrcBitCount == 8)
529  {
531  nNextIndex = 16;
532  }
533  else if (nSrcBitCount == 4)
534  {
536  nNextIndex = 2;
537  }
538 
539  if( nNextIndex )
540  {
541  ScopedReadAccess pSrcAcc(*pSrc);
542  BitmapScopedWriteAccess pDstAcc(*this);
543 
544  if( pSrcAcc && pDstAcc )
545  {
546  const int nSrcCount = pDstAcc->GetPaletteEntryCount();
547  const int nDstCount = 1 << nDstBitCount;
548 
549  for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); ++i)
550  {
551  const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
552 
553  bool bFound = false;
554 
555  for (int j = 0; j < nDstCount; ++j)
556  {
557  if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
558  {
559  bFound = true;
560  break;
561  }
562  }
563 
564  if( !bFound )
565  pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
566  }
567  }
568  }
569  }
570 
571  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
572 
573  if( !aRectSrc.IsEmpty() )
574  {
575  ScopedReadAccess pReadAcc(*pSrc);
576 
577  if( pReadAcc )
578  {
579  BitmapScopedWriteAccess pWriteAcc(*this);
580 
581  if( pWriteAcc )
582  {
583  const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
584  const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
585  const long nSrcEndX = aRectSrc.Left() + nWidth;
586  const long nSrcEndY = aRectSrc.Top() + nHeight;
587  long nDstY = aRectDst.Top();
588 
589  if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
590  {
591  const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
592  std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
593 
594  // Create index map for the color table, as the bitmap should be copied
595  // retaining it's color information relatively well
596  for( sal_uInt16 i = 0; i < nCount; i++ )
597  pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
598 
599  for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
600  {
601  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
602  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
603  for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
604  pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
605  }
606  }
607  else if( pReadAcc->HasPalette() )
608  {
609  for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
610  {
611  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
612  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
613  for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
614  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
615  }
616  }
617  else
618  for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
619  {
620  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
621  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
622  for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
623  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
624  }
625 
626  pWriteAcc.reset();
627  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
628  }
629 
630  pReadAcc.reset();
631  }
632  }
633  }
634  else
635  {
636  tools::Rectangle aRectSrc( rRectSrc );
637 
638  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
639 
640  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
641  {
642  BitmapScopedWriteAccess pWriteAcc(*this);
643 
644  if( pWriteAcc )
645  {
646  const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
647  const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
648  const long nSrcX = aRectSrc.Left();
649  const long nSrcY = aRectSrc.Top();
650  const long nSrcEndX1 = nSrcX + nWidth - 1;
651  const long nSrcEndY1 = nSrcY + nHeight - 1;
652  const long nDstX = aRectDst.Left();
653  const long nDstY = aRectDst.Top();
654  const long nDstEndX1 = nDstX + nWidth - 1;
655  const long nDstEndY1 = nDstY + nHeight - 1;
656 
657  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
658  {
659  for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
660  {
661  Scanline pScanline = pWriteAcc->GetScanline(nYN);
662  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
663  for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
664  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
665  }
666  }
667  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
668  {
669  for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
670  {
671  Scanline pScanline = pWriteAcc->GetScanline(nYN);
672  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
673  for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
674  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
675  }
676  }
677  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
678  {
679  for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
680  {
681  Scanline pScanline = pWriteAcc->GetScanline(nYN);
682  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
683  for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
684  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
685  }
686  }
687  else
688  {
689  for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
690  {
691  Scanline pScanline = pWriteAcc->GetScanline(nYN);
692  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
693  for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
694  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
695  }
696  }
697 
698  pWriteAcc.reset();
699  bRet = true;
700  }
701  }
702  }
703  }
704 
705  return bRet;
706 }
707 
709  const Bitmap* pBmpSrc )
710 {
711  // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
712  // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
713  const Size aSizePix( GetSizePixel() );
714  tools::Rectangle aRectDst( rRectDst );
715  bool bRet = false;
716 
717  aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
718 
719  if( !aRectDst.IsEmpty() )
720  {
721  if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
722  {
723  Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
724  const Size aCopySizePix( pSrc->GetSizePixel() );
725  tools::Rectangle aRectSrc( rRectSrc );
726 
727  aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
728 
729  if( !aRectSrc.IsEmpty() )
730  {
731  ScopedReadAccess pReadAcc(*pSrc);
732 
733  if( pReadAcc )
734  {
735  BitmapScopedWriteAccess pWriteAcc(*this);
736 
737  if( pWriteAcc )
738  {
739  const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
740  const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
741  const long nSrcEndX = aRectSrc.Left() + nWidth;
742  const long nSrcEndY = aRectSrc.Top() + nHeight;
743  long nDstY = aRectDst.Top();
744 
745  for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
746  {
747  Scanline pScanline = pWriteAcc->GetScanline(nDstY);
748  Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
749  for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
750  pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
751  }
752 
753  pWriteAcc.reset();
754  bRet = ( nWidth > 0 ) && ( nHeight > 0 );
755  }
756 
757  pReadAcc.reset();
758  }
759  }
760  }
761  else
762  {
763  tools::Rectangle aRectSrc( rRectSrc );
764 
765  aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
766 
767  if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
768  {
769  BitmapScopedWriteAccess pWriteAcc(*this);
770 
771  if( pWriteAcc )
772  {
773  const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
774  const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
775  const long nSrcX = aRectSrc.Left();
776  const long nSrcY = aRectSrc.Top();
777  const long nSrcEndX1 = nSrcX + nWidth - 1;
778  const long nSrcEndY1 = nSrcY + nHeight - 1;
779  const long nDstX = aRectDst.Left();
780  const long nDstY = aRectDst.Top();
781  const long nDstEndX1 = nDstX + nWidth - 1;
782  const long nDstEndY1 = nDstY + nHeight - 1;
783 
784  if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
785  {
786  for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
787  {
788  Scanline pScanline = pWriteAcc->GetScanline(nYN);
789  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
790  for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
791  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
792  }
793  }
794  else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
795  {
796  for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
797  {
798  Scanline pScanline = pWriteAcc->GetScanline(nYN);
799  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
800  for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
801  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
802  }
803  }
804  else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
805  {
806  for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
807  {
808  Scanline pScanline = pWriteAcc->GetScanline(nYN);
809  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
810  for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
811  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
812  }
813  }
814  else
815  {
816  for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
817  {
818  Scanline pScanline = pWriteAcc->GetScanline(nYN);
819  Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
820  for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
821  pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
822  }
823  }
824 
825  pWriteAcc.reset();
826  bRet = true;
827  }
828  }
829  }
830  }
831 
832  return bRet;
833 
834 }
835 
836 bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
837 {
838  bool bRet = false;
839 
840  if( nDX || nDY )
841  {
842  const Size aSizePixel( GetSizePixel() );
843  const long nWidth = aSizePixel.Width();
844  const long nHeight = aSizePixel.Height();
845  const Size aNewSize( nWidth + nDX, nHeight + nDY );
846  ScopedReadAccess pReadAcc(*this);
847 
848  if( pReadAcc )
849  {
850  BitmapPalette aBmpPal( pReadAcc->GetPalette() );
851  Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
852  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
853 
854  if( pWriteAcc )
855  {
856  BitmapColor aColor;
857  const long nNewX = nWidth;
858  const long nNewY = nHeight;
859  const long nNewWidth = pWriteAcc->Width();
860  const long nNewHeight = pWriteAcc->Height();
861  long nX;
862  long nY;
863 
864  if( pInitColor )
865  aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
866 
867  for( nY = 0; nY < nHeight; nY++ )
868  {
869  pWriteAcc->CopyScanline( nY, *pReadAcc );
870 
871  if( pInitColor && nDX )
872  {
873  Scanline pScanline = pWriteAcc->GetScanline(nY);
874  for( nX = nNewX; nX < nNewWidth; nX++ )
875  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
876  }
877  }
878 
879  if( pInitColor && nDY )
880  for( nY = nNewY; nY < nNewHeight; nY++ )
881  {
882  Scanline pScanline = pWriteAcc->GetScanline(nY);
883  for( nX = 0; nX < nNewWidth; nX++ )
884  pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
885  }
886 
887  pWriteAcc.reset();
888  bRet = true;
889  }
890 
891  pReadAcc.reset();
892 
893  if (bRet)
894  ReassignWithSize(aNewBmp);
895  }
896  }
897 
898  return bRet;
899 }
900 
902 {
903  Bitmap aDispBmp( *this );
904 
905  SalGraphics* pDispGraphics = pDisplay->GetGraphics();
906 
907  if( mxSalBmp && pDispGraphics )
908  {
909  std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
910  if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics))
911  aDispBmp.ImplSetSalBitmap(xImpDispBmp);
912  }
913 
914  return aDispBmp;
915 }
916 
918 {
919  return mxSalBmp && mxSalBmp->GetSystemData(rData);
920 }
921 
922 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
long GetWidth() const
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
bool IsGreyPalette8Bit() const
Returns true if the palette is 8-bit grey palette.
constexpr::Color COL_BROWN(0x80, 0x80, 0x00)
long GetHeight() const
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
sal_uInt8 GetRed() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
long FRound(double fVal)
Scanline GetScanline(long nY) const
BitmapInfoAccess * AcquireInfoAccess()
void SetEntryCount(sal_uInt16 nCount)
constexpr::Color COL_LIGHTGREEN(0x00, 0xFF, 0x00)
long Height() const
bool operator==(const Bitmap &rBitmap) const
constexpr::Color COL_RED(0x80, 0x00, 0x00)
sal_uIntPtr sal_uLong
ErrCode compressAsPNG(const Graphic &rGraphic, SvStream &rOutputStream)
Size maPrefSize
Definition: bitmap.hxx:542
constexpr::Color COL_GRAY(0x80, 0x80, 0x80)
Class to import and export graphic formats.
constexpr::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
BitmapReadAccess * AcquireReadAccess()
sal_uInt16 GetBestPaletteIndex(const BitmapColor &rBitmapColor) const
Definition: bmpacc.cxx:79
constexpr::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
This template handles BitmapAccess the RAII way.
Size GetSizePixel() const
long Width() const
bool Expand(sal_uLong nDX, sal_uLong nDY, const Color *pInitColor=nullptr)
Expand the bitmap by pixel padding.
constexpr::Color COL_YELLOW(0xFF, 0xFF, 0x00)
constexpr::Color COL_MAGENTA(0x80, 0x00, 0x80)
bool IsEmpty() const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
constexpr::Color COL_LIGHTCYAN(0x00, 0xFF, 0xFF)
bool HasGreyPalette8Bit() const
constexpr::Color COL_CYAN(0x00, 0x80, 0x80)
int nCount
void SetPixelOnData(sal_uInt8 *pData, long nX, const BitmapColor &rBitmapColor)
long Top() const
sal_uInt8 GetBlue() const
Bitmap & operator=(const Bitmap &rBitmap)
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
sal_uInt16 GetEntryCount() const
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
Bitmap CreateDisplayBitmap(OutputDevice *pDisplay) const
int i
bool HasPalette() const
BitmapChecksum GetChecksum() const
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:302
bool GetSystemData(BitmapSystemData &rData) const
get system dependent bitmap data
static void ReleaseAccess(BitmapInfoAccess *pAccess)
constexpr::Color COL_LIGHTMAGENTA(0xFF, 0x00, 0xFF)
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()
sal_uInt8 GetGreen() const
virtual std::shared_ptr< SalBitmap > CreateSalBitmap()=0
long Height() const
unsigned char sal_uInt8
constexpr::Color COL_GREEN(0x00, 0x80, 0x00)
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: bitmap3.cxx:229
bool HasGreyPaletteAny() const
const BitmapPalette & GetPalette() const
SalGraphics const * GetGraphics() const
Get the graphic context that the output device uses to draw on.
Definition: outdev.cxx:198
BitmapWriteAccess * AcquireWriteAccess()
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
long Left() const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, long nX) const
std::vector< BitmapColor > maBitmapColor
constexpr::Color COL_LIGHTBLUE(0x00, 0x00, 0xFF)
SAL_DLLPRIVATE void ImplMakeUnique()
static GraphicFilter & GetGraphicFilter()
MapUnit
void CopyScanline(long nY, const BitmapReadAccess &rReadAcc)
Definition: bmpacc.cxx:334
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:541
void setWidth(long nWidth)
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)
virtual ~Bitmap()
void SetPaletteColor(sal_uInt16 nColor, const BitmapColor &rBitmapColor)
std::shared_ptr< SalBitmap > mxSalBmp
Definition: bitmap.hxx:540
SalInstance * mpDefInst
Definition: svdata.hxx:381
static const BitmapPalette & GetGreyPalette(int nEntries)
bool IsGreyPaletteAny() const
Returns true if the palette is a grey palette (may not be 8-bit).
SAL_DLLPRIVATE void ImplSetSalBitmap(const std::shared_ptr< SalBitmap > &xImpBmp)
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, long nX) const
void setHeight(long nHeight)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo