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