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