diff options
-rw-r--r-- | cui/source/dialogs/cuigrfflt.cxx | 3 | ||||
-rw-r--r-- | include/vcl/BitmapColorQuantizationFilter.hxx | 45 | ||||
-rw-r--r-- | include/vcl/BitmapMedianColorQuantizationFilter.hxx | 49 | ||||
-rw-r--r-- | include/vcl/BitmapSimpleColorQuantizationFilter.hxx | 39 | ||||
-rw-r--r-- | include/vcl/bitmap.hxx | 28 | ||||
-rw-r--r-- | include/vcl/bitmapex.hxx | 9 | ||||
-rw-r--r-- | sd/source/ui/dlg/vectdlg.cxx | 9 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 3 | ||||
-rw-r--r-- | vcl/source/bitmap/BitmapColorQuantizationFilter.cxx | 229 | ||||
-rw-r--r-- | vcl/source/bitmap/BitmapMedianColorQuantizationFilter.cxx | 300 | ||||
-rw-r--r-- | vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx | 108 | ||||
-rw-r--r-- | vcl/source/gdi/animate.cxx | 14 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap3.cxx | 493 | ||||
-rw-r--r-- | vcl/source/gdi/bitmapex.cxx | 5 | ||||
-rw-r--r-- | vcl/unx/generic/dtrans/bmp.cxx | 39 |
15 files changed, 817 insertions, 556 deletions
diff --git a/cui/source/dialogs/cuigrfflt.cxx b/cui/source/dialogs/cuigrfflt.cxx index 9f0f60d27aa3..406e2b6a7f7f 100644 --- a/cui/source/dialogs/cuigrfflt.cxx +++ b/cui/source/dialogs/cuigrfflt.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <vcl/BitmapColorQuantizationFilter.hxx> #include <vcl/builderfactory.hxx> #include <sfx2/viewfrm.hxx> #include <sfx2/viewsh.hxx> @@ -502,7 +503,7 @@ Graphic GraphicFilterPoster::GetFilteredGraphic( const Graphic& rGraphic, double { BitmapEx aBmpEx( rGraphic.GetBitmapEx() ); - if( aBmpEx.ReduceColors( nPosterCount ) ) + if (BitmapFilter::Filter(aBmpEx, BitmapColorQuantizationFilter(nPosterCount))) aRet = aBmpEx; } diff --git a/include/vcl/BitmapColorQuantizationFilter.hxx b/include/vcl/BitmapColorQuantizationFilter.hxx new file mode 100644 index 000000000000..e695567a7bc0 --- /dev/null +++ b/include/vcl/BitmapColorQuantizationFilter.hxx @@ -0,0 +1,45 @@ +/* -*- 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/. + * + */ + +#ifndef INCLUDED_INCLUDE_VCL_BITMAPCOLORQUANTIZATIONFILTER_HXX +#define INCLUDED_INCLUDE_VCL_BITMAPCOLORQUANTIZATIONFILTER_HXX + +#include <tools/color.hxx> + +#include <vcl/BitmapFilter.hxx> + +class VCL_DLLPUBLIC BitmapColorQuantizationFilter : public BitmapFilter +{ +public: + /** Reduce number of colors for the bitmap using the POPULAR algorithm + + @param nNewColorCount + Maximal number of bitmap colors after the reduce operation + */ + BitmapColorQuantizationFilter(sal_uInt16 nNewColorCount) + : mnNewColorCount(nNewColorCount) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) override; + +private: + sal_uInt16 mnNewColorCount; + + struct PopularColorCount + { + sal_uInt32 mnIndex; + sal_uInt32 mnCount; + }; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/BitmapMedianColorQuantizationFilter.hxx b/include/vcl/BitmapMedianColorQuantizationFilter.hxx new file mode 100644 index 000000000000..c15b0ac80ac7 --- /dev/null +++ b/include/vcl/BitmapMedianColorQuantizationFilter.hxx @@ -0,0 +1,49 @@ +/* -*- 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/. + * + */ + +#ifndef INCLUDED_INCLUDE_VCL_BITMAPMEDIANCOLORQUANTIZATIONFILTER_HXX +#define INCLUDED_INCLUDE_VCL_BITMAPMEDIANCOLORQUANTIZATIONFILTER_HXX + +#include <tools/color.hxx> + +#include <vcl/BitmapFilter.hxx> + +#define RGB15(_def_cR, _def_cG, _def_cB) \ + ((static_cast<sal_uLong>(_def_cR) << 10) | (static_cast<sal_uLong>(_def_cG) << 5) \ + | static_cast<sal_uLong>(_def_cB)) +#define GAMMA(_def_cVal, _def_InvGamma) \ + (static_cast<sal_uInt8>(MinMax(FRound(pow(_def_cVal / 255.0, _def_InvGamma) * 255.0), 0, 255))) + +class VCL_DLLPUBLIC BitmapMedianColorQuantizationFilter : public BitmapFilter +{ +public: + /** Reduce number of colors for the bitmap using the median algorithm + + @param nNewColorCount + Maximal number of bitmap colors after the reduce operation + */ + BitmapMedianColorQuantizationFilter(sal_uInt16 nNewColorCount) + : mnNewColorCount(nNewColorCount) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) override; + +private: + sal_uInt16 mnNewColorCount; + + void medianCut(Bitmap& rBitmap, sal_uLong* pColBuf, BitmapPalette& rPal, long nR1, long nR2, + long nG1, long nG2, long nB1, long nB2, long nColors, long nPixels, + long& rIndex); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/BitmapSimpleColorQuantizationFilter.hxx b/include/vcl/BitmapSimpleColorQuantizationFilter.hxx new file mode 100644 index 000000000000..b05b13fe6896 --- /dev/null +++ b/include/vcl/BitmapSimpleColorQuantizationFilter.hxx @@ -0,0 +1,39 @@ +/* -*- 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/. + * + */ + +#ifndef INCLUDED_INCLUDE_VCL_BITMAPSIMPLECOLORQUANTIZATIONFILTER_HXX +#define INCLUDED_INCLUDE_VCL_BITMAPSIMPLECOLORQUANTIZATIONFILTER_HXX + +#include <tools/color.hxx> + +#include <vcl/BitmapFilter.hxx> + +class VCL_DLLPUBLIC BitmapSimpleColorQuantizationFilter : public BitmapFilter +{ +public: + /** Reduce number of colors for the bitmap using the POPULAR algorithm + + @param nNewColorCount + Maximal number of bitmap colors after the reduce operation + */ + BitmapSimpleColorQuantizationFilter(sal_uInt16 nNewColorCount) + : mnNewColorCount(nNewColorCount) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) override; + +private: + sal_uInt16 mnNewColorCount; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index 6370a63d116f..ad1efb8bb862 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -89,12 +89,6 @@ enum class BmpCombine Or, And }; -enum BmpReduce -{ - BMP_REDUCE_SIMPLE = 0, - BMP_REDUCE_POPULAR = 1 -}; - enum class BmpFilter { Smooth = 0, @@ -285,20 +279,6 @@ public: */ bool MakeMonochrome(sal_uInt8 cThreshold); - /** Reduce number of colors for the bitmap - - @param nNewColorCount - Maximal number of bitmap colors after the reduce operation - - @param eReduce - Algorithm to use for color reduction - - @return true the color reduction operation was completed successfully. - */ - bool ReduceColors( - sal_uInt16 nNewColorCount, - BmpReduce eReduce = BMP_REDUCE_SIMPLE ); - /** Apply a dither algorithm to the bitmap This method dithers the bitmap inplace, i.e. a true color @@ -680,14 +660,6 @@ public: SAL_DLLPRIVATE bool ImplDitherMatrix(); SAL_DLLPRIVATE bool ImplDitherFloyd(); SAL_DLLPRIVATE bool ImplDitherFloyd16(); - SAL_DLLPRIVATE bool ImplReduceSimple( sal_uInt16 nColorCount ); - SAL_DLLPRIVATE bool ImplReducePopular( sal_uInt16 nColorCount ); - SAL_DLLPRIVATE bool ImplReduceMedian( sal_uInt16 nColorCount ); - SAL_DLLPRIVATE void ImplMedianCut( - sal_uLong* pColBuf, - BitmapPalette& rPal, - long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, - long nColors, long nPixels, long& rIndex ); SAL_DLLPRIVATE bool ImplConvolute3( const long* pMatrix ); diff --git a/include/vcl/bitmapex.hxx b/include/vcl/bitmapex.hxx index 41b1fb28a010..390a2c0eef45 100644 --- a/include/vcl/bitmapex.hxx +++ b/include/vcl/bitmapex.hxx @@ -109,15 +109,6 @@ public: */ bool Convert( BmpConversion eConversion ); - /** Reduce number of colors for the bitmap using the POPULAR algorithm - - @param nNewColorCount - Maximal number of bitmap colors after the reduce operation - - @return true, if the color reduction operation was completed successfully. - */ - bool ReduceColors( sal_uInt16 nNewColorCount ); - /** Apply a dither algorithm to the bitmap This method dithers the bitmap inplace, i.e. a true color diff --git a/sd/source/ui/dlg/vectdlg.cxx b/sd/source/ui/dlg/vectdlg.cxx index 2c64760f3265..44ed925dc767 100644 --- a/sd/source/ui/dlg/vectdlg.cxx +++ b/sd/source/ui/dlg/vectdlg.cxx @@ -19,13 +19,14 @@ #include <vcl/vclenum.hxx> #include <vcl/wrkwin.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/metaact.hxx> +#include <vcl/BitmapSimpleColorQuantizationFilter.hxx> #include <DrawDocShell.hxx> #include <sdmod.hxx> #include <sdiocmpt.hxx> #include <vectdlg.hxx> -#include <vcl/bitmapaccess.hxx> -#include <vcl/metaact.hxx> #define VECTORIZE_MAX_EXTENT 512 @@ -140,7 +141,9 @@ Bitmap SdVectorizeDlg::GetPreparedBitmap( Bitmap const & rBmp, Fraction& rScale else rScale = Fraction( 1, 1 ); - aNew.ReduceColors( static_cast<sal_uInt16>(m_pNmLayers->GetValue()) ); + BitmapEx aNewBmpEx(aNew); + BitmapFilter::Filter(aNewBmpEx, BitmapSimpleColorQuantizationFilter(static_cast<sal_uInt16>(m_pNmLayers->GetValue()))); + aNew = aNewBmpEx.GetBitmap(); return aNew; } diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 03c705aa5544..cfd5da379ab3 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -322,6 +322,9 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/bitmap/BitmapScaleSuperFilter \ vcl/source/bitmap/BitmapScaleConvolutionFilter \ vcl/source/bitmap/BitmapSymmetryCheck \ + vcl/source/bitmap/BitmapColorQuantizationFilter \ + vcl/source/bitmap/BitmapSimpleColorQuantizationFilter \ + vcl/source/bitmap/BitmapMedianColorQuantizationFilter \ vcl/source/bitmap/BitmapTools \ vcl/source/bitmap/checksum \ vcl/source/image/Image \ diff --git a/vcl/source/bitmap/BitmapColorQuantizationFilter.cxx b/vcl/source/bitmap/BitmapColorQuantizationFilter.cxx new file mode 100644 index 000000000000..13e88341c0d9 --- /dev/null +++ b/vcl/source/bitmap/BitmapColorQuantizationFilter.cxx @@ -0,0 +1,229 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/BitmapColorQuantizationFilter.hxx> +#include <vcl/bitmapaccess.hxx> + +#include <bitmapwriteaccess.hxx> + +#include <cstdlib> + +BitmapEx BitmapColorQuantizationFilter::execute(BitmapEx const& aBitmapEx) +{ + Bitmap aBitmap = aBitmapEx.GetBitmap(); + + bool bRet = false; + + if (aBitmap.GetColorCount() <= static_cast<sal_uLong>(mnNewColorCount)) + { + bRet = true; + } + else + { + Bitmap::ScopedReadAccess pRAcc(aBitmap); + sal_uInt16 nBitCount; + + if (mnNewColorCount > 256) + mnNewColorCount = 256; + + if (mnNewColorCount < 17) + nBitCount = 4; + else + nBitCount = 8; + + if (pRAcc) + { + const sal_uInt32 nValidBits = 4; + const sal_uInt32 nRightShiftBits = 8 - nValidBits; + const sal_uInt32 nLeftShiftBits1 = nValidBits; + const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; + const sal_uInt32 nColorsPerComponent = 1 << nValidBits; + const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; + const sal_uInt32 nTotalColors + = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; + const long nWidth = pRAcc->Width(); + const long nHeight = pRAcc->Height(); + std::unique_ptr<PopularColorCount[]> pCountTable(new PopularColorCount[nTotalColors]); + + memset(pCountTable.get(), 0, nTotalColors * sizeof(PopularColorCount)); + + for (long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset) + { + for (long nG = 0; nG < 256; nG += nColorOffset) + { + for (long nB = 0; nB < 256; nB += nColorOffset) + { + pCountTable[nIndex].mnIndex = nIndex; + nIndex++; + } + } + } + + if (pRAcc->HasPalette()) + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor& rCol + = pRAcc->GetPaletteColor(pRAcc->GetIndexFromData(pScanlineRead, nX)); + pCountTable[((static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits) + << nLeftShiftBits2) + | ((static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits) + << nLeftShiftBits1) + | (static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits)] + .mnCount++; + } + } + } + else + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX)); + pCountTable[((static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits) + << nLeftShiftBits2) + | ((static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits) + << nLeftShiftBits1) + | (static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits)] + .mnCount++; + } + } + } + + BitmapPalette aNewPal(mnNewColorCount); + + std::qsort(pCountTable.get(), nTotalColors, sizeof(PopularColorCount), + [](const void* p1, const void* p2) { + int nRet; + + if (static_cast<PopularColorCount const*>(p1)->mnCount + < static_cast<PopularColorCount const*>(p2)->mnCount) + nRet = 1; + else if (static_cast<PopularColorCount const*>(p1)->mnCount + == static_cast<PopularColorCount const*>(p2)->mnCount) + nRet = 0; + else + nRet = -1; + + return nRet; + }); + + for (sal_uInt16 n = 0; n < mnNewColorCount; n++) + { + const PopularColorCount& rPop = pCountTable[n]; + aNewPal[n] = BitmapColor( + static_cast<sal_uInt8>((rPop.mnIndex >> nLeftShiftBits2) << nRightShiftBits), + static_cast<sal_uInt8>( + ((rPop.mnIndex >> nLeftShiftBits1) & (nColorsPerComponent - 1)) + << nRightShiftBits), + static_cast<sal_uInt8>((rPop.mnIndex & (nColorsPerComponent - 1)) + << nRightShiftBits)); + } + + Bitmap aNewBmp(aBitmap.GetSizePixel(), nBitCount, &aNewPal); + BitmapScopedWriteAccess pWAcc(aNewBmp); + + if (pWAcc) + { + BitmapColor aDstCol(sal_uInt8(0)); + std::unique_ptr<sal_uInt8[]> pIndexMap(new sal_uInt8[nTotalColors]); + + for (long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset) + { + for (long nG = 0; nG < 256; nG += nColorOffset) + { + for (long nB = 0; nB < 256; nB += nColorOffset) + { + pIndexMap[nIndex++] = static_cast<sal_uInt8>(aNewPal.GetBestIndex( + BitmapColor(static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), + static_cast<sal_uInt8>(nB)))); + } + } + } + + if (pRAcc->HasPalette()) + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWAcc->GetScanline(nY); + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor& rCol = pRAcc->GetPaletteColor( + pRAcc->GetIndexFromData(pScanlineRead, nX)); + aDstCol.SetIndex(pIndexMap[((static_cast<sal_uInt32>(rCol.GetRed()) + >> nRightShiftBits) + << nLeftShiftBits2) + | ((static_cast<sal_uInt32>(rCol.GetGreen()) + >> nRightShiftBits) + << nLeftShiftBits1) + | (static_cast<sal_uInt32>(rCol.GetBlue()) + >> nRightShiftBits)]); + pWAcc->SetPixelOnData(pScanline, nX, aDstCol); + } + } + } + else + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWAcc->GetScanline(nY); + Scanline pScanlineRead = pRAcc->GetScanline(nY); + + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX)); + aDstCol.SetIndex(pIndexMap[((static_cast<sal_uInt32>(aCol.GetRed()) + >> nRightShiftBits) + << nLeftShiftBits2) + | ((static_cast<sal_uInt32>(aCol.GetGreen()) + >> nRightShiftBits) + << nLeftShiftBits1) + | (static_cast<sal_uInt32>(aCol.GetBlue()) + >> nRightShiftBits)]); + pWAcc->SetPixelOnData(pScanline, nX, aDstCol); + } + } + } + + pWAcc.reset(); + bRet = true; + } + + pCountTable.reset(); + pRAcc.reset(); + + if (bRet) + { + const MapMode aMap(aBitmap.GetPrefMapMode()); + const Size aSize(aBitmap.GetPrefSize()); + + aBitmap = aNewBmp; + + aBitmap.SetPrefMapMode(aMap); + aBitmap.SetPrefSize(aSize); + } + } + } + + if (bRet) + return BitmapEx(aBitmap); + + return BitmapEx(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/bitmap/BitmapMedianColorQuantizationFilter.cxx b/vcl/source/bitmap/BitmapMedianColorQuantizationFilter.cxx new file mode 100644 index 000000000000..807e8a049a13 --- /dev/null +++ b/vcl/source/bitmap/BitmapMedianColorQuantizationFilter.cxx @@ -0,0 +1,300 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/BitmapMedianColorQuantizationFilter.hxx> + +#include <bitmapwriteaccess.hxx> +#include <impoctree.hxx> + +#include <cstdlib> + +BitmapEx BitmapMedianColorQuantizationFilter::execute(BitmapEx const& aBitmapEx) +{ + Bitmap aBitmap = aBitmapEx.GetBitmap(); + + bool bRet = false; + + if (aBitmap.GetColorCount() <= static_cast<sal_uLong>(mnNewColorCount)) + { + bRet = true; + } + else + { + Bitmap::ScopedReadAccess pRAcc(aBitmap); + sal_uInt16 nBitCount; + + if (mnNewColorCount < 17) + { + nBitCount = 4; + } + else if (mnNewColorCount < 257) + { + nBitCount = 8; + } + else + { + OSL_FAIL("Bitmap::ImplReduceMedian(): invalid color count!"); + nBitCount = 8; + mnNewColorCount = 256; + } + + if (pRAcc) + { + Bitmap aNewBmp(aBitmap.GetSizePixel(), nBitCount); + BitmapScopedWriteAccess pWAcc(aNewBmp); + + if (pWAcc) + { + const sal_uLong nSize = 32768 * sizeof(sal_uLong); + sal_uLong* pColBuf = static_cast<sal_uLong*>(rtl_allocateMemory(nSize)); + const long nWidth = pWAcc->Width(); + const long nHeight = pWAcc->Height(); + long nIndex = 0; + + memset(pColBuf, 0, nSize); + + // create Buffer + if (pRAcc->HasPalette()) + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor& rCol = pRAcc->GetPaletteColor( + pRAcc->GetIndexFromData(pScanlineRead, nX)); + + pColBuf[RGB15(rCol.GetRed() >> 3, rCol.GetGreen() >> 3, + rCol.GetBlue() >> 3)]++; + } + } + } + else + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX)); + pColBuf[RGB15(aCol.GetRed() >> 3, aCol.GetGreen() >> 3, + aCol.GetBlue() >> 3)]++; + } + } + } + + // create palette via median cut + BitmapPalette aPal(pWAcc->GetPaletteEntryCount()); + medianCut(aBitmap, pColBuf, aPal, 0, 31, 0, 31, 0, 31, mnNewColorCount, + nWidth * nHeight, nIndex); + + // do mapping of colors to palette + InverseColorMap aMap(aPal); + pWAcc->SetPalette(aPal); + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + pWAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(static_cast<sal_uInt8>( + aMap.GetBestPaletteIndex(pRAcc->GetColor(nY, nX))))); + } + } + + rtl_freeMemory(pColBuf); + pWAcc.reset(); + bRet = true; + } + + pRAcc.reset(); + if (bRet) + { + const MapMode aMap(aBitmap.GetPrefMapMode()); + const Size aSize(aBitmap.GetPrefSize()); + + aBitmap = aNewBmp; + + aBitmap.SetPrefMapMode(aMap); + aBitmap.SetPrefSize(aSize); + } + } + } + + if (bRet) + return BitmapEx(aBitmap); + + return BitmapEx(); +} + +void BitmapMedianColorQuantizationFilter::medianCut(Bitmap& rBitmap, sal_uLong* pColBuf, + BitmapPalette& rPal, long nR1, long nR2, + long nG1, long nG2, long nB1, long nB2, + long nColors, long nPixels, long& rIndex) +{ + if (!nPixels) + return; + + BitmapColor aCol; + const long nRLen = nR2 - nR1; + const long nGLen = nG2 - nG1; + const long nBLen = nB2 - nB1; + sal_uLong* pBuf = pColBuf; + + if (!nRLen && !nGLen && !nBLen) + { + if (pBuf[RGB15(nR1, nG1, nB1)]) + { + aCol.SetRed(static_cast<sal_uInt8>(nR1 << 3)); + aCol.SetGreen(static_cast<sal_uInt8>(nG1 << 3)); + aCol.SetBlue(static_cast<sal_uInt8>(nB1 << 3)); + rPal[static_cast<sal_uInt16>(rIndex++)] = aCol; + } + } + else + { + if (nColors == 1 || nPixels == 1) + { + long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; + + for (long nR = nR1; nR <= nR2; nR++) + { + for (long nG = nG1; nG <= nG2; nG++) + { + for (long nB = nB1; nB <= nB2; nB++) + { + nPixSum = pBuf[RGB15(nR, nG, nB)]; + + if (nPixSum) + { + nRSum += nR * nPixSum; + nGSum += nG * nPixSum; + nBSum += nB * nPixSum; + } + } + } + } + + aCol.SetRed(static_cast<sal_uInt8>((nRSum / nPixels) << 3)); + aCol.SetGreen(static_cast<sal_uInt8>((nGSum / nPixels) << 3)); + aCol.SetBlue(static_cast<sal_uInt8>((nBSum / nPixels) << 3)); + rPal[static_cast<sal_uInt16>(rIndex++)] = aCol; + } + else + { + const long nTest = (nPixels >> 1); + long nPixOld = 0; + long nPixNew = 0; + + if (nBLen > nGLen && nBLen > nRLen) + { + long nB = nB1 - 1; + + while (nPixNew < nTest) + { + nB++; + nPixOld = nPixNew; + for (long nR = nR1; nR <= nR2; nR++) + { + for (long nG = nG1; nG <= nG2; nG++) + { + nPixNew += pBuf[RGB15(nR, nG, nB)]; + } + } + } + + if (nB < nB2) + { + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, + nPixNew, rIndex); + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, + nPixels - nPixNew, rIndex); + } + else + { + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, + nPixOld, rIndex); + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, + nPixels - nPixOld, rIndex); + } + } + else if (nGLen > nRLen) + { + long nG = nG1 - 1; + + while (nPixNew < nTest) + { + nG++; + nPixOld = nPixNew; + for (long nR = nR1; nR <= nR2; nR++) + { + for (long nB = nB1; nB <= nB2; nB++) + { + nPixNew += pBuf[RGB15(nR, nG, nB)]; + } + } + } + + if (nG < nG2) + { + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, + nPixNew, rIndex); + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, + nPixels - nPixNew, rIndex); + } + else + { + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, + nPixOld, rIndex); + medianCut(rBitmap, pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, + nPixels - nPixOld, rIndex); + } + } + else + { + long nR = nR1 - 1; + + while (nPixNew < nTest) + { + nR++; + nPixOld = nPixNew; + for (long nG = nG1; nG <= nG2; nG++) + { + for (long nB = nB1; nB <= nB2; nB++) + { + nPixNew += pBuf[RGB15(nR, nG, nB)]; + } + } + } + + if (nR < nR2) + { + medianCut(rBitmap, pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, + nPixNew, rIndex); + medianCut(rBitmap, pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, + nPixels - nPixNew, rIndex); + } + else + { + medianCut(rBitmap, pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, + nPixOld, rIndex); + medianCut(rBitmap, pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, + nPixels - nPixOld, rIndex); + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx b/vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx new file mode 100644 index 000000000000..3ffade558c41 --- /dev/null +++ b/vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx @@ -0,0 +1,108 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/BitmapSimpleColorQuantizationFilter.hxx> + +#include <bitmapwriteaccess.hxx> +#include <impoctree.hxx> + +#include <cstdlib> + +BitmapEx BitmapSimpleColorQuantizationFilter::execute(BitmapEx const& aBitmapEx) +{ + Bitmap aBitmap = aBitmapEx.GetBitmap(); + + bool bRet = false; + + if (aBitmap.GetColorCount() <= static_cast<sal_uLong>(mnNewColorCount)) + { + bRet = true; + } + else + { + Bitmap aNewBmp; + Bitmap::ScopedReadAccess pRAcc(aBitmap); + const sal_uInt16 nColorCount = std::min(nColorCount, sal_uInt16(256)); + sal_uInt16 nBitCount = 0; + + if (pRAcc) + { + Octree aOct(*pRAcc, nColorCount); + const BitmapPalette& rPal = aOct.GetPalette(); + + aNewBmp = Bitmap(aBitmap.GetSizePixel(), nBitCount, &rPal); + BitmapScopedWriteAccess pWAcc(aNewBmp); + + if (pWAcc) + { + const long nWidth = pRAcc->Width(); + const long nHeight = pRAcc->Height(); + + if (pRAcc->HasPalette()) + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWAcc->GetScanline(nY); + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + auto c = pRAcc->GetPaletteColor( + pRAcc->GetIndexFromData(pScanlineRead, nX)); + pWAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(static_cast<sal_uInt8>(aOct.GetBestPaletteIndex(c)))); + } + } + } + else + { + for (long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWAcc->GetScanline(nY); + Scanline pScanlineRead = pRAcc->GetScanline(nY); + for (long nX = 0; nX < nWidth; nX++) + { + auto c = pRAcc->GetPixelFromData(pScanlineRead, nX); + pWAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(static_cast<sal_uInt8>(aOct.GetBestPaletteIndex(c)))); + } + } + } + + pWAcc.reset(); + bRet = true; + } + + pRAcc.reset(); + } + + if (bRet) + { + const MapMode aMap(aBitmap.GetPrefMapMode()); + const Size aSize(aBitmap.GetPrefSize()); + + aBitmap = aNewBmp; + + aBitmap.SetPrefMapMode(aMap); + aBitmap.SetPrefSize(aSize); + } + } + + if (bRet) + return BitmapEx(aBitmap); + + return BitmapEx(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/animate.cxx b/vcl/source/gdi/animate.cxx index d3c5031441f7..5adfc6ca5736 100644 --- a/vcl/source/gdi/animate.cxx +++ b/vcl/source/gdi/animate.cxx @@ -17,12 +17,14 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <vcl/animate.hxx> #include <tools/stream.hxx> #include <rtl/crc.h> + +#include <vcl/animate.hxx> #include <vcl/virdev.hxx> #include <vcl/window.hxx> #include <vcl/dibtools.hxx> +#include <vcl/BitmapColorQuantizationFilter.hxx> #include <impanmvw.hxx> @@ -527,13 +529,17 @@ bool Animation::ReduceColors( sal_uInt16 nNewColorCount ) { bRet = true; - for( size_t i = 0, n = maList.size(); ( i < n ) && bRet; ++i ) - bRet = maList[ i ]->aBmpEx.ReduceColors( nNewColorCount ); + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + { + bRet = BitmapFilter::Filter(maList[i]->aBmpEx, BitmapColorQuantizationFilter(nNewColorCount)); + } - maBitmapEx.ReduceColors( nNewColorCount ); + BitmapFilter::Filter(maBitmapEx, BitmapColorQuantizationFilter(nNewColorCount)); } else + { bRet = false; + } return bRet; } diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index 3bf068c3444a..8503db8fc2ca 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -43,7 +43,6 @@ #include <memory> -#define RGB15( _def_cR, _def_cG, _def_cB ) ((static_cast<sal_uLong>(_def_cR)<<10)|(static_cast<sal_uLong>(_def_cG)<<5)|static_cast<sal_uLong>(_def_cB)) #define GAMMA( _def_cVal, _def_InvGamma ) (static_cast<sal_uInt8>(MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0,255))) #define CALC_ERRORS \ @@ -1209,498 +1208,6 @@ bool Bitmap::ImplDitherFloyd16() return bRet; } -bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) -{ - bool bRet; - - if( GetColorCount() <= static_cast<sal_uLong>(nColorCount) ) - bRet = true; - else if( nColorCount ) - { - if( BMP_REDUCE_SIMPLE == eReduce ) - bRet = ImplReduceSimple( nColorCount ); - else if( BMP_REDUCE_POPULAR == eReduce ) - bRet = ImplReducePopular( nColorCount ); - else - bRet = ImplReduceMedian( nColorCount ); - } - else - bRet = false; - - return bRet; -} - -bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) -{ - Bitmap aNewBmp; - ScopedReadAccess pRAcc(*this); - const sal_uInt16 nColCount = std::min( nColorCount, sal_uInt16(256) ); - sal_uInt16 nBitCount; - bool bRet = false; - - if( nColCount <= 2 ) - nBitCount = 1; - else if( nColCount <= 16 ) - nBitCount = 4; - else - nBitCount = 8; - - if( pRAcc ) - { - Octree aOct( *pRAcc, nColCount ); - const BitmapPalette& rPal = aOct.GetPalette(); - - aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); - BitmapScopedWriteAccess pWAcc(aNewBmp); - - if( pWAcc ) - { - const long nWidth = pRAcc->Width(); - const long nHeight = pRAcc->Height(); - - if( pRAcc->HasPalette() ) - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanline = pWAcc->GetScanline(nY); - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX =0; nX < nWidth; nX++ ) - { - auto c = pRAcc->GetPaletteColor( pRAcc->GetIndexFromData( pScanlineRead, nX ) ); - pWAcc->SetPixelOnData( pScanline, nX, BitmapColor(static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( c ))) ); - } - } - } - else - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanline = pWAcc->GetScanline(nY); - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX =0; nX < nWidth; nX++ ) - { - auto c = pRAcc->GetPixelFromData( pScanlineRead, nX ); - pWAcc->SetPixelOnData( pScanline, nX, BitmapColor(static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( c ))) ); - } - } - } - - pWAcc.reset(); - bRet = true; - } - - pRAcc.reset(); - } - - if( bRet ) - { - const MapMode aMap( maPrefMapMode ); - const Size aSize( maPrefSize ); - - *this = aNewBmp; - maPrefMapMode = aMap; - maPrefSize = aSize; - } - - return bRet; -} - -struct PopularColorCount -{ - sal_uInt32 mnIndex; - sal_uInt32 mnCount; -}; - -extern "C" int ImplPopularCmpFnc( const void* p1, const void* p2 ) -{ - int nRet; - - if( static_cast<PopularColorCount const *>(p1)->mnCount < static_cast<PopularColorCount const *>(p2)->mnCount ) - nRet = 1; - else if( static_cast<PopularColorCount const *>(p1)->mnCount == static_cast<PopularColorCount const *>(p2)->mnCount ) - nRet = 0; - else - nRet = -1; - - return nRet; -} - -bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) -{ - ScopedReadAccess pRAcc(*this); - sal_uInt16 nBitCount; - bool bRet = false; - - if( nColCount > 256 ) - nColCount = 256; - - if( nColCount < 17 ) - nBitCount = 4; - else - nBitCount = 8; - - if( pRAcc ) - { - const sal_uInt32 nValidBits = 4; - const sal_uInt32 nRightShiftBits = 8 - nValidBits; - const sal_uInt32 nLeftShiftBits1 = nValidBits; - const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; - const sal_uInt32 nColorsPerComponent = 1 << nValidBits; - const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; - const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; - const long nWidth = pRAcc->Width(); - const long nHeight = pRAcc->Height(); - std::unique_ptr<PopularColorCount[]> pCountTable(new PopularColorCount[ nTotalColors ]); - - memset( pCountTable.get(), 0, nTotalColors * sizeof( PopularColorCount ) ); - - for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) - { - for( long nG = 0; nG < 256; nG += nColorOffset ) - { - for( long nB = 0; nB < 256; nB += nColorOffset ) - { - pCountTable[ nIndex ].mnIndex = nIndex; - nIndex++; - } - } - } - - if( pRAcc->HasPalette() ) - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetIndexFromData( pScanlineRead, nX ) ); - pCountTable[ ( ( static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits ) << nLeftShiftBits2 ) | - ( ( static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits ) << nLeftShiftBits1 ) | - ( static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits ) ].mnCount++; - } - } - } - else - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor aCol( pRAcc->GetPixelFromData( pScanlineRead, nX ) ); - pCountTable[ ( ( static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits ) << nLeftShiftBits2 ) | - ( ( static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits ) << nLeftShiftBits1 ) | - ( static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits ) ].mnCount++; - } - } - } - - BitmapPalette aNewPal( nColCount ); - - qsort( pCountTable.get(), nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); - - for( sal_uInt16 n = 0; n < nColCount; n++ ) - { - const PopularColorCount& rPop = pCountTable[ n ]; - aNewPal[ n ] = BitmapColor( static_cast<sal_uInt8>( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), - static_cast<sal_uInt8>( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), - static_cast<sal_uInt8>( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); - } - - Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); - BitmapScopedWriteAccess pWAcc(aNewBmp); - - if( pWAcc ) - { - BitmapColor aDstCol( sal_uInt8(0) ); - std::unique_ptr<sal_uInt8[]> pIndexMap(new sal_uInt8[ nTotalColors ]); - - for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) - for( long nG = 0; nG < 256; nG += nColorOffset ) - for( long nB = 0; nB < 256; nB += nColorOffset ) - pIndexMap[ nIndex++ ] = static_cast<sal_uInt8>(aNewPal.GetBestIndex( BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) ) )); - - if( pRAcc->HasPalette() ) - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanline = pWAcc->GetScanline(nY); - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetIndexFromData( pScanlineRead, nX ) ); - aDstCol.SetIndex( pIndexMap[ ( ( static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits ) << nLeftShiftBits2 ) | - ( ( static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits ) << nLeftShiftBits1 ) | - ( static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits ) ] ); - pWAcc->SetPixelOnData( pScanline, nX, aDstCol ); - } - } - } - else - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanline = pWAcc->GetScanline(nY); - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor aCol( pRAcc->GetPixelFromData( pScanlineRead, nX ) ); - aDstCol.SetIndex( pIndexMap[ ( ( static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits ) << nLeftShiftBits2 ) | - ( ( static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits ) << nLeftShiftBits1 ) | - ( static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits ) ] ); - pWAcc->SetPixelOnData( pScanline, nX, aDstCol ); - } - } - } - - pWAcc.reset(); - bRet = true; - } - - pCountTable.reset(); - pRAcc.reset(); - - if( bRet ) - { - const MapMode aMap( maPrefMapMode ); - const Size aSize( maPrefSize ); - - *this = aNewBmp; - maPrefMapMode = aMap; - maPrefSize = aSize; - } - } - - return bRet; -} - -bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) -{ - ScopedReadAccess pRAcc(*this); - sal_uInt16 nBitCount; - bool bRet = false; - - if( nColCount < 17 ) - nBitCount = 4; - else if( nColCount < 257 ) - nBitCount = 8; - else - { - OSL_FAIL( "Bitmap::ImplReduceMedian(): invalid color count!" ); - nBitCount = 8; - nColCount = 256; - } - - if( pRAcc ) - { - Bitmap aNewBmp( GetSizePixel(), nBitCount ); - BitmapScopedWriteAccess pWAcc(aNewBmp); - - if( pWAcc ) - { - const sal_uLong nSize = 32768 * sizeof( sal_uLong ); - sal_uLong* pColBuf = static_cast<sal_uLong*>(rtl_allocateMemory( nSize )); - const long nWidth = pWAcc->Width(); - const long nHeight = pWAcc->Height(); - long nIndex = 0; - - memset( pColBuf, 0, nSize ); - - // create Buffer - if( pRAcc->HasPalette() ) - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetIndexFromData( pScanlineRead, nX ) ); - pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; - } - } - } - else - { - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanlineRead = pRAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - { - const BitmapColor aCol( pRAcc->GetPixelFromData( pScanlineRead, nX ) ); - pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; - } - } - } - - // create palette via median cut - BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); - ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, - nColCount, nWidth * nHeight, nIndex ); - - // do mapping of colors to palette - InverseColorMap aMap( aPal ); - pWAcc->SetPalette( aPal ); - for( long nY = 0; nY < nHeight; nY++ ) - { - Scanline pScanline = pWAcc->GetScanline(nY); - for( long nX = 0; nX < nWidth; nX++ ) - pWAcc->SetPixelOnData( pScanline, nX, BitmapColor(static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ))) ); - } - - rtl_freeMemory( pColBuf ); - pWAcc.reset(); - bRet = true; - } - - pRAcc.reset(); - - if( bRet ) - { - const MapMode aMap( maPrefMapMode ); - const Size aSize( maPrefSize ); - - *this = aNewBmp; - maPrefMapMode = aMap; - maPrefSize = aSize; - } - } - - return bRet; -} - -void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, - long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, - long nColors, long nPixels, long& rIndex ) -{ - if( !nPixels ) - return; - - BitmapColor aCol; - const long nRLen = nR2 - nR1; - const long nGLen = nG2 - nG1; - const long nBLen = nB2 - nB1; - sal_uLong* pBuf = pColBuf; - - if( !nRLen && !nGLen && !nBLen ) - { - if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) - { - aCol.SetRed( static_cast<sal_uInt8>( nR1 << 3 ) ); - aCol.SetGreen( static_cast<sal_uInt8>( nG1 << 3 ) ); - aCol.SetBlue( static_cast<sal_uInt8>( nB1 << 3 ) ); - rPal[ static_cast<sal_uInt16>(rIndex++) ] = aCol; - } - } - else - { - if( 1 == nColors || 1 == nPixels ) - { - long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; - - for( long nR = nR1; nR <= nR2; nR++ ) - { - for( long nG = nG1; nG <= nG2; nG++ ) - { - for( long nB = nB1; nB <= nB2; nB++ ) - { - nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; - - if( nPixSum ) - { - nRSum += nR * nPixSum; - nGSum += nG * nPixSum; - nBSum += nB * nPixSum; - } - } - } - } - - aCol.SetRed( static_cast<sal_uInt8>( ( nRSum / nPixels ) << 3 ) ); - aCol.SetGreen( static_cast<sal_uInt8>( ( nGSum / nPixels ) << 3 ) ); - aCol.SetBlue( static_cast<sal_uInt8>( ( nBSum / nPixels ) << 3 ) ); - rPal[ static_cast<sal_uInt16>(rIndex++) ] = aCol; - } - else - { - const long nTest = ( nPixels >> 1 ); - long nPixOld = 0; - long nPixNew = 0; - - if( nBLen > nGLen && nBLen > nRLen ) - { - long nB = nB1 - 1; - - while( nPixNew < nTest ) - { - nB++; - nPixOld = nPixNew; - for( long nR = nR1; nR <= nR2; nR++ ) - for( long nG = nG1; nG <= nG2; nG++ ) - nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; - } - - if( nB < nB2 ) - { - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); - } - else - { - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); - } - } - else if( nGLen > nRLen ) - { - long nG = nG1 - 1; - - while( nPixNew < nTest ) - { - nG++; - nPixOld = nPixNew; - for( long nR = nR1; nR <= nR2; nR++ ) - for( long nB = nB1; nB <= nB2; nB++ ) - nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; - } - - if( nG < nG2 ) - { - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); - ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); - } - else - { - ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); - ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); - } - } - else - { - long nR = nR1 - 1; - - while( nPixNew < nTest ) - { - nR++; - nPixOld = nPixNew; - for( long nG = nG1; nG <= nG2; nG++ ) - for( long nB = nB1; nB <= nB2; nB++ ) - nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; - } - - if( nR < nR2 ) - { - ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); - ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); - } - else - { - ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); - ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); - } - } - } - } -} void Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, const Link<long,void>* pProgress ) { diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index 5b03870578cd..2f6f9bfb5870 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -446,11 +446,6 @@ bool BitmapEx::Convert( BmpConversion eConversion ) return !!maBitmap && maBitmap.Convert( eConversion ); } -bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount ) -{ - return !!maBitmap && maBitmap.ReduceColors( nNewColorCount, BMP_REDUCE_POPULAR ); -} - void BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, bool bExpandTransparent ) { bool bRet = false; diff --git a/vcl/unx/generic/dtrans/bmp.cxx b/vcl/unx/generic/dtrans/bmp.cxx index c72e93100eb4..b6b5d1888aa1 100644 --- a/vcl/unx/generic/dtrans/bmp.cxx +++ b/vcl/unx/generic/dtrans/bmp.cxx @@ -17,20 +17,23 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <unistd.h> -#include <cstdio> -#include <cstring> - -#include "bmp.hxx" - -#include "X11_selection.hxx" -#include <unx/x11/xlimits.hxx> - #include <sal/macros.h> #include <tools/stream.hxx> + #include <vcl/dibtools.hxx> #include <vcl/svapp.hxx> #include <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/BitmapSimpleColorQuantizationFilter.hxx> + +#include <unx/x11/xlimits.hxx> + +#include "bmp.hxx" +#include "X11_selection.hxx" + +#include <unistd.h> +#include <cstdio> +#include <cstring> using namespace x11; @@ -753,11 +756,21 @@ css::uno::Sequence<sal_Int8> x11::convertBitmapDepth( bm.Convert(BmpConversion::N1BitThreshold); break; case 4: - bm.ReduceColors(1<<4); - break; + { + BitmapEx aBmpEx(bm); + BitmapFilter::Filter(aBmpEx, BitmapSimpleColorQuantizationFilter(1<<4)); + bm = aBmpEx.GetBitmap(); + } + break; + case 8: - bm.ReduceColors(1<<8); - break; + { + BitmapEx aBmpEx(bm); + BitmapFilter::Filter(aBmpEx, BitmapSimpleColorQuantizationFilter(1<<8)); + bm = aBmpEx.GetBitmap(); + } + break; + case 24: bm.Convert(BmpConversion::N24Bit); break; |