• 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 #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 
GuidContainerFormat_to_Format(REFGUID guid)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 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)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 
decodeStream(SkStream * stream,SkBitmap * bm,WICModes wicMode,Format * format) const110 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 
Factory(SkStreamRewindable * stream)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 
DecodeStream(SkStreamRewindable * stream)269 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
270     return nullptr;
271 }
272 
273 /////////////////////////////////////////////////////////////////////////
274 
275 class SkImageEncoder_WIC : public SkImageEncoder {
276 public:
SkImageEncoder_WIC(Type t)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 
onEncode(SkWStream * stream,const SkBitmap & bitmapOrig,int quality)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 
sk_imageencoder_wic_factory(SkImageEncoder::Type t)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 
get_format_wic(SkStreamRewindable * stream)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