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 tools::Long nWidth = pRAcc->Width();
49  const tools::Long nHeight = pRAcc->Height();
50  std::unique_ptr<PopularColorCount[]> pCountTable(new PopularColorCount[nTotalColors]);
51 
52  memset(pCountTable.get(), 0, nTotalColors * sizeof(PopularColorCount));
53 
54  for (tools::Long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
55  {
56  for (tools::Long nG = 0; nG < 256; nG += nColorOffset)
57  {
58  for (tools::Long 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 (tools::Long nY = 0; nY < nHeight; nY++)
69  {
70  Scanline pScanlineRead = pRAcc->GetScanline(nY);
71  for (tools::Long 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 (tools::Long nY = 0; nY < nHeight; nY++)
87  {
88  Scanline pScanlineRead = pRAcc->GetScanline(nY);
89  for (tools::Long 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 (tools::Long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset)
141  {
142  for (tools::Long nG = 0; nG < 256; nG += nColorOffset)
143  {
144  for (tools::Long 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 (tools::Long nY = 0; nY < nHeight; nY++)
156  {
157  Scanline pScanline = pWAcc->GetScanline(nY);
158  Scanline pScanlineRead = pRAcc->GetScanline(nY);
159  for (tools::Long 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 (tools::Long nY = 0; nY < nHeight; nY++)
178  {
179  Scanline pScanline = pWAcc->GetScanline(nY);
180  Scanline pScanlineRead = pRAcc->GetScanline(nY);
181 
182  for (tools::Long 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 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
tools::Long Height() const
sal_Int32 nIndex
sal_uInt8 GetRed() const
long Long
sal_Int64 n
Size GetSizePixel() const
const Size & GetPrefSize() const
HashMap_OWString_Interface aMap
Scanline GetScanline(tools::Long nY) const
sal_uInt8 GetBlue() const
const MapMode & GetPrefMapMode() const
void SetPrefMapMode(const MapMode &rMapMode)
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
vcl::PixelFormat getPixelFormat() const
bool HasPalette() const
virtual BitmapEx execute(BitmapEx const &rBitmapEx) const override
tools::Long Width() const
std::size_t mnCount
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
void SetIndex(sal_uInt8 cIndex)
Definition: BitmapColor.hxx:75
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
sal_uInt8 GetGreen() const
unsigned char sal_uInt8
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
constexpr sal_Int64 numberOfColors(PixelFormat ePixelFormat)
Definition: BitmapTypes.hxx:40