diff options
Diffstat (limited to 'vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx')
-rw-r--r-- | vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx b/vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx new file mode 100644 index 000000000..db68bff1d --- /dev/null +++ b/vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <tools/helpers.hxx> + +#include <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/BitmapConvolutionMatrixFilter.hxx> +#include <vcl/BitmapSharpenFilter.hxx> + +#include <bitmap/BitmapWriteAccess.hxx> + +#include <array> + +BitmapEx BitmapConvolutionMatrixFilter::execute(BitmapEx const& rBitmapEx) const +{ + Bitmap aBitmap(rBitmapEx.GetBitmap()); + + const sal_Int32 nDivisor = 8; + Bitmap::ScopedReadAccess pReadAcc(aBitmap); + bool bRet = false; + + if (pReadAcc) + { + Bitmap aNewBmp(aBitmap.GetSizePixel(), vcl::PixelFormat::N24_BPP); + BitmapScopedWriteAccess pWriteAcc(aNewBmp); + + if (pWriteAcc) + { + const sal_Int32 nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2; + const sal_Int32 nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2; + std::unique_ptr<sal_Int32[]> pColm(new sal_Int32[nWidth2]); + std::unique_ptr<sal_Int32[]> pRows(new sal_Int32[nHeight2]); + std::unique_ptr<BitmapColor[]> pColRow1(new BitmapColor[nWidth2]); + std::unique_ptr<BitmapColor[]> pColRow2(new BitmapColor[nWidth2]); + std::unique_ptr<BitmapColor[]> pColRow3(new BitmapColor[nWidth2]); + BitmapColor* pRowTmp1 = pColRow1.get(); + BitmapColor* pRowTmp2 = pColRow2.get(); + BitmapColor* pRowTmp3 = pColRow3.get(); + BitmapColor* pColor; + sal_Int32 nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp; + std::array<std::array<sal_Int32, 256>, 9> aKoeff; + sal_Int32* pTmp; + + // create LUT of products of matrix value and possible color component values + for (nY = 0; nY < 9; nY++) + { + for (nX = nTmp = 0, nMatrixVal = mrMatrix[nY]; nX < 256; nX++, nTmp += nMatrixVal) + { + aKoeff[nY][nX] = nTmp; + } + } + + // create column LUT + for (i = 0; i < nWidth2; i++) + { + pColm[i] = (i > 0) ? (i - 1) : 0; + } + + pColm[nWidth + 1] = pColm[nWidth]; + + // create row LUT + for (i = 0; i < nHeight2; i++) + { + pRows[i] = (i > 0) ? (i - 1) : 0; + } + + pRows[nHeight + 1] = pRows[nHeight]; + + // read first three rows of bitmap color + for (i = 0; i < nWidth2; i++) + { + pColRow1[i] = pReadAcc->GetColor(pRows[0], pColm[i]); + pColRow2[i] = pReadAcc->GetColor(pRows[1], pColm[i]); + pColRow3[i] = pReadAcc->GetColor(pRows[2], pColm[i]); + } + + // do convolution + for (nY = 0; nY < nHeight;) + { + Scanline pScanline = pWriteAcc->GetScanline(nY); + for (nX = 0; nX < nWidth; nX++) + { + // first row + pTmp = aKoeff[0].data(); + pColor = pRowTmp1 + nX; + nSumR = pTmp[pColor->GetRed()]; + nSumG = pTmp[pColor->GetGreen()]; + nSumB = pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[1].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[2].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + // second row + pTmp = aKoeff[3].data(); + pColor = pRowTmp2 + nX; + nSumR += pTmp[pColor->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[4].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[5].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + // third row + pTmp = aKoeff[6].data(); + pColor = pRowTmp3 + nX; + nSumR += pTmp[pColor->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[7].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + pTmp = aKoeff[8].data(); + nSumR += pTmp[(++pColor)->GetRed()]; + nSumG += pTmp[pColor->GetGreen()]; + nSumB += pTmp[pColor->GetBlue()]; + + // calculate destination color + pWriteAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(static_cast<sal_uInt8>(MinMax(nSumR / nDivisor, 0, 255)), + static_cast<sal_uInt8>(MinMax(nSumG / nDivisor, 0, 255)), + static_cast<sal_uInt8>(MinMax(nSumB / nDivisor, 0, 255)))); + } + + if (++nY < nHeight) + { + if (pRowTmp1 == pColRow1.get()) + { + pRowTmp1 = pColRow2.get(); + pRowTmp2 = pColRow3.get(); + pRowTmp3 = pColRow1.get(); + } + else if (pRowTmp1 == pColRow2.get()) + { + pRowTmp1 = pColRow3.get(); + pRowTmp2 = pColRow1.get(); + pRowTmp3 = pColRow2.get(); + } + else + { + pRowTmp1 = pColRow1.get(); + pRowTmp2 = pColRow2.get(); + pRowTmp3 = pColRow3.get(); + } + + for (i = 0; i < nWidth2; i++) + { + pRowTmp3[i] = pReadAcc->GetColor(pRows[nY + 2], pColm[i]); + } + } + } + + pWriteAcc.reset(); + + bRet = true; + } + + pReadAcc.reset(); + + if (bRet) + { + const MapMode aMap(aBitmap.GetPrefMapMode()); + const Size aPrefSize(aBitmap.GetPrefSize()); + + aBitmap = aNewBmp; + + aBitmap.SetPrefMapMode(aMap); + aBitmap.SetPrefSize(aPrefSize); + } + } + + if (bRet) + return BitmapEx(aBitmap); + + return BitmapEx(); +} + +const sal_Int32 g_SharpenMatrix[] = { -1, -1, -1, -1, 16, -1, -1, -1, -1 }; + +BitmapSharpenFilter::BitmapSharpenFilter() + : BitmapConvolutionMatrixFilter(g_SharpenMatrix) +{ +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |