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