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
25 namespace {
26 class ImageGeneratorWIC : public SkImageGenerator {
27 public:
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>);
34 protected:
35 sk_sp<SkData> onRefEncodedData() override;
36
37 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&)
38 override;
39
40 private:
41 SkTScopedComPtr<IWICImagingFactory> fImagingFactory;
42 SkTScopedComPtr<IWICBitmapSource> fImageSource;
43 sk_sp<SkData> fData;
44
45 using INHERITED = SkImageGenerator;
46 };
47 } // namespace
48
MakeFromEncodedWIC(sk_sp<SkData> data)49 std::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
ImageGeneratorWIC(const SkImageInfo & info,IWICImagingFactory * imagingFactory,IWICBitmapSource * imageSource,sk_sp<SkData> data)157 ImageGeneratorWIC::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
onRefEncodedData()165 sk_sp<SkData> ImageGeneratorWIC::onRefEncodedData() {
166 return fData;
167 }
168
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)169 bool 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