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 | |
| 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. |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 34 | hr = SkIStream::CreateFromSkStream(new SkMemoryStream(sk_ref_sp(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); |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 124 | return new SkImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), data); |
| 125 | } |
| 126 | |
| 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 | |
Brian Osman | 2feb796 | 2017-04-25 16:41:47 -0400 | [diff] [blame] | 135 | SkData* SkImageGeneratorWIC::onRefEncodedData() { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 136 | return SkRef(fData.get()); |
| 137 | } |
| 138 | |
| 139 | bool SkImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
Matt Sarett | ebb1b5c | 2017-05-12 11:41:27 -0400 | [diff] [blame] | 140 | const Options&) { |
msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 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 | } |