/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/codec/SkEncodedOrigin.h" #include "include/core/SkStream.h" #include "include/ports/SkImageGeneratorWIC.h" #include "include/private/base/SkTemplates.h" #include "src/codec/SkPixmapUtilsPriv.h" #include "src/utils/win/SkIStream.h" #include "src/utils/win/SkTScopedComPtr.h" #include // All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. // In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported // but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2. // Undo this #define if it has been done so that we link against the symbols // we intended to link against on all SDKs. #if defined(CLSID_WICImagingFactory) #undef CLSID_WICImagingFactory #endif namespace { class ImageGeneratorWIC : public SkImageGenerator { public: /* * Takes ownership of the imagingFactory * Takes ownership of the imageSource */ ImageGeneratorWIC(const SkImageInfo& info, IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp, SkEncodedOrigin); protected: sk_sp onRefEncodedData() override; bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&) override; private: SkTScopedComPtr fImagingFactory; SkTScopedComPtr fImageSource; sk_sp fData; SkEncodedOrigin fOrigin; using INHERITED = SkImageGenerator; }; } // namespace std::unique_ptr SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp data) { // Create Windows Imaging Component ImagingFactory. SkTScopedComPtr imagingFactory; HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&imagingFactory)); if (FAILED(hr)) { return nullptr; } // Create an IStream. SkTScopedComPtr iStream; // Note that iStream will take ownership of the new memory stream because // we set |deleteOnRelease| to true. hr = SkIStream::CreateFromSkStream(std::make_unique(data), &iStream); if (FAILED(hr)) { return nullptr; } // Create the decoder from the stream. SkTScopedComPtr decoder; hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr, WICDecodeMetadataCacheOnDemand, &decoder); if (FAILED(hr)) { return nullptr; } // Select the first frame from the decoder. SkTScopedComPtr imageFrame; hr = decoder->GetFrame(0, &imageFrame); if (FAILED(hr)) { return nullptr; } // Get the metadata query reader from the frame. SkEncodedOrigin origin = kDefault_SkEncodedOrigin; SkTScopedComPtr queryReader; hr = imageFrame->GetMetadataQueryReader(&queryReader); // WIC decoder doesn't support BMP and ICO metadata, so we only continue // reading metadata if GetMetadataQueryReader didn't return an error code. if (SUCCEEDED(hr)) { // Query for the orientation metadata (assuming JPEG policy). PROPVARIANT propValue; PropVariantInit(&propValue); hr = queryReader->GetMetadataByName(L"/app1/ifd/{ushort=274}", &propValue); if (SUCCEEDED(hr) && propValue.vt == VT_UI2) { SkEncodedOrigin originValue = static_cast(propValue.uiVal); if (originValue >= kTopLeft_SkEncodedOrigin && originValue <= kLast_SkEncodedOrigin) { origin = originValue; } } } // Treat the frame as an image source. SkTScopedComPtr 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::MakeS32(width, height, alphaType); if (SkEncodedOriginSwapsWidthHeight(origin)) { info = SkPixmapUtils::SwapWidthHeight(info); } return std::unique_ptr( new ImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), std::move(data), origin)); } ImageGeneratorWIC::ImageGeneratorWIC(const SkImageInfo& info, IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp data, SkEncodedOrigin origin) : INHERITED(info) , fImagingFactory(imagingFactory) , fImageSource(imageSource) , fData(std::move(data)) , fOrigin(origin) {} sk_sp ImageGeneratorWIC::onRefEncodedData() { return fData; } bool ImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&) { if (kN32_SkColorType != info.colorType()) { return false; } // Create a format converter. SkTScopedComPtr formatConverter; HRESULT hr = fImagingFactory->CreateFormatConverter(&formatConverter); if (FAILED(hr)) { return false; } GUID format = GUID_WICPixelFormat32bppPBGRA; if (kUnpremul_SkAlphaType == info.alphaType()) { format = GUID_WICPixelFormat32bppBGRA; } hr = formatConverter->Initialize(fImageSource.get(), format, WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom); if (FAILED(hr)) { return false; } // Treat the format converter as an image source. SkTScopedComPtr formatConverterSrc; hr = formatConverter->QueryInterface(IID_PPV_ARGS(&formatConverterSrc)); if (FAILED(hr)) { return false; } SkPixmap dst(info, pixels, rowBytes); auto decode = [&formatConverterSrc](const SkPixmap& pm) { // Get the destination pixels. void* pixelsAddr = pm.writable_addr(); size_t rowBytes = pm.rowBytes(); const SkImageInfo& info = pm.info(); // Set the destination pixels. HRESULT hr = formatConverterSrc->CopyPixels(nullptr, (UINT) rowBytes, (UINT) rowBytes * info.height(), (BYTE*) pixelsAddr); return SUCCEEDED(hr); }; return SkPixmapUtils::Orient(dst, fOrigin, decode); }