| 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 |