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 
     21 class SkImageDecoder_WIC : public SkImageDecoder {
     22 protected:
     23     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
     24 };
     25 
     26 bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     27     //Initialize COM.
     28     SkAutoCoInitialize scopedCo;
     29     if (!scopedCo.succeeded()) {
     30         return false;
     31     }
     32 
     33     HRESULT hr = S_OK;
     34 
     35     //Create Windows Imaging Component ImagingFactory.
     36     SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
     37     if (SUCCEEDED(hr)) {
     38         hr = CoCreateInstance(
     39             CLSID_WICImagingFactory
     40             , NULL
     41             , CLSCTX_INPROC_SERVER
     42             , IID_PPV_ARGS(&piImagingFactory)
     43         );
     44     }
     45 
     46     //Convert SkStream to IStream.
     47     SkTScopedComPtr<IStream> piStream;
     48     if (SUCCEEDED(hr)) {
     49         hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
     50     }
     51 
     52     //Make sure we're at the beginning of the stream.
     53     if (SUCCEEDED(hr)) {
     54         LARGE_INTEGER liBeginning = { 0 };
     55         hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
     56     }
     57 
     58     //Create the decoder from the stream content.
     59     SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
     60     if (SUCCEEDED(hr)) {
     61         hr = piImagingFactory->CreateDecoderFromStream(
     62             piStream.get()                    //Image to be decoded
     63             , NULL                            //No particular vendor
     64             , WICDecodeMetadataCacheOnDemand  //Cache metadata when needed
     65             , &piBitmapDecoder                //Pointer to the decoder
     66         );
     67     }
     68 
     69     //Get the first frame from the decoder.
     70     SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
     71     if (SUCCEEDED(hr)) {
     72         hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
     73     }
     74 
     75     //Get the BitmapSource interface of the frame.
     76     SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
     77     if (SUCCEEDED(hr)) {
     78         hr = piBitmapFrameDecode->QueryInterface(
     79             IID_PPV_ARGS(&piBitmapSourceOriginal)
     80         );
     81     }
     82 
     83     //Get the size of the bitmap.
     84     UINT width;
     85     UINT height;
     86     if (SUCCEEDED(hr)) {
     87         hr = piBitmapSourceOriginal->GetSize(&width, &height);
     88     }
     89 
     90     //Exit early if we're only looking for the bitmap bounds.
     91     if (SUCCEEDED(hr)) {
     92         bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
     93         if (SkImageDecoder::kDecodeBounds_Mode == mode) {
     94             return true;
     95         }
     96         if (!this->allocPixelRef(bm, NULL)) {
     97             return false;
     98         }
     99     }
    100 
    101     //Create a format converter.
    102     SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
    103     if (SUCCEEDED(hr)) {
    104         hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
    105     }
    106 
    107     if (SUCCEEDED(hr)) {
    108         hr = piFormatConverter->Initialize(
    109             piBitmapSourceOriginal.get()      //Input bitmap to convert
    110             , GUID_WICPixelFormat32bppPBGRA   //Destination pixel format
    111             , WICBitmapDitherTypeNone         //Specified dither patterm
    112             , NULL                            //Specify a particular palette
    113             , 0.f                             //Alpha threshold
    114             , WICBitmapPaletteTypeCustom      //Palette translation type
    115         );
    116     }
    117 
    118     //Get the BitmapSource interface of the format converter.
    119     SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
    120     if (SUCCEEDED(hr)) {
    121         hr = piFormatConverter->QueryInterface(
    122             IID_PPV_ARGS(&piBitmapSourceConverted)
    123         );
    124     }
    125 
    126     //Copy the pixels into the bitmap.
    127     if (SUCCEEDED(hr)) {
    128         SkAutoLockPixels alp(*bm);
    129         bm->eraseColor(0);
    130         const int stride = bm->rowBytes();
    131         hr = piBitmapSourceConverted->CopyPixels(
    132             NULL,                             //Get all the pixels
    133             stride,
    134             stride * height,
    135             reinterpret_cast<BYTE *>(bm->getPixels())
    136         );
    137     }
    138 
    139     return SUCCEEDED(hr);
    140 }
    141 
    142 /////////////////////////////////////////////////////////////////////////
    143 
    144 SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
    145     return SkNEW(SkImageDecoder_WIC);
    146 }
    147 
    148 /////////////////////////////////////////////////////////////////////////
    149 
    150 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
    151     return NULL;
    152 }
    153 
    154 /////////////////////////////////////////////////////////////////////////
    155 
    156 class SkImageEncoder_WIC : public SkImageEncoder {
    157 public:
    158     SkImageEncoder_WIC(Type t) : fType(t) {}
    159 
    160 protected:
    161     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
    162 
    163 private:
    164     Type fType;
    165 };
    166 
    167 bool SkImageEncoder_WIC::onEncode(SkWStream* stream
    168                                 , const SkBitmap& bitmapOrig
    169                                 , int quality)
    170 {
    171     GUID type;
    172     switch (fType) {
    173         case kJPEG_Type:
    174             type = GUID_ContainerFormatJpeg;
    175             break;
    176         case kPNG_Type:
    177             type = GUID_ContainerFormatPng;
    178             break;
    179         default:
    180             return false;
    181     }
    182 
    183     //Convert to 8888 if needed.
    184     const SkBitmap* bitmap;
    185     SkBitmap bitmapCopy;
    186     if (SkBitmap::kARGB_8888_Config == bitmapOrig.config()) {
    187         bitmap = &bitmapOrig;
    188     } else {
    189         if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) {
    190             return false;
    191         }
    192         bitmap = &bitmapCopy;
    193     }
    194 
    195     //Initialize COM.
    196     SkAutoCoInitialize scopedCo;
    197     if (!scopedCo.succeeded()) {
    198         return false;
    199     }
    200 
    201     HRESULT hr = S_OK;
    202 
    203     //Create Windows Imaging Component ImagingFactory.
    204     SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
    205     if (SUCCEEDED(hr)) {
    206         hr = CoCreateInstance(
    207             CLSID_WICImagingFactory
    208             , NULL
    209             , CLSCTX_INPROC_SERVER
    210             , IID_PPV_ARGS(&piImagingFactory)
    211         );
    212     }
    213 
    214     //Convert the SkWStream to an IStream.
    215     SkTScopedComPtr<IStream> piStream;
    216     if (SUCCEEDED(hr)) {
    217         hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
    218     }
    219 
    220     //Create an encode of the appropriate type.
    221     SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
    222     if (SUCCEEDED(hr)) {
    223         hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
    224     }
    225 
    226     if (SUCCEEDED(hr)) {
    227         hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
    228     }
    229 
    230     //Create a the frame.
    231     SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
    232     SkTScopedComPtr<IPropertyBag2> piPropertybag;
    233     if (SUCCEEDED(hr)) {
    234         hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
    235     }
    236 
    237     if (SUCCEEDED(hr)) {
    238         PROPBAG2 name = { 0 };
    239         name.dwType = PROPBAG2_TYPE_DATA;
    240         name.vt = VT_R4;
    241         name.pstrName = L"ImageQuality";
    242 
    243         VARIANT value;
    244         VariantInit(&value);
    245         value.vt = VT_R4;
    246         value.fltVal = (FLOAT)(quality / 100.0);
    247 
    248         //Ignore result code.
    249         //  This returns E_FAIL if the named property is not in the bag.
    250         //TODO(bungeman) enumerate the properties,
    251         //  write and set hr iff property exists.
    252         piPropertybag->Write(1, &name, &value);
    253     }
    254     if (SUCCEEDED(hr)) {
    255         hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
    256     }
    257 
    258     //Set the size of the frame.
    259     const UINT width = bitmap->width();
    260     const UINT height = bitmap->height();
    261     if (SUCCEEDED(hr)) {
    262         hr = piBitmapFrameEncode->SetSize(width, height);
    263     }
    264 
    265     //Set the pixel format of the frame.
    266     const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
    267     WICPixelFormatGUID formatGUID = formatDesired;
    268     if (SUCCEEDED(hr)) {
    269         hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
    270     }
    271     if (SUCCEEDED(hr)) {
    272         //Be sure the image format is the one requested.
    273         hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
    274     }
    275 
    276     //Write the pixels into the frame.
    277     if (SUCCEEDED(hr)) {
    278         SkAutoLockPixels alp(*bitmap);
    279         hr = piBitmapFrameEncode->WritePixels(
    280             height
    281             , bitmap->rowBytes()
    282             , bitmap->rowBytes()*height
    283             , reinterpret_cast<BYTE*>(bitmap->getPixels()));
    284     }
    285 
    286     if (SUCCEEDED(hr)) {
    287         hr = piBitmapFrameEncode->Commit();
    288     }
    289 
    290     if (SUCCEEDED(hr)) {
    291         hr = piEncoder->Commit();
    292     }
    293 
    294     return SUCCEEDED(hr);
    295 }
    296 
    297 SkImageEncoder* SkImageEncoder::Create(Type t) {
    298     switch (t) {
    299         case kJPEG_Type:
    300         case kPNG_Type:
    301             break;
    302         default:
    303             return NULL;
    304     }
    305     return SkNEW_ARGS(SkImageEncoder_WIC, (t));
    306 }
    307 
    308