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#include "SkUnPreMultiply.h"
21
22//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
23//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
24//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
25//Undo this #define if it has been done so that we link against the symbols
26//we intended to link against on all SDKs.
27#if defined(CLSID_WICImagingFactory)
28#undef CLSID_WICImagingFactory
29#endif
30
31class SkImageDecoder_WIC : public SkImageDecoder {
32public:
33    // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding
34    // only the format.
35    enum WICModes {
36        kDecodeFormat_WICMode,
37        kDecodeBounds_WICMode,
38        kDecodePixels_WICMode,
39    };
40
41    /**
42     *  Helper function to decode an SkStream.
43     *  @param stream SkStream to decode. Must be at the beginning.
44     *  @param bm   SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or
45     *      kDecodePixels_WICMode, in which case it must not be NULL.
46     *  @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if
47     *      wicMode is kDecodeFormat_WICMode.
48     */
49    bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
50
51protected:
52    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
53};
54
55struct FormatConversion {
56    GUID                    fGuidFormat;
57    SkImageDecoder::Format  fFormat;
58};
59
60static const FormatConversion gFormatConversions[] = {
61    { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format },
62    { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format },
63    { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format },
64    { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format },
65    { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format },
66};
67
68static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) {
69    for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
70        if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) {
71            return gFormatConversions[i].fFormat;
72        }
73    }
74    return SkImageDecoder::kUnknown_Format;
75}
76
77bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
78    WICModes wicMode;
79    switch (mode) {
80        case SkImageDecoder::kDecodeBounds_Mode:
81            wicMode = kDecodeBounds_WICMode;
82            break;
83        case SkImageDecoder::kDecodePixels_Mode:
84            wicMode = kDecodePixels_WICMode;
85            break;
86    }
87    return this->decodeStream(stream, bm, wicMode, NULL);
88}
89
90bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
91                                      Format* format) const {
92    //Initialize COM.
93    SkAutoCoInitialize scopedCo;
94    if (!scopedCo.succeeded()) {
95        return false;
96    }
97
98    HRESULT hr = S_OK;
99
100    //Create Windows Imaging Component ImagingFactory.
101    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
102    if (SUCCEEDED(hr)) {
103        hr = CoCreateInstance(
104            CLSID_WICImagingFactory
105            , NULL
106            , CLSCTX_INPROC_SERVER
107            , IID_PPV_ARGS(&piImagingFactory)
108        );
109    }
110
111    //Convert SkStream to IStream.
112    SkTScopedComPtr<IStream> piStream;
113    if (SUCCEEDED(hr)) {
114        hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
115    }
116
117    //Make sure we're at the beginning of the stream.
118    if (SUCCEEDED(hr)) {
119        LARGE_INTEGER liBeginning = { 0 };
120        hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
121    }
122
123    //Create the decoder from the stream content.
124    SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
125    if (SUCCEEDED(hr)) {
126        hr = piImagingFactory->CreateDecoderFromStream(
127            piStream.get()                    //Image to be decoded
128            , NULL                            //No particular vendor
129            , WICDecodeMetadataCacheOnDemand  //Cache metadata when needed
130            , &piBitmapDecoder                //Pointer to the decoder
131        );
132    }
133
134    if (kDecodeFormat_WICMode == wicMode) {
135        SkASSERT(format != NULL);
136        //Get the format
137        if (SUCCEEDED(hr)) {
138            GUID guidFormat;
139            hr = piBitmapDecoder->GetContainerFormat(&guidFormat);
140            if (SUCCEEDED(hr)) {
141                *format = GuidContainerFormat_to_Format(guidFormat);
142                return true;
143            }
144        }
145        return false;
146    }
147
148    //Get the first frame from the decoder.
149    SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
150    if (SUCCEEDED(hr)) {
151        hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
152    }
153
154    //Get the BitmapSource interface of the frame.
155    SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
156    if (SUCCEEDED(hr)) {
157        hr = piBitmapFrameDecode->QueryInterface(
158            IID_PPV_ARGS(&piBitmapSourceOriginal)
159        );
160    }
161
162    //Get the size of the bitmap.
163    UINT width;
164    UINT height;
165    if (SUCCEEDED(hr)) {
166        hr = piBitmapSourceOriginal->GetSize(&width, &height);
167    }
168
169    //Exit early if we're only looking for the bitmap bounds.
170    if (SUCCEEDED(hr)) {
171        bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
172        if (kDecodeBounds_WICMode == wicMode) {
173            return true;
174        }
175        if (!this->allocPixelRef(bm, NULL)) {
176            return false;
177        }
178    }
179
180    //Create a format converter.
181    SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
182    if (SUCCEEDED(hr)) {
183        hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
184    }
185
186    GUID destinationPixelFormat;
187    if (this->getRequireUnpremultipliedColors()) {
188        destinationPixelFormat = GUID_WICPixelFormat32bppBGRA;
189    } else {
190        destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA;
191    }
192
193    if (SUCCEEDED(hr)) {
194        hr = piFormatConverter->Initialize(
195            piBitmapSourceOriginal.get()      //Input bitmap to convert
196            , destinationPixelFormat          //Destination pixel format
197            , WICBitmapDitherTypeNone         //Specified dither patterm
198            , NULL                            //Specify a particular palette
199            , 0.f                             //Alpha threshold
200            , WICBitmapPaletteTypeCustom      //Palette translation type
201        );
202    }
203
204    //Get the BitmapSource interface of the format converter.
205    SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
206    if (SUCCEEDED(hr)) {
207        hr = piFormatConverter->QueryInterface(
208            IID_PPV_ARGS(&piBitmapSourceConverted)
209        );
210    }
211
212    //Copy the pixels into the bitmap.
213    if (SUCCEEDED(hr)) {
214        SkAutoLockPixels alp(*bm);
215        bm->eraseColor(SK_ColorTRANSPARENT);
216        const UINT stride = bm->rowBytes();
217        hr = piBitmapSourceConverted->CopyPixels(
218            NULL,                             //Get all the pixels
219            stride,
220            stride * height,
221            reinterpret_cast<BYTE *>(bm->getPixels())
222        );
223
224        // Note: we don't need to premultiply here since we specified PBGRA
225        bm->computeAndSetOpaquePredicate();
226    }
227
228    return SUCCEEDED(hr);
229}
230
231/////////////////////////////////////////////////////////////////////////
232
233extern SkImageDecoder* image_decoder_from_stream(SkStream*);
234
235SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
236    SkImageDecoder* decoder = image_decoder_from_stream(stream);
237    if (NULL == decoder) {
238        // If no image decoder specific to the stream exists, use SkImageDecoder_WIC.
239        return SkNEW(SkImageDecoder_WIC);
240    } else {
241        return decoder;
242    }
243}
244
245/////////////////////////////////////////////////////////////////////////
246
247SkMovie* SkMovie::DecodeStream(SkStream* stream) {
248    return NULL;
249}
250
251/////////////////////////////////////////////////////////////////////////
252
253class SkImageEncoder_WIC : public SkImageEncoder {
254public:
255    SkImageEncoder_WIC(Type t) : fType(t) {}
256
257protected:
258    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
259
260private:
261    Type fType;
262};
263
264bool SkImageEncoder_WIC::onEncode(SkWStream* stream
265                                , const SkBitmap& bitmapOrig
266                                , int quality)
267{
268    GUID type;
269    switch (fType) {
270        case kBMP_Type:
271            type = GUID_ContainerFormatBmp;
272            break;
273        case kICO_Type:
274            type = GUID_ContainerFormatIco;
275            break;
276        case kJPEG_Type:
277            type = GUID_ContainerFormatJpeg;
278            break;
279        case kPNG_Type:
280            type = GUID_ContainerFormatPng;
281            break;
282        default:
283            return false;
284    }
285
286    //Convert to 8888 if needed.
287    const SkBitmap* bitmap;
288    SkBitmap bitmapCopy;
289    if (SkBitmap::kARGB_8888_Config == bitmapOrig.config() && bitmapOrig.isOpaque()) {
290        bitmap = &bitmapOrig;
291    } else {
292        if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) {
293            return false;
294        }
295        bitmap = &bitmapCopy;
296    }
297
298    // We cannot use PBGRA so we need to unpremultiply ourselves
299    if (!bitmap->isOpaque()) {
300        SkAutoLockPixels alp(*bitmap);
301
302        uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels());
303        for (int y = 0; y < bitmap->height(); ++y) {
304            for (int x = 0; x < bitmap->width(); ++x) {
305                uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel();
306
307                SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
308                SkColor* dst = reinterpret_cast<SkColor*>(bytes);
309
310                *dst = SkUnPreMultiply::PMColorToColor(*src);
311            }
312        }
313    }
314
315    //Initialize COM.
316    SkAutoCoInitialize scopedCo;
317    if (!scopedCo.succeeded()) {
318        return false;
319    }
320
321    HRESULT hr = S_OK;
322
323    //Create Windows Imaging Component ImagingFactory.
324    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
325    if (SUCCEEDED(hr)) {
326        hr = CoCreateInstance(
327            CLSID_WICImagingFactory
328            , NULL
329            , CLSCTX_INPROC_SERVER
330            , IID_PPV_ARGS(&piImagingFactory)
331        );
332    }
333
334    //Convert the SkWStream to an IStream.
335    SkTScopedComPtr<IStream> piStream;
336    if (SUCCEEDED(hr)) {
337        hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
338    }
339
340    //Create an encode of the appropriate type.
341    SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
342    if (SUCCEEDED(hr)) {
343        hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
344    }
345
346    if (SUCCEEDED(hr)) {
347        hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
348    }
349
350    //Create a the frame.
351    SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
352    SkTScopedComPtr<IPropertyBag2> piPropertybag;
353    if (SUCCEEDED(hr)) {
354        hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
355    }
356
357    if (SUCCEEDED(hr)) {
358        PROPBAG2 name = { 0 };
359        name.dwType = PROPBAG2_TYPE_DATA;
360        name.vt = VT_R4;
361        name.pstrName = L"ImageQuality";
362
363        VARIANT value;
364        VariantInit(&value);
365        value.vt = VT_R4;
366        value.fltVal = (FLOAT)(quality / 100.0);
367
368        //Ignore result code.
369        //  This returns E_FAIL if the named property is not in the bag.
370        //TODO(bungeman) enumerate the properties,
371        //  write and set hr iff property exists.
372        piPropertybag->Write(1, &name, &value);
373    }
374    if (SUCCEEDED(hr)) {
375        hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
376    }
377
378    //Set the size of the frame.
379    const UINT width = bitmap->width();
380    const UINT height = bitmap->height();
381    if (SUCCEEDED(hr)) {
382        hr = piBitmapFrameEncode->SetSize(width, height);
383    }
384
385    //Set the pixel format of the frame.
386    const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
387    WICPixelFormatGUID formatGUID = formatDesired;
388    if (SUCCEEDED(hr)) {
389        hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
390    }
391    if (SUCCEEDED(hr)) {
392        //Be sure the image format is the one requested.
393        hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
394    }
395
396    //Write the pixels into the frame.
397    if (SUCCEEDED(hr)) {
398        SkAutoLockPixels alp(*bitmap);
399        const UINT stride = bitmap->rowBytes();
400        hr = piBitmapFrameEncode->WritePixels(
401            height
402            , stride
403            , stride * height
404            , reinterpret_cast<BYTE*>(bitmap->getPixels()));
405    }
406
407    if (SUCCEEDED(hr)) {
408        hr = piBitmapFrameEncode->Commit();
409    }
410
411    if (SUCCEEDED(hr)) {
412        hr = piEncoder->Commit();
413    }
414
415    return SUCCEEDED(hr);
416}
417
418///////////////////////////////////////////////////////////////////////////////
419
420#include "SkTRegistry.h"
421
422static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
423    switch (t) {
424        case SkImageEncoder::kBMP_Type:
425        case SkImageEncoder::kICO_Type:
426        case SkImageEncoder::kJPEG_Type:
427        case SkImageEncoder::kPNG_Type:
428            break;
429        default:
430            return NULL;
431    }
432    return SkNEW_ARGS(SkImageEncoder_WIC, (t));
433}
434
435static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_imageencoder_wic_factory);
436
437static SkImageDecoder::Format get_format_wic(SkStream* stream) {
438    SkImageDecoder::Format format;
439    SkImageDecoder_WIC codec;
440    if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) {
441        format = SkImageDecoder::kUnknown_Format;
442    }
443    return format;
444}
445
446static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_wic);
447