bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const { //Initialize COM. SkAutoCoInitialize scopedCo; if (!scopedCo.succeeded()) { return false; } HRESULT hr = S_OK; //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , nullptr , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert SkStream to IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkIStream::CreateFromSkStream(stream, false, &piStream); } //Make sure we're at the beginning of the stream. if (SUCCEEDED(hr)) { LARGE_INTEGER liBeginning = { 0 }; hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, nullptr); } //Create the decoder from the stream content. SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateDecoderFromStream( piStream.get() //Image to be decoded , nullptr //No particular vendor , WICDecodeMetadataCacheOnDemand //Cache metadata when needed , &piBitmapDecoder //Pointer to the decoder ); } if (kDecodeFormat_WICMode == wicMode) { SkASSERT(format != nullptr); //Get the format if (SUCCEEDED(hr)) { GUID guidFormat; hr = piBitmapDecoder->GetContainerFormat(&guidFormat); if (SUCCEEDED(hr)) { *format = GuidContainerFormat_to_Format(guidFormat); return true; } } return false; } //Get the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; if (SUCCEEDED(hr)) { hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); } //Get the BitmapSource interface of the frame. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; if (SUCCEEDED(hr)) { hr = piBitmapFrameDecode->QueryInterface( IID_PPV_ARGS(&piBitmapSourceOriginal) ); } //Get the size of the bitmap. UINT width; UINT height; if (SUCCEEDED(hr)) { hr = piBitmapSourceOriginal->GetSize(&width, &height); } //Exit early if we're only looking for the bitmap bounds. if (SUCCEEDED(hr)) { bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); if (kDecodeBounds_WICMode == wicMode) { return true; } if (!this->allocPixelRef(bm, nullptr)) { return false; } } //Create a format converter. SkTScopedComPtr<IWICFormatConverter> piFormatConverter; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); } GUID destinationPixelFormat; if (this->getRequireUnpremultipliedColors()) { destinationPixelFormat = GUID_WICPixelFormat32bppBGRA; } else { destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA; } if (SUCCEEDED(hr)) { hr = piFormatConverter->Initialize( piBitmapSourceOriginal.get() //Input bitmap to convert , destinationPixelFormat //Destination pixel format , WICBitmapDitherTypeNone //Specified dither patterm , nullptr //Specify a particular palette , 0.f //Alpha threshold , WICBitmapPaletteTypeCustom //Palette translation type ); } //Get the BitmapSource interface of the format converter. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; if (SUCCEEDED(hr)) { hr = piFormatConverter->QueryInterface( IID_PPV_ARGS(&piBitmapSourceConverted) ); } //Copy the pixels into the bitmap. if (SUCCEEDED(hr)) { SkAutoLockPixels alp(*bm); bm->eraseColor(SK_ColorTRANSPARENT); const UINT stride = (UINT) bm->rowBytes(); hr = piBitmapSourceConverted->CopyPixels( nullptr, //Get all the pixels stride, stride * height, reinterpret_cast<BYTE *>(bm->getPixels()) ); // Note: we don't need to premultiply here since we specified PBGRA if (SkBitmap::ComputeIsOpaque(*bm)) { bm->setAlphaType(kOpaque_SkAlphaType); } } return SUCCEEDED(hr); }
bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { //Initialize COM. AutoCoInitialize scopedCo; HRESULT hr = scopedCo.getHR(); //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert SkStream to IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkIStream::CreateFromSkStream(stream, false, &piStream); } //Make sure we're at the beginning of the stream. if (SUCCEEDED(hr)) { LARGE_INTEGER liBeginning = { 0 }; hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); } //Create the decoder from the stream content. SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateDecoderFromStream( piStream.get() //Image to be decoded , NULL //No particular vendor , WICDecodeMetadataCacheOnDemand //Cache metadata when needed , &piBitmapDecoder //Pointer to the decoder ); } //Get the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; if (SUCCEEDED(hr)) { hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); } //Get the BitmapSource interface of the frame. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; if (SUCCEEDED(hr)) { hr = piBitmapFrameDecode->QueryInterface( IID_PPV_ARGS(&piBitmapSourceOriginal) ); } //Get the size of the bitmap. UINT width; UINT height; if (SUCCEEDED(hr)) { hr = piBitmapSourceOriginal->GetSize(&width, &height); } //Exit early if we're only looking for the bitmap bounds. if (SUCCEEDED(hr)) { bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } } //Create a format converter. SkTScopedComPtr<IWICFormatConverter> piFormatConverter; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); } if (SUCCEEDED(hr)) { hr = piFormatConverter->Initialize( piBitmapSourceOriginal.get() //Input bitmap to convert , GUID_WICPixelFormat32bppPBGRA //Destination pixel format , WICBitmapDitherTypeNone //Specified dither patterm , NULL //Specify a particular palette , 0.f //Alpha threshold , WICBitmapPaletteTypeCustom //Palette translation type ); } //Get the BitmapSource interface of the format converter. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; if (SUCCEEDED(hr)) { hr = piFormatConverter->QueryInterface( IID_PPV_ARGS(&piBitmapSourceConverted) ); } //Copy the pixels into the bitmap. if (SUCCEEDED(hr)) { bm->lockPixels(); bm->eraseColor(0); const int stride = bm->rowBytes(); hr = piBitmapSourceConverted->CopyPixels( NULL, //Get all the pixels stride, stride * height, reinterpret_cast<BYTE *>(bm->getPixels()) ); bm->unlockPixels(); } return SUCCEEDED(hr); }
SkImageGenerator* SkImageGeneratorWIC::NewFromEncodedWIC(SkData* data) { // Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> imagingFactory; HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&imagingFactory)); if (FAILED(hr)) { return nullptr; } // Create an IStream. SkTScopedComPtr<IStream> iStream; // Note that iStream will take ownership of the new memory stream because // we set |deleteOnRelease| to true. hr = SkIStream::CreateFromSkStream(new SkMemoryStream(data), true, &iStream); if (FAILED(hr)) { return nullptr; } // Create the decoder from the stream. SkTScopedComPtr<IWICBitmapDecoder> decoder; hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr, WICDecodeMetadataCacheOnDemand, &decoder); if (FAILED(hr)) { return nullptr; } // Select the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> imageFrame; hr = decoder->GetFrame(0, &imageFrame); if (FAILED(hr)) { return nullptr; } // Treat the frame as an image source. SkTScopedComPtr<IWICBitmapSource> imageSource; hr = imageFrame->QueryInterface(IID_PPV_ARGS(&imageSource)); if (FAILED(hr)) { return nullptr; } // Get the size of the image. UINT width; UINT height; hr = imageSource->GetSize(&width, &height); if (FAILED(hr)) { return nullptr; } // Get the encoded pixel format. WICPixelFormatGUID format; hr = imageSource->GetPixelFormat(&format); if (FAILED(hr)) { return nullptr; } // Recommend kOpaque if the image is opaque and kPremul otherwise. // FIXME: We are stuck recommending kPremul for all indexed formats // (Ex: GUID_WICPixelFormat8bppIndexed) because we don't have // a way to check if the image has alpha. SkAlphaType alphaType = kPremul_SkAlphaType; if (GUID_WICPixelFormat16bppBGR555 == format || GUID_WICPixelFormat16bppBGR565 == format || GUID_WICPixelFormat32bppBGR101010 == format || GUID_WICPixelFormatBlackWhite == format || GUID_WICPixelFormat2bppGray == format || GUID_WICPixelFormat4bppGray == format || GUID_WICPixelFormat8bppGray == format || GUID_WICPixelFormat16bppGray == format || GUID_WICPixelFormat16bppGrayFixedPoint == format || GUID_WICPixelFormat16bppGrayHalf == format || GUID_WICPixelFormat32bppGrayFloat == format || GUID_WICPixelFormat32bppGrayFixedPoint == format || GUID_WICPixelFormat32bppRGBE == format || GUID_WICPixelFormat24bppRGB == format || GUID_WICPixelFormat24bppBGR == format || GUID_WICPixelFormat32bppBGR == format || GUID_WICPixelFormat48bppRGB == format || GUID_WICPixelFormat48bppBGR == format || GUID_WICPixelFormat48bppRGBFixedPoint == format || GUID_WICPixelFormat48bppBGRFixedPoint == format || GUID_WICPixelFormat48bppRGBHalf == format || GUID_WICPixelFormat64bppRGBFixedPoint == format || GUID_WICPixelFormat64bppRGBHalf == format || GUID_WICPixelFormat96bppRGBFixedPoint == format || GUID_WICPixelFormat128bppRGBFloat == format || GUID_WICPixelFormat128bppRGBFixedPoint == format || GUID_WICPixelFormat32bppRGB == format || GUID_WICPixelFormat64bppRGB == format || GUID_WICPixelFormat96bppRGBFloat == format || GUID_WICPixelFormat32bppCMYK == format || GUID_WICPixelFormat64bppCMYK == format || GUID_WICPixelFormat8bppY == format || GUID_WICPixelFormat8bppCb == format || GUID_WICPixelFormat8bppCr == format || GUID_WICPixelFormat16bppCbCr == format) { alphaType = kOpaque_SkAlphaType; } // FIXME: If we change the implementation to handle swizzling ourselves, // we can support more output formats. SkImageInfo info = SkImageInfo::MakeN32(width, height, alphaType); return new SkImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), data); }