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" |
| 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 | |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 21 | std::unique_ptr<SkImageGenerator> SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp<SkData> data) { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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. |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 34 | hr = SkIStream::CreateFromSkStream(new SkMemoryStream(data), true, &iStream); |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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. |
Matt Sarett | 1e86044d | 2016-12-16 09:02:18 -0500 | [diff] [blame] | 123 | SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType); |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 124 | return std::unique_ptr<SkImageGenerator>( |
| 125 | new SkImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), |
| 126 | std::move(data))); |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | SkImageGeneratorWIC::SkImageGeneratorWIC(const SkImageInfo& info, |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 130 | IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp<SkData> data) |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 131 | : INHERITED(info) |
| 132 | , fImagingFactory(imagingFactory) |
| 133 | , fImageSource(imageSource) |
Leon Scroggins III | a57488a | 2018-06-25 14:01:29 -0400 | [diff] [blame] | 134 | , fData(std::move(data)) |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 135 | {} |
| 136 | |
Ben Wagner | bdf5433 | 2018-05-15 14:12:14 -0400 | [diff] [blame] | 137 | sk_sp<SkData> SkImageGeneratorWIC::onRefEncodedData() { |
| 138 | return fData; |
| 139 | } |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 140 | |
| 141 | bool SkImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
Matt Sarett | ebb1b5c | 2017-05-12 11:41:27 -0400 | [diff] [blame] | 142 | const Options&) { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 143 | if (kN32_SkColorType != info.colorType()) { |
| 144 | return false; |
| 145 | } |
| 146 | |
| 147 | // Create a format converter. |
| 148 | SkTScopedComPtr<IWICFormatConverter> formatConverter; |
| 149 | HRESULT hr = fImagingFactory->CreateFormatConverter(&formatConverter); |
| 150 | if (FAILED(hr)) { |
| 151 | return false; |
| 152 | } |
| 153 | |
| 154 | GUID format = GUID_WICPixelFormat32bppPBGRA; |
| 155 | if (kUnpremul_SkAlphaType == info.alphaType()) { |
| 156 | format = GUID_WICPixelFormat32bppBGRA; |
| 157 | } |
| 158 | |
| 159 | hr = formatConverter->Initialize(fImageSource.get(), format, WICBitmapDitherTypeNone, nullptr, |
| 160 | 0.0, WICBitmapPaletteTypeCustom); |
| 161 | if (FAILED(hr)) { |
| 162 | return false; |
| 163 | } |
| 164 | |
| 165 | // Treat the format converter as an image source. |
| 166 | SkTScopedComPtr<IWICBitmapSource> formatConverterSrc; |
| 167 | hr = formatConverter->QueryInterface(IID_PPV_ARGS(&formatConverterSrc)); |
| 168 | if (FAILED(hr)) { |
| 169 | return false; |
| 170 | } |
| 171 | |
| 172 | // Set the destination pixels. |
| 173 | hr = formatConverterSrc->CopyPixels(nullptr, (UINT) rowBytes, (UINT) rowBytes * info.height(), |
| 174 | (BYTE*) pixels); |
| 175 | |
| 176 | return SUCCEEDED(hr); |
| 177 | } |