• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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