1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkImageDecoder_WIC.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,464 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkTypes.h" 1.13 + 1.14 +// Workaround for: 1.15 +// http://connect.microsoft.com/VisualStudio/feedback/details/621653/ 1.16 +// http://crbug.com/225822 1.17 +// In VS2010 both intsafe.h and stdint.h define the following without guards. 1.18 +// SkTypes brought in windows.h and stdint.h and the following defines are 1.19 +// not used by this file. However, they may be re-introduced by wincodec.h. 1.20 +#undef INT8_MIN 1.21 +#undef INT16_MIN 1.22 +#undef INT32_MIN 1.23 +#undef INT64_MIN 1.24 +#undef INT8_MAX 1.25 +#undef UINT8_MAX 1.26 +#undef INT16_MAX 1.27 +#undef UINT16_MAX 1.28 +#undef INT32_MAX 1.29 +#undef UINT32_MAX 1.30 +#undef INT64_MAX 1.31 +#undef UINT64_MAX 1.32 + 1.33 +#include <wincodec.h> 1.34 +#include "SkAutoCoInitialize.h" 1.35 +#include "SkImageDecoder.h" 1.36 +#include "SkImageEncoder.h" 1.37 +#include "SkIStream.h" 1.38 +#include "SkMovie.h" 1.39 +#include "SkStream.h" 1.40 +#include "SkTScopedComPtr.h" 1.41 +#include "SkUnPreMultiply.h" 1.42 + 1.43 +//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. 1.44 +//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported 1.45 +//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2. 1.46 +//Undo this #define if it has been done so that we link against the symbols 1.47 +//we intended to link against on all SDKs. 1.48 +#if defined(CLSID_WICImagingFactory) 1.49 +#undef CLSID_WICImagingFactory 1.50 +#endif 1.51 + 1.52 +class SkImageDecoder_WIC : public SkImageDecoder { 1.53 +public: 1.54 + // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding 1.55 + // only the format. 1.56 + enum WICModes { 1.57 + kDecodeFormat_WICMode, 1.58 + kDecodeBounds_WICMode, 1.59 + kDecodePixels_WICMode, 1.60 + }; 1.61 + 1.62 + /** 1.63 + * Helper function to decode an SkStream. 1.64 + * @param stream SkStream to decode. Must be at the beginning. 1.65 + * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or 1.66 + * kDecodePixels_WICMode, in which case it must not be NULL. 1.67 + * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if 1.68 + * wicMode is kDecodeFormat_WICMode. 1.69 + */ 1.70 + bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const; 1.71 + 1.72 +protected: 1.73 + virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE; 1.74 +}; 1.75 + 1.76 +struct FormatConversion { 1.77 + GUID fGuidFormat; 1.78 + SkImageDecoder::Format fFormat; 1.79 +}; 1.80 + 1.81 +static const FormatConversion gFormatConversions[] = { 1.82 + { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format }, 1.83 + { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format }, 1.84 + { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format }, 1.85 + { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format }, 1.86 + { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format }, 1.87 +}; 1.88 + 1.89 +static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) { 1.90 + for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) { 1.91 + if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) { 1.92 + return gFormatConversions[i].fFormat; 1.93 + } 1.94 + } 1.95 + return SkImageDecoder::kUnknown_Format; 1.96 +} 1.97 + 1.98 +bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 1.99 + WICModes wicMode; 1.100 + switch (mode) { 1.101 + case SkImageDecoder::kDecodeBounds_Mode: 1.102 + wicMode = kDecodeBounds_WICMode; 1.103 + break; 1.104 + case SkImageDecoder::kDecodePixels_Mode: 1.105 + wicMode = kDecodePixels_WICMode; 1.106 + break; 1.107 + } 1.108 + return this->decodeStream(stream, bm, wicMode, NULL); 1.109 +} 1.110 + 1.111 +bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, 1.112 + Format* format) const { 1.113 + //Initialize COM. 1.114 + SkAutoCoInitialize scopedCo; 1.115 + if (!scopedCo.succeeded()) { 1.116 + return false; 1.117 + } 1.118 + 1.119 + HRESULT hr = S_OK; 1.120 + 1.121 + //Create Windows Imaging Component ImagingFactory. 1.122 + SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 1.123 + if (SUCCEEDED(hr)) { 1.124 + hr = CoCreateInstance( 1.125 + CLSID_WICImagingFactory 1.126 + , NULL 1.127 + , CLSCTX_INPROC_SERVER 1.128 + , IID_PPV_ARGS(&piImagingFactory) 1.129 + ); 1.130 + } 1.131 + 1.132 + //Convert SkStream to IStream. 1.133 + SkTScopedComPtr<IStream> piStream; 1.134 + if (SUCCEEDED(hr)) { 1.135 + hr = SkIStream::CreateFromSkStream(stream, false, &piStream); 1.136 + } 1.137 + 1.138 + //Make sure we're at the beginning of the stream. 1.139 + if (SUCCEEDED(hr)) { 1.140 + LARGE_INTEGER liBeginning = { 0 }; 1.141 + hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); 1.142 + } 1.143 + 1.144 + //Create the decoder from the stream content. 1.145 + SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; 1.146 + if (SUCCEEDED(hr)) { 1.147 + hr = piImagingFactory->CreateDecoderFromStream( 1.148 + piStream.get() //Image to be decoded 1.149 + , NULL //No particular vendor 1.150 + , WICDecodeMetadataCacheOnDemand //Cache metadata when needed 1.151 + , &piBitmapDecoder //Pointer to the decoder 1.152 + ); 1.153 + } 1.154 + 1.155 + if (kDecodeFormat_WICMode == wicMode) { 1.156 + SkASSERT(format != NULL); 1.157 + //Get the format 1.158 + if (SUCCEEDED(hr)) { 1.159 + GUID guidFormat; 1.160 + hr = piBitmapDecoder->GetContainerFormat(&guidFormat); 1.161 + if (SUCCEEDED(hr)) { 1.162 + *format = GuidContainerFormat_to_Format(guidFormat); 1.163 + return true; 1.164 + } 1.165 + } 1.166 + return false; 1.167 + } 1.168 + 1.169 + //Get the first frame from the decoder. 1.170 + SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; 1.171 + if (SUCCEEDED(hr)) { 1.172 + hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); 1.173 + } 1.174 + 1.175 + //Get the BitmapSource interface of the frame. 1.176 + SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; 1.177 + if (SUCCEEDED(hr)) { 1.178 + hr = piBitmapFrameDecode->QueryInterface( 1.179 + IID_PPV_ARGS(&piBitmapSourceOriginal) 1.180 + ); 1.181 + } 1.182 + 1.183 + //Get the size of the bitmap. 1.184 + UINT width; 1.185 + UINT height; 1.186 + if (SUCCEEDED(hr)) { 1.187 + hr = piBitmapSourceOriginal->GetSize(&width, &height); 1.188 + } 1.189 + 1.190 + //Exit early if we're only looking for the bitmap bounds. 1.191 + if (SUCCEEDED(hr)) { 1.192 + bm->setConfig(SkImageInfo::MakeN32Premul(width, height)); 1.193 + if (kDecodeBounds_WICMode == wicMode) { 1.194 + return true; 1.195 + } 1.196 + if (!this->allocPixelRef(bm, NULL)) { 1.197 + return false; 1.198 + } 1.199 + } 1.200 + 1.201 + //Create a format converter. 1.202 + SkTScopedComPtr<IWICFormatConverter> piFormatConverter; 1.203 + if (SUCCEEDED(hr)) { 1.204 + hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); 1.205 + } 1.206 + 1.207 + GUID destinationPixelFormat; 1.208 + if (this->getRequireUnpremultipliedColors()) { 1.209 + destinationPixelFormat = GUID_WICPixelFormat32bppBGRA; 1.210 + } else { 1.211 + destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA; 1.212 + } 1.213 + 1.214 + if (SUCCEEDED(hr)) { 1.215 + hr = piFormatConverter->Initialize( 1.216 + piBitmapSourceOriginal.get() //Input bitmap to convert 1.217 + , destinationPixelFormat //Destination pixel format 1.218 + , WICBitmapDitherTypeNone //Specified dither patterm 1.219 + , NULL //Specify a particular palette 1.220 + , 0.f //Alpha threshold 1.221 + , WICBitmapPaletteTypeCustom //Palette translation type 1.222 + ); 1.223 + } 1.224 + 1.225 + //Get the BitmapSource interface of the format converter. 1.226 + SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; 1.227 + if (SUCCEEDED(hr)) { 1.228 + hr = piFormatConverter->QueryInterface( 1.229 + IID_PPV_ARGS(&piBitmapSourceConverted) 1.230 + ); 1.231 + } 1.232 + 1.233 + //Copy the pixels into the bitmap. 1.234 + if (SUCCEEDED(hr)) { 1.235 + SkAutoLockPixels alp(*bm); 1.236 + bm->eraseColor(SK_ColorTRANSPARENT); 1.237 + const UINT stride = (UINT) bm->rowBytes(); 1.238 + hr = piBitmapSourceConverted->CopyPixels( 1.239 + NULL, //Get all the pixels 1.240 + stride, 1.241 + stride * height, 1.242 + reinterpret_cast<BYTE *>(bm->getPixels()) 1.243 + ); 1.244 + 1.245 + // Note: we don't need to premultiply here since we specified PBGRA 1.246 + if (SkBitmap::ComputeIsOpaque(*bm)) { 1.247 + bm->setAlphaType(kOpaque_SkAlphaType); 1.248 + } 1.249 + } 1.250 + 1.251 + return SUCCEEDED(hr); 1.252 +} 1.253 + 1.254 +///////////////////////////////////////////////////////////////////////// 1.255 + 1.256 +extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*); 1.257 + 1.258 +SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) { 1.259 + SkImageDecoder* decoder = image_decoder_from_stream(stream); 1.260 + if (NULL == decoder) { 1.261 + // If no image decoder specific to the stream exists, use SkImageDecoder_WIC. 1.262 + return SkNEW(SkImageDecoder_WIC); 1.263 + } else { 1.264 + return decoder; 1.265 + } 1.266 +} 1.267 + 1.268 +///////////////////////////////////////////////////////////////////////// 1.269 + 1.270 +SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { 1.271 + return NULL; 1.272 +} 1.273 + 1.274 +///////////////////////////////////////////////////////////////////////// 1.275 + 1.276 +class SkImageEncoder_WIC : public SkImageEncoder { 1.277 +public: 1.278 + SkImageEncoder_WIC(Type t) : fType(t) {} 1.279 + 1.280 +protected: 1.281 + virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 1.282 + 1.283 +private: 1.284 + Type fType; 1.285 +}; 1.286 + 1.287 +bool SkImageEncoder_WIC::onEncode(SkWStream* stream 1.288 + , const SkBitmap& bitmapOrig 1.289 + , int quality) 1.290 +{ 1.291 + GUID type; 1.292 + switch (fType) { 1.293 + case kBMP_Type: 1.294 + type = GUID_ContainerFormatBmp; 1.295 + break; 1.296 + case kICO_Type: 1.297 + type = GUID_ContainerFormatIco; 1.298 + break; 1.299 + case kJPEG_Type: 1.300 + type = GUID_ContainerFormatJpeg; 1.301 + break; 1.302 + case kPNG_Type: 1.303 + type = GUID_ContainerFormatPng; 1.304 + break; 1.305 + default: 1.306 + return false; 1.307 + } 1.308 + 1.309 + //Convert to 8888 if needed. 1.310 + const SkBitmap* bitmap; 1.311 + SkBitmap bitmapCopy; 1.312 + if (kPMColor_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) { 1.313 + bitmap = &bitmapOrig; 1.314 + } else { 1.315 + if (!bitmapOrig.copyTo(&bitmapCopy, kPMColor_SkColorType)) { 1.316 + return false; 1.317 + } 1.318 + bitmap = &bitmapCopy; 1.319 + } 1.320 + 1.321 + // We cannot use PBGRA so we need to unpremultiply ourselves 1.322 + if (!bitmap->isOpaque()) { 1.323 + SkAutoLockPixels alp(*bitmap); 1.324 + 1.325 + uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels()); 1.326 + for (int y = 0; y < bitmap->height(); ++y) { 1.327 + for (int x = 0; x < bitmap->width(); ++x) { 1.328 + uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel(); 1.329 + 1.330 + SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes); 1.331 + SkColor* dst = reinterpret_cast<SkColor*>(bytes); 1.332 + 1.333 + *dst = SkUnPreMultiply::PMColorToColor(*src); 1.334 + } 1.335 + } 1.336 + } 1.337 + 1.338 + //Initialize COM. 1.339 + SkAutoCoInitialize scopedCo; 1.340 + if (!scopedCo.succeeded()) { 1.341 + return false; 1.342 + } 1.343 + 1.344 + HRESULT hr = S_OK; 1.345 + 1.346 + //Create Windows Imaging Component ImagingFactory. 1.347 + SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 1.348 + if (SUCCEEDED(hr)) { 1.349 + hr = CoCreateInstance( 1.350 + CLSID_WICImagingFactory 1.351 + , NULL 1.352 + , CLSCTX_INPROC_SERVER 1.353 + , IID_PPV_ARGS(&piImagingFactory) 1.354 + ); 1.355 + } 1.356 + 1.357 + //Convert the SkWStream to an IStream. 1.358 + SkTScopedComPtr<IStream> piStream; 1.359 + if (SUCCEEDED(hr)) { 1.360 + hr = SkWIStream::CreateFromSkWStream(stream, &piStream); 1.361 + } 1.362 + 1.363 + //Create an encode of the appropriate type. 1.364 + SkTScopedComPtr<IWICBitmapEncoder> piEncoder; 1.365 + if (SUCCEEDED(hr)) { 1.366 + hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder); 1.367 + } 1.368 + 1.369 + if (SUCCEEDED(hr)) { 1.370 + hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); 1.371 + } 1.372 + 1.373 + //Create a the frame. 1.374 + SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; 1.375 + SkTScopedComPtr<IPropertyBag2> piPropertybag; 1.376 + if (SUCCEEDED(hr)) { 1.377 + hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); 1.378 + } 1.379 + 1.380 + if (SUCCEEDED(hr)) { 1.381 + PROPBAG2 name = { 0 }; 1.382 + name.dwType = PROPBAG2_TYPE_DATA; 1.383 + name.vt = VT_R4; 1.384 + name.pstrName = L"ImageQuality"; 1.385 + 1.386 + VARIANT value; 1.387 + VariantInit(&value); 1.388 + value.vt = VT_R4; 1.389 + value.fltVal = (FLOAT)(quality / 100.0); 1.390 + 1.391 + //Ignore result code. 1.392 + // This returns E_FAIL if the named property is not in the bag. 1.393 + //TODO(bungeman) enumerate the properties, 1.394 + // write and set hr iff property exists. 1.395 + piPropertybag->Write(1, &name, &value); 1.396 + } 1.397 + if (SUCCEEDED(hr)) { 1.398 + hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); 1.399 + } 1.400 + 1.401 + //Set the size of the frame. 1.402 + const UINT width = bitmap->width(); 1.403 + const UINT height = bitmap->height(); 1.404 + if (SUCCEEDED(hr)) { 1.405 + hr = piBitmapFrameEncode->SetSize(width, height); 1.406 + } 1.407 + 1.408 + //Set the pixel format of the frame. 1.409 + const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; 1.410 + WICPixelFormatGUID formatGUID = formatDesired; 1.411 + if (SUCCEEDED(hr)) { 1.412 + hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); 1.413 + } 1.414 + if (SUCCEEDED(hr)) { 1.415 + //Be sure the image format is the one requested. 1.416 + hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; 1.417 + } 1.418 + 1.419 + //Write the pixels into the frame. 1.420 + if (SUCCEEDED(hr)) { 1.421 + SkAutoLockPixels alp(*bitmap); 1.422 + const UINT stride = (UINT) bitmap->rowBytes(); 1.423 + hr = piBitmapFrameEncode->WritePixels( 1.424 + height 1.425 + , stride 1.426 + , stride * height 1.427 + , reinterpret_cast<BYTE*>(bitmap->getPixels())); 1.428 + } 1.429 + 1.430 + if (SUCCEEDED(hr)) { 1.431 + hr = piBitmapFrameEncode->Commit(); 1.432 + } 1.433 + 1.434 + if (SUCCEEDED(hr)) { 1.435 + hr = piEncoder->Commit(); 1.436 + } 1.437 + 1.438 + return SUCCEEDED(hr); 1.439 +} 1.440 + 1.441 +/////////////////////////////////////////////////////////////////////////////// 1.442 + 1.443 +static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) { 1.444 + switch (t) { 1.445 + case SkImageEncoder::kBMP_Type: 1.446 + case SkImageEncoder::kICO_Type: 1.447 + case SkImageEncoder::kJPEG_Type: 1.448 + case SkImageEncoder::kPNG_Type: 1.449 + break; 1.450 + default: 1.451 + return NULL; 1.452 + } 1.453 + return SkNEW_ARGS(SkImageEncoder_WIC, (t)); 1.454 +} 1.455 + 1.456 +static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); 1.457 + 1.458 +static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) { 1.459 + SkImageDecoder::Format format; 1.460 + SkImageDecoder_WIC codec; 1.461 + if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) { 1.462 + format = SkImageDecoder::kUnknown_Format; 1.463 + } 1.464 + return format; 1.465 +} 1.466 + 1.467 +static SkImageDecoder_FormatReg gFormatReg(get_format_wic);