1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vclhelperbitmaptransform.hxx>
21 #include <vcl/bmpacc.hxx>
22 #include <basegfx/point/b2dpoint.hxx>
23 #include <basegfx/color/bcolormodifier.hxx>
25 //////////////////////////////////////////////////////////////////////////////
26 // support for rendering Bitmap and BitmapEx contents
28 namespace drawinglayer
32 void impSmoothPoint(BitmapColor
& rValue
, const basegfx::B2DPoint
& rSource
, sal_Int32 nIntX
, sal_Int32 nIntY
, BitmapReadAccess
& rRead
)
34 double fDeltaX(rSource
.getX() - nIntX
);
35 double fDeltaY(rSource
.getY() - nIntY
);
39 if(fDeltaX
> 0.0 && nIntX
+ 1L < rRead
.Width())
43 else if(fDeltaX
< 0.0 && nIntX
>= 1L)
49 if(fDeltaY
> 0.0 && nIntY
+ 1L < rRead
.Height())
53 else if(fDeltaY
< 0.0 && nIntY
>= 1L)
61 const double fColorToReal(1.0 / 255.0);
62 double fR(rValue
.GetRed() * fColorToReal
);
63 double fG(rValue
.GetGreen() * fColorToReal
);
64 double fB(rValue
.GetBlue() * fColorToReal
);
65 double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
69 const double fMulA(fDeltaX
* fColorToReal
);
70 double fMulB(1.0 - fDeltaX
);
71 const BitmapColor
aTopPartner(rRead
.GetColor(nIntY
, nIntX
+ nIndX
));
73 fR
= (fR
* fMulB
) + (aTopPartner
.GetRed() * fMulA
);
74 fG
= (fG
* fMulB
) + (aTopPartner
.GetGreen() * fMulA
);
75 fB
= (fB
* fMulB
) + (aTopPartner
.GetBlue() * fMulA
);
79 fMulB
*= fColorToReal
;
80 const BitmapColor
aBottom(rRead
.GetColor(nIntY
+ nIndY
, nIntX
));
81 const BitmapColor
aBottomPartner(rRead
.GetColor(nIntY
+ nIndY
, nIntX
+ nIndX
));
83 fRBottom
= (aBottom
.GetRed() * fMulB
) + (aBottomPartner
.GetRed() * fMulA
);
84 fGBottom
= (aBottom
.GetGreen() * fMulB
) + (aBottomPartner
.GetGreen() * fMulA
);
85 fBBottom
= (aBottom
.GetBlue() * fMulB
) + (aBottomPartner
.GetBlue() * fMulA
);
93 const BitmapColor
aBottom(rRead
.GetColor(nIntY
+ nIndY
, nIntX
));
95 fRBottom
= aBottom
.GetRed() * fColorToReal
;
96 fGBottom
= aBottom
.GetGreen() * fColorToReal
;
97 fBBottom
= aBottom
.GetBlue() * fColorToReal
;
100 const double fMulB(1.0 - fDeltaY
);
102 fR
= (fR
* fMulB
) + (fRBottom
* fDeltaY
);
103 fG
= (fG
* fMulB
) + (fGBottom
* fDeltaY
);
104 fB
= (fB
* fMulB
) + (fBBottom
* fDeltaY
);
107 rValue
.SetRed((sal_uInt8
)(fR
* 255.0));
108 rValue
.SetGreen((sal_uInt8
)(fG
* 255.0));
109 rValue
.SetBlue((sal_uInt8
)(fB
* 255.0));
113 void impSmoothIndex(BitmapColor
& rValue
, const basegfx::B2DPoint
& rSource
, sal_Int32 nIntX
, sal_Int32 nIntY
, BitmapReadAccess
& rRead
)
115 double fDeltaX(rSource
.getX() - nIntX
);
116 double fDeltaY(rSource
.getY() - nIntY
);
120 if(fDeltaX
> 0.0 && nIntX
+ 1L < rRead
.Width())
124 else if(fDeltaX
< 0.0 && nIntX
>= 1L)
130 if(fDeltaY
> 0.0 && nIntY
+ 1L < rRead
.Height())
134 else if(fDeltaY
< 0.0 && nIntY
>= 1L)
142 const double fColorToReal(1.0 / 255.0);
143 double fVal(rValue
.GetIndex() * fColorToReal
);
144 double fValBottom(0.0);
148 const double fMulA(fDeltaX
* fColorToReal
);
149 double fMulB(1.0 - fDeltaX
);
150 const BitmapColor
aTopPartner(rRead
.GetPixel(nIntY
, nIntX
+ nIndX
));
152 fVal
= (fVal
* fMulB
) + (aTopPartner
.GetIndex() * fMulA
);
156 fMulB
*= fColorToReal
;
157 const BitmapColor
aBottom(rRead
.GetPixel(nIntY
+ nIndY
, nIntX
));
158 const BitmapColor
aBottomPartner(rRead
.GetPixel(nIntY
+ nIndY
, nIntX
+ nIndX
));
160 fValBottom
= (aBottom
.GetIndex() * fMulB
) + (aBottomPartner
.GetIndex() * fMulA
);
168 const BitmapColor
aBottom(rRead
.GetPixel(nIntY
+ nIndY
, nIntX
));
170 fValBottom
= aBottom
.GetIndex() * fColorToReal
;
173 const double fMulB(1.0 - fDeltaY
);
175 fVal
= (fVal
* fMulB
) + (fValBottom
* fDeltaY
);
178 rValue
.SetIndex((sal_uInt8
)(fVal
* 255.0));
182 void impTransformBitmap(const Bitmap
& rSource
, Bitmap
& rDestination
, const basegfx::B2DHomMatrix
& rTransform
, bool bSmooth
)
184 BitmapWriteAccess
* pWrite
= rDestination
.AcquireWriteAccess();
188 const Size
aContentSizePixel(rSource
.GetSizePixel());
189 BitmapReadAccess
* pRead
= (const_cast< Bitmap
& >(rSource
)).AcquireReadAccess();
193 const Size
aDestinationSizePixel(rDestination
.GetSizePixel());
194 bool bWorkWithIndex(rDestination
.GetBitCount() <= 8);
195 BitmapColor
aOutside(pRead
->GetBestMatchingColor(BitmapColor(0xff, 0xff, 0xff)));
197 for(sal_Int32
y(0L); y
< aDestinationSizePixel
.getHeight(); y
++)
199 for(sal_Int32
x(0L); x
< aDestinationSizePixel
.getWidth(); x
++)
201 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
202 const sal_Int32
nIntX(basegfx::fround(aSourceCoor
.getX()));
204 if(nIntX
>= 0L && nIntX
< aContentSizePixel
.getWidth())
206 const sal_Int32
nIntY(basegfx::fround(aSourceCoor
.getY()));
208 if(nIntY
>= 0L && nIntY
< aContentSizePixel
.getHeight())
212 BitmapColor
aValue(pRead
->GetPixel(nIntY
, nIntX
));
216 impSmoothIndex(aValue
, aSourceCoor
, nIntX
, nIntY
, *pRead
);
219 pWrite
->SetPixel(y
, x
, aValue
);
223 BitmapColor
aValue(pRead
->GetColor(nIntY
, nIntX
));
227 impSmoothPoint(aValue
, aSourceCoor
, nIntX
, nIntY
, *pRead
);
230 pWrite
->SetPixel(y
, x
, aValue
.IsIndex() ? aValue
: pWrite
->GetBestMatchingColor(aValue
));
237 // here are outside pixels. Complete mask
240 pWrite
->SetPixel(y
, x
, aOutside
);
252 Bitmap
impCreateEmptyBitmapWithPattern(const Bitmap
& rSource
, const Size
& aTargetSizePixel
)
255 BitmapReadAccess
* pReadAccess
= (const_cast< Bitmap
& >(rSource
)).AcquireReadAccess();
259 if(rSource
.GetBitCount() <= 8)
261 BitmapPalette
aPalette(pReadAccess
->GetPalette());
262 aRetval
= Bitmap(aTargetSizePixel
, rSource
.GetBitCount(), &aPalette
);
266 aRetval
= Bitmap(aTargetSizePixel
, rSource
.GetBitCount());
274 } // end of anonymous namespace
275 } // end of namespace drawinglayer
277 namespace drawinglayer
279 BitmapEx
impTransformBitmapEx(
280 const BitmapEx
& rSource
,
281 const Rectangle
& rCroppedRectPixel
,
282 const basegfx::B2DHomMatrix
& rTransform
)
284 // force destination to 24 bit, we want to smooth output
285 const Size
aDestinationSize(rCroppedRectPixel
.GetSize());
286 Bitmap
aDestination(impCreateEmptyBitmapWithPattern(rSource
.GetBitmap(), aDestinationSize
));
287 static bool bDoSmoothAtAll(true);
288 impTransformBitmap(rSource
.GetBitmap(), aDestination
, rTransform
, bDoSmoothAtAll
);
291 if(rSource
.IsTransparent())
293 if(rSource
.IsAlpha())
295 Bitmap
aAlpha(impCreateEmptyBitmapWithPattern(rSource
.GetAlpha().GetBitmap(), aDestinationSize
));
296 impTransformBitmap(rSource
.GetAlpha().GetBitmap(), aAlpha
, rTransform
, bDoSmoothAtAll
);
297 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
301 Bitmap
aMask(impCreateEmptyBitmapWithPattern(rSource
.GetMask(), aDestinationSize
));
302 impTransformBitmap(rSource
.GetMask(), aMask
, rTransform
, false);
303 return BitmapEx(aDestination
, aMask
);
307 return BitmapEx(aDestination
);
310 BitmapEx
impModifyBitmapEx(
311 const basegfx::BColorModifierStack
& rBColorModifierStack
,
312 const BitmapEx
& rSource
)
314 Bitmap
aChangedBitmap(rSource
.GetBitmap());
317 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
319 const basegfx::BColorModifier
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
321 switch(rModifier
.getMode())
323 case basegfx::BCOLORMODIFYMODE_REPLACE
:
326 if(rSource
.IsTransparent())
328 // clear bitmap with dest color
329 if(aChangedBitmap
.GetBitCount() <= 8)
331 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
332 // erase color is determined and used -> this may be different from what is
333 // wanted here. Better create a new bitmap with the needed color explicitly
334 BitmapReadAccess
* pReadAccess
= aChangedBitmap
.AcquireReadAccess();
335 OSL_ENSURE(pReadAccess
, "Got no Bitmap ReadAccess ?!?");
339 BitmapPalette
aNewPalette(pReadAccess
->GetPalette());
340 aNewPalette
[0] = BitmapColor(Color(rModifier
.getBColor()));
341 aChangedBitmap
= Bitmap(
342 aChangedBitmap
.GetSizePixel(),
343 aChangedBitmap
.GetBitCount(),
350 aChangedBitmap
.Erase(Color(rModifier
.getBColor()));
355 // erase bitmap, caller will know to paint direct
356 aChangedBitmap
.SetEmpty();
363 default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
365 BitmapWriteAccess
* pContent
= aChangedBitmap
.AcquireWriteAccess();
369 const double fConvertColor(1.0 / 255.0);
371 for(sal_uInt32
y(0L); y
< (sal_uInt32
)pContent
->Height(); y
++)
373 for(sal_uInt32
x(0L); x
< (sal_uInt32
)pContent
->Width(); x
++)
375 const BitmapColor
aBMCol(pContent
->GetColor(y
, x
));
376 const basegfx::BColor
aBSource(
377 (double)aBMCol
.GetRed() * fConvertColor
,
378 (double)aBMCol
.GetGreen() * fConvertColor
,
379 (double)aBMCol
.GetBlue() * fConvertColor
);
380 const basegfx::BColor
aBDest(rModifier
.getModifiedColor(aBSource
));
382 pContent
->SetPixel(y
, x
, BitmapColor(Color(aBDest
)));
394 if(aChangedBitmap
.IsEmpty())
400 if(rSource
.IsTransparent())
402 if(rSource
.IsAlpha())
404 return BitmapEx(aChangedBitmap
, rSource
.GetAlpha());
408 return BitmapEx(aChangedBitmap
, rSource
.GetMask());
413 return BitmapEx(aChangedBitmap
);
417 } // end of namespace drawinglayer
419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */