vcl: move Bitmap{Ex}::ReduceColors() to BitmapColorQuantizationFilter class
Change-Id: I32b58e8d451e7303e94788a546a5b5f9a5bb4590
Reviewed-on: https://gerrit.libreoffice.org/53037
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/cui/source/dialogs/cuigrfflt.cxx b/cui/source/dialogs/cuigrfflt.cxx
index 9f0f60d2..406e2b6 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 0000000..e695567
--- /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 0000000..c15b0ac
--- /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 0000000..b05b13f
--- /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 6370a63..ad1efb8 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 41b1fb2..390a2c0 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 2c64760..44ed925 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 03c705a..cfd5da3 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 0000000..13e8834
--- /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 0000000..807e8a0
--- /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 0000000..3ffade5
--- /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 d3c5031..5adfc6c 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 3bf068c..8503db8 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 5b03870..2f6f9bf 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 c72e931..b6b5d18 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;