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