msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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" |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 11 | #include "SkTScopedComPtr.h" |
| 12 | #include "SkTemplates.h" |
| 13 | |
| 14 | #include <wincodec.h> |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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 | |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 25 | namespace { |
| 26 | class ImageGeneratorWIC : public SkImageGenerator { |
| 27 | public: |
| 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>); |
| 34 | protected: |
| 35 | sk_sp<SkData> onRefEncodedData() override; |
| 36 | |
| 37 | bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&) |
| 38 | override; |
| 39 | |
| 40 | private: |
| 41 | SkTScopedComPtr<IWICImagingFactory> fImagingFactory; |
| 42 | SkTScopedComPtr<IWICBitmapSource> fImageSource; |
| 43 | sk_sp<SkData> fData; |
| 44 | |
| 45 | typedef SkImageGenerator INHERITED; |
| 46 | }; |
| 47 | } // namespace |
| 48 | |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 49 | std::unique_ptr<SkImageGenerator> SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp<SkData> data) { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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. |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 62 | hr = SkIStream::CreateFromSkStream(new SkMemoryStream(data), true, &iStream); |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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. |
Matt Sarett | 1e86044d | 2016-12-16 09:02:18 -0500 | [diff] [blame] | 151 | SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 152 | return std::unique_ptr<SkImageGenerator>( |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 153 | new ImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 154 | std::move(data))); |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 155 | } |
| 156 | |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 157 | ImageGeneratorWIC::ImageGeneratorWIC(const SkImageInfo& info, |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 158 | IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp<SkData> data) |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 159 | : INHERITED(info) |
| 160 | , fImagingFactory(imagingFactory) |
| 161 | , fImageSource(imageSource) |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 162 | , fData(std::move(data)) |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 163 | {} |
| 164 | |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 165 | sk_sp<SkData> ImageGeneratorWIC::onRefEncodedData() { |
Ben Wagner | bdf5433 | 2018-05-15 14:12:14 -0400 | [diff] [blame] | 166 | return fData; |
| 167 | } |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 168 | |
Hal Canary | 912cd3d | 2018-09-19 15:54:36 -0400 | [diff] [blame] | 169 | bool ImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
Matt Sarett | ebb1b5c | 2017-05-12 11:41:27 -0400 | [diff] [blame] | 170 | const Options&) { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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 | } |