• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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