Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: src/core/SkBitmapFilter.cpp

Issue 17381008: More general version of image filtering; reworked to be robust and easier to SSE (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Separate implementation of downsampling for high quality results Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright 2013 Google Inc.
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 "SkBitmapProcState.h"
9 #include "SkBitmap.h"
10 #include "SkColor.h"
11 #include "SkColorPriv.h"
12 #include "SkUnPreMultiply.h"
13 #include "SkShader.h"
14 #include "SkRTConf.h"
15 #include "SkMath.h"
16
17 void highQualityFilter(const SkBitmapProcState& s, int x, int y,
reed1 2013/07/09 14:25:47 is this guy exported? (I don't see static, nor som
humper 2013/07/09 14:47:26 I suppose it's not; only a function pointer to it
humper 2013/07/09 15:26:30 ah, actually it is; I look to see if the shader pr
18 SkPMColor* SK_RESTRICT colors, int count) {
19
20 const int maxX = s.fBitmap->width() - 1;
21 const int maxY = s.fBitmap->height() - 1;
22
23 while (count-- > 0) {
24 SkPoint srcPt;
25 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
26 SkIntToScalar(y), &srcPt);
27 srcPt.fX -= SK_ScalarHalf;
28 srcPt.fY -= SK_ScalarHalf;
29 SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
30 SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
31
32 int sx = SkScalarFloorToInt(srcPt.fX);
33 int sy = SkScalarFloorToInt(srcPt.fY);
34
35 SkFixed weight = 0;
36 SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
37
38 int y0 = SkClampMax(int(ceil(sy-s.fBitmapFilter->width() + 0.5f)), maxY) ;
39 int y1 = SkClampMax(int(floor(sy+s.fBitmapFilter->width() + 0.5f)), maxY );
40 int x0 = SkClampMax(int(ceil(sx-s.fBitmapFilter->width() + 0.5f)), maxX) ;
41 int x1 = SkClampMax(int(floor(sx+s.fBitmapFilter->width() + 0.5f)), maxX );
42
43 for (int src_y = y0; src_y <= y1; src_y++) {
44 SkFixed yweight = s.fBitmapFilter->lookup((srcPt.fY - src_y));
45
46 for (int src_x = x0; src_x <= x1 ; src_x++) {
47 SkFixed xweight = s.fBitmapFilter->lookup((srcPt.fX - src_x));
48
49 SkFixed combined_weight = SkFixedMul(xweight, yweight);
50
51 SkPMColor c = *s.fBitmap->getAddr32(src_x, src_y);
52 fr += combined_weight * SkGetPackedR32(c);
53 fg += combined_weight * SkGetPackedG32(c);
54 fb += combined_weight * SkGetPackedB32(c);
55 fa += combined_weight * SkGetPackedA32(c);
56 weight += combined_weight;
57 }
58 }
59
60 fr = SkFixedDiv(fr, weight);
61 fg = SkFixedDiv(fg, weight);
62 fb = SkFixedDiv(fb, weight);
63 fa = SkFixedDiv(fa, weight);
64
65 int a = SkClampMax(SkFixedRoundToInt(fa), 255);
66 int r = SkClampMax(SkFixedRoundToInt(fr), a);
67 int g = SkClampMax(SkFixedRoundToInt(fg), a);
68 int b = SkClampMax(SkFixedRoundToInt(fb), a);
69
70 *colors++ = SkPackARGB32(a, r, g, b);
71
72 x++;
73 }
74 }
75
76 void highQualityFilter_ScaleOnly(const SkBitmapProcState &s, int x, int y,
77 SkPMColor *SK_RESTRICT colors, int count) {
78 const int maxX = s.fBitmap->width() - 1;
79 const int maxY = s.fBitmap->height() - 1;
80
81 SkPoint srcPt;
82
83 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
84 SkIntToScalar(y), &srcPt);
85 srcPt.fY -= SK_ScalarHalf;
86 SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
87 int sy = SkScalarFloorToInt(srcPt.fY);
88 int y0 = SkClampMax(int(ceil(sy-s.fBitmapFilter->width() + 0.5f)), maxY);
89 int y1 = SkClampMax(int(floor(sy+s.fBitmapFilter->width() + 0.5f)), maxY);
90
91 while (count-- > 0) {
92 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
93 SkIntToScalar(y), &srcPt);
94 srcPt.fX -= SK_ScalarHalf;
95 srcPt.fY -= SK_ScalarHalf;
96 SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
97
98 int sx = SkScalarFloorToInt(srcPt.fX);
99
100 SkFixed weight = 0;
101 SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
102
103 int x0 = SkClampMax(int(ceil(sx-s.fBitmapFilter->width() + 0.5f)), maxX );
104 int x1 = SkClampMax(int(floor(sx+s.fBitmapFilter->width() + 0.5f)), max X);
105
106 for (int src_y = y0; src_y <= y1; src_y++) {
107 SkFixed yweight = s.fBitmapFilter->lookup((srcPt.fY - src_y));
108
109 for (int src_x = x0; src_x <= x1 ; src_x++) {
110 SkFixed xweight = s.fBitmapFilter->lookup((srcPt.fX - src_x));
111
112 SkFixed combined_weight = SkFixedMul(xweight, yweight);
113
114 SkPMColor c = *s.fBitmap->getAddr32(src_x, src_y);
115 fr += combined_weight * SkGetPackedR32(c);
116 fg += combined_weight * SkGetPackedG32(c);
117 fb += combined_weight * SkGetPackedB32(c);
118 fa += combined_weight * SkGetPackedA32(c);
119 weight += combined_weight;
120 }
121 }
122
123 fr = SkFixedDiv(fr, weight);
124 fg = SkFixedDiv(fg, weight);
125 fb = SkFixedDiv(fb, weight);
126 fa = SkFixedDiv(fa, weight);
127
128 int a = SkClampMax(SkFixedRoundToInt(fa), 255);
129 int r = SkClampMax(SkFixedRoundToInt(fr), a);
130 int g = SkClampMax(SkFixedRoundToInt(fg), a);
131 int b = SkClampMax(SkFixedRoundToInt(fb), a);
132
133 *colors++ = SkPackARGB32(a, r, g, b);
134
135 x++;
136 }
137 }
138
139 SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Whic h bitmap filter to use [mitchell, sinc, gaussian, triangle, box]");
140
141 static SkBitmapFilter *allocateBitmapFilter() {
142 if (!strcmp(c_bitmapFilter, "mitchell")) {
143 return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f));
144 } else if (!strcmp(c_bitmapFilter, "sinc")) {
145 return SkNEW_ARGS(SkSincFilter,(3));
146 } else if (!strcmp(c_bitmapFilter, "gaussian")) {
147 return SkNEW_ARGS(SkGaussianFilter,(2));
148 } else if (!strcmp(c_bitmapFilter, "triangle")) {
149 return SkNEW(SkTriangleFilter);
150 } else if (!strcmp(c_bitmapFilter, "box")) {
151 return SkNEW(SkBoxFilter);
152 } else {
153 SkASSERT(!!!"Unknown filter type");
154 }
155
156 return NULL;
157 }
158
159 SkBitmapProcState::ShaderProc32
160 SkBitmapProcState::chooseBitmapFilterProc(const SkPaint& paint) {
161 // we need to be requested
162 uint32_t mask = SkPaint::kFilterBitmap_Flag
163 | SkPaint::kHighQualityFilterBitmap_Flag
164 ;
165 if ((paint.getFlags() & mask) != mask) {
166 return NULL;
167 }
168
169 // TODO: consider supporting other configs (e.g. 565, A8)
170 if (fBitmap->config() != SkBitmap::kARGB_8888_Config) {
171 return NULL;
172 }
173
174 // TODO: consider supporting repeat and mirror
175 if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
176 return NULL;
177 }
178
179 // TODO: support blending inside our procs
180 if (0xFF != paint.getAlpha()) {
181 return NULL;
182 }
183
184 if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) {
185 fBitmapFilter = allocateBitmapFilter();
186 }
187
188 if (fInvType & SkMatrix::kAffine_Mask) {
189 return highQualityFilter;
190 } else if (fInvType & SkMatrix::kScale_Mask) {
191 return highQualityFilter_ScaleOnly;
192 } else {
193 return NULL;
194 }
195 }
196
197 static void divideByWeights(SkFixed *sums, SkFixed *weights, SkBitmap *dst) {
198 for (int y = 0 ; y < dst->height() ; y++) {
199 for (int x = 0 ; x < dst->width() ; x++) {
200 SkFixed fr = SkFixedDiv(sums[4*(y*dst->width() + x) + 0], weights[y* dst->width() + x]);
201 SkFixed fg = SkFixedDiv(sums[4*(y*dst->width() + x) + 1], weights[y* dst->width() + x]);
202 SkFixed fb = SkFixedDiv(sums[4*(y*dst->width() + x) + 2], weights[y* dst->width() + x]);
203 SkFixed fa = SkFixedDiv(sums[4*(y*dst->width() + x) + 3], weights[y* dst->width() + x]);
204 int a = SkClampMax(SkFixedRoundToInt(fa), 255);
205 int r = SkClampMax(SkFixedRoundToInt(fr), a);
206 int g = SkClampMax(SkFixedRoundToInt(fg), a);
207 int b = SkClampMax(SkFixedRoundToInt(fb), a);
208
209 *dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
210 }
211 }
212 }
213
214 static void upScaleHoriz(const SkBitmap *src, SkBitmap *dst, float scale, SkBitm apFilter *filter) {
215 for (int y = 0 ; y < src->height() ; y++) {
216 for (int x = 0 ; x < dst->width() ; x++) {
217 float sx = x / scale - 0.5f;
218 int x0 = SkClampMax(int(ceil(sx-filter->width() + 0.5f)), src->width ()-1);
219 int x1 = SkClampMax(int(floor(sx+filter->width() + 0.5f)), src->widt h()-1);
220
221 SkFixed total_weight = 0;
222 SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
223
224 for (int src_x = x0 ; src_x <= x1 ; src_x++) {
225 SkFixed weight = filter->lookup(sx - src_x);
226 SkPMColor c = *src->getAddr32(src_x,y);
227 fr += weight * SkGetPackedR32(c);
228 fg += weight * SkGetPackedG32(c);
229 fb += weight * SkGetPackedB32(c);
230 fa += weight * SkGetPackedA32(c);
231 total_weight += weight;
232 }
233 fr = SkFixedDiv(fr, total_weight);
234 fg = SkFixedDiv(fg, total_weight);
235 fb = SkFixedDiv(fb, total_weight);
236 fa = SkFixedDiv(fa, total_weight);
237
238 int a = SkClampMax(SkFixedRoundToInt(fa), 255);
239 int r = SkClampMax(SkFixedRoundToInt(fr), a);
240 int g = SkClampMax(SkFixedRoundToInt(fg), a);
241 int b = SkClampMax(SkFixedRoundToInt(fb), a);
242
243 *dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
244 }
245 }
246 }
247
248 static void downScaleHoriz(const SkBitmap *src, SkBitmap *dst, float scale, SkBi tmapFilter *filter) {
249 SkFixed *sums = SkNEW_ARRAY(SkFixed, dst->width() * dst->height() * 4);
250 SkFixed *weights = SkNEW_ARRAY(SkFixed, dst->width() * dst->height());
251
252 SkAutoTDeleteArray<SkFixed> ada1(sums);
253 SkAutoTDeleteArray<SkFixed> ada2(weights);
254
255 memset(sums, 0, dst->width() * dst->height() * sizeof(SkFixed) * 4);
256 memset(weights, 0, dst->width() * dst->height() * sizeof(SkFixed));
257
258 for (int y = 0 ; y < src->height() ; y++) {
259 for (int x = 0 ; x < src->width() ; x++) {
260 // splat each source pixel into the destination image
261 float dx = (x + 0.5f) * scale;
262 int x0 = SkClampMax(int(ceil(dx-filter->width() + 0.5f)), dst->width ()-1);
263 int x1 = SkClampMax(int(floor(dx+filter->width() + 0.5f)), dst->widt h()-1);
264
265 SkPMColor c = *src->getAddr32(x,y);
266
267 for (int dst_x = x0 ; dst_x <= x1 ; dst_x++) {
268 SkFixed weight = filter->lookup(dx - dst_x);
269 sums[4*(y*dst->width() + dst_x) + 0] += weight*SkGetPackedR32(c) ;
270 sums[4*(y*dst->width() + dst_x) + 1] += weight*SkGetPackedG32(c) ;
271 sums[4*(y*dst->width() + dst_x) + 2] += weight*SkGetPackedB32(c) ;
272 sums[4*(y*dst->width() + dst_x) + 3] += weight*SkGetPackedA32(c) ;
273 weights[y*dst->width() + dst_x] += weight;
274 }
275 }
276 }
277
278 divideByWeights(sums, weights, dst);
279 }
280
281 static void upScaleVert(const SkBitmap *src, SkBitmap *dst, float scale, SkBitma pFilter *filter) {
282 for (int y = 0 ; y < dst->height() ; y++) {
283 for (int x = 0 ; x < dst->width() ; x++) {
284 float sy = y / scale - 0.5f;
285 int y0 = SkClampMax(int(ceil(sy-filter->width() + 0.5f)), src->heigh t()-1);
286 int y1 = SkClampMax(int(floor(sy+filter->width() + 0.5f)), src->heig ht()-1);
287
288 SkFixed total_weight = 0;
289 SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
290
291 for (int src_y = y0 ; src_y <= y1 ; src_y++) {
292 SkFixed weight = filter->lookup(sy - src_y);
293 SkPMColor c = *src->getAddr32(x,src_y);
294 fr += weight * SkGetPackedR32(c);
295 fg += weight * SkGetPackedG32(c);
296 fb += weight * SkGetPackedB32(c);
297 fa += weight * SkGetPackedA32(c);
298 total_weight += weight;
299 }
300 fr = SkFixedDiv(fr, total_weight);
301 fg = SkFixedDiv(fg, total_weight);
302 fb = SkFixedDiv(fb, total_weight);
303 fa = SkFixedDiv(fa, total_weight);
304
305 int a = SkClampMax(SkFixedRoundToInt(fa), 255);
306 int r = SkClampMax(SkFixedRoundToInt(fr), a);
307 int g = SkClampMax(SkFixedRoundToInt(fg), a);
308 int b = SkClampMax(SkFixedRoundToInt(fb), a);
309
310 *dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
311 }
312 }
313 }
314
315 static void downScaleVert(const SkBitmap *src, SkBitmap *dst, float scale, SkBit mapFilter *filter) {
316 SkFixed *sums = SkNEW_ARRAY(SkFixed, dst->width() * dst->height() * 4);
317 SkFixed *weights = SkNEW_ARRAY(SkFixed, dst->width() * dst->height());
318
319 SkAutoTDeleteArray<SkFixed> ada1(sums);
320 SkAutoTDeleteArray<SkFixed> ada2(weights);
321
322 memset(sums, 0, dst->width() * dst->height() * sizeof(SkFixed) * 4);
323 memset(weights, 0, dst->width() * dst->height() * sizeof(SkFixed));
324
325 for (int y = 0 ; y < src->height() ; y++) {
326 for (int x = 0 ; x < src->width() ; x++) {
327 // splat each source pixel into the destination image
328 float dy = (y + 0.5f) * scale;
329 int y0 = SkClampMax(int(ceil(dy-filter->width() + 0.5f)), dst->heigh t()-1);
330 int y1 = SkClampMax(int(floor(dy+filter->width() + 0.5f)), dst->heig ht()-1);
331
332 SkPMColor c = *src->getAddr32(x,y);
333
334 for (int dst_y = y0 ; dst_y <= y1 ; dst_y++) {
335 SkFixed weight = filter->lookup(dy - dst_y);
336 sums[4*(dst_y*dst->width() + x) + 0] += weight*SkGetPackedR32(c) ;
337 sums[4*(dst_y*dst->width() + x) + 1] += weight*SkGetPackedG32(c) ;
338 sums[4*(dst_y*dst->width() + x) + 2] += weight*SkGetPackedB32(c) ;
339 sums[4*(dst_y*dst->width() + x) + 3] += weight*SkGetPackedA32(c) ;
340 weights[dst_y*dst->width() + x] += weight;
341 }
342 }
343 }
344
345 divideByWeights(sums, weights, dst);
346 }
347
348 void SkBitmap::scale(SkBitmap *dst) const {
349
350 SkBitmap horiz_temp;
351
352 horiz_temp.setConfig(SkBitmap::kARGB_8888_Config, dst->width(), height());
353 horiz_temp.allocPixels();
354
355 SkBitmapFilter *filter = allocateBitmapFilter();
356
357 float horiz_scale = float(dst->width()) / width();
358
359 if (horiz_scale == 1) {
360 this->copyPixelsTo(horiz_temp.getPixels(), getSize());
361 } else if (horiz_scale > 1) {
362 upScaleHoriz(this, &horiz_temp, horiz_scale, filter);
363 } else if (horiz_scale < 1) {
364 downScaleHoriz(this, &horiz_temp, horiz_scale, filter);
365 }
366
367 float vert_scale = float(dst->height()) / height();
368
369 if (vert_scale == 1) {
370 horiz_temp.copyPixelsTo(dst->getPixels(), dst->getSize());
371 } else if (vert_scale > 1) {
372 upScaleVert(&horiz_temp, dst, vert_scale, filter);
373 } else if (vert_scale < 1) {
374 downScaleVert(&horiz_temp, dst, vert_scale, filter);
375 }
376
377 SkDELETE(filter);
378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698