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