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