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 21 class SkImageDecoder_WIC : public SkImageDecoder { 22 protected: 23 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode); 24 }; 25 26 bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 27 //Initialize COM. 28 SkAutoCoInitialize scopedCo; 29 if (!scopedCo.succeeded()) { 30 return false; 31 } 32 33 HRESULT hr = S_OK; 34 35 //Create Windows Imaging Component ImagingFactory. 36 SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 37 if (SUCCEEDED(hr)) { 38 hr = CoCreateInstance( 39 CLSID_WICImagingFactory 40 , NULL 41 , CLSCTX_INPROC_SERVER 42 , IID_PPV_ARGS(&piImagingFactory) 43 ); 44 } 45 46 //Convert SkStream to IStream. 47 SkTScopedComPtr<IStream> piStream; 48 if (SUCCEEDED(hr)) { 49 hr = SkIStream::CreateFromSkStream(stream, false, &piStream); 50 } 51 52 //Make sure we're at the beginning of the stream. 53 if (SUCCEEDED(hr)) { 54 LARGE_INTEGER liBeginning = { 0 }; 55 hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); 56 } 57 58 //Create the decoder from the stream content. 59 SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; 60 if (SUCCEEDED(hr)) { 61 hr = piImagingFactory->CreateDecoderFromStream( 62 piStream.get() //Image to be decoded 63 , NULL //No particular vendor 64 , WICDecodeMetadataCacheOnDemand //Cache metadata when needed 65 , &piBitmapDecoder //Pointer to the decoder 66 ); 67 } 68 69 //Get the first frame from the decoder. 70 SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; 71 if (SUCCEEDED(hr)) { 72 hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); 73 } 74 75 //Get the BitmapSource interface of the frame. 76 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; 77 if (SUCCEEDED(hr)) { 78 hr = piBitmapFrameDecode->QueryInterface( 79 IID_PPV_ARGS(&piBitmapSourceOriginal) 80 ); 81 } 82 83 //Get the size of the bitmap. 84 UINT width; 85 UINT height; 86 if (SUCCEEDED(hr)) { 87 hr = piBitmapSourceOriginal->GetSize(&width, &height); 88 } 89 90 //Exit early if we're only looking for the bitmap bounds. 91 if (SUCCEEDED(hr)) { 92 bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); 93 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 94 return true; 95 } 96 if (!this->allocPixelRef(bm, NULL)) { 97 return false; 98 } 99 } 100 101 //Create a format converter. 102 SkTScopedComPtr<IWICFormatConverter> piFormatConverter; 103 if (SUCCEEDED(hr)) { 104 hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); 105 } 106 107 if (SUCCEEDED(hr)) { 108 hr = piFormatConverter->Initialize( 109 piBitmapSourceOriginal.get() //Input bitmap to convert 110 , GUID_WICPixelFormat32bppPBGRA //Destination pixel format 111 , WICBitmapDitherTypeNone //Specified dither patterm 112 , NULL //Specify a particular palette 113 , 0.f //Alpha threshold 114 , WICBitmapPaletteTypeCustom //Palette translation type 115 ); 116 } 117 118 //Get the BitmapSource interface of the format converter. 119 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; 120 if (SUCCEEDED(hr)) { 121 hr = piFormatConverter->QueryInterface( 122 IID_PPV_ARGS(&piBitmapSourceConverted) 123 ); 124 } 125 126 //Copy the pixels into the bitmap. 127 if (SUCCEEDED(hr)) { 128 SkAutoLockPixels alp(*bm); 129 bm->eraseColor(0); 130 const int stride = bm->rowBytes(); 131 hr = piBitmapSourceConverted->CopyPixels( 132 NULL, //Get all the pixels 133 stride, 134 stride * height, 135 reinterpret_cast<BYTE *>(bm->getPixels()) 136 ); 137 } 138 139 return SUCCEEDED(hr); 140 } 141 142 ///////////////////////////////////////////////////////////////////////// 143 144 SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) { 145 return SkNEW(SkImageDecoder_WIC); 146 } 147 148 ///////////////////////////////////////////////////////////////////////// 149 150 SkMovie* SkMovie::DecodeStream(SkStream* stream) { 151 return NULL; 152 } 153 154 ///////////////////////////////////////////////////////////////////////// 155 156 class SkImageEncoder_WIC : public SkImageEncoder { 157 public: 158 SkImageEncoder_WIC(Type t) : fType(t) {} 159 160 protected: 161 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 162 163 private: 164 Type fType; 165 }; 166 167 bool SkImageEncoder_WIC::onEncode(SkWStream* stream 168 , const SkBitmap& bitmapOrig 169 , int quality) 170 { 171 GUID type; 172 switch (fType) { 173 case kJPEG_Type: 174 type = GUID_ContainerFormatJpeg; 175 break; 176 case kPNG_Type: 177 type = GUID_ContainerFormatPng; 178 break; 179 default: 180 return false; 181 } 182 183 //Convert to 8888 if needed. 184 const SkBitmap* bitmap; 185 SkBitmap bitmapCopy; 186 if (SkBitmap::kARGB_8888_Config == bitmapOrig.config()) { 187 bitmap = &bitmapOrig; 188 } else { 189 if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) { 190 return false; 191 } 192 bitmap = &bitmapCopy; 193 } 194 195 //Initialize COM. 196 SkAutoCoInitialize scopedCo; 197 if (!scopedCo.succeeded()) { 198 return false; 199 } 200 201 HRESULT hr = S_OK; 202 203 //Create Windows Imaging Component ImagingFactory. 204 SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 205 if (SUCCEEDED(hr)) { 206 hr = CoCreateInstance( 207 CLSID_WICImagingFactory 208 , NULL 209 , CLSCTX_INPROC_SERVER 210 , IID_PPV_ARGS(&piImagingFactory) 211 ); 212 } 213 214 //Convert the SkWStream to an IStream. 215 SkTScopedComPtr<IStream> piStream; 216 if (SUCCEEDED(hr)) { 217 hr = SkWIStream::CreateFromSkWStream(stream, &piStream); 218 } 219 220 //Create an encode of the appropriate type. 221 SkTScopedComPtr<IWICBitmapEncoder> piEncoder; 222 if (SUCCEEDED(hr)) { 223 hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder); 224 } 225 226 if (SUCCEEDED(hr)) { 227 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); 228 } 229 230 //Create a the frame. 231 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; 232 SkTScopedComPtr<IPropertyBag2> piPropertybag; 233 if (SUCCEEDED(hr)) { 234 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); 235 } 236 237 if (SUCCEEDED(hr)) { 238 PROPBAG2 name = { 0 }; 239 name.dwType = PROPBAG2_TYPE_DATA; 240 name.vt = VT_R4; 241 name.pstrName = L"ImageQuality"; 242 243 VARIANT value; 244 VariantInit(&value); 245 value.vt = VT_R4; 246 value.fltVal = (FLOAT)(quality / 100.0); 247 248 //Ignore result code. 249 // This returns E_FAIL if the named property is not in the bag. 250 //TODO(bungeman) enumerate the properties, 251 // write and set hr iff property exists. 252 piPropertybag->Write(1, &name, &value); 253 } 254 if (SUCCEEDED(hr)) { 255 hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); 256 } 257 258 //Set the size of the frame. 259 const UINT width = bitmap->width(); 260 const UINT height = bitmap->height(); 261 if (SUCCEEDED(hr)) { 262 hr = piBitmapFrameEncode->SetSize(width, height); 263 } 264 265 //Set the pixel format of the frame. 266 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; 267 WICPixelFormatGUID formatGUID = formatDesired; 268 if (SUCCEEDED(hr)) { 269 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); 270 } 271 if (SUCCEEDED(hr)) { 272 //Be sure the image format is the one requested. 273 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; 274 } 275 276 //Write the pixels into the frame. 277 if (SUCCEEDED(hr)) { 278 SkAutoLockPixels alp(*bitmap); 279 hr = piBitmapFrameEncode->WritePixels( 280 height 281 , bitmap->rowBytes() 282 , bitmap->rowBytes()*height 283 , reinterpret_cast<BYTE*>(bitmap->getPixels())); 284 } 285 286 if (SUCCEEDED(hr)) { 287 hr = piBitmapFrameEncode->Commit(); 288 } 289 290 if (SUCCEEDED(hr)) { 291 hr = piEncoder->Commit(); 292 } 293 294 return SUCCEEDED(hr); 295 } 296 297 SkImageEncoder* SkImageEncoder::Create(Type t) { 298 switch (t) { 299 case kJPEG_Type: 300 case kPNG_Type: 301 break; 302 default: 303 return NULL; 304 } 305 return SkNEW_ARGS(SkImageEncoder_WIC, (t)); 306 } 307 308