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