OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBitmapScaler.h" | 8 #include "SkBitmapScaler.h" |
9 #include "SkBitmapFilter.h" | 9 #include "SkBitmapFilter.h" |
10 #include "SkConvolver.h" | 10 #include "SkConvolver.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 SkConvolutionFilter1D fXFilter; | 55 SkConvolutionFilter1D fXFilter; |
56 SkConvolutionFilter1D fYFilter; | 56 SkConvolutionFilter1D fYFilter; |
57 }; | 57 }; |
58 | 58 |
59 SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, | 59 SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, |
60 int srcFullWidth, int srcFullHeight, | 60 int srcFullWidth, int srcFullHeight, |
61 float destWidth, float destHeight, | 61 float destWidth, float destHeight, |
62 const SkRect& destSubset, | 62 const SkRect& destSubset, |
63 const SkConvolutionProcs& convolveProcs) { | 63 const SkConvolutionProcs& convolveProcs) { |
64 | 64 |
65 // method will only ever refer to an "algorithm method". | 65 SkASSERT(method >= SkBitmapScaler::RESIZE_FirstMethod && |
66 SkASSERT((SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD <= method) && | 66 method <= SkBitmapScaler::RESIZE_LastMethod); |
67 (method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD)); | |
68 | 67 |
| 68 fBitmapFilter = nullptr; |
69 switch(method) { | 69 switch(method) { |
70 case SkBitmapScaler::RESIZE_BOX: | 70 case SkBitmapScaler::RESIZE_BOX: |
71 fBitmapFilter = new SkBoxFilter; | 71 fBitmapFilter = new SkBoxFilter; |
72 break; | 72 break; |
73 case SkBitmapScaler::RESIZE_TRIANGLE: | 73 case SkBitmapScaler::RESIZE_TRIANGLE: |
74 fBitmapFilter = new SkTriangleFilter; | 74 fBitmapFilter = new SkTriangleFilter; |
75 break; | 75 break; |
76 case SkBitmapScaler::RESIZE_MITCHELL: | 76 case SkBitmapScaler::RESIZE_MITCHELL: |
77 fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); | 77 fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); |
78 break; | 78 break; |
79 case SkBitmapScaler::RESIZE_HAMMING: | 79 case SkBitmapScaler::RESIZE_HAMMING: |
80 fBitmapFilter = new SkHammingFilter; | 80 fBitmapFilter = new SkHammingFilter; |
81 break; | 81 break; |
82 case SkBitmapScaler::RESIZE_LANCZOS3: | 82 case SkBitmapScaler::RESIZE_LANCZOS3: |
83 fBitmapFilter = new SkLanczosFilter; | 83 fBitmapFilter = new SkLanczosFilter; |
84 break; | 84 break; |
85 default: | |
86 // NOTREACHED: | |
87 fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); | |
88 break; | |
89 } | 85 } |
90 | 86 |
91 | 87 |
92 float scaleX = destWidth / srcFullWidth; | 88 float scaleX = destWidth / srcFullWidth; |
93 float scaleY = destHeight / srcFullHeight; | 89 float scaleY = destHeight / srcFullHeight; |
94 | 90 |
95 this->computeFilters(srcFullWidth, destSubset.fLeft, destSubset.width(), | 91 this->computeFilters(srcFullWidth, destSubset.fLeft, destSubset.width(), |
96 scaleX, &fXFilter, convolveProcs); | 92 scaleX, &fXFilter, convolveProcs); |
97 if (srcFullWidth == srcFullHeight && | 93 if (srcFullWidth == srcFullHeight && |
98 destSubset.fLeft == destSubset.fTop && | 94 destSubset.fLeft == destSubset.fTop && |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // Now it's ready to go. | 203 // Now it's ready to go. |
208 output->AddFilter(srcBegin, &fixedFilterValues[0], | 204 output->AddFilter(srcBegin, &fixedFilterValues[0], |
209 static_cast<int>(fixedFilterValues.count())); | 205 static_cast<int>(fixedFilterValues.count())); |
210 } | 206 } |
211 | 207 |
212 if (convolveProcs.fApplySIMDPadding) { | 208 if (convolveProcs.fApplySIMDPadding) { |
213 convolveProcs.fApplySIMDPadding( output ); | 209 convolveProcs.fApplySIMDPadding( output ); |
214 } | 210 } |
215 } | 211 } |
216 | 212 |
217 static SkBitmapScaler::ResizeMethod ResizeMethodToAlgorithmMethod( | |
218 SkBitmapScaler::ResizeMethod method) { | |
219 // Convert any "Quality Method" into an "Algorithm Method" | |
220 if (method >= SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD && | |
221 method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD) { | |
222 return method; | |
223 } | |
224 // The call to SkBitmapScalerGtv::Resize() above took care of | |
225 // GPU-acceleration in the cases where it is possible. So now we just | |
226 // pick the appropriate software method for each resize quality. | |
227 switch (method) { | |
228 // Users of RESIZE_GOOD are willing to trade a lot of quality to | |
229 // get speed, allowing the use of linear resampling to get hardware | |
230 // acceleration (SRB). Hence any of our "good" software filters | |
231 // will be acceptable, so we use a triangle. | |
232 case SkBitmapScaler::RESIZE_GOOD: | |
233 return SkBitmapScaler::RESIZE_TRIANGLE; | |
234 // Users of RESIZE_BETTER are willing to trade some quality in order | |
235 // to improve performance, but are guaranteed not to devolve to a linear | |
236 // resampling. In visual tests we see that Hamming-1 is not as good as | |
237 // Lanczos-2, however it is about 40% faster and Lanczos-2 itself is | |
238 // about 30% faster than Lanczos-3. The use of Hamming-1 has been deemed | |
239 // an acceptable trade-off between quality and speed. | |
240 case SkBitmapScaler::RESIZE_BETTER: | |
241 return SkBitmapScaler::RESIZE_HAMMING; | |
242 default: | |
243 #ifdef SK_HIGH_QUALITY_IS_LANCZOS | |
244 return SkBitmapScaler::RESIZE_LANCZOS3; | |
245 #else | |
246 return SkBitmapScaler::RESIZE_MITCHELL; | |
247 #endif | |
248 } | |
249 } | |
250 | |
251 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeM
ethod method, | 213 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeM
ethod method, |
252 float destWidth, float destHeight, | 214 int destWidth, int destHeight, SkBitmap::Allocator*
allocator) { |
253 SkBitmap::Allocator* allocator) { | |
254 if (nullptr == source.addr() || source.colorType() != kN32_SkColorType || | 215 if (nullptr == source.addr() || source.colorType() != kN32_SkColorType || |
255 source.width() < 1 || source.height() < 1) | 216 source.width() < 1 || source.height() < 1) |
256 { | 217 { |
257 return false; | 218 return false; |
258 } | 219 } |
259 | 220 |
260 if (destWidth < 1 || destHeight < 1) { | 221 if (destWidth < 1 || destHeight < 1) { |
261 // todo: seems like we could handle negative dstWidth/Height, since that | |
262 // is just a negative scale (flip) | |
263 return false; | 222 return false; |
264 } | 223 } |
265 | 224 |
266 SkConvolutionProcs convolveProcs= { 0, nullptr, nullptr, nullptr, nullptr }; | 225 SkConvolutionProcs convolveProcs= { 0, nullptr, nullptr, nullptr, nullptr }; |
267 PlatformConvolutionProcs(&convolveProcs); | 226 PlatformConvolutionProcs(&convolveProcs); |
268 | 227 |
269 SkRect destSubset = { 0, 0, destWidth, destHeight }; | 228 SkRect destSubset = SkRect::MakeIWH(destWidth, destHeight); |
270 | |
271 // Ensure that the ResizeMethod enumeration is sound. | |
272 SkASSERT(((RESIZE_FIRST_QUALITY_METHOD <= method) && | |
273 (method <= RESIZE_LAST_QUALITY_METHOD)) || | |
274 ((RESIZE_FIRST_ALGORITHM_METHOD <= method) && | |
275 (method <= RESIZE_LAST_ALGORITHM_METHOD))); | |
276 | |
277 method = ResizeMethodToAlgorithmMethod(method); | |
278 | |
279 // Check that we deal with an "algorithm methods" from this point onward. | |
280 SkASSERT((SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD <= method) && | |
281 (method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD)); | |
282 | 229 |
283 SkResizeFilter filter(method, source.width(), source.height(), | 230 SkResizeFilter filter(method, source.width(), source.height(), |
284 destWidth, destHeight, destSubset, convolveProcs); | 231 destWidth, destHeight, destSubset, convolveProcs); |
285 | 232 |
286 // Get a subset encompassing this touched area. We construct the | 233 // Get a subset encompassing this touched area. We construct the |
287 // offsets and row strides such that it looks like a new bitmap, while | 234 // offsets and row strides such that it looks like a new bitmap, while |
288 // referring to the old data. | 235 // referring to the old data. |
289 const uint8_t* sourceSubset = reinterpret_cast<const uint8_t*>(source.addr()
); | 236 const uint8_t* sourceSubset = reinterpret_cast<const uint8_t*>(source.addr()
); |
290 | 237 |
291 // Convolve into the result. | 238 // Convolve into the result. |
(...skipping 11 matching lines...) Expand all Loading... |
303 static_cast<int>(result.rowBytes()), | 250 static_cast<int>(result.rowBytes()), |
304 static_cast<unsigned char*>(result.getPixels()), | 251 static_cast<unsigned char*>(result.getPixels()), |
305 convolveProcs, true); | 252 convolveProcs, true); |
306 | 253 |
307 *resultPtr = result; | 254 *resultPtr = result; |
308 resultPtr->lockPixels(); | 255 resultPtr->lockPixels(); |
309 SkASSERT(resultPtr->getPixels()); | 256 SkASSERT(resultPtr->getPixels()); |
310 return true; | 257 return true; |
311 } | 258 } |
312 | 259 |
OLD | NEW |