// static bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkBitmap& source, ResizeMethod method, float destWidth, float destHeight, SkBitmap::Allocator* allocator) { SkConvolutionProcs convolveProcs= { 0, NULL, NULL, NULL, NULL }; PlatformConvolutionProcs(&convolveProcs); SkRect destSubset = { 0, 0, destWidth, destHeight }; // Ensure that the ResizeMethod enumeration is sound. SkASSERT(((RESIZE_FIRST_QUALITY_METHOD <= method) && (method <= RESIZE_LAST_QUALITY_METHOD)) || ((RESIZE_FIRST_ALGORITHM_METHOD <= method) && (method <= RESIZE_LAST_ALGORITHM_METHOD))); SkRect dest = { 0, 0, destWidth, destHeight }; if (!dest.contains(destSubset)) { SkErrorInternals::SetError( kInvalidArgument_SkError, "Sorry, the destination bitmap scale subset " "falls outside the full destination bitmap." ); return false; } // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just // return empty. if (source.width() < 1 || source.height() < 1 || destWidth < 1 || destHeight < 1) { // todo: seems like we could handle negative dstWidth/Height, since that // is just a negative scale (flip) return false; } method = ResizeMethodToAlgorithmMethod(method); // Check that we deal with an "algorithm methods" from this point onward. SkASSERT((SkBitmapScaler::RESIZE_FIRST_ALGORITHM_METHOD <= method) && (method <= SkBitmapScaler::RESIZE_LAST_ALGORITHM_METHOD)); SkAutoLockPixels locker(source); if (!source.readyToDraw() || source.colorType() != kN32_SkColorType) { return false; } SkResizeFilter filter(method, source.width(), source.height(), destWidth, destHeight, destSubset, convolveProcs); // Get a source bitmap encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while // referring to the old data. const unsigned char* sourceSubset = reinterpret_cast<const unsigned char*>(source.getPixels()); // Convolve into the result. SkBitmap result; result.setInfo(SkImageInfo::MakeN32(SkScalarCeilToInt(destSubset.width()), SkScalarCeilToInt(destSubset.height()), source.alphaType())); result.allocPixels(allocator, NULL); if (!result.readyToDraw()) { return false; } BGRAConvolve2D(sourceSubset, static_cast<int>(source.rowBytes()), !source.isOpaque(), filter.xFilter(), filter.yFilter(), static_cast<int>(result.rowBytes()), static_cast<unsigned char*>(result.getPixels()), convolveProcs, true); *resultPtr = result; resultPtr->lockPixels(); SkASSERT(resultPtr->getPixels()); return true; }
// static SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source, ResizeMethod method, int dest_width, int dest_height, const SkIRect& dest_subset, void* dest_pixels /* = nullptr */) { // Ensure that the ResizeMethod enumeration is sound. SkASSERT(((RESIZE_FIRST_QUALITY_METHOD <= method) && (method <= RESIZE_LAST_QUALITY_METHOD)) || ((RESIZE_FIRST_ALGORITHM_METHOD <= method) && (method <= RESIZE_LAST_ALGORITHM_METHOD))); // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just // return empty. if (source.width() < 1 || source.height() < 1 || dest_width < 1 || dest_height < 1) return SkBitmap(); method = ResizeMethodToAlgorithmMethod(method); // Check that we deal with an "algorithm methods" from this point onward. SkASSERT((ImageOperations::RESIZE_FIRST_ALGORITHM_METHOD <= method) && (method <= ImageOperations::RESIZE_LAST_ALGORITHM_METHOD)); SkAutoLockPixels locker(source); if (!source.readyToDraw()) return SkBitmap(); ConvolutionFilter1D x_filter; ConvolutionFilter1D y_filter; resize::ComputeFilters(method, source.width(), dest_width, dest_subset.fLeft, dest_subset.width(), &x_filter); resize::ComputeFilters(method, source.height(), dest_height, dest_subset.fTop, dest_subset.height(), &y_filter); // Get a source bitmap encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while // referring to the old data. const uint8_t* source_subset = reinterpret_cast<const uint8_t*>(source.getPixels()); // Convolve into the result. SkBitmap result; SkImageInfo info = SkImageInfo::Make(dest_subset.width(), dest_subset.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType); if (dest_pixels) { result.installPixels(info, dest_pixels, info.minRowBytes()); } else { result.allocPixels(info); } if (!result.readyToDraw()) return SkBitmap(); BGRAConvolve2D(source_subset, static_cast<int>(source.rowBytes()), !source.isOpaque(), x_filter, y_filter, static_cast<int>(result.rowBytes()), static_cast<unsigned char*>(result.getPixels())); // Preserve the "opaque" flag for use as an optimization later. result.setAlphaType(source.alphaType()); return result; }
// static SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source, ResizeMethod method, int dest_width, int dest_height, const SkIRect& dest_subset) { // 确保枚举值合法. SkASSERT(((RESIZE_FIRST_QUALITY_METHOD<=method) && (method<=RESIZE_LAST_QUALITY_METHOD)) || ((RESIZE_FIRST_ALGORITHM_METHOD<=method) && (method<=RESIZE_LAST_ALGORITHM_METHOD))); // 用于计算函数执行时间, 方便查看是否有问题. base::TimeTicks resize_start = base::TimeTicks::Now(); SkIRect dest = { 0, 0, dest_width, dest_height }; DCHECK(dest.contains(dest_subset)) << "The supplied subset does not fall within the destination image."; // 如果源和目的大小都是0(0*0 0*N N*0), 返回一个空位图. if(source.width()<1 || source.height()<1 || dest_width<1 || dest_height<1) { return SkBitmap(); } method = ResizeMethodToAlgorithmMethod(method); // Check that we deal with an "algorithm methods" from this point onward. SkASSERT((ImageOperations::RESIZE_FIRST_ALGORITHM_METHOD<=method) && (method<=ImageOperations::RESIZE_LAST_ALGORITHM_METHOD)); SkAutoLockPixels locker(source); ResizeFilter filter(method, source.width(), source.height(), dest_width, dest_height, dest_subset); // Get a source bitmap encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while // referring to the old data. const uint8* source_subset = reinterpret_cast<const uint8*>(source.getPixels()); // Convolve into the result. base::CPU cpu; SkBitmap result; result.setConfig(SkBitmap::kARGB_8888_Config, dest_subset.width(), dest_subset.height()); result.allocPixels(); BGRAConvolve2D(source_subset, static_cast<int>(source.rowBytes()), !source.isOpaque(), filter.x_filter(), filter.y_filter(), static_cast<int>(result.rowBytes()), static_cast<unsigned char*>(result.getPixels()), cpu.has_sse2()); // Preserve the "opaque" flag for use as an optimization later. result.setIsOpaque(source.isOpaque()); base::TimeDelta delta = base::TimeTicks::Now() - resize_start; UMA_HISTOGRAM_TIMES("Image.ResampleMS", delta); return result; }