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
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 ) \
30case( ScanlineFormat::Format ): \
31{ \
32 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
33 pDstBuffer->mnBitCount = BitCount; \
34} \
35break
36
37#define DOUBLE_SCANLINES() \
38while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
39{ \
40 memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
41 nActY++; \
42}
43
44constexpr 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
53static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
54 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
55 Scanline* pSrcScanMap, Scanline* pDstScanMap, sal_Int32 const * pMapX, const sal_Int32* 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();
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
86static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
87 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
88 Scanline* pSrcScanMap, Scanline* pDstScanMap, sal_Int32 const * pMapX, const sal_Int32* 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
145static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
146 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
147 Scanline* pSrcScanMap, Scanline* pDstScanMap, sal_Int32 const * pMapX, const sal_Int32* 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
190static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
191 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
192 Scanline* pSrcScanMap, Scanline* pDstScanMap, sal_Int32 const * pMapX, const sal_Int32* 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
229std::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 {
261
262 default:
263 // should never come here
264 // initialize pFncSetPixel to something valid that is
265 // least likely to crash
267 pDstBuffer->mnBitCount = 1;
268 OSL_FAIL( "unknown write format" );
269 break;
270 }
271
272 // fill destination buffer
273 pDstBuffer->mnFormat = nDstBitmapFormat;
274 pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
275 pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
276 tools::Long nScanlineBase;
277 bool bFail = o3tl::checked_multiply<tools::Long>(pDstBuffer->mnBitCount, pDstBuffer->mnWidth, nScanlineBase);
278 if (bFail)
279 {
280 SAL_WARN("vcl.gdi", "checked multiply failed");
281 pDstBuffer->mpBits = nullptr;
282 return nullptr;
283 }
284 pDstBuffer->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
285 if (pDstBuffer->mnScanlineSize < nScanlineBase/8)
286 {
287 SAL_WARN("vcl.gdi", "scanline calculation wraparound");
288 pDstBuffer->mpBits = nullptr;
289 return nullptr;
290 }
291 try
292 {
293 pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
294 }
295 catch( const std::bad_alloc& )
296 {
297 // memory exception, clean up
298 pDstBuffer->mpBits = nullptr;
299 return nullptr;
300 }
301
302 // do we need a destination palette or color mask?
303 if( ( nDstScanlineFormat == ScanlineFormat::N1BitMsbPal ) ||
304 ( nDstScanlineFormat == ScanlineFormat::N8BitPal ) )
305 {
306 assert(pDstPal && "destination buffer requires palette");
307 if (!pDstPal)
308 {
309 return nullptr;
310 }
311 pDstBuffer->maPalette = *pDstPal;
312 }
313 else if(nDstScanlineFormat == ScanlineFormat::N32BitTcMask )
314 {
315 assert(pDstMask && "destination buffer requires color mask");
316 if (!pDstMask)
317 {
318 return nullptr;
319 }
320 pDstBuffer->maColorMask = *pDstMask;
321 }
322
323 // short circuit the most important conversions
324 bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
325 if( bFastConvert )
326 return pDstBuffer;
327
328 std::unique_ptr<Scanline[]> pSrcScan;
329 std::unique_ptr<Scanline[]> pDstScan;
330 std::unique_ptr<sal_Int32[]> pMapX;
331 std::unique_ptr<sal_Int32[]> pMapY;
332
333 try
334 {
335 pSrcScan.reset(new Scanline[rSrcBuffer.mnHeight]);
336 pDstScan.reset(new Scanline[pDstBuffer->mnHeight]);
337 pMapX.reset(new sal_Int32[pDstBuffer->mnWidth]);
338 pMapY.reset(new sal_Int32[pDstBuffer->mnHeight]);
339 }
340 catch( const std::bad_alloc& )
341 {
342 // memory exception, clean up
343 // remark: the buffer ptr causing the exception
344 // is still NULL here
345 return nullptr;
346 }
347
348 // horizontal mapping table
349 if( (pDstBuffer->mnWidth != rTwoRect.mnSrcWidth) && (pDstBuffer->mnWidth != 0) )
350 {
351 const double fFactorX = static_cast<double>(rTwoRect.mnSrcWidth) / pDstBuffer->mnWidth;
352
353 for (tools::Long i = 0; i < pDstBuffer->mnWidth; ++i)
354 pMapX[ i ] = rTwoRect.mnSrcX + static_cast<int>( i * fFactorX );
355 }
356 else
357 {
358 for (tools::Long i = 0, nTmp = rTwoRect.mnSrcX ; i < pDstBuffer->mnWidth; ++i)
359 pMapX[ i ] = nTmp++;
360 }
361
362 // vertical mapping table
363 if( (pDstBuffer->mnHeight != rTwoRect.mnSrcHeight) && (pDstBuffer->mnHeight != 0) )
364 {
365 const double fFactorY = static_cast<double>(rTwoRect.mnSrcHeight) / pDstBuffer->mnHeight;
366
367 for (tools::Long i = 0; i < pDstBuffer->mnHeight; ++i)
368 pMapY[ i ] = rTwoRect.mnSrcY + static_cast<int>( i * fFactorY );
369 }
370 else
371 {
372 for (tools::Long i = 0, nTmp = rTwoRect.mnSrcY; i < pDstBuffer->mnHeight; ++i)
373 pMapY[ i ] = nTmp++;
374 }
375
376 // source scanline buffer
377 Scanline pTmpScan;
378 tools::Long nOffset;
379 if( rSrcBuffer.mnFormat & ScanlineFormat::TopDown )
380 {
381 pTmpScan = rSrcBuffer.mpBits;
382 nOffset = rSrcBuffer.mnScanlineSize;
383 }
384 else
385 {
386 pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
387 nOffset = -rSrcBuffer.mnScanlineSize;
388 }
389
390 for (tools::Long i = 0; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset)
391 pSrcScan[ i ] = pTmpScan;
392
393 // destination scanline buffer
394 if( pDstBuffer->mnFormat & ScanlineFormat::TopDown )
395 {
396 pTmpScan = pDstBuffer->mpBits;
397 nOffset = pDstBuffer->mnScanlineSize;
398 }
399 else
400 {
401 pTmpScan = pDstBuffer->mpBits + ( pDstBuffer->mnHeight - 1 ) * pDstBuffer->mnScanlineSize;
402 nOffset = -pDstBuffer->mnScanlineSize;
403 }
404
405 for (tools::Long i = 0; i < pDstBuffer->mnHeight; i++, pTmpScan += nOffset)
406 pDstScan[ i ] = pTmpScan;
407
408 // do buffer scaling and conversion
409 if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
410 {
411 ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
412 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
413 }
414 else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
415 {
416 ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
417 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
418 }
419 else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
420 {
421 ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
422 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
423 }
424 else
425 {
426 ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
427 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
428 }
429
430 return pDstBuffer;
431}
432
433/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void(* FncSetPixel)(Scanline pScanline, tools::Long nX, const BitmapColor &rBitmapColor, const ColorMask &rMask)
BitmapColor(* FncGetPixel)(ConstScanline pScanline, tools::Long nX, const ColorMask &rMask)
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
ScanlineFormat
Definition: Scanline.hxx:29
ScanlineFormat RemoveScanline(ScanlineFormat nFormat)
Definition: Scanline.hxx:53
bool ImplFastBitmapConversion(BitmapBuffer &rDst, const BitmapBuffer &rSrc, const SalTwoRect &rTR)
Definition: bmpfast.cxx:370
sal_uInt16 GetEntryCount() const
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
SAL_DLLPRIVATE const BitmapColor * ImplGetColorBuffer() const
static FncGetPixel GetPixelFunction(ScanlineFormat nFormat)
static void SetPixelForN1BitMsbPal(Scanline pScanline, tools::Long nX, const BitmapColor &rBitmapColor, const ColorMask &rMask)
static BitmapColor GetPixelForN1BitMsbPal(ConstScanline pScanline, tools::Long nX, const ColorMask &rMask)
sal_uInt8 GetBlue() const
void SetGreen(sal_uInt8 nGreen)
void SetRed(sal_uInt8 nRed)
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
void SetBlue(sal_uInt8 nBlue)
std::deque< AttacherIndex_Impl > aIndex
sal_uInt32 AlignedWidth4Bytes(sal_uInt32 nWidthBits)
#define SAL_WARN(area, stream)
int i
long Long
static void ImplTCToTC(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, sal_Int32 const *pMapX, const sal_Int32 *pMapY)
Definition: salmisc.cxx:145
constexpr int TC_TO_PAL_COLORS
Definition: salmisc.cxx:44
#define IMPL_CASE_SET_FORMAT(Format, BitCount)
Definition: salmisc.cxx:29
static tools::Long ImplIndexFromColor(const BitmapColor &rCol)
Definition: salmisc.cxx:46
static void ImplPALToPAL(const BitmapBuffer &rSrcBuffer, BitmapBuffer &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, sal_Int32 const *pMapX, const sal_Int32 *pMapY)
Definition: salmisc.cxx:53
#define DOUBLE_SCANLINES()
Definition: salmisc.cxx:37
static void ImplPALToTC(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, sal_Int32 const *pMapX, const sal_Int32 *pMapY)
Definition: salmisc.cxx:86
static void ImplTCToPAL(const BitmapBuffer &rSrcBuffer, BitmapBuffer const &rDstBuffer, FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, Scanline *pSrcScanMap, Scanline *pDstScanMap, sal_Int32 const *pMapX, const sal_Int32 *pMapY)
Definition: salmisc.cxx:190
std::unique_ptr< BitmapBuffer > StretchAndConvert(const BitmapBuffer &rSrcBuffer, const SalTwoRect &rTwoRect, ScanlineFormat nDstBitmapFormat, std::optional< BitmapPalette > pDstPal, const ColorMask *pDstMask)
Definition: salmisc.cxx:229
double mnWidth
double mnHeight
BitmapPalette maPalette
tools::Long mnWidth
sal_uInt8 * mpBits
tools::Long mnScanlineSize
sal_uInt16 mnBitCount
ColorMask maColorMask
ScanlineFormat mnFormat
tools::Long mnHeight
tools::Long mnSrcX
Definition: salgtype.hxx:39
tools::Long mnDestWidth
Definition: salgtype.hxx:45
tools::Long mnSrcHeight
Definition: salgtype.hxx:42
tools::Long mnSrcWidth
Definition: salgtype.hxx:41
tools::Long mnSrcY
Definition: salgtype.hxx:40
tools::Long mnDestHeight
Definition: salgtype.hxx:46
unsigned char sal_uInt8