bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) { if (!m_image) return false; m_skiaImage = m_image->nativeImageForCurrentFrame(); m_alphaOp = AlphaDoNothing; bool hasAlpha = m_skiaImage ? !m_skiaImage->bitmap().isOpaque() : true; if ((!m_skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && m_image->data()) { // Attempt to get raw unpremultiplied image data. OwnPtr<ImageDecoder> decoder(ImageDecoder::create( *(m_image->data()), ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied)); if (!decoder) return false; decoder->setData(m_image->data(), true); if (!decoder->frameCount()) return false; ImageFrame* frame = decoder->frameBufferAtIndex(0); if (!frame || frame->status() != ImageFrame::FrameComplete) return false; hasAlpha = frame->hasAlpha(); m_nativeImage = adoptPtr(frame->asNewNativeImage()); if (!m_nativeImage.get() || !m_nativeImage->isDataComplete() || !m_nativeImage->bitmap().width() || !m_nativeImage->bitmap().height()) return false; SkBitmap::Config skiaConfig = m_nativeImage->bitmap().config(); if (skiaConfig != SkBitmap::kARGB_8888_Config) return false; m_skiaImage = m_nativeImage.get(); if (hasAlpha && premultiplyAlpha) m_alphaOp = AlphaDoPremultiply; } else if (!premultiplyAlpha && hasAlpha) { // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value for each pixel is 0xFF // which is true at present and may be changed in the future and needs adjustment accordingly. // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. if (m_imageHtmlDomSource != HtmlDomVideo) m_alphaOp = AlphaDoUnmultiply; } if (!m_skiaImage) return false; m_imageSourceFormat = SK_B32_SHIFT ? DataFormatRGBA8 : DataFormatBGRA8; m_imageWidth = m_skiaImage->bitmap().width(); m_imageHeight = m_skiaImage->bitmap().height(); if (!m_imageWidth || !m_imageHeight) return false; m_imageSourceUnpackAlignment = 0; m_skiaImage->bitmap().lockPixels(); m_imagePixelData = m_skiaImage->bitmap().getPixels(); return true; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; ImageFrame* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == ImageFrame::FrameEmpty) return 0; // Zero-height images can cause problems for some ports. If we have an // empty image dimension, just bail. if (size().isEmpty()) return 0; // Return the buffer contents as a native image. For some ports, the data // is already in a native container, and this just increments its refcount. return buffer->asNewNativeImage(); }
WebImage WebImage::fromData(const WebData& data, const WebSize& desiredSize) { RefPtr<SharedBuffer> buffer = PassRefPtr<SharedBuffer>(data); OwnPtr<ImageDecoder> decoder(ImageDecoder::create(*buffer.get(), ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored)); if (!decoder) return WebImage(); decoder->setData(buffer.get(), true); if (!decoder->isSizeAvailable()) return WebImage(); // Frames are arranged by decreasing size, then decreasing bit depth. // Pick the frame closest to |desiredSize|'s area without being smaller, // which has the highest bit depth. const size_t frameCount = decoder->frameCount(); size_t index = 0; // Default to first frame if none are large enough. int frameAreaAtIndex = 0; for (size_t i = 0; i < frameCount; ++i) { const IntSize frameSize = decoder->frameSizeAtIndex(i); if (WebSize(frameSize) == desiredSize) { index = i; break; // Perfect match. } const int frameArea = frameSize.width() * frameSize.height(); if (frameArea < (desiredSize.width * desiredSize.height)) break; // No more frames that are large enough. if (!i || (frameArea < frameAreaAtIndex)) { index = i; // Closer to desired area than previous best match. frameAreaAtIndex = frameArea; } } ImageFrame* frame = decoder->frameBufferAtIndex(index); if (!frame) return WebImage(); RefPtr<NativeImageSkia> image = frame->asNewNativeImage(); if (!image) return WebImage(); return WebImage(image->bitmap()); }
WebVector<WebImage> WebImage::framesFromData(const WebData& data) { // This is to protect from malicious images. It should be big enough that it's never hit in pracice. const size_t maxFrameCount = 8; RefPtr<SharedBuffer> buffer = PassRefPtr<SharedBuffer>(data); OwnPtr<ImageDecoder> decoder(ImageDecoder::create(*buffer.get(), ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored)); if (!decoder) return WebVector<WebImage>(); decoder->setData(buffer.get(), true); if (!decoder->isSizeAvailable()) return WebVector<WebImage>(); // Frames are arranged by decreasing size, then decreasing bit depth. // Keep the first frame at every size, has the highest bit depth. const size_t frameCount = decoder->frameCount(); IntSize lastSize; Vector<WebImage> frames; for (size_t i = 0; i < std::min(frameCount, maxFrameCount); ++i) { const IntSize frameSize = decoder->frameSizeAtIndex(i); if (frameSize == lastSize) continue; lastSize = frameSize; ImageFrame* frame = decoder->frameBufferAtIndex(i); if (!frame) continue; RefPtr<NativeImageSkia> image = frame->asNewNativeImage(); if (image && image->isDataComplete()) frames.append(WebImage(image->bitmap())); } return frames; }