// 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; }
SkBitmap ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_t index) { TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecodeAndScale", "index", static_cast<int>(index)); ImageDecoder* decoder = 0; const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder); ASSERT(!resumeDecoding || decoder); SkBitmap fullSizeImage; bool complete = decode(index, &decoder, &fullSizeImage); if (!decoder) return SkBitmap(); if (index >= m_frameComplete.size()) m_frameComplete.resize(index + 1); m_frameComplete[index] = complete; // If we are not resuming decoding that means the decoder is freshly // created and we have ownership. If we are resuming decoding then // the decoder is owned by ImageDecodingStore. OwnPtr<ImageDecoder> decoderContainer; if (!resumeDecoding) decoderContainer = adoptPtr(decoder); if (fullSizeImage.isNull()) { // If decode has failed and resulted an empty image we can save work // in the future by returning early. m_decodeFailedAndEmpty = !m_isMultiFrame && decoder->failed(); if (resumeDecoding) ImageDecodingStore::instance().unlockDecoder(this, decoder); return SkBitmap(); } // If the image generated is complete then there is no need to keep // the decoder. For multi-frame images, if all frames in the image are // decoded, we remove the decoder. bool removeDecoder; if (m_isMultiFrame) { size_t decodedFrameCount = 0; for (Vector<bool>::iterator it = m_frameComplete.begin(); it != m_frameComplete.end(); ++it) { if (*it) decodedFrameCount++; } removeDecoder = m_frameCount && (decodedFrameCount == m_frameCount); } else { removeDecoder = complete; } if (resumeDecoding) { if (removeDecoder) { ImageDecodingStore::instance().removeDecoder(this, decoder); m_frameComplete.clear(); } else { ImageDecodingStore::instance().unlockDecoder(this, decoder); } } else if (!removeDecoder) { ImageDecodingStore::instance().insertDecoder(this, decoderContainer.release()); } return fullSizeImage; }
// static SkBitmap ImageOperations::ResizeSubpixel(const SkBitmap& source, int dest_width, int dest_height, const SkIRect& dest_subset) { // Currently only works on Linux/BSD because these are the only platforms // where SkFontHost::GetSubpixelOrder is defined. #if defined(XP_UNIX) // Understand the display. const SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder(); const SkFontHost::LCDOrientation orientation = SkFontHost::GetSubpixelOrientation(); // Decide on which dimension, if any, to deploy subpixel rendering. int w = 1; int h = 1; switch (orientation) { case SkFontHost::kHorizontal_LCDOrientation: w = dest_width < source.width() ? 3 : 1; break; case SkFontHost::kVertical_LCDOrientation: h = dest_height < source.height() ? 3 : 1; break; } // Resize the image. const int width = dest_width * w; const int height = dest_height * h; SkIRect subset = { dest_subset.fLeft, dest_subset.fTop, dest_subset.fLeft + dest_subset.width() * w, dest_subset.fTop + dest_subset.height() * h }; SkBitmap img = ResizeBasic(source, ImageOperations::RESIZE_LANCZOS3, width, height, subset); const int row_words = img.rowBytes() / 4; if (w == 1 && h == 1) return img; // Render into subpixels. SkBitmap result; SkImageInfo info = SkImageInfo::Make(dest_subset.width(), dest_subset.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType); result.allocPixels(info); if (!result.readyToDraw()) return img; SkAutoLockPixels locker(img); if (!img.readyToDraw()) return img; uint32_t* src_row = img.getAddr32(0, 0); uint32_t* dst_row = result.getAddr32(0, 0); for (int y = 0; y < dest_subset.height(); y++) { uint32_t* src = src_row; uint32_t* dst = dst_row; for (int x = 0; x < dest_subset.width(); x++, src += w, dst++) { uint8_t r = 0, g = 0, b = 0, a = 0; switch (order) { case SkFontHost::kRGB_LCDOrder: switch (orientation) { case SkFontHost::kHorizontal_LCDOrientation: r = SkGetPackedR32(src[0]); g = SkGetPackedG32(src[1]); b = SkGetPackedB32(src[2]); a = SkGetPackedA32(src[1]); break; case SkFontHost::kVertical_LCDOrientation: r = SkGetPackedR32(src[0 * row_words]); g = SkGetPackedG32(src[1 * row_words]); b = SkGetPackedB32(src[2 * row_words]); a = SkGetPackedA32(src[1 * row_words]); break; } break; case SkFontHost::kBGR_LCDOrder: switch (orientation) { case SkFontHost::kHorizontal_LCDOrientation: b = SkGetPackedB32(src[0]); g = SkGetPackedG32(src[1]); r = SkGetPackedR32(src[2]); a = SkGetPackedA32(src[1]); break; case SkFontHost::kVertical_LCDOrientation: b = SkGetPackedB32(src[0 * row_words]); g = SkGetPackedG32(src[1 * row_words]); r = SkGetPackedR32(src[2 * row_words]); a = SkGetPackedA32(src[1 * row_words]); break; } break; case SkFontHost::kNONE_LCDOrder: break; } // Premultiplied alpha is very fragile. a = a > r ? a : r; a = a > g ? a : g; a = a > b ? a : b; *dst = SkPackARGB32(a, r, g, b); } src_row += h * row_words; dst_row += result.rowBytes() / 4; } result.setAlphaType(img.alphaType()); return result; #else return SkBitmap(); #endif // OS_POSIX && !OS_MACOSX && !defined(OS_ANDROID) }
// Returns the icon to be displayed in the window. SkBitmap WidgetDelegate::GetWindowIcon() { return SkBitmap(); }
void ImageButton::SetImage(ButtonState aState, const SkBitmap* anImage) { images_[aState] = anImage ? *anImage : SkBitmap(); PreferredSizeChanged(); }
Menu* Menu::AddSubMenu(int index, int item_id, const std::wstring& label) { return AddSubMenuWithIcon(index, item_id, label, SkBitmap()); }
// 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; }