1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkStream.h" 9#include "include/ports/SkImageGeneratorWIC.h" 10#include "include/private/SkTemplates.h" 11#include "src/utils/win/SkIStream.h" 12#include "src/utils/win/SkTScopedComPtr.h" 13 14#include <wincodec.h> 15 16// All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. 17// In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported 18// but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2. 19// Undo this #define if it has been done so that we link against the symbols 20// we intended to link against on all SDKs. 21#if defined(CLSID_WICImagingFactory) 22 #undef CLSID_WICImagingFactory 23#endif 24 25namespace { 26class ImageGeneratorWIC : public SkImageGenerator { 27public: 28 /* 29 * Takes ownership of the imagingFactory 30 * Takes ownership of the imageSource 31 */ 32 ImageGeneratorWIC(const SkImageInfo& info, IWICImagingFactory* imagingFactory, 33 IWICBitmapSource* imageSource, sk_sp<SkData>); 34protected: 35 sk_sp<SkData> onRefEncodedData() override; 36 37 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&) 38 override; 39 40private: 41 SkTScopedComPtr<IWICImagingFactory> fImagingFactory; 42 SkTScopedComPtr<IWICBitmapSource> fImageSource; 43 sk_sp<SkData> fData; 44 45 using INHERITED = SkImageGenerator; 46}; 47} // namespace 48 49std::unique_ptr<SkImageGenerator> SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp<SkData> data) { 50 // Create Windows Imaging Component ImagingFactory. 51 SkTScopedComPtr<IWICImagingFactory> imagingFactory; 52 HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, 53 IID_PPV_ARGS(&imagingFactory)); 54 if (FAILED(hr)) { 55 return nullptr; 56 } 57 58 // Create an IStream. 59 SkTScopedComPtr<IStream> iStream; 60 // Note that iStream will take ownership of the new memory stream because 61 // we set |deleteOnRelease| to true. 62 hr = SkIStream::CreateFromSkStream(std::make_unique<SkMemoryStream>(data), &iStream); 63 if (FAILED(hr)) { 64 return nullptr; 65 } 66 67 // Create the decoder from the stream. 68 SkTScopedComPtr<IWICBitmapDecoder> decoder; 69 hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr, 70 WICDecodeMetadataCacheOnDemand, &decoder); 71 if (FAILED(hr)) { 72 return nullptr; 73 } 74 75 // Select the first frame from the decoder. 76 SkTScopedComPtr<IWICBitmapFrameDecode> imageFrame; 77 hr = decoder->GetFrame(0, &imageFrame); 78 if (FAILED(hr)) { 79 return nullptr; 80 } 81 82 // Treat the frame as an image source. 83 SkTScopedComPtr<IWICBitmapSource> imageSource; 84 hr = imageFrame->QueryInterface(IID_PPV_ARGS(&imageSource)); 85 if (FAILED(hr)) { 86 return nullptr; 87 } 88 89 // Get the size of the image. 90 UINT width; 91 UINT height; 92 hr = imageSource->GetSize(&width, &height); 93 if (FAILED(hr)) { 94 return nullptr; 95 } 96 97 // Get the encoded pixel format. 98 WICPixelFormatGUID format; 99 hr = imageSource->GetPixelFormat(&format); 100 if (FAILED(hr)) { 101 return nullptr; 102 } 103 104 // Recommend kOpaque if the image is opaque and kPremul otherwise. 105 // FIXME: We are stuck recommending kPremul for all indexed formats 106 // (Ex: GUID_WICPixelFormat8bppIndexed) because we don't have 107 // a way to check if the image has alpha. 108 SkAlphaType alphaType = kPremul_SkAlphaType; 109 110 if (GUID_WICPixelFormat16bppBGR555 == format || 111 GUID_WICPixelFormat16bppBGR565 == format || 112 GUID_WICPixelFormat32bppBGR101010 == format || 113 GUID_WICPixelFormatBlackWhite == format || 114 GUID_WICPixelFormat2bppGray == format || 115 GUID_WICPixelFormat4bppGray == format || 116 GUID_WICPixelFormat8bppGray == format || 117 GUID_WICPixelFormat16bppGray == format || 118 GUID_WICPixelFormat16bppGrayFixedPoint == format || 119 GUID_WICPixelFormat16bppGrayHalf == format || 120 GUID_WICPixelFormat32bppGrayFloat == format || 121 GUID_WICPixelFormat32bppGrayFixedPoint == format || 122 GUID_WICPixelFormat32bppRGBE == format || 123 GUID_WICPixelFormat24bppRGB == format || 124 GUID_WICPixelFormat24bppBGR == format || 125 GUID_WICPixelFormat32bppBGR == format || 126 GUID_WICPixelFormat48bppRGB == format || 127 GUID_WICPixelFormat48bppBGR == format || 128 GUID_WICPixelFormat48bppRGBFixedPoint == format || 129 GUID_WICPixelFormat48bppBGRFixedPoint == format || 130 GUID_WICPixelFormat48bppRGBHalf == format || 131 GUID_WICPixelFormat64bppRGBFixedPoint == format || 132 GUID_WICPixelFormat64bppRGBHalf == format || 133 GUID_WICPixelFormat96bppRGBFixedPoint == format || 134 GUID_WICPixelFormat128bppRGBFloat == format || 135 GUID_WICPixelFormat128bppRGBFixedPoint == format || 136 GUID_WICPixelFormat32bppRGB == format || 137 GUID_WICPixelFormat64bppRGB == format || 138 GUID_WICPixelFormat96bppRGBFloat == format || 139 GUID_WICPixelFormat32bppCMYK == format || 140 GUID_WICPixelFormat64bppCMYK == format || 141 GUID_WICPixelFormat8bppY == format || 142 GUID_WICPixelFormat8bppCb == format || 143 GUID_WICPixelFormat8bppCr == format || 144 GUID_WICPixelFormat16bppCbCr == format) 145 { 146 alphaType = kOpaque_SkAlphaType; 147 } 148 149 // FIXME: If we change the implementation to handle swizzling ourselves, 150 // we can support more output formats. 151 SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); 152 return std::unique_ptr<SkImageGenerator>( 153 new ImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), 154 std::move(data))); 155} 156 157ImageGeneratorWIC::ImageGeneratorWIC(const SkImageInfo& info, 158 IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp<SkData> data) 159 : INHERITED(info) 160 , fImagingFactory(imagingFactory) 161 , fImageSource(imageSource) 162 , fData(std::move(data)) 163{} 164 165sk_sp<SkData> ImageGeneratorWIC::onRefEncodedData() { 166 return fData; 167} 168 169bool ImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 170 const Options&) { 171 if (kN32_SkColorType != info.colorType()) { 172 return false; 173 } 174 175 // Create a format converter. 176 SkTScopedComPtr<IWICFormatConverter> formatConverter; 177 HRESULT hr = fImagingFactory->CreateFormatConverter(&formatConverter); 178 if (FAILED(hr)) { 179 return false; 180 } 181 182 GUID format = GUID_WICPixelFormat32bppPBGRA; 183 if (kUnpremul_SkAlphaType == info.alphaType()) { 184 format = GUID_WICPixelFormat32bppBGRA; 185 } 186 187 hr = formatConverter->Initialize(fImageSource.get(), format, WICBitmapDitherTypeNone, nullptr, 188 0.0, WICBitmapPaletteTypeCustom); 189 if (FAILED(hr)) { 190 return false; 191 } 192 193 // Treat the format converter as an image source. 194 SkTScopedComPtr<IWICBitmapSource> formatConverterSrc; 195 hr = formatConverter->QueryInterface(IID_PPV_ARGS(&formatConverterSrc)); 196 if (FAILED(hr)) { 197 return false; 198 } 199 200 // Set the destination pixels. 201 hr = formatConverterSrc->CopyPixels(nullptr, (UINT) rowBytes, (UINT) rowBytes * info.height(), 202 (BYTE*) pixels); 203 204 return SUCCEEDED(hr); 205} 206