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