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
GuidContainerFormat_to_Format(REFGUID guid)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
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)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
decodeStream(SkStream * stream,SkBitmap * bm,WICModes wicMode,Format * format) const108 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->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
253 extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
254
Factory(SkStreamRewindable * stream)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
DecodeStream(SkStreamRewindable * stream)267 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
268 return NULL;
269 }
270
271 /////////////////////////////////////////////////////////////////////////
272
273 class SkImageEncoder_WIC : public SkImageEncoder {
274 public:
SkImageEncoder_WIC(Type t)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
onEncode(SkWStream * stream,const SkBitmap & bitmapOrig,int quality)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 (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
sk_imageencoder_wic_factory(SkImageEncoder::Type t)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
get_format_wic(SkStreamRewindable * stream)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