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. 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 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 135 SkData* SkImageGeneratorWIC::onRefEncodedData() { 136 return SkRef(fData.get()); 137 } 138 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