LibreOffice Module vcl (master)  1
BitmapMedianFilter.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 <vcl/bitmap.hxx>
12 #include <vcl/bitmapex.hxx>
13 #include <vcl/bitmapaccess.hxx>
15 
16 #include <bitmapwriteaccess.hxx>
17 
18 #define S2(a, b) \
19  { \
20  long t; \
21  if ((t = b - a) < 0) \
22  { \
23  a += t; \
24  b -= t; \
25  } \
26  }
27 #define MN3(a, b, c) \
28  S2(a, b); \
29  S2(a, c);
30 #define MX3(a, b, c) \
31  S2(b, c); \
32  S2(a, c);
33 #define MNMX3(a, b, c) \
34  MX3(a, b, c); \
35  S2(a, b);
36 #define MNMX4(a, b, c, d) \
37  S2(a, b); \
38  S2(c, d); \
39  S2(a, c); \
40  S2(b, d);
41 #define MNMX5(a, b, c, d, e) \
42  S2(a, b); \
43  S2(c, d); \
44  MN3(a, c, e); \
45  MX3(b, d, e);
46 #define MNMX6(a, b, c, d, e, f) \
47  S2(a, d); \
48  S2(b, e); \
49  S2(c, f); \
50  MN3(a, b, c); \
51  MX3(d, e, f);
52 
54 {
55  Bitmap aBitmap(rBitmapEx.GetBitmap());
56 
57  Bitmap::ScopedReadAccess pReadAcc(aBitmap);
58  bool bRet = false;
59 
60  if (pReadAcc)
61  {
62  Bitmap aNewBmp(aBitmap.GetSizePixel(), 24);
63  BitmapScopedWriteAccess pWriteAcc(aNewBmp);
64 
65  if (pWriteAcc)
66  {
67  const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
68  const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
69  std::unique_ptr<long[]> pColm(new long[nWidth2]);
70  std::unique_ptr<long[]> pRows(new long[nHeight2]);
71  std::unique_ptr<BitmapColor[]> pColRow1(new BitmapColor[nWidth2]);
72  std::unique_ptr<BitmapColor[]> pColRow2(new BitmapColor[nWidth2]);
73  std::unique_ptr<BitmapColor[]> pColRow3(new BitmapColor[nWidth2]);
74  BitmapColor* pRowTmp1 = pColRow1.get();
75  BitmapColor* pRowTmp2 = pColRow2.get();
76  BitmapColor* pRowTmp3 = pColRow3.get();
77  BitmapColor* pColor;
78  long nY, nX, i;
79  long nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9;
80  long nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9;
81  long nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9;
82 
83  // create column LUT
84  for (i = 0; i < nWidth2; i++)
85  pColm[i] = (i > 0) ? (i - 1) : 0;
86 
87  pColm[nWidth + 1] = pColm[nWidth];
88 
89  // create row LUT
90  for (i = 0; i < nHeight2; i++)
91  pRows[i] = (i > 0) ? (i - 1) : 0;
92 
93  pRows[nHeight + 1] = pRows[nHeight];
94 
95  // read first three rows of bitmap color
96  if (nHeight2 > 2)
97  {
98  for (i = 0; i < nWidth2; i++)
99  {
100  pColRow1[i] = pReadAcc->GetColor(pRows[0], pColm[i]);
101  pColRow2[i] = pReadAcc->GetColor(pRows[1], pColm[i]);
102  pColRow3[i] = pReadAcc->GetColor(pRows[2], pColm[i]);
103  }
104  }
105 
106  // do median filtering
107  for (nY = 0; nY < nHeight;)
108  {
109  Scanline pScanline = pWriteAcc->GetScanline(nY);
110  for (nX = 0; nX < nWidth; nX++)
111  {
112  pColor = pRowTmp1 + nX;
113  nR1 = pColor->GetRed();
114  nG1 = pColor->GetGreen();
115  nB1 = pColor->GetBlue();
116  nR2 = (++pColor)->GetRed();
117  nG2 = pColor->GetGreen();
118  nB2 = pColor->GetBlue();
119  nR3 = (++pColor)->GetRed();
120  nG3 = pColor->GetGreen();
121  nB3 = pColor->GetBlue();
122 
123  pColor = pRowTmp2 + nX;
124  nR4 = pColor->GetRed();
125  nG4 = pColor->GetGreen();
126  nB4 = pColor->GetBlue();
127  nR5 = (++pColor)->GetRed();
128  nG5 = pColor->GetGreen();
129  nB5 = pColor->GetBlue();
130  nR6 = (++pColor)->GetRed();
131  nG6 = pColor->GetGreen();
132  nB6 = pColor->GetBlue();
133 
134  pColor = pRowTmp3 + nX;
135  nR7 = pColor->GetRed();
136  nG7 = pColor->GetGreen();
137  nB7 = pColor->GetBlue();
138  nR8 = (++pColor)->GetRed();
139  nG8 = pColor->GetGreen();
140  nB8 = pColor->GetBlue();
141  nR9 = (++pColor)->GetRed();
142  nG9 = pColor->GetGreen();
143  nB9 = pColor->GetBlue();
144 
145  MNMX6(nR1, nR2, nR3, nR4, nR5, nR6);
146  MNMX5(nR7, nR2, nR3, nR4, nR5);
147  MNMX4(nR8, nR2, nR3, nR4);
148  MNMX3(nR9, nR2, nR3);
149 
150  MNMX6(nG1, nG2, nG3, nG4, nG5, nG6);
151  MNMX5(nG7, nG2, nG3, nG4, nG5);
152  MNMX4(nG8, nG2, nG3, nG4);
153  MNMX3(nG9, nG2, nG3);
154 
155  MNMX6(nB1, nB2, nB3, nB4, nB5, nB6);
156  MNMX5(nB7, nB2, nB3, nB4, nB5);
157  MNMX4(nB8, nB2, nB3, nB4);
158  MNMX3(nB9, nB2, nB3);
159 
160  // set destination color
161  pWriteAcc->SetPixelOnData(pScanline, nX,
162  BitmapColor(static_cast<sal_uInt8>(nR2),
163  static_cast<sal_uInt8>(nG2),
164  static_cast<sal_uInt8>(nB2)));
165  }
166 
167  if (++nY < nHeight)
168  {
169  if (pRowTmp1 == pColRow1.get())
170  {
171  pRowTmp1 = pColRow2.get();
172  pRowTmp2 = pColRow3.get();
173  pRowTmp3 = pColRow1.get();
174  }
175  else if (pRowTmp1 == pColRow2.get())
176  {
177  pRowTmp1 = pColRow3.get();
178  pRowTmp2 = pColRow1.get();
179  pRowTmp3 = pColRow2.get();
180  }
181  else
182  {
183  pRowTmp1 = pColRow1.get();
184  pRowTmp2 = pColRow2.get();
185  pRowTmp3 = pColRow3.get();
186  }
187 
188  for (i = 0; i < nWidth2; i++)
189  pRowTmp3[i] = pReadAcc->GetColor(pRows[nY + 2], pColm[i]);
190  }
191  }
192 
193  pWriteAcc.reset();
194 
195  bRet = true;
196  }
197 
198  pReadAcc.reset();
199 
200  if (bRet)
201  {
202  const MapMode aMap(aBitmap.GetPrefMapMode());
203  const Size aPrefSize(aBitmap.GetPrefSize());
204 
205  aBitmap = aNewBmp;
206 
207  aBitmap.SetPrefMapMode(aMap);
208  aBitmap.SetPrefSize(aPrefSize);
209  }
210  }
211 
212  if (bRet)
213  return BitmapEx(aBitmap);
214 
215  return BitmapEx();
216 }
217 
218 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 GetRed() const
sal_uInt8 GetBlue() const
Bitmap GetBitmap(const Color *pTransReplaceColor=nullptr) const
Definition: bitmapex.cxx:236
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
#define MNMX4(a, b, c, d)
int i
#define MNMX5(a, b, c, d, e)
sal_uInt8 GetGreen() const
virtual BitmapEx execute(BitmapEx const &rBitmapEx) const override
#define MNMX6(a, b, c, d, e, f)
#define MNMX3(a, b, c)