• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 "SkBlurImageFilter.h"
9 #include "SkColorPriv.h"
10 
SkBlurImageFilter(SkFlattenableReadBuffer & buffer)11 SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
12   : INHERITED(buffer) {
13     fSigma.fWidth = buffer.readScalar();
14     fSigma.fHeight = buffer.readScalar();
15 }
16 
SkBlurImageFilter(SkScalar sigmaX,SkScalar sigmaY)17 SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY)
18     : fSigma(SkSize::Make(sigmaX, sigmaY)) {
19     SkASSERT(sigmaX >= 0 && sigmaY >= 0);
20 }
21 
asABlur(SkSize * sigma) const22 bool SkBlurImageFilter::asABlur(SkSize* sigma) const {
23     *sigma = fSigma;
24     return true;
25 }
26 
flatten(SkFlattenableWriteBuffer & buffer)27 void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
28     this->INHERITED::flatten(buffer);
29     buffer.writeScalar(fSigma.fWidth);
30     buffer.writeScalar(fSigma.fHeight);
31 }
32 
boxBlurX(const SkBitmap & src,SkBitmap * dst,int kernelSize,int leftOffset,int rightOffset)33 static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
34                      int leftOffset, int rightOffset)
35 {
36     int width = src.width(), height = src.height();
37     int rightBorder = SkMin32(rightOffset + 1, width);
38     for (int y = 0; y < height; ++y) {
39         int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
40         SkPMColor* p = src.getAddr32(0, y);
41         for (int i = 0; i < rightBorder; ++i) {
42             sumA += SkGetPackedA32(*p);
43             sumR += SkGetPackedR32(*p);
44             sumG += SkGetPackedG32(*p);
45             sumB += SkGetPackedB32(*p);
46             p++;
47         }
48 
49         const SkColor* sptr = src.getAddr32(0, y);
50         SkColor* dptr = dst->getAddr32(0, y);
51         for (int x = 0; x < width; ++x) {
52             *dptr = SkPackARGB32(sumA / kernelSize,
53                                  sumR / kernelSize,
54                                  sumG / kernelSize,
55                                  sumB / kernelSize);
56             if (x >= leftOffset) {
57                 SkColor l = *(sptr - leftOffset);
58                 sumA -= SkGetPackedA32(l);
59                 sumR -= SkGetPackedR32(l);
60                 sumG -= SkGetPackedG32(l);
61                 sumB -= SkGetPackedB32(l);
62             }
63             if (x + rightOffset + 1 < width) {
64                 SkColor r = *(sptr + rightOffset + 1);
65                 sumA += SkGetPackedA32(r);
66                 sumR += SkGetPackedR32(r);
67                 sumG += SkGetPackedG32(r);
68                 sumB += SkGetPackedB32(r);
69             }
70             sptr++;
71             dptr++;
72         }
73     }
74 }
75 
boxBlurY(const SkBitmap & src,SkBitmap * dst,int kernelSize,int topOffset,int bottomOffset)76 static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
77                      int topOffset, int bottomOffset)
78 {
79     int width = src.width(), height = src.height();
80     int bottomBorder = SkMin32(bottomOffset + 1, height);
81     int srcStride = src.rowBytesAsPixels();
82     int dstStride = dst->rowBytesAsPixels();
83     for (int x = 0; x < width; ++x) {
84         int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
85         SkColor* p = src.getAddr32(x, 0);
86         for (int i = 0; i < bottomBorder; ++i) {
87             sumA += SkGetPackedA32(*p);
88             sumR += SkGetPackedR32(*p);
89             sumG += SkGetPackedG32(*p);
90             sumB += SkGetPackedB32(*p);
91             p += srcStride;
92         }
93 
94         const SkColor* sptr = src.getAddr32(x, 0);
95         SkColor* dptr = dst->getAddr32(x, 0);
96         for (int y = 0; y < height; ++y) {
97             *dptr = SkPackARGB32(sumA / kernelSize,
98                                  sumR / kernelSize,
99                                  sumG / kernelSize,
100                                  sumB / kernelSize);
101             if (y >= topOffset) {
102                 SkColor l = *(sptr - topOffset * srcStride);
103                 sumA -= SkGetPackedA32(l);
104                 sumR -= SkGetPackedR32(l);
105                 sumG -= SkGetPackedG32(l);
106                 sumB -= SkGetPackedB32(l);
107             }
108             if (y + bottomOffset + 1 < height) {
109                 SkColor r = *(sptr + (bottomOffset + 1) * srcStride);
110                 sumA += SkGetPackedA32(r);
111                 sumR += SkGetPackedR32(r);
112                 sumG += SkGetPackedG32(r);
113                 sumB += SkGetPackedB32(r);
114             }
115             sptr += srcStride;
116             dptr += dstStride;
117         }
118     }
119 }
120 
getBox3Params(SkScalar s,int * kernelSize,int * kernelSize3,int * lowOffset,int * highOffset)121 static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
122 {
123     float pi = SkScalarToFloat(SK_ScalarPI);
124     int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
125     *kernelSize = d;
126     if (d % 2 == 1) {
127         *lowOffset = *highOffset = (d - 1) / 2;
128         *kernelSize3 = d;
129     } else {
130         *highOffset = d / 2;
131         *lowOffset = *highOffset - 1;
132         *kernelSize3 = d + 1;
133     }
134 }
135 
onFilterImage(Proxy *,const SkBitmap & src,const SkMatrix &,SkBitmap * dst,SkIPoint *)136 bool SkBlurImageFilter::onFilterImage(Proxy*,
137                                       const SkBitmap& src, const SkMatrix&,
138                                       SkBitmap* dst, SkIPoint*) {
139     if (src.config() != SkBitmap::kARGB_8888_Config) {
140         return false;
141     }
142 
143     SkAutoLockPixels alp(src);
144     if (!src.getPixels()) {
145         return false;
146     }
147 
148     dst->setConfig(src.config(), src.width(), src.height());
149     dst->allocPixels();
150     int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
151     int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
152     getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
153     getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY);
154 
155     if (kernelSizeX < 0 || kernelSizeY < 0) {
156         return false;
157     }
158 
159     if (kernelSizeX == 0 && kernelSizeY == 0) {
160         src.copyTo(dst, dst->config());
161         return true;
162     }
163 
164     SkBitmap temp;
165     temp.setConfig(dst->config(), dst->width(), dst->height());
166     if (!temp.allocPixels()) {
167         return false;
168     }
169 
170     if (kernelSizeX > 0 && kernelSizeY > 0) {
171         boxBlurX(src,  &temp, kernelSizeX,  lowOffsetX, highOffsetX);
172         boxBlurY(temp, dst,   kernelSizeY,  lowOffsetY, highOffsetY);
173         boxBlurX(*dst, &temp, kernelSizeX,  highOffsetX,  lowOffsetX);
174         boxBlurY(temp, dst,   kernelSizeY,  highOffsetY,  lowOffsetY);
175         boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
176         boxBlurY(temp, dst,   kernelSizeY3, highOffsetY, highOffsetY);
177     } else if (kernelSizeX > 0) {
178         boxBlurX(src,  dst,   kernelSizeX,  lowOffsetX, highOffsetX);
179         boxBlurX(*dst, &temp, kernelSizeX,  highOffsetX,  lowOffsetX);
180         boxBlurX(temp, dst,   kernelSizeX3, highOffsetX, highOffsetX);
181     } else if (kernelSizeY > 0) {
182         boxBlurY(src,  dst,   kernelSizeY,  lowOffsetY, highOffsetY);
183         boxBlurY(*dst, &temp, kernelSizeY,  highOffsetY, lowOffsetY);
184         boxBlurY(temp, dst,   kernelSizeY3, highOffsetY, highOffsetY);
185     }
186     return true;
187 }
188 
189 SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlurImageFilter)
190