[Libreoffice-commits] core.git: cui/source include/vcl sd/source vcl/Library_vcl.mk vcl/source vcl/unx

Chris Sherlock chris.sherlock79 at gmail.com
Fri Apr 20 06:36:45 UTC 2018


 cui/source/dialogs/cuigrfflt.cxx                          |    3 
 include/vcl/BitmapColorQuantizationFilter.hxx             |   45 +
 include/vcl/BitmapMedianColorQuantizationFilter.hxx       |   49 +
 include/vcl/BitmapSimpleColorQuantizationFilter.hxx       |   39 +
 include/vcl/bitmap.hxx                                    |   28 
 include/vcl/bitmapex.hxx                                  |    9 
 sd/source/ui/dlg/vectdlg.cxx                              |    9 
 vcl/Library_vcl.mk                                        |    3 
 vcl/source/bitmap/BitmapColorQuantizationFilter.cxx       |  229 ++++++
 vcl/source/bitmap/BitmapMedianColorQuantizationFilter.cxx |  300 ++++++++
 vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx |  108 +++
 vcl/source/gdi/animate.cxx                                |   14 
 vcl/source/gdi/bitmap3.cxx                                |  493 --------------
 vcl/source/gdi/bitmapex.cxx                               |    5 
 vcl/unx/generic/dtrans/bmp.cxx                            |   39 -
 15 files changed, 817 insertions(+), 556 deletions(-)

New commits:
commit 900b1109a94c1d72c17ab429da1b6c6c2bf79ac6
Author: Chris Sherlock <chris.sherlock79 at gmail.com>
Date:   Tue Apr 17 22:06:20 2018 +1000

    vcl: move Bitmap{Ex}::ReduceColors() to BitmapColorQuantizationFilter class
    
    Change-Id: I32b58e8d451e7303e94788a546a5b5f9a5bb4590
    Reviewed-on: https://gerrit.libreoffice.org/53037
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

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;


More information about the Libreoffice-commits mailing list