gfx/skia/trunk/src/ports/SkImageDecoder_WIC.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/ports/SkImageDecoder_WIC.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,464 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +#include "SkTypes.h"
    1.13 +
    1.14 +// Workaround for:
    1.15 +// http://connect.microsoft.com/VisualStudio/feedback/details/621653/
    1.16 +// http://crbug.com/225822
    1.17 +// In VS2010 both intsafe.h and stdint.h define the following without guards.
    1.18 +// SkTypes brought in windows.h and stdint.h and the following defines are
    1.19 +// not used by this file. However, they may be re-introduced by wincodec.h.
    1.20 +#undef INT8_MIN
    1.21 +#undef INT16_MIN
    1.22 +#undef INT32_MIN
    1.23 +#undef INT64_MIN
    1.24 +#undef INT8_MAX
    1.25 +#undef UINT8_MAX
    1.26 +#undef INT16_MAX
    1.27 +#undef UINT16_MAX
    1.28 +#undef INT32_MAX
    1.29 +#undef UINT32_MAX
    1.30 +#undef INT64_MAX
    1.31 +#undef UINT64_MAX
    1.32 +
    1.33 +#include <wincodec.h>
    1.34 +#include "SkAutoCoInitialize.h"
    1.35 +#include "SkImageDecoder.h"
    1.36 +#include "SkImageEncoder.h"
    1.37 +#include "SkIStream.h"
    1.38 +#include "SkMovie.h"
    1.39 +#include "SkStream.h"
    1.40 +#include "SkTScopedComPtr.h"
    1.41 +#include "SkUnPreMultiply.h"
    1.42 +
    1.43 +//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
    1.44 +//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
    1.45 +//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
    1.46 +//Undo this #define if it has been done so that we link against the symbols
    1.47 +//we intended to link against on all SDKs.
    1.48 +#if defined(CLSID_WICImagingFactory)
    1.49 +#undef CLSID_WICImagingFactory
    1.50 +#endif
    1.51 +
    1.52 +class SkImageDecoder_WIC : public SkImageDecoder {
    1.53 +public:
    1.54 +    // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding
    1.55 +    // only the format.
    1.56 +    enum WICModes {
    1.57 +        kDecodeFormat_WICMode,
    1.58 +        kDecodeBounds_WICMode,
    1.59 +        kDecodePixels_WICMode,
    1.60 +    };
    1.61 +
    1.62 +    /**
    1.63 +     *  Helper function to decode an SkStream.
    1.64 +     *  @param stream SkStream to decode. Must be at the beginning.
    1.65 +     *  @param bm   SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or
    1.66 +     *      kDecodePixels_WICMode, in which case it must not be NULL.
    1.67 +     *  @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if
    1.68 +     *      wicMode is kDecodeFormat_WICMode.
    1.69 +     */
    1.70 +    bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
    1.71 +
    1.72 +protected:
    1.73 +    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
    1.74 +};
    1.75 +
    1.76 +struct FormatConversion {
    1.77 +    GUID                    fGuidFormat;
    1.78 +    SkImageDecoder::Format  fFormat;
    1.79 +};
    1.80 +
    1.81 +static const FormatConversion gFormatConversions[] = {
    1.82 +    { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format },
    1.83 +    { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format },
    1.84 +    { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format },
    1.85 +    { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format },
    1.86 +    { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format },
    1.87 +};
    1.88 +
    1.89 +static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) {
    1.90 +    for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
    1.91 +        if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) {
    1.92 +            return gFormatConversions[i].fFormat;
    1.93 +        }
    1.94 +    }
    1.95 +    return SkImageDecoder::kUnknown_Format;
    1.96 +}
    1.97 +
    1.98 +bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
    1.99 +    WICModes wicMode;
   1.100 +    switch (mode) {
   1.101 +        case SkImageDecoder::kDecodeBounds_Mode:
   1.102 +            wicMode = kDecodeBounds_WICMode;
   1.103 +            break;
   1.104 +        case SkImageDecoder::kDecodePixels_Mode:
   1.105 +            wicMode = kDecodePixels_WICMode;
   1.106 +            break;
   1.107 +    }
   1.108 +    return this->decodeStream(stream, bm, wicMode, NULL);
   1.109 +}
   1.110 +
   1.111 +bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
   1.112 +                                      Format* format) const {
   1.113 +    //Initialize COM.
   1.114 +    SkAutoCoInitialize scopedCo;
   1.115 +    if (!scopedCo.succeeded()) {
   1.116 +        return false;
   1.117 +    }
   1.118 +
   1.119 +    HRESULT hr = S_OK;
   1.120 +
   1.121 +    //Create Windows Imaging Component ImagingFactory.
   1.122 +    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
   1.123 +    if (SUCCEEDED(hr)) {
   1.124 +        hr = CoCreateInstance(
   1.125 +            CLSID_WICImagingFactory
   1.126 +            , NULL
   1.127 +            , CLSCTX_INPROC_SERVER
   1.128 +            , IID_PPV_ARGS(&piImagingFactory)
   1.129 +        );
   1.130 +    }
   1.131 +
   1.132 +    //Convert SkStream to IStream.
   1.133 +    SkTScopedComPtr<IStream> piStream;
   1.134 +    if (SUCCEEDED(hr)) {
   1.135 +        hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
   1.136 +    }
   1.137 +
   1.138 +    //Make sure we're at the beginning of the stream.
   1.139 +    if (SUCCEEDED(hr)) {
   1.140 +        LARGE_INTEGER liBeginning = { 0 };
   1.141 +        hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
   1.142 +    }
   1.143 +
   1.144 +    //Create the decoder from the stream content.
   1.145 +    SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
   1.146 +    if (SUCCEEDED(hr)) {
   1.147 +        hr = piImagingFactory->CreateDecoderFromStream(
   1.148 +            piStream.get()                    //Image to be decoded
   1.149 +            , NULL                            //No particular vendor
   1.150 +            , WICDecodeMetadataCacheOnDemand  //Cache metadata when needed
   1.151 +            , &piBitmapDecoder                //Pointer to the decoder
   1.152 +        );
   1.153 +    }
   1.154 +
   1.155 +    if (kDecodeFormat_WICMode == wicMode) {
   1.156 +        SkASSERT(format != NULL);
   1.157 +        //Get the format
   1.158 +        if (SUCCEEDED(hr)) {
   1.159 +            GUID guidFormat;
   1.160 +            hr = piBitmapDecoder->GetContainerFormat(&guidFormat);
   1.161 +            if (SUCCEEDED(hr)) {
   1.162 +                *format = GuidContainerFormat_to_Format(guidFormat);
   1.163 +                return true;
   1.164 +            }
   1.165 +        }
   1.166 +        return false;
   1.167 +    }
   1.168 +
   1.169 +    //Get the first frame from the decoder.
   1.170 +    SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
   1.171 +    if (SUCCEEDED(hr)) {
   1.172 +        hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
   1.173 +    }
   1.174 +
   1.175 +    //Get the BitmapSource interface of the frame.
   1.176 +    SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
   1.177 +    if (SUCCEEDED(hr)) {
   1.178 +        hr = piBitmapFrameDecode->QueryInterface(
   1.179 +            IID_PPV_ARGS(&piBitmapSourceOriginal)
   1.180 +        );
   1.181 +    }
   1.182 +
   1.183 +    //Get the size of the bitmap.
   1.184 +    UINT width;
   1.185 +    UINT height;
   1.186 +    if (SUCCEEDED(hr)) {
   1.187 +        hr = piBitmapSourceOriginal->GetSize(&width, &height);
   1.188 +    }
   1.189 +
   1.190 +    //Exit early if we're only looking for the bitmap bounds.
   1.191 +    if (SUCCEEDED(hr)) {
   1.192 +        bm->setConfig(SkImageInfo::MakeN32Premul(width, height));
   1.193 +        if (kDecodeBounds_WICMode == wicMode) {
   1.194 +            return true;
   1.195 +        }
   1.196 +        if (!this->allocPixelRef(bm, NULL)) {
   1.197 +            return false;
   1.198 +        }
   1.199 +    }
   1.200 +
   1.201 +    //Create a format converter.
   1.202 +    SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
   1.203 +    if (SUCCEEDED(hr)) {
   1.204 +        hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
   1.205 +    }
   1.206 +
   1.207 +    GUID destinationPixelFormat;
   1.208 +    if (this->getRequireUnpremultipliedColors()) {
   1.209 +        destinationPixelFormat = GUID_WICPixelFormat32bppBGRA;
   1.210 +    } else {
   1.211 +        destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA;
   1.212 +    }
   1.213 +
   1.214 +    if (SUCCEEDED(hr)) {
   1.215 +        hr = piFormatConverter->Initialize(
   1.216 +            piBitmapSourceOriginal.get()      //Input bitmap to convert
   1.217 +            , destinationPixelFormat          //Destination pixel format
   1.218 +            , WICBitmapDitherTypeNone         //Specified dither patterm
   1.219 +            , NULL                            //Specify a particular palette
   1.220 +            , 0.f                             //Alpha threshold
   1.221 +            , WICBitmapPaletteTypeCustom      //Palette translation type
   1.222 +        );
   1.223 +    }
   1.224 +
   1.225 +    //Get the BitmapSource interface of the format converter.
   1.226 +    SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
   1.227 +    if (SUCCEEDED(hr)) {
   1.228 +        hr = piFormatConverter->QueryInterface(
   1.229 +            IID_PPV_ARGS(&piBitmapSourceConverted)
   1.230 +        );
   1.231 +    }
   1.232 +
   1.233 +    //Copy the pixels into the bitmap.
   1.234 +    if (SUCCEEDED(hr)) {
   1.235 +        SkAutoLockPixels alp(*bm);
   1.236 +        bm->eraseColor(SK_ColorTRANSPARENT);
   1.237 +        const UINT stride = (UINT) bm->rowBytes();
   1.238 +        hr = piBitmapSourceConverted->CopyPixels(
   1.239 +            NULL,                             //Get all the pixels
   1.240 +            stride,
   1.241 +            stride * height,
   1.242 +            reinterpret_cast<BYTE *>(bm->getPixels())
   1.243 +        );
   1.244 +
   1.245 +        // Note: we don't need to premultiply here since we specified PBGRA
   1.246 +        if (SkBitmap::ComputeIsOpaque(*bm)) {
   1.247 +            bm->setAlphaType(kOpaque_SkAlphaType);
   1.248 +        }
   1.249 +    }
   1.250 +
   1.251 +    return SUCCEEDED(hr);
   1.252 +}
   1.253 +
   1.254 +/////////////////////////////////////////////////////////////////////////
   1.255 +
   1.256 +extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
   1.257 +
   1.258 +SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
   1.259 +    SkImageDecoder* decoder = image_decoder_from_stream(stream);
   1.260 +    if (NULL == decoder) {
   1.261 +        // If no image decoder specific to the stream exists, use SkImageDecoder_WIC.
   1.262 +        return SkNEW(SkImageDecoder_WIC);
   1.263 +    } else {
   1.264 +        return decoder;
   1.265 +    }
   1.266 +}
   1.267 +
   1.268 +/////////////////////////////////////////////////////////////////////////
   1.269 +
   1.270 +SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
   1.271 +    return NULL;
   1.272 +}
   1.273 +
   1.274 +/////////////////////////////////////////////////////////////////////////
   1.275 +
   1.276 +class SkImageEncoder_WIC : public SkImageEncoder {
   1.277 +public:
   1.278 +    SkImageEncoder_WIC(Type t) : fType(t) {}
   1.279 +
   1.280 +protected:
   1.281 +    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
   1.282 +
   1.283 +private:
   1.284 +    Type fType;
   1.285 +};
   1.286 +
   1.287 +bool SkImageEncoder_WIC::onEncode(SkWStream* stream
   1.288 +                                , const SkBitmap& bitmapOrig
   1.289 +                                , int quality)
   1.290 +{
   1.291 +    GUID type;
   1.292 +    switch (fType) {
   1.293 +        case kBMP_Type:
   1.294 +            type = GUID_ContainerFormatBmp;
   1.295 +            break;
   1.296 +        case kICO_Type:
   1.297 +            type = GUID_ContainerFormatIco;
   1.298 +            break;
   1.299 +        case kJPEG_Type:
   1.300 +            type = GUID_ContainerFormatJpeg;
   1.301 +            break;
   1.302 +        case kPNG_Type:
   1.303 +            type = GUID_ContainerFormatPng;
   1.304 +            break;
   1.305 +        default:
   1.306 +            return false;
   1.307 +    }
   1.308 +
   1.309 +    //Convert to 8888 if needed.
   1.310 +    const SkBitmap* bitmap;
   1.311 +    SkBitmap bitmapCopy;
   1.312 +    if (kPMColor_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) {
   1.313 +        bitmap = &bitmapOrig;
   1.314 +    } else {
   1.315 +        if (!bitmapOrig.copyTo(&bitmapCopy, kPMColor_SkColorType)) {
   1.316 +            return false;
   1.317 +        }
   1.318 +        bitmap = &bitmapCopy;
   1.319 +    }
   1.320 +
   1.321 +    // We cannot use PBGRA so we need to unpremultiply ourselves
   1.322 +    if (!bitmap->isOpaque()) {
   1.323 +        SkAutoLockPixels alp(*bitmap);
   1.324 +
   1.325 +        uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels());
   1.326 +        for (int y = 0; y < bitmap->height(); ++y) {
   1.327 +            for (int x = 0; x < bitmap->width(); ++x) {
   1.328 +                uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel();
   1.329 +
   1.330 +                SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
   1.331 +                SkColor* dst = reinterpret_cast<SkColor*>(bytes);
   1.332 +
   1.333 +                *dst = SkUnPreMultiply::PMColorToColor(*src);
   1.334 +            }
   1.335 +        }
   1.336 +    }
   1.337 +
   1.338 +    //Initialize COM.
   1.339 +    SkAutoCoInitialize scopedCo;
   1.340 +    if (!scopedCo.succeeded()) {
   1.341 +        return false;
   1.342 +    }
   1.343 +
   1.344 +    HRESULT hr = S_OK;
   1.345 +
   1.346 +    //Create Windows Imaging Component ImagingFactory.
   1.347 +    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
   1.348 +    if (SUCCEEDED(hr)) {
   1.349 +        hr = CoCreateInstance(
   1.350 +            CLSID_WICImagingFactory
   1.351 +            , NULL
   1.352 +            , CLSCTX_INPROC_SERVER
   1.353 +            , IID_PPV_ARGS(&piImagingFactory)
   1.354 +        );
   1.355 +    }
   1.356 +
   1.357 +    //Convert the SkWStream to an IStream.
   1.358 +    SkTScopedComPtr<IStream> piStream;
   1.359 +    if (SUCCEEDED(hr)) {
   1.360 +        hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
   1.361 +    }
   1.362 +
   1.363 +    //Create an encode of the appropriate type.
   1.364 +    SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
   1.365 +    if (SUCCEEDED(hr)) {
   1.366 +        hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
   1.367 +    }
   1.368 +
   1.369 +    if (SUCCEEDED(hr)) {
   1.370 +        hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
   1.371 +    }
   1.372 +
   1.373 +    //Create a the frame.
   1.374 +    SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
   1.375 +    SkTScopedComPtr<IPropertyBag2> piPropertybag;
   1.376 +    if (SUCCEEDED(hr)) {
   1.377 +        hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
   1.378 +    }
   1.379 +
   1.380 +    if (SUCCEEDED(hr)) {
   1.381 +        PROPBAG2 name = { 0 };
   1.382 +        name.dwType = PROPBAG2_TYPE_DATA;
   1.383 +        name.vt = VT_R4;
   1.384 +        name.pstrName = L"ImageQuality";
   1.385 +
   1.386 +        VARIANT value;
   1.387 +        VariantInit(&value);
   1.388 +        value.vt = VT_R4;
   1.389 +        value.fltVal = (FLOAT)(quality / 100.0);
   1.390 +
   1.391 +        //Ignore result code.
   1.392 +        //  This returns E_FAIL if the named property is not in the bag.
   1.393 +        //TODO(bungeman) enumerate the properties,
   1.394 +        //  write and set hr iff property exists.
   1.395 +        piPropertybag->Write(1, &name, &value);
   1.396 +    }
   1.397 +    if (SUCCEEDED(hr)) {
   1.398 +        hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
   1.399 +    }
   1.400 +
   1.401 +    //Set the size of the frame.
   1.402 +    const UINT width = bitmap->width();
   1.403 +    const UINT height = bitmap->height();
   1.404 +    if (SUCCEEDED(hr)) {
   1.405 +        hr = piBitmapFrameEncode->SetSize(width, height);
   1.406 +    }
   1.407 +
   1.408 +    //Set the pixel format of the frame.
   1.409 +    const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
   1.410 +    WICPixelFormatGUID formatGUID = formatDesired;
   1.411 +    if (SUCCEEDED(hr)) {
   1.412 +        hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
   1.413 +    }
   1.414 +    if (SUCCEEDED(hr)) {
   1.415 +        //Be sure the image format is the one requested.
   1.416 +        hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
   1.417 +    }
   1.418 +
   1.419 +    //Write the pixels into the frame.
   1.420 +    if (SUCCEEDED(hr)) {
   1.421 +        SkAutoLockPixels alp(*bitmap);
   1.422 +        const UINT stride = (UINT) bitmap->rowBytes();
   1.423 +        hr = piBitmapFrameEncode->WritePixels(
   1.424 +            height
   1.425 +            , stride
   1.426 +            , stride * height
   1.427 +            , reinterpret_cast<BYTE*>(bitmap->getPixels()));
   1.428 +    }
   1.429 +
   1.430 +    if (SUCCEEDED(hr)) {
   1.431 +        hr = piBitmapFrameEncode->Commit();
   1.432 +    }
   1.433 +
   1.434 +    if (SUCCEEDED(hr)) {
   1.435 +        hr = piEncoder->Commit();
   1.436 +    }
   1.437 +
   1.438 +    return SUCCEEDED(hr);
   1.439 +}
   1.440 +
   1.441 +///////////////////////////////////////////////////////////////////////////////
   1.442 +
   1.443 +static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
   1.444 +    switch (t) {
   1.445 +        case SkImageEncoder::kBMP_Type:
   1.446 +        case SkImageEncoder::kICO_Type:
   1.447 +        case SkImageEncoder::kJPEG_Type:
   1.448 +        case SkImageEncoder::kPNG_Type:
   1.449 +            break;
   1.450 +        default:
   1.451 +            return NULL;
   1.452 +    }
   1.453 +    return SkNEW_ARGS(SkImageEncoder_WIC, (t));
   1.454 +}
   1.455 +
   1.456 +static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory);
   1.457 +
   1.458 +static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) {
   1.459 +    SkImageDecoder::Format format;
   1.460 +    SkImageDecoder_WIC codec;
   1.461 +    if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) {
   1.462 +        format = SkImageDecoder::kUnknown_Format;
   1.463 +    }
   1.464 +    return format;
   1.465 +}
   1.466 +
   1.467 +static SkImageDecoder_FormatReg gFormatReg(get_format_wic);

mercurial