125ea7f45SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 325ea7f45SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 425ea7f45SAndrew Rist * or more contributor license agreements. See the NOTICE file 525ea7f45SAndrew Rist * distributed with this work for additional information 625ea7f45SAndrew Rist * regarding copyright ownership. The ASF licenses this file 725ea7f45SAndrew Rist * to you under the Apache License, Version 2.0 (the 825ea7f45SAndrew Rist * "License"); you may not use this file except in compliance 925ea7f45SAndrew Rist * with the License. You may obtain a copy of the License at 1025ea7f45SAndrew Rist * 1125ea7f45SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 1225ea7f45SAndrew Rist * 1325ea7f45SAndrew Rist * Unless required by applicable law or agreed to in writing, 1425ea7f45SAndrew Rist * software distributed under the License is distributed on an 1525ea7f45SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1625ea7f45SAndrew Rist * KIND, either express or implied. See the License for the 1725ea7f45SAndrew Rist * specific language governing permissions and limitations 1825ea7f45SAndrew Rist * under the License. 1925ea7f45SAndrew Rist * 2025ea7f45SAndrew Rist *************************************************************/ 2125ea7f45SAndrew Rist 2225ea7f45SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_canvas.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <canvas/debug.hxx> 28cdf0e10cSrcweir #include <tools/diagnose_ex.h> 29cdf0e10cSrcweir 30cdf0e10cSrcweir #include <rtl/math.hxx> 31cdf0e10cSrcweir #include <rtl/logfile.hxx> 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <com/sun/star/geometry/RealSize2D.hpp> 34cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp> 35cdf0e10cSrcweir #include <com/sun/star/geometry/RealRectangle2D.hpp> 36cdf0e10cSrcweir #include <com/sun/star/rendering/RenderState.hpp> 37cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp> 38cdf0e10cSrcweir #include <com/sun/star/rendering/XBitmap.hpp> 39cdf0e10cSrcweir #include <com/sun/star/rendering/XPolyPolygon2D.hpp> 40cdf0e10cSrcweir #include <com/sun/star/geometry/RealBezierSegment2D.hpp> 41cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmap.hpp> 42cdf0e10cSrcweir 43cdf0e10cSrcweir #include <vcl/salbtype.hxx> 44cdf0e10cSrcweir #include <vcl/bmpacc.hxx> 45cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 46cdf0e10cSrcweir #include <vcl/metric.hxx> 47cdf0e10cSrcweir #include <vcl/canvastools.hxx> 48cdf0e10cSrcweir 49cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 50cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx> 51cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 52cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 53cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 54cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 55cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 56cdf0e10cSrcweir 57cdf0e10cSrcweir #include <canvas/canvastools.hxx> 58cdf0e10cSrcweir 59cdf0e10cSrcweir #include "impltools.hxx" 60cdf0e10cSrcweir #include "canvasbitmap.hxx" 61cdf0e10cSrcweir 62cdf0e10cSrcweir #include <numeric> 63cdf0e10cSrcweir 64cdf0e10cSrcweir 65cdf0e10cSrcweir using namespace ::com::sun::star; 66cdf0e10cSrcweir 67cdf0e10cSrcweir namespace vclcanvas 68cdf0e10cSrcweir { 69cdf0e10cSrcweir namespace tools 70cdf0e10cSrcweir { bitmapExFromXBitmap(const uno::Reference<rendering::XBitmap> & xBitmap)71cdf0e10cSrcweir ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) 72cdf0e10cSrcweir { 73cdf0e10cSrcweir // TODO(F3): CanvasCustomSprite should also be tunnelled 74cdf0e10cSrcweir // through (also implements XIntegerBitmap interface) 75cdf0e10cSrcweir CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() ); 76cdf0e10cSrcweir 77cdf0e10cSrcweir if( pBitmapImpl ) 78cdf0e10cSrcweir { 79cdf0e10cSrcweir return pBitmapImpl->getBitmap(); 80cdf0e10cSrcweir } 81cdf0e10cSrcweir else 82cdf0e10cSrcweir { 83cdf0e10cSrcweir SpriteCanvas* pCanvasImpl = dynamic_cast< SpriteCanvas* >( xBitmap.get() ); 84cdf0e10cSrcweir if( pCanvasImpl && pCanvasImpl->getBackBuffer() ) 85cdf0e10cSrcweir { 86cdf0e10cSrcweir // TODO(F3): mind the plain Canvas impl. Consolidate with CWS canvas05 87cdf0e10cSrcweir const ::OutputDevice& rDev( pCanvasImpl->getBackBuffer()->getOutDev() ); 88cdf0e10cSrcweir const ::Point aEmptyPoint; 89cdf0e10cSrcweir return rDev.GetBitmapEx( aEmptyPoint, 90cdf0e10cSrcweir rDev.GetOutputSizePixel() ); 91cdf0e10cSrcweir } 92cdf0e10cSrcweir 93cdf0e10cSrcweir // TODO(F2): add support for floating point bitmap formats 94cdf0e10cSrcweir uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp( 95cdf0e10cSrcweir xBitmap, uno::UNO_QUERY_THROW ); 96cdf0e10cSrcweir 97cdf0e10cSrcweir ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp ); 98cdf0e10cSrcweir if( !!aBmpEx ) 99cdf0e10cSrcweir return aBmpEx; 100cdf0e10cSrcweir 101cdf0e10cSrcweir // TODO(F1): extract pixel from XBitmap interface 102cdf0e10cSrcweir ENSURE_OR_THROW( false, 103cdf0e10cSrcweir "bitmapExFromXBitmap(): could not extract bitmap" ); 104cdf0e10cSrcweir } 105cdf0e10cSrcweir 106cdf0e10cSrcweir return ::BitmapEx(); 107cdf0e10cSrcweir } 108cdf0e10cSrcweir setupFontTransform(::Point & o_rPoint,::Font & io_rVCLFont,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState,::OutputDevice & rOutDev)109cdf0e10cSrcweir bool setupFontTransform( ::Point& o_rPoint, 110cdf0e10cSrcweir ::Font& io_rVCLFont, 111cdf0e10cSrcweir const rendering::ViewState& rViewState, 112cdf0e10cSrcweir const rendering::RenderState& rRenderState, 113cdf0e10cSrcweir ::OutputDevice& rOutDev ) 114cdf0e10cSrcweir { 115cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 116cdf0e10cSrcweir 117cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 118cdf0e10cSrcweir rViewState, 119cdf0e10cSrcweir rRenderState); 120cdf0e10cSrcweir 121cdf0e10cSrcweir ::basegfx::B2DTuple aScale; 122cdf0e10cSrcweir ::basegfx::B2DTuple aTranslate; 123cdf0e10cSrcweir double nRotate, nShearX; 124cdf0e10cSrcweir 125cdf0e10cSrcweir aMatrix.decompose( aScale, aTranslate, nRotate, nShearX ); 126cdf0e10cSrcweir 127cdf0e10cSrcweir // #i72417# detecting the 180 degree rotation case manually here. 128cdf0e10cSrcweir if( aScale.getX() < 0.0 && 129cdf0e10cSrcweir aScale.getY() < 0.0 && 130cdf0e10cSrcweir basegfx::fTools::equalZero(nRotate) ) 131cdf0e10cSrcweir { 132cdf0e10cSrcweir aScale *= -1.0; 133cdf0e10cSrcweir nRotate += M_PI; 134cdf0e10cSrcweir } 135cdf0e10cSrcweir 136cdf0e10cSrcweir // query font metric _before_ tampering with width and height 137cdf0e10cSrcweir if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) ) 138cdf0e10cSrcweir { 139cdf0e10cSrcweir // retrieve true font width 140cdf0e10cSrcweir const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() ); 141cdf0e10cSrcweir 142cdf0e10cSrcweir const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) ); 143cdf0e10cSrcweir 144cdf0e10cSrcweir if( !nScaledFontWidth ) 145cdf0e10cSrcweir { 146cdf0e10cSrcweir // scale is smaller than one pixel - disable text 147cdf0e10cSrcweir // output altogether 148cdf0e10cSrcweir return false; 149cdf0e10cSrcweir } 150cdf0e10cSrcweir 151cdf0e10cSrcweir io_rVCLFont.SetWidth( nScaledFontWidth ); 152cdf0e10cSrcweir } 153cdf0e10cSrcweir 154cdf0e10cSrcweir if( !::rtl::math::approxEqual(aScale.getY(), 1.0) ) 155cdf0e10cSrcweir { 156cdf0e10cSrcweir const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() ); 157cdf0e10cSrcweir io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) ); 158cdf0e10cSrcweir } 159cdf0e10cSrcweir 160cdf0e10cSrcweir io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) ); 161cdf0e10cSrcweir 162cdf0e10cSrcweir // TODO(F2): Missing functionality in VCL: shearing 163cdf0e10cSrcweir o_rPoint.X() = ::basegfx::fround(aTranslate.getX()); 164cdf0e10cSrcweir o_rPoint.Y() = ::basegfx::fround(aTranslate.getY()); 165cdf0e10cSrcweir 166cdf0e10cSrcweir return true; 167cdf0e10cSrcweir } 168cdf0e10cSrcweir isRectangle(const PolyPolygon & rPolyPoly)169cdf0e10cSrcweir bool isRectangle( const PolyPolygon& rPolyPoly ) 170cdf0e10cSrcweir { 171cdf0e10cSrcweir // exclude some cheap cases first 172cdf0e10cSrcweir if( rPolyPoly.Count() != 1 ) 173cdf0e10cSrcweir return false; 174cdf0e10cSrcweir 175cdf0e10cSrcweir const ::Polygon& rPoly( rPolyPoly[0] ); 176cdf0e10cSrcweir 177cdf0e10cSrcweir sal_uInt16 nCount( rPoly.GetSize() ); 178cdf0e10cSrcweir if( nCount < 4 ) 179cdf0e10cSrcweir return false; 180cdf0e10cSrcweir 181cdf0e10cSrcweir // delegate to basegfx 182cdf0e10cSrcweir return ::basegfx::tools::isRectangle( rPoly.getB2DPolygon() ); 183cdf0e10cSrcweir } 184cdf0e10cSrcweir 185cdf0e10cSrcweir 186cdf0e10cSrcweir // VCL-Canvas related 187cdf0e10cSrcweir //--------------------------------------------------------------------- 188cdf0e10cSrcweir mapRealPoint2D(const geometry::RealPoint2D & rPoint,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState)189cdf0e10cSrcweir ::Point mapRealPoint2D( const geometry::RealPoint2D& rPoint, 190cdf0e10cSrcweir const rendering::ViewState& rViewState, 191cdf0e10cSrcweir const rendering::RenderState& rRenderState ) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir ::basegfx::B2DPoint aPoint( ::basegfx::unotools::b2DPointFromRealPoint2D(rPoint) ); 194cdf0e10cSrcweir 195cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 196cdf0e10cSrcweir aPoint *= ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 197cdf0e10cSrcweir rViewState, 198cdf0e10cSrcweir rRenderState); 199cdf0e10cSrcweir 200cdf0e10cSrcweir return ::vcl::unotools::pointFromB2DPoint( aPoint ); 201cdf0e10cSrcweir } 202cdf0e10cSrcweir mapPolyPolygon(const::basegfx::B2DPolyPolygon & rPoly,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState)203cdf0e10cSrcweir ::PolyPolygon mapPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, 204cdf0e10cSrcweir const rendering::ViewState& rViewState, 205cdf0e10cSrcweir const rendering::RenderState& rRenderState ) 206cdf0e10cSrcweir { 207cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 208cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 209cdf0e10cSrcweir rViewState, 210cdf0e10cSrcweir rRenderState); 211cdf0e10cSrcweir 212cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aTemp( rPoly ); 213cdf0e10cSrcweir 214cdf0e10cSrcweir aTemp.transform( aMatrix ); 215cdf0e10cSrcweir 216cdf0e10cSrcweir return ::PolyPolygon( aTemp ); 217cdf0e10cSrcweir } 218cdf0e10cSrcweir transformBitmap(const BitmapEx & rBitmap,const::basegfx::B2DHomMatrix & rTransform,const uno::Sequence<double> & rDeviceColor,ModulationMode eModulationMode)219cdf0e10cSrcweir ::BitmapEx transformBitmap( const BitmapEx& rBitmap, 220cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rTransform, 221cdf0e10cSrcweir const uno::Sequence< double >& rDeviceColor, 222cdf0e10cSrcweir ModulationMode eModulationMode ) 223cdf0e10cSrcweir { 224cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::tools::transformBitmap()" ); 225cdf0e10cSrcweir RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::vclcanvas::tools::transformBitmap: 0x%X", &rBitmap ); 226cdf0e10cSrcweir 227cdf0e10cSrcweir // calc transformation and size of bitmap to be 228cdf0e10cSrcweir // generated. Note, that the translational components are 229cdf0e10cSrcweir // deleted from the transformation; this can be handled by 230cdf0e10cSrcweir // an offset when painting the bitmap 231cdf0e10cSrcweir const Size aBmpSize( rBitmap.GetSizePixel() ); 232cdf0e10cSrcweir ::basegfx::B2DRectangle aDestRect; 233cdf0e10cSrcweir 234cdf0e10cSrcweir bool bCopyBack( false ); 235cdf0e10cSrcweir 236cdf0e10cSrcweir // calc effective transformation for bitmap 237cdf0e10cSrcweir const ::basegfx::B2DRectangle aSrcRect( 0, 0, 238cdf0e10cSrcweir aBmpSize.Width(), 239cdf0e10cSrcweir aBmpSize.Height() ); 240cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aDestRect, 241cdf0e10cSrcweir aSrcRect, 242cdf0e10cSrcweir rTransform ); 243cdf0e10cSrcweir 244cdf0e10cSrcweir // re-center bitmap, such that it's left, top border is 245cdf0e10cSrcweir // aligned with (0,0). The method takes the given 246cdf0e10cSrcweir // rectangle, and calculates a transformation that maps 247cdf0e10cSrcweir // this rectangle unscaled to the origin. 248cdf0e10cSrcweir ::basegfx::B2DHomMatrix aLocalTransform; 249cdf0e10cSrcweir ::canvas::tools::calcRectToOriginTransform( aLocalTransform, 250cdf0e10cSrcweir aSrcRect, 251cdf0e10cSrcweir rTransform ); 252cdf0e10cSrcweir 253cdf0e10cSrcweir const bool bModulateColors( eModulationMode == MODULATE_WITH_DEVICECOLOR && 254cdf0e10cSrcweir rDeviceColor.getLength() > 2 ); 255cdf0e10cSrcweir const double nRedModulation( bModulateColors ? rDeviceColor[0] : 1.0 ); 256cdf0e10cSrcweir const double nGreenModulation( bModulateColors ? rDeviceColor[1] : 1.0 ); 257cdf0e10cSrcweir const double nBlueModulation( bModulateColors ? rDeviceColor[2] : 1.0 ); 258cdf0e10cSrcweir const double nAlphaModulation( bModulateColors && rDeviceColor.getLength() > 3 ? 259cdf0e10cSrcweir rDeviceColor[3] : 1.0 ); 260cdf0e10cSrcweir 261cdf0e10cSrcweir Bitmap aSrcBitmap( rBitmap.GetBitmap() ); 262cdf0e10cSrcweir Bitmap aSrcAlpha; 263cdf0e10cSrcweir 264cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 265cdf0e10cSrcweir // vs. multi-level transparency) 266cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 267cdf0e10cSrcweir { 268cdf0e10cSrcweir if( rBitmap.IsAlpha() ) 269cdf0e10cSrcweir aSrcAlpha = rBitmap.GetAlpha().GetBitmap(); 270cdf0e10cSrcweir else 271cdf0e10cSrcweir aSrcAlpha = rBitmap.GetMask(); 272cdf0e10cSrcweir } 273cdf0e10cSrcweir 274cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aSrcBitmap.AcquireReadAccess(), 275cdf0e10cSrcweir aSrcBitmap ); 276cdf0e10cSrcweir ScopedBitmapReadAccess pAlphaReadAccess( rBitmap.IsTransparent() ? 277cdf0e10cSrcweir aSrcAlpha.AcquireReadAccess() : 278cdf0e10cSrcweir (BitmapReadAccess*)NULL, 279cdf0e10cSrcweir aSrcAlpha ); 280cdf0e10cSrcweir 281cdf0e10cSrcweir if( pReadAccess.get() == NULL || 282cdf0e10cSrcweir (pAlphaReadAccess.get() == NULL && rBitmap.IsTransparent()) ) 283cdf0e10cSrcweir { 284cdf0e10cSrcweir // TODO(E2): Error handling! 285cdf0e10cSrcweir ENSURE_OR_THROW( false, 286cdf0e10cSrcweir "transformBitmap(): could not access source bitmap" ); 287cdf0e10cSrcweir } 288cdf0e10cSrcweir 289cdf0e10cSrcweir // mapping table, to translate pAlphaReadAccess' pixel 290cdf0e10cSrcweir // values into destination alpha values (needed e.g. for 291cdf0e10cSrcweir // paletted 1-bit masks). 292cdf0e10cSrcweir sal_uInt8 aAlphaMap[256]; 293cdf0e10cSrcweir 294cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 295cdf0e10cSrcweir { 296cdf0e10cSrcweir if( rBitmap.IsAlpha() ) 297cdf0e10cSrcweir { 298cdf0e10cSrcweir // source already has alpha channel - 1:1 mapping, 299cdf0e10cSrcweir // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255. 300*83d0117dSHerbert Dürr sal_uInt8* p = aAlphaMap; 301*83d0117dSHerbert Dürr for( int n = 0; n < 256; ++n) *(p++) = n; 302cdf0e10cSrcweir } 303cdf0e10cSrcweir else 304cdf0e10cSrcweir { 305cdf0e10cSrcweir // mask transparency - determine used palette colors 306cdf0e10cSrcweir const BitmapColor& rCol0( pAlphaReadAccess->GetPaletteColor( 0 ) ); 307cdf0e10cSrcweir const BitmapColor& rCol1( pAlphaReadAccess->GetPaletteColor( 1 ) ); 308cdf0e10cSrcweir 309cdf0e10cSrcweir // shortcut for true luminance calculation 310cdf0e10cSrcweir // (assumes that palette is grey-level) 311cdf0e10cSrcweir aAlphaMap[0] = rCol0.GetRed(); 312cdf0e10cSrcweir aAlphaMap[1] = rCol1.GetRed(); 313cdf0e10cSrcweir } 314cdf0e10cSrcweir } 315cdf0e10cSrcweir // else: mapping table is not used 316cdf0e10cSrcweir 317cdf0e10cSrcweir const Size aDestBmpSize( ::basegfx::fround( aDestRect.getWidth() ), 318cdf0e10cSrcweir ::basegfx::fround( aDestRect.getHeight() ) ); 319cdf0e10cSrcweir 320cdf0e10cSrcweir if( aDestBmpSize.Width() == 0 || aDestBmpSize.Height() == 0 ) 321cdf0e10cSrcweir return BitmapEx(); 322cdf0e10cSrcweir 323cdf0e10cSrcweir Bitmap aDstBitmap( aDestBmpSize, aSrcBitmap.GetBitCount(), &pReadAccess->GetPalette() ); 324cdf0e10cSrcweir Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() ); 325cdf0e10cSrcweir 326cdf0e10cSrcweir { 327cdf0e10cSrcweir // just to be on the safe side: let the 328cdf0e10cSrcweir // ScopedAccessors get destructed before 329cdf0e10cSrcweir // copy-constructing the resulting bitmap. This will 330cdf0e10cSrcweir // rule out the possibility that cached accessor data 331cdf0e10cSrcweir // is not yet written back. 332cdf0e10cSrcweir ScopedBitmapWriteAccess pWriteAccess( aDstBitmap.AcquireWriteAccess(), 333cdf0e10cSrcweir aDstBitmap ); 334cdf0e10cSrcweir ScopedBitmapWriteAccess pAlphaWriteAccess( aDstAlpha.AcquireWriteAccess(), 335cdf0e10cSrcweir aDstAlpha ); 336cdf0e10cSrcweir 337cdf0e10cSrcweir 338cdf0e10cSrcweir if( pWriteAccess.get() != NULL && 339cdf0e10cSrcweir pAlphaWriteAccess.get() != NULL && 340cdf0e10cSrcweir rTransform.isInvertible() ) 341cdf0e10cSrcweir { 342cdf0e10cSrcweir // we're doing inverse mapping here, i.e. mapping 343cdf0e10cSrcweir // points from the destination bitmap back to the 344cdf0e10cSrcweir // source 345cdf0e10cSrcweir ::basegfx::B2DHomMatrix aTransform( aLocalTransform ); 346cdf0e10cSrcweir aTransform.invert(); 347cdf0e10cSrcweir 348cdf0e10cSrcweir // for the time being, always read as ARGB 349cdf0e10cSrcweir for( int y=0; y<aDestBmpSize.Height(); ++y ) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir if( bModulateColors ) 352cdf0e10cSrcweir { 353cdf0e10cSrcweir // TODO(P2): Have different branches for 354cdf0e10cSrcweir // alpha-only modulation (color 355cdf0e10cSrcweir // modulations eq. 1.0) 356cdf0e10cSrcweir 357cdf0e10cSrcweir // modulate all color channels with given 358cdf0e10cSrcweir // values 359cdf0e10cSrcweir 360cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 361cdf0e10cSrcweir // vs. multi-level transparency) 362cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 363cdf0e10cSrcweir { 364cdf0e10cSrcweir // Handling alpha and mask just the same... 365cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 366cdf0e10cSrcweir { 367cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 368cdf0e10cSrcweir aPoint *= aTransform; 369cdf0e10cSrcweir 370cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 371cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 372cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 373cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 374cdf0e10cSrcweir { 375cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 376cdf0e10cSrcweir } 377cdf0e10cSrcweir else 378cdf0e10cSrcweir { 379cdf0e10cSrcweir // modulate alpha with 380cdf0e10cSrcweir // nAlphaModulation. This is a 381cdf0e10cSrcweir // little bit verbose, formula 382cdf0e10cSrcweir // is 255 - (255-pixAlpha)*nAlphaModulation 383cdf0e10cSrcweir // (invert 'alpha' pixel value, 384cdf0e10cSrcweir // to get the standard alpha 385cdf0e10cSrcweir // channel behaviour) 38687bc88d3SHerbert Dürr const sal_uInt8 cMappedAlphaIdx = aAlphaMap[ pAlphaReadAccess->GetPixelIndex( nSrcY, nSrcX ) ]; 38787bc88d3SHerbert Dürr const sal_uInt8 cModulatedAlphaIdx = 255U - static_cast<sal_uInt8>( nAlphaModulation* (255U - cMappedAlphaIdx) + .5 ); 38887bc88d3SHerbert Dürr pAlphaWriteAccess->SetPixelIndex( y, x, cModulatedAlphaIdx ); 38987bc88d3SHerbert Dürr BitmapColor aColor( pReadAccess->GetPixel( nSrcY, nSrcX ) ); 390cdf0e10cSrcweir 391cdf0e10cSrcweir aColor.SetRed( 392cdf0e10cSrcweir static_cast<sal_uInt8>( 393cdf0e10cSrcweir nRedModulation * 394cdf0e10cSrcweir aColor.GetRed() + .5 )); 395cdf0e10cSrcweir aColor.SetGreen( 396cdf0e10cSrcweir static_cast<sal_uInt8>( 397cdf0e10cSrcweir nGreenModulation * 398cdf0e10cSrcweir aColor.GetGreen() + .5 )); 399cdf0e10cSrcweir aColor.SetBlue( 400cdf0e10cSrcweir static_cast<sal_uInt8>( 401cdf0e10cSrcweir nBlueModulation * 402cdf0e10cSrcweir aColor.GetBlue() + .5 )); 403cdf0e10cSrcweir 404cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, 405cdf0e10cSrcweir aColor ); 406cdf0e10cSrcweir } 407cdf0e10cSrcweir } 408cdf0e10cSrcweir } 409cdf0e10cSrcweir else 410cdf0e10cSrcweir { 411cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 412cdf0e10cSrcweir { 413cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 414cdf0e10cSrcweir aPoint *= aTransform; 415cdf0e10cSrcweir 416cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 417cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 418cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 419cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 420cdf0e10cSrcweir { 421cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 422cdf0e10cSrcweir } 423cdf0e10cSrcweir else 424cdf0e10cSrcweir { 425cdf0e10cSrcweir // modulate alpha with 426cdf0e10cSrcweir // nAlphaModulation. This is a 427cdf0e10cSrcweir // little bit verbose, formula 428cdf0e10cSrcweir // is 255 - 255*nAlphaModulation 429cdf0e10cSrcweir // (invert 'alpha' pixel value, 430cdf0e10cSrcweir // to get the standard alpha 431cdf0e10cSrcweir // channel behaviour) 432cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, 433cdf0e10cSrcweir BitmapColor( 434cdf0e10cSrcweir 255U - 435cdf0e10cSrcweir static_cast<sal_uInt8>( 436cdf0e10cSrcweir nAlphaModulation*255.0 437cdf0e10cSrcweir + .5 ) ) ); 438cdf0e10cSrcweir 439cdf0e10cSrcweir BitmapColor aColor( pReadAccess->GetPixel( nSrcY, 440cdf0e10cSrcweir nSrcX ) ); 441cdf0e10cSrcweir 442cdf0e10cSrcweir aColor.SetRed( 443cdf0e10cSrcweir static_cast<sal_uInt8>( 444cdf0e10cSrcweir nRedModulation * 445cdf0e10cSrcweir aColor.GetRed() + .5 )); 446cdf0e10cSrcweir aColor.SetGreen( 447cdf0e10cSrcweir static_cast<sal_uInt8>( 448cdf0e10cSrcweir nGreenModulation * 449cdf0e10cSrcweir aColor.GetGreen() + .5 )); 450cdf0e10cSrcweir aColor.SetBlue( 451cdf0e10cSrcweir static_cast<sal_uInt8>( 452cdf0e10cSrcweir nBlueModulation * 453cdf0e10cSrcweir aColor.GetBlue() + .5 )); 454cdf0e10cSrcweir 455cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, 456cdf0e10cSrcweir aColor ); 457cdf0e10cSrcweir } 458cdf0e10cSrcweir } 459cdf0e10cSrcweir } 460cdf0e10cSrcweir } 461cdf0e10cSrcweir else 462cdf0e10cSrcweir { 463cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 464cdf0e10cSrcweir // vs. multi-level transparency) 465cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 466cdf0e10cSrcweir { 467cdf0e10cSrcweir // Handling alpha and mask just the same... 468cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 469cdf0e10cSrcweir { 470cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 471cdf0e10cSrcweir aPoint *= aTransform; 472cdf0e10cSrcweir 473cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 474cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 475cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 476cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 477cdf0e10cSrcweir { 47887bc88d3SHerbert Dürr pAlphaWriteAccess->SetPixelIndex( y, x, 255 ); 479cdf0e10cSrcweir } 480cdf0e10cSrcweir else 481cdf0e10cSrcweir { 48287bc88d3SHerbert Dürr const sal_uInt8 cAlphaIdx = pAlphaReadAccess->GetPixelIndex( nSrcY, nSrcX ); 48387bc88d3SHerbert Dürr pAlphaWriteAccess->SetPixelIndex( y, x, aAlphaMap[ cAlphaIdx ] ); 48487bc88d3SHerbert Dürr pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, nSrcX ) ); 485cdf0e10cSrcweir } 486cdf0e10cSrcweir } 487cdf0e10cSrcweir } 488cdf0e10cSrcweir else 489cdf0e10cSrcweir { 490cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 491cdf0e10cSrcweir { 492cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 493cdf0e10cSrcweir aPoint *= aTransform; 494cdf0e10cSrcweir 495cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 496cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 497cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 498cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 499cdf0e10cSrcweir { 500cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 501cdf0e10cSrcweir } 502cdf0e10cSrcweir else 503cdf0e10cSrcweir { 504cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(0) ); 505cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, 506cdf0e10cSrcweir nSrcX ) ); 507cdf0e10cSrcweir } 508cdf0e10cSrcweir } 509cdf0e10cSrcweir } 510cdf0e10cSrcweir } 511cdf0e10cSrcweir } 512cdf0e10cSrcweir 513cdf0e10cSrcweir bCopyBack = true; 514cdf0e10cSrcweir } 515cdf0e10cSrcweir else 516cdf0e10cSrcweir { 517cdf0e10cSrcweir // TODO(E2): Error handling! 518cdf0e10cSrcweir ENSURE_OR_THROW( false, 519cdf0e10cSrcweir "transformBitmap(): could not access bitmap" ); 520cdf0e10cSrcweir } 521cdf0e10cSrcweir } 522cdf0e10cSrcweir 523cdf0e10cSrcweir if( bCopyBack ) 524cdf0e10cSrcweir return BitmapEx( aDstBitmap, AlphaMask( aDstAlpha ) ); 525cdf0e10cSrcweir else 526cdf0e10cSrcweir return BitmapEx(); 527cdf0e10cSrcweir } 528cdf0e10cSrcweir } 529cdf0e10cSrcweir } 530