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 49 class SkImageDecoder_WIC : public SkImageDecoder { 50 public: 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 69 protected: 70 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE; 71 }; 72 73 struct FormatConversion { 74 GUID fGuidFormat; 75 SkImageDecoder::Format fFormat; 76 }; 77 78 static 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 86 static 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 95 bool 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); 106 } 107 108 bool 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->setConfig(SkBitmap::kARGB_8888_Config, 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 253 extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*); 254 255 SkImageDecoder* 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 SkNEW(SkImageDecoder_WIC); 260 } else { 261 return decoder; 262 } 263 } 264 265 ///////////////////////////////////////////////////////////////////////// 266 267 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { 268 return NULL; 269 } 270 271 ///////////////////////////////////////////////////////////////////////// 272 273 class SkImageEncoder_WIC : public SkImageEncoder { 274 public: 275 SkImageEncoder_WIC(Type t) : fType(t) {} 276 277 protected: 278 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 279 280 private: 281 Type fType; 282 }; 283 284 bool 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 (SkBitmap::kARGB_8888_Config == bitmapOrig.config() && bitmapOrig.isOpaque()) { 310 bitmap = &bitmapOrig; 311 } else { 312 if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) { 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 440 static 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 SkNEW_ARGS(SkImageEncoder_WIC, (t)); 451 } 452 453 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); 454 455 static 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 464 static SkImageDecoder_FormatReg gFormatReg(get_format_wic); 465