LibreOffice Module vcl (master) 1
BitmapColorQuantizationFilter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <sal/config.h>
12
13#include <vcl/bitmap.hxx>
14#include <vcl/bitmapex.hxx>
16
18
19#include <algorithm>
20#include <cstdlib>
21
23{
24 Bitmap aBitmap = aBitmapEx.GetBitmap();
25
26 if (vcl::numberOfColors(aBitmap.getPixelFormat()) <= sal_Int64(mnNewColorCount))
27 return BitmapEx(aBitmap);
28
29 Bitmap::ScopedReadAccess pRAcc(aBitmap);
30 if (!pRAcc)
31 return BitmapEx();
32
33 auto const cappedNewColorCount = std::min(mnNewColorCount, sal_uInt16(256));
34
35 const sal_uInt32 nValidBits = 4;
36 const sal_uInt32 nRightShiftBits = 8 - nValidBits;
37 const sal_uInt32 nLeftShiftBits1 = nValidBits;
38 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
39 const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
40 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
41 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
42 const sal_Int32 nWidth = pRAcc->Width();
43 const sal_Int32 nHeight = pRAcc->Height();
44 std::unique_ptr<PopularColorCount[]> pCountTable(new PopularColorCount[nTotalColors]);
45
46 memset(pCountTable.get(), 0, nTotalColors * sizeof(PopularColorCount));
47
48 for (sal_Int32 nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
49 {
50 for (sal_Int32 nG = 0; nG < 256; nG += nColorOffset)
51 {
52 for (sal_Int32 nB = 0; nB < 256; nB += nColorOffset)
53 {
54 pCountTable[nIndex].mnIndex = nIndex;
55 nIndex++;
56 }
57 }
58 }
59
60 if (pRAcc->HasPalette())
61 {
62 for (sal_Int32 nY = 0; nY < nHeight; nY++)
63 {
64 Scanline pScanlineRead = pRAcc->GetScanline(nY);
65 for (sal_Int32 nX = 0; nX < nWidth; nX++)
66 {
67 const BitmapColor& rCol
68 = pRAcc->GetPaletteColor(pRAcc->GetIndexFromData(pScanlineRead, nX));
69 pCountTable[((static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits)
70 << nLeftShiftBits2)
71 | ((static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits)
72 << nLeftShiftBits1)
73 | (static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits)]
74 .mnCount++;
75 }
76 }
77 }
78 else
79 {
80 for (sal_Int32 nY = 0; nY < nHeight; nY++)
81 {
82 Scanline pScanlineRead = pRAcc->GetScanline(nY);
83 for (sal_Int32 nX = 0; nX < nWidth; nX++)
84 {
85 const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX));
86 pCountTable[((static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits)
87 << nLeftShiftBits2)
88 | ((static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits)
89 << nLeftShiftBits1)
90 | (static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits)]
91 .mnCount++;
92 }
93 }
94 }
95
96 BitmapPalette aNewPal(cappedNewColorCount);
97
98 std::qsort(pCountTable.get(), nTotalColors, sizeof(PopularColorCount),
99 [](const void* p1, const void* p2) {
100 int nRet;
101
102 if (static_cast<PopularColorCount const*>(p1)->mnCount
103 < static_cast<PopularColorCount const*>(p2)->mnCount)
104 nRet = 1;
105 else if (static_cast<PopularColorCount const*>(p1)->mnCount
106 == static_cast<PopularColorCount const*>(p2)->mnCount)
107 nRet = 0;
108 else
109 nRet = -1;
110
111 return nRet;
112 });
113
114 for (sal_uInt16 n = 0; n < cappedNewColorCount; n++)
115 {
116 const PopularColorCount& rPop = pCountTable[n];
117 aNewPal[n] = BitmapColor(
118 static_cast<sal_uInt8>((rPop.mnIndex >> nLeftShiftBits2) << nRightShiftBits),
119 static_cast<sal_uInt8>(((rPop.mnIndex >> nLeftShiftBits1) & (nColorsPerComponent - 1))
120 << nRightShiftBits),
121 static_cast<sal_uInt8>((rPop.mnIndex & (nColorsPerComponent - 1)) << nRightShiftBits));
122 }
123
124 Bitmap aNewBmp(aBitmap.GetSizePixel(), vcl::PixelFormat::N8_BPP, &aNewPal);
125 BitmapScopedWriteAccess pWAcc(aNewBmp);
126 if (!pWAcc)
127 return BitmapEx();
128
129 BitmapColor aDstCol(sal_uInt8(0));
130 std::unique_ptr<sal_uInt8[]> pIndexMap(new sal_uInt8[nTotalColors]);
131
132 for (sal_Int32 nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
133 {
134 for (sal_Int32 nG = 0; nG < 256; nG += nColorOffset)
135 {
136 for (sal_Int32 nB = 0; nB < 256; nB += nColorOffset)
137 {
138 pIndexMap[nIndex++] = static_cast<sal_uInt8>(aNewPal.GetBestIndex(
139 BitmapColor(static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG),
140 static_cast<sal_uInt8>(nB))));
141 }
142 }
143 }
144
145 if (pRAcc->HasPalette())
146 {
147 for (sal_Int32 nY = 0; nY < nHeight; nY++)
148 {
149 Scanline pScanline = pWAcc->GetScanline(nY);
150 Scanline pScanlineRead = pRAcc->GetScanline(nY);
151 for (sal_Int32 nX = 0; nX < nWidth; nX++)
152 {
153 const BitmapColor& rCol
154 = pRAcc->GetPaletteColor(pRAcc->GetIndexFromData(pScanlineRead, nX));
155 aDstCol.SetIndex(
156 pIndexMap[((static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits)
157 << nLeftShiftBits2)
158 | ((static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits)
159 << nLeftShiftBits1)
160 | (static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits)]);
161 pWAcc->SetPixelOnData(pScanline, nX, aDstCol);
162 }
163 }
164 }
165 else
166 {
167 for (sal_Int32 nY = 0; nY < nHeight; nY++)
168 {
169 Scanline pScanline = pWAcc->GetScanline(nY);
170 Scanline pScanlineRead = pRAcc->GetScanline(nY);
171
172 for (sal_Int32 nX = 0; nX < nWidth; nX++)
173 {
174 const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX));
175 aDstCol.SetIndex(
176 pIndexMap[((static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits)
177 << nLeftShiftBits2)
178 | ((static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits)
179 << nLeftShiftBits1)
180 | (static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits)]);
181 pWAcc->SetPixelOnData(pScanline, nX, aDstCol);
182 }
183 }
184 }
185
186 pWAcc.reset();
187 pCountTable.reset();
188 pRAcc.reset();
189
190 const MapMode aMap(aBitmap.GetPrefMapMode());
191 const Size aSize(aBitmap.GetPrefSize());
192
193 aBitmap = aNewBmp;
194
195 aBitmap.SetPrefMapMode(aMap);
196 aBitmap.SetPrefSize(aSize);
197
198 return BitmapEx(aBitmap);
199}
200
201/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
virtual BitmapEx execute(BitmapEx const &rBitmapEx) const override
void SetIndex(sal_uInt8 cIndex)
Definition: BitmapColor.hxx:75
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:217
tools::Long Height() const
tools::Long Width() const
bool HasPalette() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
void SetPrefMapMode(const MapMode &rMapMode)
const MapMode & GetPrefMapMode() const
Size GetSizePixel() const
void SetPrefSize(const Size &rSize)
const Size & GetPrefSize() const
vcl::PixelFormat getPixelFormat() const
sal_uInt8 GetBlue() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
sal_Int32 nIndex
sal_Int64 n
constexpr sal_Int64 numberOfColors(PixelFormat ePixelFormat)
Definition: BitmapTypes.hxx:39
HashMap_OWString_Interface aMap
unsigned char sal_uInt8