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