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