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::MakeS32(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()135 SkData* SkImageGeneratorWIC::onRefEncodedData() {
136 return SkRef(fData.get());
137 }
138
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)139 bool SkImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
140 const Options&) {
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