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