xref: /aosp_15_r20/external/skia/src/ports/SkImageGeneratorWIC.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/codec/SkEncodedOrigin.h"
9 #include "include/core/SkStream.h"
10 #include "include/ports/SkImageGeneratorWIC.h"
11 #include "include/private/base/SkTemplates.h"
12 #include "src/codec/SkPixmapUtilsPriv.h"
13 #include "src/utils/win/SkIStream.h"
14 #include "src/utils/win/SkTScopedComPtr.h"
15 
16 #include <wincodec.h>
17 
18 // All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
19 // In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
20 // but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
21 // Undo this #define if it has been done so that we link against the symbols
22 // we intended to link against on all SDKs.
23 #if defined(CLSID_WICImagingFactory)
24     #undef CLSID_WICImagingFactory
25 #endif
26 
27 namespace {
28 class ImageGeneratorWIC : public SkImageGenerator {
29 public:
30     /*
31      * Takes ownership of the imagingFactory
32      * Takes ownership of the imageSource
33      */
34     ImageGeneratorWIC(const SkImageInfo& info, IWICImagingFactory* imagingFactory,
35             IWICBitmapSource* imageSource, sk_sp<SkData>, SkEncodedOrigin);
36 protected:
37     sk_sp<SkData> onRefEncodedData() override;
38 
39     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&)
40     override;
41 
42 private:
43     SkTScopedComPtr<IWICImagingFactory> fImagingFactory;
44     SkTScopedComPtr<IWICBitmapSource>   fImageSource;
45     sk_sp<SkData>                       fData;
46     SkEncodedOrigin                     fOrigin;
47 
48     using INHERITED = SkImageGenerator;
49 };
50 }  // namespace
51 
MakeFromEncodedWIC(sk_sp<SkData> data)52 std::unique_ptr<SkImageGenerator> SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp<SkData> data) {
53     // Create Windows Imaging Component ImagingFactory.
54     SkTScopedComPtr<IWICImagingFactory> imagingFactory;
55     HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
56             IID_PPV_ARGS(&imagingFactory));
57     if (FAILED(hr)) {
58         return nullptr;
59     }
60 
61     // Create an IStream.
62     SkTScopedComPtr<IStream> iStream;
63     // Note that iStream will take ownership of the new memory stream because
64     // we set |deleteOnRelease| to true.
65     hr = SkIStream::CreateFromSkStream(std::make_unique<SkMemoryStream>(data), &iStream);
66     if (FAILED(hr)) {
67         return nullptr;
68     }
69 
70     // Create the decoder from the stream.
71     SkTScopedComPtr<IWICBitmapDecoder> decoder;
72     hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr,
73             WICDecodeMetadataCacheOnDemand, &decoder);
74     if (FAILED(hr)) {
75         return nullptr;
76     }
77 
78     // Select the first frame from the decoder.
79     SkTScopedComPtr<IWICBitmapFrameDecode> imageFrame;
80     hr = decoder->GetFrame(0, &imageFrame);
81     if (FAILED(hr)) {
82         return nullptr;
83     }
84 
85     // Get the metadata query reader from the frame.
86     SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
87     SkTScopedComPtr<IWICMetadataQueryReader> queryReader;
88     hr = imageFrame->GetMetadataQueryReader(&queryReader);
89 
90     // WIC decoder doesn't support BMP and ICO metadata, so we only continue
91     // reading metadata if GetMetadataQueryReader didn't return an error code.
92     if (SUCCEEDED(hr)) {
93       // Query for the orientation metadata (assuming JPEG policy).
94       PROPVARIANT propValue;
95       PropVariantInit(&propValue);
96       hr = queryReader->GetMetadataByName(L"/app1/ifd/{ushort=274}", &propValue);
97       if (SUCCEEDED(hr) && propValue.vt == VT_UI2) {
98           SkEncodedOrigin originValue = static_cast<SkEncodedOrigin>(propValue.uiVal);
99           if (originValue >= kTopLeft_SkEncodedOrigin && originValue <= kLast_SkEncodedOrigin) {
100             origin = originValue;
101           }
102       }
103     }
104 
105     // Treat the frame as an image source.
106     SkTScopedComPtr<IWICBitmapSource> imageSource;
107     hr = imageFrame->QueryInterface(IID_PPV_ARGS(&imageSource));
108     if (FAILED(hr)) {
109         return nullptr;
110     }
111 
112     // Get the size of the image.
113     UINT width;
114     UINT height;
115     hr = imageSource->GetSize(&width, &height);
116     if (FAILED(hr)) {
117         return nullptr;
118     }
119 
120     // Get the encoded pixel format.
121     WICPixelFormatGUID format;
122     hr = imageSource->GetPixelFormat(&format);
123     if (FAILED(hr)) {
124         return nullptr;
125     }
126 
127     // Recommend kOpaque if the image is opaque and kPremul otherwise.
128     // FIXME: We are stuck recommending kPremul for all indexed formats
129     //        (Ex: GUID_WICPixelFormat8bppIndexed) because we don't have
130     //        a way to check if the image has alpha.
131     SkAlphaType alphaType = kPremul_SkAlphaType;
132 
133     if (GUID_WICPixelFormat16bppBGR555 == format ||
134         GUID_WICPixelFormat16bppBGR565 == format ||
135         GUID_WICPixelFormat32bppBGR101010 == format ||
136         GUID_WICPixelFormatBlackWhite == format ||
137         GUID_WICPixelFormat2bppGray == format ||
138         GUID_WICPixelFormat4bppGray == format ||
139         GUID_WICPixelFormat8bppGray == format ||
140         GUID_WICPixelFormat16bppGray == format ||
141         GUID_WICPixelFormat16bppGrayFixedPoint == format ||
142         GUID_WICPixelFormat16bppGrayHalf == format ||
143         GUID_WICPixelFormat32bppGrayFloat == format ||
144         GUID_WICPixelFormat32bppGrayFixedPoint == format ||
145         GUID_WICPixelFormat32bppRGBE == format ||
146         GUID_WICPixelFormat24bppRGB == format ||
147         GUID_WICPixelFormat24bppBGR == format ||
148         GUID_WICPixelFormat32bppBGR == format ||
149         GUID_WICPixelFormat48bppRGB == format ||
150         GUID_WICPixelFormat48bppBGR == format ||
151         GUID_WICPixelFormat48bppRGBFixedPoint == format ||
152         GUID_WICPixelFormat48bppBGRFixedPoint == format ||
153         GUID_WICPixelFormat48bppRGBHalf == format ||
154         GUID_WICPixelFormat64bppRGBFixedPoint == format ||
155         GUID_WICPixelFormat64bppRGBHalf == format ||
156         GUID_WICPixelFormat96bppRGBFixedPoint == format ||
157         GUID_WICPixelFormat128bppRGBFloat == format ||
158         GUID_WICPixelFormat128bppRGBFixedPoint == format ||
159         GUID_WICPixelFormat32bppRGB == format ||
160         GUID_WICPixelFormat64bppRGB == format ||
161         GUID_WICPixelFormat96bppRGBFloat == format ||
162         GUID_WICPixelFormat32bppCMYK == format ||
163         GUID_WICPixelFormat64bppCMYK == format ||
164         GUID_WICPixelFormat8bppY == format ||
165         GUID_WICPixelFormat8bppCb == format ||
166         GUID_WICPixelFormat8bppCr == format ||
167         GUID_WICPixelFormat16bppCbCr == format)
168     {
169         alphaType = kOpaque_SkAlphaType;
170     }
171 
172     // FIXME: If we change the implementation to handle swizzling ourselves,
173     //        we can support more output formats.
174     SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
175     if (SkEncodedOriginSwapsWidthHeight(origin)) {
176         info = SkPixmapUtils::SwapWidthHeight(info);
177     }
178     return std::unique_ptr<SkImageGenerator>(
179             new ImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(),
180                                     std::move(data), origin));
181 }
182 
ImageGeneratorWIC(const SkImageInfo & info,IWICImagingFactory * imagingFactory,IWICBitmapSource * imageSource,sk_sp<SkData> data,SkEncodedOrigin origin)183 ImageGeneratorWIC::ImageGeneratorWIC(const SkImageInfo& info,
184         IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp<SkData> data, SkEncodedOrigin origin)
185     : INHERITED(info)
186     , fImagingFactory(imagingFactory)
187     , fImageSource(imageSource)
188     , fData(std::move(data))
189     , fOrigin(origin)
190 {}
191 
onRefEncodedData()192 sk_sp<SkData> ImageGeneratorWIC::onRefEncodedData() {
193     return fData;
194 }
195 
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)196 bool ImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
197         const Options&) {
198     if (kN32_SkColorType != info.colorType()) {
199         return false;
200     }
201 
202     // Create a format converter.
203     SkTScopedComPtr<IWICFormatConverter> formatConverter;
204     HRESULT hr = fImagingFactory->CreateFormatConverter(&formatConverter);
205     if (FAILED(hr)) {
206         return false;
207     }
208 
209     GUID format = GUID_WICPixelFormat32bppPBGRA;
210     if (kUnpremul_SkAlphaType == info.alphaType()) {
211         format = GUID_WICPixelFormat32bppBGRA;
212     }
213 
214     hr = formatConverter->Initialize(fImageSource.get(), format, WICBitmapDitherTypeNone, nullptr,
215             0.0, WICBitmapPaletteTypeCustom);
216     if (FAILED(hr)) {
217         return false;
218     }
219 
220     // Treat the format converter as an image source.
221     SkTScopedComPtr<IWICBitmapSource> formatConverterSrc;
222     hr = formatConverter->QueryInterface(IID_PPV_ARGS(&formatConverterSrc));
223     if (FAILED(hr)) {
224         return false;
225     }
226 
227     SkPixmap dst(info, pixels, rowBytes);
228     auto decode = [&formatConverterSrc](const SkPixmap& pm) {
229         // Get the destination pixels.
230         void* pixelsAddr = pm.writable_addr();
231         size_t rowBytes = pm.rowBytes();
232         const SkImageInfo& info = pm.info();
233 
234         // Set the destination pixels.
235         HRESULT hr = formatConverterSrc->CopyPixels(nullptr, (UINT) rowBytes, (UINT) rowBytes * info.height(),
236             (BYTE*) pixelsAddr);
237         return SUCCEEDED(hr);
238     };
239     return SkPixmapUtils::Orient(dst, fOrigin, decode);
240 }
241