Index: src/ports/SkImageDecoder_WIC.cpp |
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp |
index ef6de00dc93335bbbb967711eb53cc0f02fb729d..c7222e635a993f97f5e07ee0bc140f64b1864f5b 100644 |
--- a/src/ports/SkImageDecoder_WIC.cpp |
+++ b/src/ports/SkImageDecoder_WIC.cpp |
@@ -31,6 +31,7 @@ |
#include <wincodec.h> |
#include "SkAutoCoInitialize.h" |
+#include "SkImageDecoder.h" |
#include "SkImageEncoder.h" |
#include "SkIStream.h" |
#include "SkMovie.h" |
@@ -47,6 +48,222 @@ |
#undef CLSID_WICImagingFactory |
#endif |
+class SkImageDecoder_WIC : public SkImageDecoder { |
+public: |
+ // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding |
+ // only the format. |
+ enum WICModes { |
+ kDecodeFormat_WICMode, |
+ kDecodeBounds_WICMode, |
+ kDecodePixels_WICMode, |
+ }; |
+ |
+ /** |
+ * Helper function to decode an SkStream. |
+ * @param stream SkStream to decode. Must be at the beginning. |
+ * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or |
+ * kDecodePixels_WICMode, in which case it must not be nullptr. |
+ * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if |
+ * wicMode is kDecodeFormat_WICMode. |
+ */ |
+ bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const; |
+ |
+protected: |
+ Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override; |
+}; |
+ |
+struct FormatConversion { |
+ GUID fGuidFormat; |
+ SkImageDecoder::Format fFormat; |
+}; |
+ |
+static const FormatConversion gFormatConversions[] = { |
+ { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format }, |
+ { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format }, |
+ { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format }, |
+ { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format }, |
+ { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format }, |
+}; |
+ |
+static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) { |
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) { |
+ if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) { |
+ return gFormatConversions[i].fFormat; |
+ } |
+ } |
+ return SkImageDecoder::kUnknown_Format; |
+} |
+ |
+SkImageDecoder::Result SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
+ WICModes wicMode; |
+ switch (mode) { |
+ case SkImageDecoder::kDecodeBounds_Mode: |
+ wicMode = kDecodeBounds_WICMode; |
+ break; |
+ case SkImageDecoder::kDecodePixels_Mode: |
+ wicMode = kDecodePixels_WICMode; |
+ break; |
+ } |
+ return this->decodeStream(stream, bm, wicMode, nullptr) ? kSuccess : kFailure; |
+} |
+ |
+bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, |
+ Format* format) const { |
+ //Initialize COM. |
+ SkAutoCoInitialize scopedCo; |
+ if (!scopedCo.succeeded()) { |
+ return false; |
+ } |
+ |
+ HRESULT hr = S_OK; |
+ |
+ //Create Windows Imaging Component ImagingFactory. |
+ SkTScopedComPtr<IWICImagingFactory> piImagingFactory; |
+ if (SUCCEEDED(hr)) { |
+ hr = CoCreateInstance( |
+ CLSID_WICImagingFactory |
+ , nullptr |
+ , CLSCTX_INPROC_SERVER |
+ , IID_PPV_ARGS(&piImagingFactory) |
+ ); |
+ } |
+ |
+ //Convert SkStream to IStream. |
+ SkTScopedComPtr<IStream> piStream; |
+ if (SUCCEEDED(hr)) { |
+ hr = SkIStream::CreateFromSkStream(stream, false, &piStream); |
+ } |
+ |
+ //Make sure we're at the beginning of the stream. |
+ if (SUCCEEDED(hr)) { |
+ LARGE_INTEGER liBeginning = { 0 }; |
+ hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, nullptr); |
+ } |
+ |
+ //Create the decoder from the stream content. |
+ SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; |
+ if (SUCCEEDED(hr)) { |
+ hr = piImagingFactory->CreateDecoderFromStream( |
+ piStream.get() //Image to be decoded |
+ , nullptr //No particular vendor |
+ , WICDecodeMetadataCacheOnDemand //Cache metadata when needed |
+ , &piBitmapDecoder //Pointer to the decoder |
+ ); |
+ } |
+ |
+ if (kDecodeFormat_WICMode == wicMode) { |
+ SkASSERT(format != nullptr); |
+ //Get the format |
+ if (SUCCEEDED(hr)) { |
+ GUID guidFormat; |
+ hr = piBitmapDecoder->GetContainerFormat(&guidFormat); |
+ if (SUCCEEDED(hr)) { |
+ *format = GuidContainerFormat_to_Format(guidFormat); |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ //Get the first frame from the decoder. |
+ SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; |
+ if (SUCCEEDED(hr)) { |
+ hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); |
+ } |
+ |
+ //Get the BitmapSource interface of the frame. |
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; |
+ if (SUCCEEDED(hr)) { |
+ hr = piBitmapFrameDecode->QueryInterface( |
+ IID_PPV_ARGS(&piBitmapSourceOriginal) |
+ ); |
+ } |
+ |
+ //Get the size of the bitmap. |
+ UINT width; |
+ UINT height; |
+ if (SUCCEEDED(hr)) { |
+ hr = piBitmapSourceOriginal->GetSize(&width, &height); |
+ } |
+ |
+ //Exit early if we're only looking for the bitmap bounds. |
+ if (SUCCEEDED(hr)) { |
+ bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); |
+ if (kDecodeBounds_WICMode == wicMode) { |
+ return true; |
+ } |
+ if (!this->allocPixelRef(bm, nullptr)) { |
+ return false; |
+ } |
+ } |
+ |
+ //Create a format converter. |
+ SkTScopedComPtr<IWICFormatConverter> piFormatConverter; |
+ if (SUCCEEDED(hr)) { |
+ hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); |
+ } |
+ |
+ GUID destinationPixelFormat; |
+ if (this->getRequireUnpremultipliedColors()) { |
+ destinationPixelFormat = GUID_WICPixelFormat32bppBGRA; |
+ } else { |
+ destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA; |
+ } |
+ |
+ if (SUCCEEDED(hr)) { |
+ hr = piFormatConverter->Initialize( |
+ piBitmapSourceOriginal.get() //Input bitmap to convert |
+ , destinationPixelFormat //Destination pixel format |
+ , WICBitmapDitherTypeNone //Specified dither patterm |
+ , nullptr //Specify a particular palette |
+ , 0.f //Alpha threshold |
+ , WICBitmapPaletteTypeCustom //Palette translation type |
+ ); |
+ } |
+ |
+ //Get the BitmapSource interface of the format converter. |
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; |
+ if (SUCCEEDED(hr)) { |
+ hr = piFormatConverter->QueryInterface( |
+ IID_PPV_ARGS(&piBitmapSourceConverted) |
+ ); |
+ } |
+ |
+ //Copy the pixels into the bitmap. |
+ if (SUCCEEDED(hr)) { |
+ SkAutoLockPixels alp(*bm); |
+ bm->eraseColor(SK_ColorTRANSPARENT); |
+ const UINT stride = (UINT) bm->rowBytes(); |
+ hr = piBitmapSourceConverted->CopyPixels( |
+ nullptr, //Get all the pixels |
+ stride, |
+ stride * height, |
+ reinterpret_cast<BYTE *>(bm->getPixels()) |
+ ); |
+ |
+ // Note: we don't need to premultiply here since we specified PBGRA |
+ if (SkBitmap::ComputeIsOpaque(*bm)) { |
+ bm->setAlphaType(kOpaque_SkAlphaType); |
+ } |
+ } |
+ |
+ return SUCCEEDED(hr); |
+} |
+ |
+///////////////////////////////////////////////////////////////////////// |
+ |
+extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*); |
+ |
+SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) { |
+ SkImageDecoder* decoder = image_decoder_from_stream(stream); |
+ if (nullptr == decoder) { |
+ // If no image decoder specific to the stream exists, use SkImageDecoder_WIC. |
+ return new SkImageDecoder_WIC; |
+ } else { |
+ return decoder; |
+ } |
+} |
+ |
///////////////////////////////////////////////////////////////////////// |
SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { |
@@ -58,10 +275,6 @@ |
class SkImageEncoder_WIC : public SkImageEncoder { |
public: |
SkImageEncoder_WIC(Type t) : fType(t) {} |
- |
- // DO NOT USE this constructor. This exists only so SkForceLinking can |
- // link the WIC image encoder. |
- SkImageEncoder_WIC() {} |
protected: |
virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); |
@@ -238,6 +451,15 @@ |
static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); |
-DEFINE_ENCODER_CREATOR(ImageEncoder_WIC); |
+static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) { |
+ SkImageDecoder::Format format; |
+ SkImageDecoder_WIC codec; |
+ if (!codec.decodeStream(stream, nullptr, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) { |
+ format = SkImageDecoder::kUnknown_Format; |
+ } |
+ return format; |
+} |
+ |
+static SkImageDecoder_FormatReg gFormatReg(get_format_wic); |
#endif // defined(SK_BUILD_FOR_WIN32) |