SkImageDecoder_WIC.cpp revision 385fe4d4b62d7d1dd76116dd570df3290a2f487b
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkTypes.h" 10 11// Workaround for: 12// http://connect.microsoft.com/VisualStudio/feedback/details/621653/ 13// http://crbug.com/225822 14// In VS2010 both intsafe.h and stdint.h define the following without guards. 15// SkTypes brought in windows.h and stdint.h and the following defines are 16// not used by this file. However, they may be re-introduced by wincodec.h. 17#undef INT8_MIN 18#undef INT16_MIN 19#undef INT32_MIN 20#undef INT64_MIN 21#undef INT8_MAX 22#undef UINT8_MAX 23#undef INT16_MAX 24#undef UINT16_MAX 25#undef INT32_MAX 26#undef UINT32_MAX 27#undef INT64_MAX 28#undef UINT64_MAX 29 30#include <wincodec.h> 31#include "SkAutoCoInitialize.h" 32#include "SkImageDecoder.h" 33#include "SkImageEncoder.h" 34#include "SkIStream.h" 35#include "SkMovie.h" 36#include "SkStream.h" 37#include "SkTScopedComPtr.h" 38#include "SkUnPreMultiply.h" 39 40//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. 41//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported 42//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2. 43//Undo this #define if it has been done so that we link against the symbols 44//we intended to link against on all SDKs. 45#if defined(CLSID_WICImagingFactory) 46#undef CLSID_WICImagingFactory 47#endif 48 49class SkImageDecoder_WIC : public SkImageDecoder { 50public: 51 // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding 52 // only the format. 53 enum WICModes { 54 kDecodeFormat_WICMode, 55 kDecodeBounds_WICMode, 56 kDecodePixels_WICMode, 57 }; 58 59 /** 60 * Helper function to decode an SkStream. 61 * @param stream SkStream to decode. Must be at the beginning. 62 * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or 63 * kDecodePixels_WICMode, in which case it must not be NULL. 64 * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if 65 * wicMode is kDecodeFormat_WICMode. 66 */ 67 bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const; 68 69protected: 70 Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override; 71}; 72 73struct FormatConversion { 74 GUID fGuidFormat; 75 SkImageDecoder::Format fFormat; 76}; 77 78static const FormatConversion gFormatConversions[] = { 79 { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format }, 80 { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format }, 81 { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format }, 82 { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format }, 83 { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format }, 84}; 85 86static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) { 87 for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) { 88 if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) { 89 return gFormatConversions[i].fFormat; 90 } 91 } 92 return SkImageDecoder::kUnknown_Format; 93} 94 95SkImageDecoder::Result SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 96 WICModes wicMode; 97 switch (mode) { 98 case SkImageDecoder::kDecodeBounds_Mode: 99 wicMode = kDecodeBounds_WICMode; 100 break; 101 case SkImageDecoder::kDecodePixels_Mode: 102 wicMode = kDecodePixels_WICMode; 103 break; 104 } 105 return this->decodeStream(stream, bm, wicMode, NULL) ? kSuccess : kFailure; 106} 107 108bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, 109 Format* format) const { 110 //Initialize COM. 111 SkAutoCoInitialize scopedCo; 112 if (!scopedCo.succeeded()) { 113 return false; 114 } 115 116 HRESULT hr = S_OK; 117 118 //Create Windows Imaging Component ImagingFactory. 119 SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 120 if (SUCCEEDED(hr)) { 121 hr = CoCreateInstance( 122 CLSID_WICImagingFactory 123 , NULL 124 , CLSCTX_INPROC_SERVER 125 , IID_PPV_ARGS(&piImagingFactory) 126 ); 127 } 128 129 //Convert SkStream to IStream. 130 SkTScopedComPtr<IStream> piStream; 131 if (SUCCEEDED(hr)) { 132 hr = SkIStream::CreateFromSkStream(stream, false, &piStream); 133 } 134 135 //Make sure we're at the beginning of the stream. 136 if (SUCCEEDED(hr)) { 137 LARGE_INTEGER liBeginning = { 0 }; 138 hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); 139 } 140 141 //Create the decoder from the stream content. 142 SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; 143 if (SUCCEEDED(hr)) { 144 hr = piImagingFactory->CreateDecoderFromStream( 145 piStream.get() //Image to be decoded 146 , NULL //No particular vendor 147 , WICDecodeMetadataCacheOnDemand //Cache metadata when needed 148 , &piBitmapDecoder //Pointer to the decoder 149 ); 150 } 151 152 if (kDecodeFormat_WICMode == wicMode) { 153 SkASSERT(format != NULL); 154 //Get the format 155 if (SUCCEEDED(hr)) { 156 GUID guidFormat; 157 hr = piBitmapDecoder->GetContainerFormat(&guidFormat); 158 if (SUCCEEDED(hr)) { 159 *format = GuidContainerFormat_to_Format(guidFormat); 160 return true; 161 } 162 } 163 return false; 164 } 165 166 //Get the first frame from the decoder. 167 SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; 168 if (SUCCEEDED(hr)) { 169 hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); 170 } 171 172 //Get the BitmapSource interface of the frame. 173 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; 174 if (SUCCEEDED(hr)) { 175 hr = piBitmapFrameDecode->QueryInterface( 176 IID_PPV_ARGS(&piBitmapSourceOriginal) 177 ); 178 } 179 180 //Get the size of the bitmap. 181 UINT width; 182 UINT height; 183 if (SUCCEEDED(hr)) { 184 hr = piBitmapSourceOriginal->GetSize(&width, &height); 185 } 186 187 //Exit early if we're only looking for the bitmap bounds. 188 if (SUCCEEDED(hr)) { 189 bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); 190 if (kDecodeBounds_WICMode == wicMode) { 191 return true; 192 } 193 if (!this->allocPixelRef(bm, NULL)) { 194 return false; 195 } 196 } 197 198 //Create a format converter. 199 SkTScopedComPtr<IWICFormatConverter> piFormatConverter; 200 if (SUCCEEDED(hr)) { 201 hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); 202 } 203 204 GUID destinationPixelFormat; 205 if (this->getRequireUnpremultipliedColors()) { 206 destinationPixelFormat = GUID_WICPixelFormat32bppBGRA; 207 } else { 208 destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA; 209 } 210 211 if (SUCCEEDED(hr)) { 212 hr = piFormatConverter->Initialize( 213 piBitmapSourceOriginal.get() //Input bitmap to convert 214 , destinationPixelFormat //Destination pixel format 215 , WICBitmapDitherTypeNone //Specified dither patterm 216 , NULL //Specify a particular palette 217 , 0.f //Alpha threshold 218 , WICBitmapPaletteTypeCustom //Palette translation type 219 ); 220 } 221 222 //Get the BitmapSource interface of the format converter. 223 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; 224 if (SUCCEEDED(hr)) { 225 hr = piFormatConverter->QueryInterface( 226 IID_PPV_ARGS(&piBitmapSourceConverted) 227 ); 228 } 229 230 //Copy the pixels into the bitmap. 231 if (SUCCEEDED(hr)) { 232 SkAutoLockPixels alp(*bm); 233 bm->eraseColor(SK_ColorTRANSPARENT); 234 const UINT stride = (UINT) bm->rowBytes(); 235 hr = piBitmapSourceConverted->CopyPixels( 236 NULL, //Get all the pixels 237 stride, 238 stride * height, 239 reinterpret_cast<BYTE *>(bm->getPixels()) 240 ); 241 242 // Note: we don't need to premultiply here since we specified PBGRA 243 if (SkBitmap::ComputeIsOpaque(*bm)) { 244 bm->setAlphaType(kOpaque_SkAlphaType); 245 } 246 } 247 248 return SUCCEEDED(hr); 249} 250 251///////////////////////////////////////////////////////////////////////// 252 253extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*); 254 255SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) { 256 SkImageDecoder* decoder = image_decoder_from_stream(stream); 257 if (NULL == decoder) { 258 // If no image decoder specific to the stream exists, use SkImageDecoder_WIC. 259 return new SkImageDecoder_WIC; 260 } else { 261 return decoder; 262 } 263} 264 265///////////////////////////////////////////////////////////////////////// 266 267SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { 268 return NULL; 269} 270 271///////////////////////////////////////////////////////////////////////// 272 273class SkImageEncoder_WIC : public SkImageEncoder { 274public: 275 SkImageEncoder_WIC(Type t) : fType(t) {} 276 277protected: 278 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 279 280private: 281 Type fType; 282}; 283 284bool SkImageEncoder_WIC::onEncode(SkWStream* stream 285 , const SkBitmap& bitmapOrig 286 , int quality) 287{ 288 GUID type; 289 switch (fType) { 290 case kBMP_Type: 291 type = GUID_ContainerFormatBmp; 292 break; 293 case kICO_Type: 294 type = GUID_ContainerFormatIco; 295 break; 296 case kJPEG_Type: 297 type = GUID_ContainerFormatJpeg; 298 break; 299 case kPNG_Type: 300 type = GUID_ContainerFormatPng; 301 break; 302 default: 303 return false; 304 } 305 306 //Convert to 8888 if needed. 307 const SkBitmap* bitmap; 308 SkBitmap bitmapCopy; 309 if (kN32_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) { 310 bitmap = &bitmapOrig; 311 } else { 312 if (!bitmapOrig.copyTo(&bitmapCopy, kN32_SkColorType)) { 313 return false; 314 } 315 bitmap = &bitmapCopy; 316 } 317 318 // We cannot use PBGRA so we need to unpremultiply ourselves 319 if (!bitmap->isOpaque()) { 320 SkAutoLockPixels alp(*bitmap); 321 322 uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels()); 323 for (int y = 0; y < bitmap->height(); ++y) { 324 for (int x = 0; x < bitmap->width(); ++x) { 325 uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel(); 326 327 SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes); 328 SkColor* dst = reinterpret_cast<SkColor*>(bytes); 329 330 *dst = SkUnPreMultiply::PMColorToColor(*src); 331 } 332 } 333 } 334 335 //Initialize COM. 336 SkAutoCoInitialize scopedCo; 337 if (!scopedCo.succeeded()) { 338 return false; 339 } 340 341 HRESULT hr = S_OK; 342 343 //Create Windows Imaging Component ImagingFactory. 344 SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 345 if (SUCCEEDED(hr)) { 346 hr = CoCreateInstance( 347 CLSID_WICImagingFactory 348 , NULL 349 , CLSCTX_INPROC_SERVER 350 , IID_PPV_ARGS(&piImagingFactory) 351 ); 352 } 353 354 //Convert the SkWStream to an IStream. 355 SkTScopedComPtr<IStream> piStream; 356 if (SUCCEEDED(hr)) { 357 hr = SkWIStream::CreateFromSkWStream(stream, &piStream); 358 } 359 360 //Create an encode of the appropriate type. 361 SkTScopedComPtr<IWICBitmapEncoder> piEncoder; 362 if (SUCCEEDED(hr)) { 363 hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder); 364 } 365 366 if (SUCCEEDED(hr)) { 367 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); 368 } 369 370 //Create a the frame. 371 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; 372 SkTScopedComPtr<IPropertyBag2> piPropertybag; 373 if (SUCCEEDED(hr)) { 374 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); 375 } 376 377 if (SUCCEEDED(hr)) { 378 PROPBAG2 name = { 0 }; 379 name.dwType = PROPBAG2_TYPE_DATA; 380 name.vt = VT_R4; 381 name.pstrName = L"ImageQuality"; 382 383 VARIANT value; 384 VariantInit(&value); 385 value.vt = VT_R4; 386 value.fltVal = (FLOAT)(quality / 100.0); 387 388 //Ignore result code. 389 // This returns E_FAIL if the named property is not in the bag. 390 //TODO(bungeman) enumerate the properties, 391 // write and set hr iff property exists. 392 piPropertybag->Write(1, &name, &value); 393 } 394 if (SUCCEEDED(hr)) { 395 hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); 396 } 397 398 //Set the size of the frame. 399 const UINT width = bitmap->width(); 400 const UINT height = bitmap->height(); 401 if (SUCCEEDED(hr)) { 402 hr = piBitmapFrameEncode->SetSize(width, height); 403 } 404 405 //Set the pixel format of the frame. 406 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; 407 WICPixelFormatGUID formatGUID = formatDesired; 408 if (SUCCEEDED(hr)) { 409 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); 410 } 411 if (SUCCEEDED(hr)) { 412 //Be sure the image format is the one requested. 413 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; 414 } 415 416 //Write the pixels into the frame. 417 if (SUCCEEDED(hr)) { 418 SkAutoLockPixels alp(*bitmap); 419 const UINT stride = (UINT) bitmap->rowBytes(); 420 hr = piBitmapFrameEncode->WritePixels( 421 height 422 , stride 423 , stride * height 424 , reinterpret_cast<BYTE*>(bitmap->getPixels())); 425 } 426 427 if (SUCCEEDED(hr)) { 428 hr = piBitmapFrameEncode->Commit(); 429 } 430 431 if (SUCCEEDED(hr)) { 432 hr = piEncoder->Commit(); 433 } 434 435 return SUCCEEDED(hr); 436} 437 438/////////////////////////////////////////////////////////////////////////////// 439 440static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) { 441 switch (t) { 442 case SkImageEncoder::kBMP_Type: 443 case SkImageEncoder::kICO_Type: 444 case SkImageEncoder::kJPEG_Type: 445 case SkImageEncoder::kPNG_Type: 446 break; 447 default: 448 return NULL; 449 } 450 return new SkImageEncoder_WIC(t); 451} 452 453static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); 454 455static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) { 456 SkImageDecoder::Format format; 457 SkImageDecoder_WIC codec; 458 if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) { 459 format = SkImageDecoder::kUnknown_Format; 460 } 461 return format; 462} 463 464static SkImageDecoder_FormatReg gFormatReg(get_format_wic); 465