LibreOffice Module vcl (master)  1
salmisc.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 <vcl/BitmapReadAccess.hxx>
21 #include <vcl/salgtype.hxx>
22 #include <bitmap/bmpfast.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <sal/log.hxx>
26 #include <tools/helpers.hxx>
27 #include <memory>
28 
29 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
30 case( ScanlineFormat::Format ): \
31 { \
32  pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
33  pDstBuffer->mnBitCount = BitCount; \
34 } \
35 break
36 
37 #define DOUBLE_SCANLINES() \
38 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
39 { \
40  memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
41  nActY++; \
42 }
43 
44 constexpr int TC_TO_PAL_COLORS = 4096;
45 
47 {
48  return ( ( static_cast<tools::Long>(rCol.GetBlue()) >> 4) << 8 ) |
49  ( ( static_cast<tools::Long>(rCol.GetGreen()) >> 4 ) << 4 ) |
50  ( static_cast<tools::Long>(rCol.GetRed()) >> 4 );
51 }
52 
53 static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
54  FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
55  Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
56 {
57  const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
58  const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
59  const ColorMask& rDstMask = rDstBuffer.maColorMask;
60  BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
61  BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer();
62  BitmapColor aIndex( 0 );
63 
64  for( sal_uInt16 i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
65  {
66  if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
67  aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(i) );
68  else
69  aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
70 
71  pColMapBuf[ i ] = aIndex;
72  }
73 
74  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
75  {
76  tools::Long nMapY = pMapY[nActY];
77  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
78 
79  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
80  pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
81 
83  }
84 }
85 
86 static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
87  FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
88  Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
89 {
90  const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
91  const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
92  const ColorMask& rDstMask = rDstBuffer.maColorMask;
93  const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
94 
96  {
97  const BitmapColor aCol0( pColBuf[ 0 ] );
98  const BitmapColor aCol1( pColBuf[ 1 ] );
99  tools::Long nMapX;
100 
101  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
102  {
103  tools::Long nMapY = pMapY[nActY];
104  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
105 
106  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth;)
107  {
108  nMapX = pMapX[ nX ];
109  pFncSetPixel( pDstScan, nX++,
110  pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
111  rDstMask );
112  }
113 
115  }
116  }
117  else if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N8BitPal )
118  {
119  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
120  {
121  tools::Long nMapY = pMapY[nActY];
122  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
123 
124  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
125  pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
126 
128  }
129  }
130  else
131  {
132  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
133  {
134  tools::Long nMapY = pMapY[nActY];
135  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
136 
137  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
138  pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
139 
141  }
142  }
143 }
144 
145 static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
146  FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
147  Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
148 {
149  const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
150  const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
151  const ColorMask& rDstMask = rDstBuffer.maColorMask;
152 
154  {
155  BitmapColor aCol;
156  sal_uInt8* pPixel = nullptr;
157 
158  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
159  {
160  tools::Long nMapY = pMapY[nActY];
161  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
162 
163  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
164  {
165  pPixel = pSrcScan + pMapX[ nX ] * 3;
166  aCol.SetBlue( *pPixel++ );
167  aCol.SetGreen( *pPixel++ );
168  aCol.SetRed( *pPixel );
169  pFncSetPixel( pDstScan, nX, aCol, rDstMask );
170  }
171 
173  }
174  }
175  else
176  {
177  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
178  {
179  tools::Long nMapY = pMapY[nActY];
180  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
181 
182  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
183  pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
184 
186  }
187  }
188 }
189 
190 static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
191  FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
192  Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
193 {
194  const tools::Long nHeight1 = rDstBuffer.mnHeight- 1;
195  const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
196  const ColorMask& rDstMask = rDstBuffer.maColorMask;
197  std::unique_ptr<sal_uInt8[]> pColToPalMap(new sal_uInt8[ TC_TO_PAL_COLORS ]);
198  BitmapColor aIndex( 0 );
199 
200  for( tools::Long nR = 0; nR < 16; nR++ )
201  {
202  for( tools::Long nG = 0; nG < 16; nG++ )
203  {
204  for( tools::Long nB = 0; nB < 16; nB++ )
205  {
206  BitmapColor aCol( sal::static_int_cast<sal_uInt8>(nR << 4),
207  sal::static_int_cast<sal_uInt8>(nG << 4),
208  sal::static_int_cast<sal_uInt8>(nB << 4) );
209  pColToPalMap[ ImplIndexFromColor( aCol ) ] = static_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( aCol ));
210  }
211  }
212  }
213 
214  for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
215  {
216  tools::Long nMapY = pMapY[nActY];
217  Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
218 
219  for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
220  {
221  aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
222  pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
223  }
224 
226  }
227 }
228 
229 std::unique_ptr<BitmapBuffer> StretchAndConvert(
230  const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
231  ScanlineFormat nDstBitmapFormat, std::optional<BitmapPalette> pDstPal, const ColorMask* pDstMask )
232 {
233  FncGetPixel pFncGetPixel;
234  FncSetPixel pFncSetPixel;
235  std::unique_ptr<BitmapBuffer> pDstBuffer(new BitmapBuffer);
236 
237  // set function for getting pixels
238  pFncGetPixel = BitmapReadAccess::GetPixelFunction( rSrcBuffer.mnFormat );
239  if( !pFncGetPixel )
240  {
241  // should never come here
242  // initialize pFncGetPixel to something valid that is
243  // least likely to crash
245  OSL_FAIL( "unknown read format" );
246  }
247 
248  // set function for setting pixels
249  const ScanlineFormat nDstScanlineFormat = RemoveScanline( nDstBitmapFormat );
250  switch( nDstScanlineFormat )
251  {
262 
263  default:
264  // should never come here
265  // initialize pFncSetPixel to something valid that is
266  // least likely to crash
268  pDstBuffer->mnBitCount = 1;
269  OSL_FAIL( "unknown write format" );
270  break;
271  }
272 
273  // fill destination buffer
274  pDstBuffer->mnFormat = nDstBitmapFormat;
275  pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
276  pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
277  tools::Long nScanlineBase;
278  bool bFail = o3tl::checked_multiply<tools::Long>(pDstBuffer->mnBitCount, pDstBuffer->mnWidth, nScanlineBase);
279  if (bFail)
280  {
281  SAL_WARN("vcl.gdi", "checked multiply failed");
282  pDstBuffer->mpBits = nullptr;
283  return nullptr;
284  }
285  pDstBuffer->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
286  if (pDstBuffer->mnScanlineSize < nScanlineBase/8)
287  {
288  SAL_WARN("vcl.gdi", "scanline calculation wraparound");
289  pDstBuffer->mpBits = nullptr;
290  return nullptr;
291  }
292  try
293  {
294  pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
295  }
296  catch( const std::bad_alloc& )
297  {
298  // memory exception, clean up
299  pDstBuffer->mpBits = nullptr;
300  return nullptr;
301  }
302 
303  // do we need a destination palette or color mask?
304  if( ( nDstScanlineFormat == ScanlineFormat::N1BitMsbPal ) ||
305  ( nDstScanlineFormat == ScanlineFormat::N1BitLsbPal ) ||
306  ( nDstScanlineFormat == ScanlineFormat::N8BitPal ) )
307  {
308  assert(pDstPal && "destination buffer requires palette");
309  if (!pDstPal)
310  {
311  return nullptr;
312  }
313  pDstBuffer->maPalette = *pDstPal;
314  }
315  else if(nDstScanlineFormat == ScanlineFormat::N32BitTcMask )
316  {
317  assert(pDstMask && "destination buffer requires color mask");
318  if (!pDstMask)
319  {
320  return nullptr;
321  }
322  pDstBuffer->maColorMask = *pDstMask;
323  }
324 
325  // short circuit the most important conversions
326  bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
327  if( bFastConvert )
328  return pDstBuffer;
329 
330  std::unique_ptr<Scanline[]> pSrcScan;
331  std::unique_ptr<Scanline[]> pDstScan;
332  std::unique_ptr<tools::Long[]> pMapX;
333  std::unique_ptr<tools::Long[]> pMapY;
334 
335  try
336  {
337  pSrcScan.reset(new Scanline[rSrcBuffer.mnHeight]);
338  pDstScan.reset(new Scanline[pDstBuffer->mnHeight]);
339  pMapX.reset(new tools::Long[pDstBuffer->mnWidth]);
340  pMapY.reset(new tools::Long[pDstBuffer->mnHeight]);
341  }
342  catch( const std::bad_alloc& )
343  {
344  // memory exception, clean up
345  // remark: the buffer ptr causing the exception
346  // is still NULL here
347  return nullptr;
348  }
349 
350  // horizontal mapping table
351  if( (pDstBuffer->mnWidth != rTwoRect.mnSrcWidth) && (pDstBuffer->mnWidth != 0) )
352  {
353  const double fFactorX = static_cast<double>(rTwoRect.mnSrcWidth) / pDstBuffer->mnWidth;
354 
355  for (tools::Long i = 0; i < pDstBuffer->mnWidth; ++i)
356  pMapX[ i ] = rTwoRect.mnSrcX + static_cast<int>( i * fFactorX );
357  }
358  else
359  {
360  for (tools::Long i = 0, nTmp = rTwoRect.mnSrcX ; i < pDstBuffer->mnWidth; ++i)
361  pMapX[ i ] = nTmp++;
362  }
363 
364  // vertical mapping table
365  if( (pDstBuffer->mnHeight != rTwoRect.mnSrcHeight) && (pDstBuffer->mnHeight != 0) )
366  {
367  const double fFactorY = static_cast<double>(rTwoRect.mnSrcHeight) / pDstBuffer->mnHeight;
368 
369  for (tools::Long i = 0; i < pDstBuffer->mnHeight; ++i)
370  pMapY[ i ] = rTwoRect.mnSrcY + static_cast<int>( i * fFactorY );
371  }
372  else
373  {
374  for (tools::Long i = 0, nTmp = rTwoRect.mnSrcY; i < pDstBuffer->mnHeight; ++i)
375  pMapY[ i ] = nTmp++;
376  }
377 
378  // source scanline buffer
379  Scanline pTmpScan;
380  tools::Long nOffset;
381  if( rSrcBuffer.mnFormat & ScanlineFormat::TopDown )
382  {
383  pTmpScan = rSrcBuffer.mpBits;
384  nOffset = rSrcBuffer.mnScanlineSize;
385  }
386  else
387  {
388  pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
389  nOffset = -rSrcBuffer.mnScanlineSize;
390  }
391 
392  for (tools::Long i = 0; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset)
393  pSrcScan[ i ] = pTmpScan;
394 
395  // destination scanline buffer
396  if( pDstBuffer->mnFormat & ScanlineFormat::TopDown )
397  {
398  pTmpScan = pDstBuffer->mpBits;
399  nOffset = pDstBuffer->mnScanlineSize;
400  }
401  else
402  {
403  pTmpScan = pDstBuffer->mpBits + ( pDstBuffer->mnHeight - 1 ) * pDstBuffer->mnScanlineSize;
404  nOffset = -pDstBuffer->mnScanlineSize;
405  }
406 
407  for (tools::Long i = 0; i < pDstBuffer->mnHeight; i++, pTmpScan += nOffset)
408  pDstScan[ i ] = pTmpScan;
409 
410  // do buffer scaling and conversion
411  if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
412  {
413  ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
414  pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
415  }
416  else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
417  {
418  ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
419  pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
420  }
421  else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
422  {
423  ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
424  pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
425  }
426  else
427  {
428  ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
429  pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
430  }
431 
432  return pDstBuffer;
433 }
434 
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double mnHeight
#define IMPL_CASE_SET_FORMAT(Format, BitCount)
Definition: salmisc.cxx:29
static BitmapColor GetPixelForN1BitMsbPal(ConstScanline pScanline, tools::Long nX, const ColorMask &rMask)
sal_uInt8 GetRed() const
ColorMask maColorMask
void SetBlue(sal_uInt8 nBlue)
sal_uInt32 AlignedWidth4Bytes(sal_uInt32 nWidthBits)
tools::Long mnHeight
long Long
tools::Long mnSrcHeight
Definition: salgtype.hxx:43
SAL_DLLPRIVATE const BitmapColor * ImplGetColorBuffer() const
tools::Long mnSrcWidth
Definition: salgtype.hxx:42
tools::Long mnDestWidth
Definition: salgtype.hxx:46
sal_uInt16 mnBitCount
ScanlineFormat
Definition: Scanline.hxx:29
static void SetPixelForN1BitMsbPal(Scanline pScanline, tools::Long nX, const BitmapColor &rBitmapColor, const ColorMask &rMask)
void(* FncSetPixel)(Scanline pScanline, tools::Long nX, const BitmapColor &rBitmapColor, const ColorMask &rMask)
sal_uInt8 GetBlue() const
ScanlineFormat mnFormat
tools::Long mnDestHeight
Definition: salgtype.hxx:47
sal_uInt16 GetEntryCount() const
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
int i
void SetRed(sal_uInt8 nRed)
sal_uInt8 * mpBits
tools::Long mnSrcX
Definition: salgtype.hxx:40
tools::Long mnSrcY
Definition: salgtype.hxx:41
static void ImplPALToTC(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, tools::Long const *pMapX, const tools::Long *pMapY)
Definition: salmisc.cxx:86
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
void SetIndex(sal_uInt8 cIndex)
Definition: BitmapColor.hxx:75
static void ImplTCToPAL(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, tools::Long const *pMapX, const tools::Long *pMapY)
Definition: salmisc.cxx:190
sal_uInt8 GetGreen() const
static FncGetPixel GetPixelFunction(ScanlineFormat nFormat)
constexpr int TC_TO_PAL_COLORS
Definition: salmisc.cxx:44
std::deque< AttacherIndex_Impl > aIndex
tools::Long mnScanlineSize
static void ImplPALToPAL(const BitmapBuffer &rSrcBuffer, BitmapBuffer &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, tools::Long const *pMapX, const tools::Long *pMapY)
Definition: salmisc.cxx:53
unsigned char sal_uInt8
void SetGreen(sal_uInt8 nGreen)
#define DOUBLE_SCANLINES()
Definition: salmisc.cxx:37
static tools::Long ImplIndexFromColor(const BitmapColor &rCol)
Definition: salmisc.cxx:46
double mnWidth
ScanlineFormat RemoveScanline(ScanlineFormat nFormat)
Definition: Scanline.hxx:54
BitmapPalette maPalette
std::unique_ptr< BitmapBuffer > StretchAndConvert(const BitmapBuffer &rSrcBuffer, const SalTwoRect &rTwoRect, ScanlineFormat nDstBitmapFormat, std::optional< BitmapPalette > pDstPal, const ColorMask *pDstMask)
Definition: salmisc.cxx:229
#define SAL_WARN(area, stream)
BitmapColor(* FncGetPixel)(ConstScanline pScanline, tools::Long nX, const ColorMask &rMask)
tools::Long mnWidth
static void ImplTCToTC(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, tools::Long const *pMapX, const tools::Long *pMapY)
Definition: salmisc.cxx:145
bool ImplFastBitmapConversion(BitmapBuffer &rDst, const BitmapBuffer &rSrc, const SalTwoRect &rTR)
Definition: bmpfast.cxx:371