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 #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 
     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 
     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 
    108 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 
    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 
    267 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
    268     return NULL;
    269 }
    270 
    271 /////////////////////////////////////////////////////////////////////////
    272 
    273 class SkImageEncoder_WIC : public SkImageEncoder {
    274 public:
    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 
    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 
    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 
    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