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