2016-03-17 20:50:17 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkStream.h"
|
|
|
|
#include "include/ports/SkImageGeneratorWIC.h"
|
|
|
|
#include "include/private/SkTemplates.h"
|
|
|
|
#include "src/utils/win/SkIStream.h"
|
|
|
|
#include "src/utils/win/SkTScopedComPtr.h"
|
2018-09-19 19:54:36 +00:00
|
|
|
|
|
|
|
#include <wincodec.h>
|
2016-03-17 20:50:17 +00:00
|
|
|
|
|
|
|
// All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
|
|
|
|
// In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
|
|
|
|
// but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
|
|
|
|
// Undo this #define if it has been done so that we link against the symbols
|
|
|
|
// we intended to link against on all SDKs.
|
|
|
|
#if defined(CLSID_WICImagingFactory)
|
|
|
|
#undef CLSID_WICImagingFactory
|
|
|
|
#endif
|
|
|
|
|
2018-09-19 19:54:36 +00:00
|
|
|
namespace {
|
|
|
|
class ImageGeneratorWIC : public SkImageGenerator {
|
|
|
|
public:
|
|
|
|
/*
|
|
|
|
* Takes ownership of the imagingFactory
|
|
|
|
* Takes ownership of the imageSource
|
|
|
|
*/
|
|
|
|
ImageGeneratorWIC(const SkImageInfo& info, IWICImagingFactory* imagingFactory,
|
|
|
|
IWICBitmapSource* imageSource, sk_sp<SkData>);
|
|
|
|
protected:
|
|
|
|
sk_sp<SkData> onRefEncodedData() override;
|
|
|
|
|
|
|
|
bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options&)
|
|
|
|
override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkTScopedComPtr<IWICImagingFactory> fImagingFactory;
|
|
|
|
SkTScopedComPtr<IWICBitmapSource> fImageSource;
|
|
|
|
sk_sp<SkData> fData;
|
|
|
|
|
|
|
|
typedef SkImageGenerator INHERITED;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2018-06-25 18:01:29 +00:00
|
|
|
std::unique_ptr<SkImageGenerator> SkImageGeneratorWIC::MakeFromEncodedWIC(sk_sp<SkData> data) {
|
2016-03-17 20:50:17 +00:00
|
|
|
// Create Windows Imaging Component ImagingFactory.
|
|
|
|
SkTScopedComPtr<IWICImagingFactory> imagingFactory;
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
|
|
|
|
IID_PPV_ARGS(&imagingFactory));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an IStream.
|
|
|
|
SkTScopedComPtr<IStream> iStream;
|
|
|
|
// Note that iStream will take ownership of the new memory stream because
|
|
|
|
// we set |deleteOnRelease| to true.
|
2019-12-11 15:45:01 +00:00
|
|
|
hr = SkIStream::CreateFromSkStream(std::make_unique<SkMemoryStream>(data), &iStream);
|
2016-03-17 20:50:17 +00:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the decoder from the stream.
|
|
|
|
SkTScopedComPtr<IWICBitmapDecoder> decoder;
|
|
|
|
hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr,
|
|
|
|
WICDecodeMetadataCacheOnDemand, &decoder);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select the first frame from the decoder.
|
|
|
|
SkTScopedComPtr<IWICBitmapFrameDecode> imageFrame;
|
|
|
|
hr = decoder->GetFrame(0, &imageFrame);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Treat the frame as an image source.
|
|
|
|
SkTScopedComPtr<IWICBitmapSource> imageSource;
|
|
|
|
hr = imageFrame->QueryInterface(IID_PPV_ARGS(&imageSource));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the size of the image.
|
|
|
|
UINT width;
|
|
|
|
UINT height;
|
|
|
|
hr = imageSource->GetSize(&width, &height);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the encoded pixel format.
|
|
|
|
WICPixelFormatGUID format;
|
|
|
|
hr = imageSource->GetPixelFormat(&format);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recommend kOpaque if the image is opaque and kPremul otherwise.
|
|
|
|
// FIXME: We are stuck recommending kPremul for all indexed formats
|
|
|
|
// (Ex: GUID_WICPixelFormat8bppIndexed) because we don't have
|
|
|
|
// a way to check if the image has alpha.
|
|
|
|
SkAlphaType alphaType = kPremul_SkAlphaType;
|
|
|
|
|
|
|
|
if (GUID_WICPixelFormat16bppBGR555 == format ||
|
|
|
|
GUID_WICPixelFormat16bppBGR565 == format ||
|
|
|
|
GUID_WICPixelFormat32bppBGR101010 == format ||
|
|
|
|
GUID_WICPixelFormatBlackWhite == format ||
|
|
|
|
GUID_WICPixelFormat2bppGray == format ||
|
|
|
|
GUID_WICPixelFormat4bppGray == format ||
|
|
|
|
GUID_WICPixelFormat8bppGray == format ||
|
|
|
|
GUID_WICPixelFormat16bppGray == format ||
|
|
|
|
GUID_WICPixelFormat16bppGrayFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat16bppGrayHalf == format ||
|
|
|
|
GUID_WICPixelFormat32bppGrayFloat == format ||
|
|
|
|
GUID_WICPixelFormat32bppGrayFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat32bppRGBE == format ||
|
|
|
|
GUID_WICPixelFormat24bppRGB == format ||
|
|
|
|
GUID_WICPixelFormat24bppBGR == format ||
|
|
|
|
GUID_WICPixelFormat32bppBGR == format ||
|
|
|
|
GUID_WICPixelFormat48bppRGB == format ||
|
|
|
|
GUID_WICPixelFormat48bppBGR == format ||
|
|
|
|
GUID_WICPixelFormat48bppRGBFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat48bppBGRFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat48bppRGBHalf == format ||
|
|
|
|
GUID_WICPixelFormat64bppRGBFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat64bppRGBHalf == format ||
|
|
|
|
GUID_WICPixelFormat96bppRGBFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat128bppRGBFloat == format ||
|
|
|
|
GUID_WICPixelFormat128bppRGBFixedPoint == format ||
|
|
|
|
GUID_WICPixelFormat32bppRGB == format ||
|
|
|
|
GUID_WICPixelFormat64bppRGB == format ||
|
|
|
|
GUID_WICPixelFormat96bppRGBFloat == format ||
|
|
|
|
GUID_WICPixelFormat32bppCMYK == format ||
|
|
|
|
GUID_WICPixelFormat64bppCMYK == format ||
|
|
|
|
GUID_WICPixelFormat8bppY == format ||
|
|
|
|
GUID_WICPixelFormat8bppCb == format ||
|
|
|
|
GUID_WICPixelFormat8bppCr == format ||
|
|
|
|
GUID_WICPixelFormat16bppCbCr == format)
|
|
|
|
{
|
|
|
|
alphaType = kOpaque_SkAlphaType;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: If we change the implementation to handle swizzling ourselves,
|
|
|
|
// we can support more output formats.
|
2016-12-16 14:02:18 +00:00
|
|
|
SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
|
2018-06-25 18:01:29 +00:00
|
|
|
return std::unique_ptr<SkImageGenerator>(
|
2018-09-19 19:54:36 +00:00
|
|
|
new ImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(),
|
2018-06-25 18:01:29 +00:00
|
|
|
std::move(data)));
|
2016-03-17 20:50:17 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 19:54:36 +00:00
|
|
|
ImageGeneratorWIC::ImageGeneratorWIC(const SkImageInfo& info,
|
2018-06-25 18:01:29 +00:00
|
|
|
IWICImagingFactory* imagingFactory, IWICBitmapSource* imageSource, sk_sp<SkData> data)
|
2016-03-17 20:50:17 +00:00
|
|
|
: INHERITED(info)
|
|
|
|
, fImagingFactory(imagingFactory)
|
|
|
|
, fImageSource(imageSource)
|
2018-06-25 18:01:29 +00:00
|
|
|
, fData(std::move(data))
|
2016-03-17 20:50:17 +00:00
|
|
|
{}
|
|
|
|
|
2018-09-19 19:54:36 +00:00
|
|
|
sk_sp<SkData> ImageGeneratorWIC::onRefEncodedData() {
|
2018-05-15 18:12:14 +00:00
|
|
|
return fData;
|
|
|
|
}
|
2016-03-17 20:50:17 +00:00
|
|
|
|
2018-09-19 19:54:36 +00:00
|
|
|
bool ImageGeneratorWIC::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
|
2017-05-12 15:41:27 +00:00
|
|
|
const Options&) {
|
2016-03-17 20:50:17 +00:00
|
|
|
if (kN32_SkColorType != info.colorType()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a format converter.
|
|
|
|
SkTScopedComPtr<IWICFormatConverter> formatConverter;
|
|
|
|
HRESULT hr = fImagingFactory->CreateFormatConverter(&formatConverter);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GUID format = GUID_WICPixelFormat32bppPBGRA;
|
|
|
|
if (kUnpremul_SkAlphaType == info.alphaType()) {
|
|
|
|
format = GUID_WICPixelFormat32bppBGRA;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = formatConverter->Initialize(fImageSource.get(), format, WICBitmapDitherTypeNone, nullptr,
|
|
|
|
0.0, WICBitmapPaletteTypeCustom);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Treat the format converter as an image source.
|
|
|
|
SkTScopedComPtr<IWICBitmapSource> formatConverterSrc;
|
|
|
|
hr = formatConverter->QueryInterface(IID_PPV_ARGS(&formatConverterSrc));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the destination pixels.
|
|
|
|
hr = formatConverterSrc->CopyPixels(nullptr, (UINT) rowBytes, (UINT) rowBytes * info.height(),
|
|
|
|
(BYTE*) pixels);
|
|
|
|
|
|
|
|
return SUCCEEDED(hr);
|
|
|
|
}
|