Home | History | Annotate | Download | only in ports
      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 
     31 class SkImageDecoder_WIC : public SkImageDecoder {
     32 public:
     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 
     51 protected:
     52     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
     53 };
     54 
     55 struct FormatConversion {
     56     GUID                    fGuidFormat;
     57     SkImageDecoder::Format  fFormat;
     58 };
     59 
     60 static 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 
     68 static 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 
     77 bool 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 
     90 bool 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 
    233 extern SkImageDecoder* image_decoder_from_stream(SkStream*);
    234 
    235 SkImageDecoder* 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 
    247 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
    248     return NULL;
    249 }
    250 
    251 /////////////////////////////////////////////////////////////////////////
    252 
    253 class SkImageEncoder_WIC : public SkImageEncoder {
    254 public:
    255     SkImageEncoder_WIC(Type t) : fType(t) {}
    256 
    257 protected:
    258     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
    259 
    260 private:
    261     Type fType;
    262 };
    263 
    264 bool 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 
    422 static 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 
    435 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_imageencoder_wic_factory);
    436 
    437 static 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 
    446 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_wic);
    447