Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / ports / SkImageDecoder_WIC.cpp
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 Result 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 SkImageDecoder::Result 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) ? kSuccess : kFailure;
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->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
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 (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
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);