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