431 lines
16 KiB
C++
431 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
#include <vclhelperbitmaptransform.hxx>
|
|
#include <vcl/bmpacc.hxx>
|
|
#include <basegfx/point/b2dpoint.hxx>
|
|
#include <basegfx/color/bcolormodifier.hxx>
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// support for rendering Bitmap and BitmapEx contents
|
|
|
|
namespace drawinglayer
|
|
{
|
|
namespace
|
|
{
|
|
void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
|
|
{
|
|
double fDeltaX(rSource.getX() - nIntX);
|
|
double fDeltaY(rSource.getY() - nIntY);
|
|
sal_Int32 nIndX(0L);
|
|
sal_Int32 nIndY(0L);
|
|
|
|
if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
|
|
{
|
|
nIndX++;
|
|
}
|
|
else if(fDeltaX < 0.0 && nIntX >= 1L)
|
|
{
|
|
fDeltaX = -fDeltaX;
|
|
nIndX--;
|
|
}
|
|
|
|
if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
|
|
{
|
|
nIndY++;
|
|
}
|
|
else if(fDeltaY < 0.0 && nIntY >= 1L)
|
|
{
|
|
fDeltaY = -fDeltaY;
|
|
nIndY--;
|
|
}
|
|
|
|
if(nIndX || nIndY)
|
|
{
|
|
const double fColorToReal(1.0 / 255.0);
|
|
double fR(rValue.GetRed() * fColorToReal);
|
|
double fG(rValue.GetGreen() * fColorToReal);
|
|
double fB(rValue.GetBlue() * fColorToReal);
|
|
double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
|
|
|
|
if(nIndX)
|
|
{
|
|
const double fMulA(fDeltaX * fColorToReal);
|
|
double fMulB(1.0 - fDeltaX);
|
|
const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
|
|
|
|
fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
|
|
fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
|
|
fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
|
|
|
|
if(nIndY)
|
|
{
|
|
fMulB *= fColorToReal;
|
|
const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
|
|
const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
|
|
|
|
fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
|
|
fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
|
|
fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
|
|
}
|
|
}
|
|
|
|
if(nIndY)
|
|
{
|
|
if(!nIndX)
|
|
{
|
|
const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
|
|
|
|
fRBottom = aBottom.GetRed() * fColorToReal;
|
|
fGBottom = aBottom.GetGreen() * fColorToReal;
|
|
fBBottom = aBottom.GetBlue() * fColorToReal;
|
|
}
|
|
|
|
const double fMulB(1.0 - fDeltaY);
|
|
|
|
fR = (fR * fMulB) + (fRBottom * fDeltaY);
|
|
fG = (fG * fMulB) + (fGBottom * fDeltaY);
|
|
fB = (fB * fMulB) + (fBBottom * fDeltaY);
|
|
}
|
|
|
|
rValue.SetRed((sal_uInt8)(fR * 255.0));
|
|
rValue.SetGreen((sal_uInt8)(fG * 255.0));
|
|
rValue.SetBlue((sal_uInt8)(fB * 255.0));
|
|
}
|
|
}
|
|
|
|
void impSmoothIndex(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
|
|
{
|
|
double fDeltaX(rSource.getX() - nIntX);
|
|
double fDeltaY(rSource.getY() - nIntY);
|
|
sal_Int32 nIndX(0L);
|
|
sal_Int32 nIndY(0L);
|
|
|
|
if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
|
|
{
|
|
nIndX++;
|
|
}
|
|
else if(fDeltaX < 0.0 && nIntX >= 1L)
|
|
{
|
|
fDeltaX = -fDeltaX;
|
|
nIndX--;
|
|
}
|
|
|
|
if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
|
|
{
|
|
nIndY++;
|
|
}
|
|
else if(fDeltaY < 0.0 && nIntY >= 1L)
|
|
{
|
|
fDeltaY = -fDeltaY;
|
|
nIndY--;
|
|
}
|
|
|
|
if(nIndX || nIndY)
|
|
{
|
|
const double fColorToReal(1.0 / 255.0);
|
|
double fVal(rValue.GetIndex() * fColorToReal);
|
|
double fValBottom(0.0);
|
|
|
|
if(nIndX)
|
|
{
|
|
const double fMulA(fDeltaX * fColorToReal);
|
|
double fMulB(1.0 - fDeltaX);
|
|
const BitmapColor aTopPartner(rRead.GetPixel(nIntY, nIntX + nIndX));
|
|
|
|
fVal = (fVal * fMulB) + (aTopPartner.GetIndex() * fMulA);
|
|
|
|
if(nIndY)
|
|
{
|
|
fMulB *= fColorToReal;
|
|
const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
|
|
const BitmapColor aBottomPartner(rRead.GetPixel(nIntY + nIndY, nIntX + nIndX));
|
|
|
|
fValBottom = (aBottom.GetIndex() * fMulB) + (aBottomPartner.GetIndex() * fMulA);
|
|
}
|
|
}
|
|
|
|
if(nIndY)
|
|
{
|
|
if(!nIndX)
|
|
{
|
|
const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
|
|
|
|
fValBottom = aBottom.GetIndex() * fColorToReal;
|
|
}
|
|
|
|
const double fMulB(1.0 - fDeltaY);
|
|
|
|
fVal = (fVal * fMulB) + (fValBottom * fDeltaY);
|
|
}
|
|
|
|
rValue.SetIndex((sal_uInt8)(fVal * 255.0));
|
|
}
|
|
}
|
|
|
|
void impTransformBitmap(const Bitmap& rSource, Bitmap& rDestination, const basegfx::B2DHomMatrix& rTransform, bool bSmooth)
|
|
{
|
|
BitmapWriteAccess* pWrite = rDestination.AcquireWriteAccess();
|
|
|
|
if(pWrite)
|
|
{
|
|
const Size aContentSizePixel(rSource.GetSizePixel());
|
|
BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
|
|
|
|
if(pRead)
|
|
{
|
|
const Size aDestinationSizePixel(rDestination.GetSizePixel());
|
|
bool bWorkWithIndex(rDestination.GetBitCount() <= 8);
|
|
BitmapColor aOutside(pRead->GetBestMatchingColor(BitmapColor(0xff, 0xff, 0xff)));
|
|
|
|
for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
|
|
{
|
|
for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
|
|
{
|
|
const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
|
|
const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
|
|
|
|
if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
|
|
{
|
|
const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
|
|
|
|
if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
|
|
{
|
|
if(bWorkWithIndex)
|
|
{
|
|
BitmapColor aValue(pRead->GetPixel(nIntY, nIntX));
|
|
|
|
if(bSmooth)
|
|
{
|
|
impSmoothIndex(aValue, aSourceCoor, nIntX, nIntY, *pRead);
|
|
}
|
|
|
|
pWrite->SetPixel(y, x, aValue);
|
|
}
|
|
else
|
|
{
|
|
BitmapColor aValue(pRead->GetColor(nIntY, nIntX));
|
|
|
|
if(bSmooth)
|
|
{
|
|
impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
|
|
}
|
|
|
|
pWrite->SetPixel(y, x, aValue.IsIndex() ? aValue : pWrite->GetBestMatchingColor(aValue));
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// here are outside pixels. Complete mask
|
|
if(bWorkWithIndex)
|
|
{
|
|
pWrite->SetPixel(y, x, aOutside);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pRead;
|
|
}
|
|
|
|
delete pWrite;
|
|
}
|
|
}
|
|
|
|
Bitmap impCreateEmptyBitmapWithPattern(const Bitmap& rSource, const Size& aTargetSizePixel)
|
|
{
|
|
Bitmap aRetval;
|
|
BitmapReadAccess* pReadAccess = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
|
|
|
|
if(pReadAccess)
|
|
{
|
|
if(rSource.GetBitCount() <= 8)
|
|
{
|
|
BitmapPalette aPalette(pReadAccess->GetPalette());
|
|
aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount(), &aPalette);
|
|
}
|
|
else
|
|
{
|
|
aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount());
|
|
}
|
|
|
|
delete pReadAccess;
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
} // end of anonymous namespace
|
|
} // end of namespace drawinglayer
|
|
|
|
namespace drawinglayer
|
|
{
|
|
BitmapEx impTransformBitmapEx(
|
|
const BitmapEx& rSource,
|
|
const Rectangle& rCroppedRectPixel,
|
|
const basegfx::B2DHomMatrix& rTransform)
|
|
{
|
|
// force destination to 24 bit, we want to smooth output
|
|
const Size aDestinationSize(rCroppedRectPixel.GetSize());
|
|
Bitmap aDestination(impCreateEmptyBitmapWithPattern(rSource.GetBitmap(), aDestinationSize));
|
|
static bool bDoSmoothAtAll(true);
|
|
impTransformBitmap(rSource.GetBitmap(), aDestination, rTransform, bDoSmoothAtAll);
|
|
|
|
// create mask
|
|
if(rSource.IsTransparent())
|
|
{
|
|
if(rSource.IsAlpha())
|
|
{
|
|
Bitmap aAlpha(impCreateEmptyBitmapWithPattern(rSource.GetAlpha().GetBitmap(), aDestinationSize));
|
|
impTransformBitmap(rSource.GetAlpha().GetBitmap(), aAlpha, rTransform, bDoSmoothAtAll);
|
|
return BitmapEx(aDestination, AlphaMask(aAlpha));
|
|
}
|
|
else
|
|
{
|
|
Bitmap aMask(impCreateEmptyBitmapWithPattern(rSource.GetMask(), aDestinationSize));
|
|
impTransformBitmap(rSource.GetMask(), aMask, rTransform, false);
|
|
return BitmapEx(aDestination, aMask);
|
|
}
|
|
}
|
|
|
|
return BitmapEx(aDestination);
|
|
}
|
|
|
|
BitmapEx impModifyBitmapEx(
|
|
const basegfx::BColorModifierStack& rBColorModifierStack,
|
|
const BitmapEx& rSource)
|
|
{
|
|
Bitmap aChangedBitmap(rSource.GetBitmap());
|
|
bool bDone(false);
|
|
|
|
for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
|
|
{
|
|
const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
|
|
|
|
switch(rModifier.getMode())
|
|
{
|
|
case basegfx::BCOLORMODIFYMODE_REPLACE :
|
|
{
|
|
// complete replace
|
|
if(rSource.IsTransparent())
|
|
{
|
|
// clear bitmap with dest color
|
|
if(aChangedBitmap.GetBitCount() <= 8)
|
|
{
|
|
// do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
|
|
// erase color is determined and used -> this may be different from what is
|
|
// wanted here. Better create a new bitmap with the needed color explicitly
|
|
BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
|
|
OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
|
|
|
|
if(pReadAccess)
|
|
{
|
|
BitmapPalette aNewPalette(pReadAccess->GetPalette());
|
|
aNewPalette[0] = BitmapColor(Color(rModifier.getBColor()));
|
|
aChangedBitmap = Bitmap(
|
|
aChangedBitmap.GetSizePixel(),
|
|
aChangedBitmap.GetBitCount(),
|
|
&aNewPalette);
|
|
delete pReadAccess;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aChangedBitmap.Erase(Color(rModifier.getBColor()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// erase bitmap, caller will know to paint direct
|
|
aChangedBitmap.SetEmpty();
|
|
}
|
|
|
|
bDone = true;
|
|
break;
|
|
}
|
|
|
|
default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
|
|
{
|
|
BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
|
|
|
|
if(pContent)
|
|
{
|
|
const double fConvertColor(1.0 / 255.0);
|
|
|
|
for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
|
|
{
|
|
for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
|
|
{
|
|
const BitmapColor aBMCol(pContent->GetColor(y, x));
|
|
const basegfx::BColor aBSource(
|
|
(double)aBMCol.GetRed() * fConvertColor,
|
|
(double)aBMCol.GetGreen() * fConvertColor,
|
|
(double)aBMCol.GetBlue() * fConvertColor);
|
|
const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource));
|
|
|
|
pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
|
|
}
|
|
}
|
|
|
|
delete pContent;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(aChangedBitmap.IsEmpty())
|
|
{
|
|
return BitmapEx();
|
|
}
|
|
else
|
|
{
|
|
if(rSource.IsTransparent())
|
|
{
|
|
if(rSource.IsAlpha())
|
|
{
|
|
return BitmapEx(aChangedBitmap, rSource.GetAlpha());
|
|
}
|
|
else
|
|
{
|
|
return BitmapEx(aChangedBitmap, rSource.GetMask());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BitmapEx(aChangedBitmap);
|
|
}
|
|
}
|
|
}
|
|
} // end of namespace drawinglayer
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// eof
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|