blob: 78fabc5616e7e228013a5b25852a70bbc30b1ec4 [file] [log] [blame]
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkMorphologyImageFilter.h"
9#include "SkColorPriv.h"
10
11SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
12 : INHERITED(buffer) {
13 fRadius.fWidth = buffer.readScalar();
14 fRadius.fHeight = buffer.readScalar();
15}
16
17SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY)
18 : fRadius(SkISize::Make(radiusX, radiusY)) {
19}
20
21
22void SkMorphologyImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
23 this->INHERITED::flatten(buffer);
24 buffer.writeScalar(fRadius.fWidth);
25 buffer.writeScalar(fRadius.fHeight);
26}
27
28static void erode(const SkPMColor* src, SkPMColor* dst,
29 int radius, int width, int height,
30 int srcStrideX, int srcStrideY,
31 int dstStrideX, int dstStrideY)
32{
33 const SkPMColor* upperSrc = src + SkMin32(radius, width - 1) * srcStrideX;
34 for (int x = 0; x < width; ++x) {
35 const SkPMColor* lp = src;
36 const SkPMColor* up = upperSrc;
37 SkPMColor* dptr = dst;
38 for (int y = 0; y < height; ++y) {
39 int minB = 255, minG = 255, minR = 255, minA = 255;
40 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
41 int b = SkGetPackedB32(*p);
42 int g = SkGetPackedG32(*p);
43 int r = SkGetPackedR32(*p);
44 int a = SkGetPackedA32(*p);
45 if (b < minB) minB = b;
46 if (g < minG) minG = g;
47 if (r < minR) minR = r;
48 if (a < minA) minA = a;
49 }
50 *dptr = SkPackARGB32(minA, minR, minG, minB);
51 dptr += dstStrideY;
52 lp += srcStrideY;
53 up += srcStrideY;
54 }
55 if (x >= radius) src += srcStrideX;
56 if (x + radius < width - 1) upperSrc += srcStrideX;
57 dst += dstStrideX;
58 }
59}
60
61static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX)
62{
63 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
64 radiusX, src.width(), src.height(),
65 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
66}
67
68static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY)
69{
70 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
71 radiusY, src.height(), src.width(),
72 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
73}
74
75static void dilate(const SkPMColor* src, SkPMColor* dst,
76 int radius, int width, int height,
77 int srcStrideX, int srcStrideY,
78 int dstStrideX, int dstStrideY)
79{
80 const SkPMColor* upperSrc = src + SkMin32(radius, width - 1) * srcStrideX;
81 for (int x = 0; x < width; ++x) {
82 const SkPMColor* lp = src;
83 const SkPMColor* up = upperSrc;
84 SkPMColor* dptr = dst;
85 for (int y = 0; y < height; ++y) {
86 int maxB = 0, maxG = 0, maxR = 0, maxA = 0;
87 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
88 int b = SkGetPackedB32(*p);
89 int g = SkGetPackedG32(*p);
90 int r = SkGetPackedR32(*p);
91 int a = SkGetPackedA32(*p);
92 if (b > maxB) maxB = b;
93 if (g > maxG) maxG = g;
94 if (r > maxR) maxR = r;
95 if (a > maxA) maxA = a;
96 }
97 *dptr = SkPackARGB32(maxA, maxR, maxG, maxB);
98 dptr += dstStrideY;
99 lp += srcStrideY;
100 up += srcStrideY;
101 }
102 if (x >= radius) src += srcStrideX;
103 if (x + radius < width - 1) upperSrc += srcStrideX;
104 dst += dstStrideX;
105 }
106}
107
108static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX)
109{
110 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
111 radiusX, src.width(), src.height(),
112 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
113}
114
115static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY)
116{
117 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
118 radiusY, src.height(), src.width(),
119 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
120}
121
122bool SkErodeImageFilter::onFilterImage(Proxy*,
123 const SkBitmap& src, const SkMatrix&,
124 SkBitmap* dst, SkIPoint*) {
125 if (src.config() != SkBitmap::kARGB_8888_Config) {
126 return false;
127 }
128
129 SkAutoLockPixels alp(src);
130 if (!src.getPixels()) {
131 return false;
132 }
133
134 dst->setConfig(src.config(), src.width(), src.height());
135 dst->allocPixels();
136
137 int width = radius().width();
138 int height = radius().height();
139
140 if (width < 0 || height < 0) {
141 return false;
142 }
143
144 if (width == 0 && height == 0) {
145 src.copyTo(dst, dst->config());
146 return true;
147 }
148
149 SkBitmap temp;
150 temp.setConfig(dst->config(), dst->width(), dst->height());
151 if (!temp.allocPixels()) {
152 return false;
153 }
154
155 if (width > 0 && height > 0) {
156 erodeX(src, &temp, width);
157 erodeY(temp, dst, height);
158 } else if (width > 0) {
159 erodeX(src, dst, width);
160 } else if (height > 0) {
161 erodeY(src, dst, height);
162 }
163 return true;
164}
165
166bool SkDilateImageFilter::onFilterImage(Proxy*,
167 const SkBitmap& src, const SkMatrix&,
168 SkBitmap* dst, SkIPoint*) {
169 if (src.config() != SkBitmap::kARGB_8888_Config) {
170 return false;
171 }
172
173 SkAutoLockPixels alp(src);
174 if (!src.getPixels()) {
175 return false;
176 }
177
178 dst->setConfig(src.config(), src.width(), src.height());
179 dst->allocPixels();
180
181 int width = radius().width();
182 int height = radius().height();
183
184 if (width < 0 || height < 0) {
185 return false;
186 }
187
188 if (width == 0 && height == 0) {
189 src.copyTo(dst, dst->config());
190 return true;
191 }
192
193 SkBitmap temp;
194 temp.setConfig(dst->config(), dst->width(), dst->height());
195 if (!temp.allocPixels()) {
196 return false;
197 }
198
199 if (width > 0 && height > 0) {
200 dilateX(src, &temp, width);
201 dilateY(temp, dst, height);
202 } else if (width > 0) {
203 dilateX(src, dst, width);
204 } else if (height > 0) {
205 dilateY(src, dst, height);
206 }
207 return true;
208}
209
210bool SkDilateImageFilter::asADilate(SkISize* radius) const {
211 *radius = this->radius();
212 return true;
213}
214
215bool SkErodeImageFilter::asAnErode(SkISize* radius) const {
216 *radius = this->radius();
217 return true;
218}
219
220SK_DEFINE_FLATTENABLE_REGISTRAR(SkDilateImageFilter)
221SK_DEFINE_FLATTENABLE_REGISTRAR(SkErodeImageFilter)