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 bool bRet = false;
27
28 if (vcl::numberOfColors(aBitmap.getPixelFormat()) <= sal_Int64(mnNewColorCount))
29 {
30 bRet = true;
31 }
32 else
33 {
34 Bitmap::ScopedReadAccess pRAcc(aBitmap);
35
36 auto const cappedNewColorCount = std::min(mnNewColorCount, sal_uInt16(256));
37
38 if (pRAcc)
39 {
40 const sal_uInt32 nValidBits = 4;
41 const sal_uInt32 nRightShiftBits = 8 - nValidBits;
42 const sal_uInt32 nLeftShiftBits1 = nValidBits;
43 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
44 const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
45 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
46 const sal_uInt32 nTotalColors
47 = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
48 const sal_Int32 nWidth = pRAcc->Width();
49 const sal_Int32 nHeight = pRAcc->Height();
50 std::unique_ptr<PopularColorCount[]> pCountTable(new PopularColorCount[nTotalColors]);
51
52 memset(pCountTable.get(), 0, nTotalColors * sizeof(PopularColorCount));
53
54 for (sal_Int32 nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
55 {
56 for (sal_Int32 nG = 0; nG < 256; nG += nColorOffset)
57 {
58 for (sal_Int32 nB = 0; nB < 256; nB += nColorOffset)
59 {
60 pCountTable[nIndex].mnIndex = nIndex;
61 nIndex++;
62 }
63 }
64 }
65
66 if (pRAcc->HasPalette())
67 {
68 for (sal_Int32 nY = 0; nY < nHeight; nY++)
69 {
70 Scanline pScanlineRead = pRAcc->GetScanline(nY);
71 for (sal_Int32 nX = 0; nX < nWidth; nX++)
72 {
73 const BitmapColor& rCol
74 = pRAcc->GetPaletteColor(pRAcc->GetIndexFromData(pScanlineRead, nX));
75 pCountTable[((static_cast<sal_uInt32>(rCol.GetRed()) >> nRightShiftBits)
76 << nLeftShiftBits2)
77 | ((static_cast<sal_uInt32>(rCol.GetGreen()) >> nRightShiftBits)
78 << nLeftShiftBits1)
79 | (static_cast<sal_uInt32>(rCol.GetBlue()) >> nRightShiftBits)]
80 .mnCount++;
81 }
82 }
83 }
84 else
85 {
86 for (sal_Int32 nY = 0; nY < nHeight; nY++)
87 {
88 Scanline pScanlineRead = pRAcc->GetScanline(nY);
89 for (sal_Int32 nX = 0; nX < nWidth; nX++)
90 {
91 const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX));
92 pCountTable[((static_cast<sal_uInt32>(aCol.GetRed()) >> nRightShiftBits)
93 << nLeftShiftBits2)
94 | ((static_cast<sal_uInt32>(aCol.GetGreen()) >> nRightShiftBits)
95 << nLeftShiftBits1)
96 | (static_cast<sal_uInt32>(aCol.GetBlue()) >> nRightShiftBits)]
97 .mnCount++;
98 }
99 }
100 }
101
102 BitmapPalette aNewPal(cappedNewColorCount);
103
104 std::qsort(pCountTable.get(), nTotalColors, sizeof(PopularColorCount),
105 [](const void* p1, const void* p2) {
106 int nRet;
107
108 if (static_cast<PopularColorCount const*>(p1)->mnCount
109 < static_cast<PopularColorCount const*>(p2)->mnCount)
110 nRet = 1;
111 else if (static_cast<PopularColorCount const*>(p1)->mnCount
112 == static_cast<PopularColorCount const*>(p2)->mnCount)
113 nRet = 0;
114 else
115 nRet = -1;
116
117 return nRet;
118 });
119
120 for (sal_uInt16 n = 0; n < cappedNewColorCount; n++)
121 {
122 const PopularColorCount& rPop = pCountTable[n];
123 aNewPal[n] = BitmapColor(
124 static_cast<sal_uInt8>((rPop.mnIndex >> nLeftShiftBits2) << nRightShiftBits),
125 static_cast<sal_uInt8>(
126 ((rPop.mnIndex >> nLeftShiftBits1) & (nColorsPerComponent - 1))
127 << nRightShiftBits),
128 static_cast<sal_uInt8>((rPop.mnIndex & (nColorsPerComponent - 1))
129 << nRightShiftBits));
130 }
131
132 Bitmap aNewBmp(aBitmap.GetSizePixel(), vcl::PixelFormat::N8_BPP, &aNewPal);
133 BitmapScopedWriteAccess pWAcc(aNewBmp);
134
135 if (pWAcc)
136 {
137 BitmapColor aDstCol(sal_uInt8(0));
138 std::unique_ptr<sal_uInt8[]> pIndexMap(new sal_uInt8[nTotalColors]);
139
140 for (sal_Int32 nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
141 {
142 for (sal_Int32 nG = 0; nG < 256; nG += nColorOffset)
143 {
144 for (sal_Int32 nB = 0; nB < 256; nB += nColorOffset)
145 {
146 pIndexMap[nIndex++] = static_cast<sal_uInt8>(aNewPal.GetBestIndex(
147 BitmapColor(static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG),
148 static_cast<sal_uInt8>(nB))));
149 }
150 }
151 }
152
153 if (pRAcc->HasPalette())
154 {
155 for (sal_Int32 nY = 0; nY < nHeight; nY++)
156 {
157 Scanline pScanline = pWAcc->GetScanline(nY);
158 Scanline pScanlineRead = pRAcc->GetScanline(nY);
159 for (sal_Int32 nX = 0; nX < nWidth; nX++)
160 {
161 const BitmapColor& rCol = pRAcc->GetPaletteColor(
162 pRAcc->GetIndexFromData(pScanlineRead, nX));
163 aDstCol.SetIndex(pIndexMap[((static_cast<sal_uInt32>(rCol.GetRed())
164 >> nRightShiftBits)
165 << nLeftShiftBits2)
166 | ((static_cast<sal_uInt32>(rCol.GetGreen())
167 >> nRightShiftBits)
168 << nLeftShiftBits1)
169 | (static_cast<sal_uInt32>(rCol.GetBlue())
170 >> nRightShiftBits)]);
171 pWAcc->SetPixelOnData(pScanline, nX, aDstCol);
172 }
173 }
174 }
175 else
176 {
177 for (sal_Int32 nY = 0; nY < nHeight; nY++)
178 {
179 Scanline pScanline = pWAcc->GetScanline(nY);
180 Scanline pScanlineRead = pRAcc->GetScanline(nY);
181
182 for (sal_Int32 nX = 0; nX < nWidth; nX++)
183 {
184 const BitmapColor aCol(pRAcc->GetPixelFromData(pScanlineRead, nX));
185 aDstCol.SetIndex(pIndexMap[((static_cast<sal_uInt32>(aCol.GetRed())
186 >> nRightShiftBits)
187 << nLeftShiftBits2)
188 | ((static_cast<sal_uInt32>(aCol.GetGreen())
189 >> nRightShiftBits)
190 << nLeftShiftBits1)
191 | (static_cast<sal_uInt32>(aCol.GetBlue())
192 >> nRightShiftBits)]);
193 pWAcc->SetPixelOnData(pScanline, nX, aDstCol);
194 }
195 }
196 }
197
198 pWAcc.reset();
199 bRet = true;
200 }
201
202 pCountTable.reset();
203 pRAcc.reset();
204
205 if (bRet)
206 {
207 const MapMode aMap(aBitmap.GetPrefMapMode());
208 const Size aSize(aBitmap.GetPrefSize());
209
210 aBitmap = aNewBmp;
211
212 aBitmap.SetPrefMapMode(aMap);
213 aBitmap.SetPrefSize(aSize);
214 }
215 }
216 }
217
218 if (bRet)
219 return BitmapEx(aBitmap);
220
221 return BitmapEx();
222}
223
224/* 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:203
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:40
HashMap_OWString_Interface aMap
unsigned char sal_uInt8