OLD | NEW |
1 #include "SkBitmapScaler.h" | 1 #include "SkBitmapScaler.h" |
2 #include "SkBitmapFilter.h" | 2 #include "SkBitmapFilter.h" |
3 #include "SkRect.h" | 3 #include "SkRect.h" |
4 #include "SkTArray.h" | 4 #include "SkTArray.h" |
5 #include "SkErrorInternals.h" | 5 #include "SkErrorInternals.h" |
6 #include "SkConvolver.h" | 6 #include "SkConvolver.h" |
7 | 7 |
8 // SkResizeFilter --------------------------------------------------------------
-- | 8 // SkResizeFilter --------------------------------------------------------------
-- |
9 | 9 |
10 // Encapsulates computation and storage of the filters required for one complete | 10 // Encapsulates computation and storage of the filters required for one complete |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 // about 30% faster than Lanczos-3. The use of Hamming-1 has been deemed | 226 // about 30% faster than Lanczos-3. The use of Hamming-1 has been deemed |
227 // an acceptable trade-off between quality and speed. | 227 // an acceptable trade-off between quality and speed. |
228 case SkBitmapScaler::RESIZE_BETTER: | 228 case SkBitmapScaler::RESIZE_BETTER: |
229 return SkBitmapScaler::RESIZE_HAMMING; | 229 return SkBitmapScaler::RESIZE_HAMMING; |
230 default: | 230 default: |
231 return SkBitmapScaler::RESIZE_MITCHELL; | 231 return SkBitmapScaler::RESIZE_MITCHELL; |
232 } | 232 } |
233 } | 233 } |
234 | 234 |
235 // static | 235 // static |
236 SkBitmap SkBitmapScaler::Resize(const SkBitmap& source, | 236 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, |
237 ResizeMethod method, | 237 const SkBitmap& source, |
238 int destWidth, int destHeight, | 238 ResizeMethod method, |
239 const SkIRect& destSubset, | 239 int destWidth, int destHeight, |
240 SkConvolutionProcs* convolveProcs, | 240 const SkIRect& destSubset, |
241 SkBitmap::Allocator* allocator) { | 241 SkConvolutionProcs* convolveProcs, |
| 242 SkBitmap::Allocator* allocator) { |
242 // Ensure that the ResizeMethod enumeration is sound. | 243 // Ensure that the ResizeMethod enumeration is sound. |
243 SkASSERT(((RESIZE_FIRST_QUALITY_METHOD <= method) && | 244 SkASSERT(((RESIZE_FIRST_QUALITY_METHOD <= method) && |
244 (method <= RESIZE_LAST_QUALITY_METHOD)) || | 245 (method <= RESIZE_LAST_QUALITY_METHOD)) || |
245 ((RESIZE_FIRST_ALGORITHM_METHOD <= method) && | 246 ((RESIZE_FIRST_ALGORITHM_METHOD <= method) && |
246 (method <= RESIZE_LAST_ALGORITHM_METHOD))); | 247 (method <= RESIZE_LAST_ALGORITHM_METHOD))); |
247 | 248 |
248 SkIRect dest = { 0, 0, destWidth, destHeight }; | 249 SkIRect dest = { 0, 0, destWidth, destHeight }; |
249 if (!dest.contains(destSubset)) { | 250 if (!dest.contains(destSubset)) { |
250 SkErrorInternals::SetError( kInvalidArgument_SkError, | 251 SkErrorInternals::SetError( kInvalidArgument_SkError, |
251 "Sorry, you passed me a bitmap resize " | 252 "Sorry, you passed me a bitmap resize " |
252 " method I have never heard of: %d", | 253 " method I have never heard of: %d", |
253 method ); | 254 method ); |
254 } | 255 } |
255 | 256 |
256 // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just | 257 // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just |
257 // return empty. | 258 // return empty. |
258 if (source.width() < 1 || source.height() < 1 || | 259 if (source.width() < 1 || source.height() < 1 || |
259 destWidth < 1 || destHeight < 1) { | 260 destWidth < 1 || destHeight < 1) { |
260 return SkBitmap(); | 261 // todo: seems like we could handle negative dstWidth/Height, since that |
| 262 // is just a negative scale (flip) |
| 263 return false; |
261 } | 264 } |
262 | 265 |
263 method = ResizeMethodToAlgorithmMethod(method); | 266 method = ResizeMethodToAlgorithmMethod(method); |
264 | 267 |
265 // Check that we deal with an "algorithm methods" from this point onward. | 268 // Check that we deal with an "algorithm methods" from this point onward. |
266 SkASSERT((SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD <= method) && | 269 SkASSERT((SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD <= method) && |
267 (method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD)); | 270 (method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD)); |
268 | 271 |
269 SkAutoLockPixels locker(source); | 272 SkAutoLockPixels locker(source); |
270 if (!source.readyToDraw() || source.config() != SkBitmap::kARGB_8888_Config) | 273 if (!source.readyToDraw() || |
271 return SkBitmap(); | 274 source.config() != SkBitmap::kARGB_8888_Config) { |
| 275 return false; |
| 276 } |
272 | 277 |
273 SkResizeFilter filter(method, source.width(), source.height(), | 278 SkResizeFilter filter(method, source.width(), source.height(), |
274 destWidth, destHeight, destSubset, convolveProcs); | 279 destWidth, destHeight, destSubset, convolveProcs); |
275 | 280 |
276 // Get a source bitmap encompassing this touched area. We construct the | 281 // Get a source bitmap encompassing this touched area. We construct the |
277 // offsets and row strides such that it looks like a new bitmap, while | 282 // offsets and row strides such that it looks like a new bitmap, while |
278 // referring to the old data. | 283 // referring to the old data. |
279 const unsigned char* sourceSubset = | 284 const unsigned char* sourceSubset = |
280 reinterpret_cast<const unsigned char*>(source.getPixels()); | 285 reinterpret_cast<const unsigned char*>(source.getPixels()); |
281 | 286 |
282 // Convolve into the result. | 287 // Convolve into the result. |
283 SkBitmap result; | 288 SkBitmap result; |
284 result.setConfig(SkBitmap::kARGB_8888_Config, | 289 result.setConfig(SkBitmap::kARGB_8888_Config, |
285 destSubset.width(), destSubset.height()); | 290 destSubset.width(), destSubset.height()); |
286 result.allocPixels(allocator, NULL); | 291 result.allocPixels(allocator, NULL); |
287 if (!result.readyToDraw()) | 292 if (!result.readyToDraw()) { |
288 return SkBitmap(); | 293 return false; |
| 294 } |
289 | 295 |
290 BGRAConvolve2D(sourceSubset, static_cast<int>(source.rowBytes()), | 296 BGRAConvolve2D(sourceSubset, static_cast<int>(source.rowBytes()), |
291 !source.isOpaque(), filter.xFilter(), filter.yFilter(), | 297 !source.isOpaque(), filter.xFilter(), filter.yFilter(), |
292 static_cast<int>(result.rowBytes()), | 298 static_cast<int>(result.rowBytes()), |
293 static_cast<unsigned char*>(result.getPixels()), | 299 static_cast<unsigned char*>(result.getPixels()), |
294 convolveProcs, true); | 300 convolveProcs, true); |
295 | 301 |
296 // Preserve the "opaque" flag for use as an optimization later. | 302 // Preserve the "opaque" flag for use as an optimization later. |
297 result.setIsOpaque(source.isOpaque()); | 303 result.setIsOpaque(source.isOpaque()); |
298 | 304 *resultPtr = result; |
299 return result; | 305 return true; |
300 } | 306 } |
301 | 307 |
302 // static | 308 // static |
303 SkBitmap SkBitmapScaler::Resize(const SkBitmap& source, | 309 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, |
304 ResizeMethod method, | 310 const SkBitmap& source, |
305 int destWidth, int destHeight, | 311 ResizeMethod method, |
306 SkConvolutionProcs* convolveProcs, | 312 int destWidth, int destHeight, |
307 SkBitmap::Allocator* allocator) { | 313 SkConvolutionProcs* convolveProcs, |
| 314 SkBitmap::Allocator* allocator) { |
308 SkIRect destSubset = { 0, 0, destWidth, destHeight }; | 315 SkIRect destSubset = { 0, 0, destWidth, destHeight }; |
309 return Resize(source, method, destWidth, destHeight, destSubset, | 316 return Resize(resultPtr, source, method, destWidth, destHeight, destSubset, |
310 convolveProcs, allocator); | 317 convolveProcs, allocator); |
311 } | 318 } |
OLD | NEW |