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