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