diff options
-rw-r--r-- | include/vcl/bitmap.hxx | 15 | ||||
-rw-r--r-- | vcl/source/bitmap/bitmappaint.cxx | 253 |
2 files changed, 150 insertions, 118 deletions
diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index 123b48fcd752..a732e77f3a97 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -352,6 +352,19 @@ public: @param rTransColor Color value where the bitmask should be transparent + @return the resulting bitmask. + */ + Bitmap CreateMask( const Color& rTransColor ) const; + + /** Create on-off mask from bitmap + + This method creates a bitmask from the bitmap, where every + pixel that equals rTransColor is set transparent, the rest + opaque. + + @param rTransColor + Color value where the bitmask should be transparent + @param nTol Tolerance value. Specifies the maximal difference between rTransColor and the individual pixel values, such that the @@ -359,7 +372,7 @@ public: @return the resulting bitmask. */ - Bitmap CreateMask( const Color& rTransColor, sal_uInt8 nTol = 0 ) const; + Bitmap CreateMask( const Color& rTransColor, sal_uInt8 nTol ) const; /** Create region of similar colors in a given rectangle diff --git a/vcl/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx index c0f6715238e7..cdece0f438ed 100644 --- a/vcl/source/bitmap/bitmappaint.cxx +++ b/vcl/source/bitmap/bitmappaint.cxx @@ -433,18 +433,19 @@ bool Bitmap::Rotate(Degree10 nAngle10, const Color& rFillColor) return bRet; }; -Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const +Bitmap Bitmap::CreateMask(const Color& rTransColor) const { ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this)); + if (!pReadAcc) + return Bitmap(); // Historically LO used 1bpp masks, but 8bpp masks are much faster, // better supported by hardware, and the memory savings are not worth // it anymore. // TODO: Possibly remove the 1bpp code later. - if (!nTol && pReadAcc - && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal - || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal) + if ((pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal + || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal) && pReadAcc->GetBestMatchingColor(COL_WHITE) == pReadAcc->GetBestMatchingColor(rTransColor)) { // if we're a 1 bit pixel already, and the transcolor matches the color that would replace it @@ -455,146 +456,164 @@ Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const auto ePixelFormat = vcl::PixelFormat::N8_BPP; Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &Bitmap::GetGreyPalette(256)); BitmapScopedWriteAccess pWriteAcc(aNewBmp); - bool bRet = false; + if (!pWriteAcc) + return Bitmap(); - if (pWriteAcc && pReadAcc) - { - const tools::Long nWidth = pReadAcc->Width(); - const tools::Long nHeight = pReadAcc->Height(); - const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK)); - const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE)); + const tools::Long nWidth = pReadAcc->Width(); + const tools::Long nHeight = pReadAcc->Height(); + const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK)); + const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE)); + + const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor)); - if (!nTol) + if (pWriteAcc->GetScanlineFormat() == pReadAcc->GetScanlineFormat() && aWhite.GetIndex() == 1 + && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal + || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal)) + { + for (tools::Long nY = 0; nY < nHeight; ++nY) { - const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor)); + Scanline pSrc = pReadAcc->GetScanline(nY); + Scanline pDst = pWriteAcc->GetScanline(nY); + assert(pWriteAcc->GetScanlineSize() == pReadAcc->GetScanlineSize()); + const tools::Long nScanlineSize = pWriteAcc->GetScanlineSize(); + for (tools::Long nX = 0; nX < nScanlineSize; ++nX) + pDst[nX] = ~pSrc[nX]; + } + } + else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal) + { + // optimized for 8Bit source palette + const sal_uInt8 cTest = aTest.GetIndex(); - if (pWriteAcc->GetScanlineFormat() == pReadAcc->GetScanlineFormat() - && aWhite.GetIndex() == 1 - && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal - || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal)) + for (tools::Long nY = 0; nY < nHeight; ++nY) + { + Scanline pSrc = pReadAcc->GetScanline(nY); + Scanline pDst = pWriteAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; ++nX) { - for (tools::Long nY = 0; nY < nHeight; ++nY) - { - Scanline pSrc = pReadAcc->GetScanline(nY); - Scanline pDst = pWriteAcc->GetScanline(nY); - assert(pWriteAcc->GetScanlineSize() == pReadAcc->GetScanlineSize()); - const tools::Long nScanlineSize = pWriteAcc->GetScanlineSize(); - for (tools::Long nX = 0; nX < nScanlineSize; ++nX) - pDst[nX] = ~pSrc[nX]; - } + if (cTest == pSrc[nX]) + pDst[nX] = aWhite.GetIndex(); + else + pDst[nX] = aBlack.GetIndex(); + } + } + } + else + { + // not optimized + for (tools::Long nY = 0; nY < nHeight; ++nY) + { + Scanline pScanline = pWriteAcc->GetScanline(nY); + Scanline pScanlineRead = pReadAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; ++nX) + { + if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX)) + pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); + else + pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); } - else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal) + } + } + + pWriteAcc.reset(); + pReadAcc.reset(); + + aNewBmp.maPrefSize = maPrefSize; + aNewBmp.maPrefMapMode = maPrefMapMode; + + return aNewBmp; +} + +Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const +{ + if (nTol == 0) + return CreateMask(rTransColor); + + ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this)); + if (!pReadAcc) + return Bitmap(); + + // Historically LO used 1bpp masks, but 8bpp masks are much faster, + // better supported by hardware, and the memory savings are not worth + // it anymore. + // TODO: Possibly remove the 1bpp code later. + + auto ePixelFormat = vcl::PixelFormat::N8_BPP; + Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &Bitmap::GetGreyPalette(256)); + BitmapScopedWriteAccess pWriteAcc(aNewBmp); + if (!pWriteAcc) + return Bitmap(); + + const tools::Long nWidth = pReadAcc->Width(); + const tools::Long nHeight = pReadAcc->Height(); + const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK)); + const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE)); + + BitmapColor aCol; + tools::Long nR, nG, nB; + const tools::Long nMinR = MinMax<tools::Long>(rTransColor.GetRed() - nTol, 0, 255); + const tools::Long nMaxR = MinMax<tools::Long>(rTransColor.GetRed() + nTol, 0, 255); + const tools::Long nMinG = MinMax<tools::Long>(rTransColor.GetGreen() - nTol, 0, 255); + const tools::Long nMaxG = MinMax<tools::Long>(rTransColor.GetGreen() + nTol, 0, 255); + const tools::Long nMinB = MinMax<tools::Long>(rTransColor.GetBlue() - nTol, 0, 255); + const tools::Long nMaxB = MinMax<tools::Long>(rTransColor.GetBlue() + nTol, 0, 255); + + if (pReadAcc->HasPalette()) + { + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWriteAcc->GetScanline(nY); + Scanline pScanlineRead = pReadAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; nX++) { - // optimized for 8Bit source palette - const sal_uInt8 cTest = aTest.GetIndex(); + aCol = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX)); + nR = aCol.GetRed(); + nG = aCol.GetGreen(); + nB = aCol.GetBlue(); - for (tools::Long nY = 0; nY < nHeight; ++nY) + if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB + && nMaxB >= nB) { - Scanline pSrc = pReadAcc->GetScanline(nY); - Scanline pDst = pWriteAcc->GetScanline(nY); - for (tools::Long nX = 0; nX < nWidth; ++nX) - { - if (cTest == pSrc[nX]) - pDst[nX] = aWhite.GetIndex(); - else - pDst[nX] = aBlack.GetIndex(); - } + pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); } - } - else - { - // not optimized - for (tools::Long nY = 0; nY < nHeight; ++nY) + else { - Scanline pScanline = pWriteAcc->GetScanline(nY); - Scanline pScanlineRead = pReadAcc->GetScanline(nY); - for (tools::Long nX = 0; nX < nWidth; ++nX) - { - if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX)) - pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); - else - pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); - } + pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); } } } - else + } + else + { + for (tools::Long nY = 0; nY < nHeight; nY++) { - BitmapColor aCol; - tools::Long nR, nG, nB; - const tools::Long nMinR = MinMax<tools::Long>(rTransColor.GetRed() - nTol, 0, 255); - const tools::Long nMaxR = MinMax<tools::Long>(rTransColor.GetRed() + nTol, 0, 255); - const tools::Long nMinG = MinMax<tools::Long>(rTransColor.GetGreen() - nTol, 0, 255); - const tools::Long nMaxG = MinMax<tools::Long>(rTransColor.GetGreen() + nTol, 0, 255); - const tools::Long nMinB = MinMax<tools::Long>(rTransColor.GetBlue() - nTol, 0, 255); - const tools::Long nMaxB = MinMax<tools::Long>(rTransColor.GetBlue() + nTol, 0, 255); - - if (pReadAcc->HasPalette()) + Scanline pScanline = pWriteAcc->GetScanline(nY); + Scanline pScanlineRead = pReadAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; nX++) { - for (tools::Long nY = 0; nY < nHeight; nY++) + aCol = pReadAcc->GetPixelFromData(pScanlineRead, nX); + nR = aCol.GetRed(); + nG = aCol.GetGreen(); + nB = aCol.GetBlue(); + + if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB + && nMaxB >= nB) { - Scanline pScanline = pWriteAcc->GetScanline(nY); - Scanline pScanlineRead = pReadAcc->GetScanline(nY); - for (tools::Long nX = 0; nX < nWidth; nX++) - { - aCol = pReadAcc->GetPaletteColor( - pReadAcc->GetIndexFromData(pScanlineRead, nX)); - nR = aCol.GetRed(); - nG = aCol.GetGreen(); - nB = aCol.GetBlue(); - - if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB - && nMaxB >= nB) - { - pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); - } - else - { - pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); - } - } + pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); } - } - else - { - for (tools::Long nY = 0; nY < nHeight; nY++) + else { - Scanline pScanline = pWriteAcc->GetScanline(nY); - Scanline pScanlineRead = pReadAcc->GetScanline(nY); - for (tools::Long nX = 0; nX < nWidth; nX++) - { - aCol = pReadAcc->GetPixelFromData(pScanlineRead, nX); - nR = aCol.GetRed(); - nG = aCol.GetGreen(); - nB = aCol.GetBlue(); - - if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB - && nMaxB >= nB) - { - pWriteAcc->SetPixelOnData(pScanline, nX, aWhite); - } - else - { - pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); - } - } + pWriteAcc->SetPixelOnData(pScanline, nX, aBlack); } } } - - bRet = true; } pWriteAcc.reset(); pReadAcc.reset(); - if (bRet) - { - aNewBmp.maPrefSize = maPrefSize; - aNewBmp.maPrefMapMode = maPrefMapMode; - } - else - aNewBmp = Bitmap(); + aNewBmp.maPrefSize = maPrefSize; + aNewBmp.maPrefMapMode = maPrefMapMode; return aNewBmp; } |