1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_WIN) 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 13cb93a386Sopenharmony_ci#include "include/core/SkImageEncoder.h" 14cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 15cb93a386Sopenharmony_ci#include "include/core/SkUnPreMultiply.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 17cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 18cb93a386Sopenharmony_ci#include "src/images/SkImageEncoderPriv.h" 19cb93a386Sopenharmony_ci#include "src/utils/win/SkAutoCoInitialize.h" 20cb93a386Sopenharmony_ci#include "src/utils/win/SkIStream.h" 21cb93a386Sopenharmony_ci#include "src/utils/win/SkTScopedComPtr.h" 22cb93a386Sopenharmony_ci#include <wincodec.h> 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol. 25cb93a386Sopenharmony_ci//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported 26cb93a386Sopenharmony_ci//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2. 27cb93a386Sopenharmony_ci//Undo this #define if it has been done so that we link against the symbols 28cb93a386Sopenharmony_ci//we intended to link against on all SDKs. 29cb93a386Sopenharmony_ci#if defined(CLSID_WICImagingFactory) 30cb93a386Sopenharmony_ci#undef CLSID_WICImagingFactory 31cb93a386Sopenharmony_ci#endif 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cibool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap, 34cb93a386Sopenharmony_ci SkEncodedImageFormat format, int quality) { 35cb93a386Sopenharmony_ci GUID type; 36cb93a386Sopenharmony_ci switch (format) { 37cb93a386Sopenharmony_ci case SkEncodedImageFormat::kJPEG: 38cb93a386Sopenharmony_ci type = GUID_ContainerFormatJpeg; 39cb93a386Sopenharmony_ci break; 40cb93a386Sopenharmony_ci case SkEncodedImageFormat::kPNG: 41cb93a386Sopenharmony_ci type = GUID_ContainerFormatPng; 42cb93a386Sopenharmony_ci break; 43cb93a386Sopenharmony_ci default: 44cb93a386Sopenharmony_ci return false; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci SkBitmap bitmapOrig; 47cb93a386Sopenharmony_ci if (!bitmapOrig.installPixels(pixmap)) { 48cb93a386Sopenharmony_ci return false; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci bitmapOrig.setImmutable(); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci // First convert to BGRA if necessary. 53cb93a386Sopenharmony_ci SkBitmap bitmap; 54cb93a386Sopenharmony_ci if (!bitmap.tryAllocPixels(bitmapOrig.info().makeColorType(kBGRA_8888_SkColorType)) || 55cb93a386Sopenharmony_ci !bitmapOrig.readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0)) 56cb93a386Sopenharmony_ci { 57cb93a386Sopenharmony_ci return false; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci // WIC expects unpremultiplied pixels. Unpremultiply if necessary. 61cb93a386Sopenharmony_ci if (kPremul_SkAlphaType == bitmap.alphaType()) { 62cb93a386Sopenharmony_ci uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels()); 63cb93a386Sopenharmony_ci for (int y = 0; y < bitmap.height(); ++y) { 64cb93a386Sopenharmony_ci for (int x = 0; x < bitmap.width(); ++x) { 65cb93a386Sopenharmony_ci uint8_t* bytes = pixels + y * bitmap.rowBytes() + x * bitmap.bytesPerPixel(); 66cb93a386Sopenharmony_ci SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes); 67cb93a386Sopenharmony_ci SkColor* dst = reinterpret_cast<SkColor*>(bytes); 68cb93a386Sopenharmony_ci *dst = SkUnPreMultiply::PMColorToColor(*src); 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci // Finally, if we are performing a jpeg encode, we must convert to BGR. 74cb93a386Sopenharmony_ci void* pixels = bitmap.getPixels(); 75cb93a386Sopenharmony_ci size_t rowBytes = bitmap.rowBytes(); 76cb93a386Sopenharmony_ci SkAutoMalloc pixelStorage; 77cb93a386Sopenharmony_ci WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; 78cb93a386Sopenharmony_ci if (SkEncodedImageFormat::kJPEG == format) { 79cb93a386Sopenharmony_ci formatDesired = GUID_WICPixelFormat24bppBGR; 80cb93a386Sopenharmony_ci rowBytes = SkAlign4(bitmap.width() * 3); 81cb93a386Sopenharmony_ci pixelStorage.reset(rowBytes * bitmap.height()); 82cb93a386Sopenharmony_ci for (int y = 0; y < bitmap.height(); y++) { 83cb93a386Sopenharmony_ci uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes); 84cb93a386Sopenharmony_ci for (int x = 0; x < bitmap.width(); x++) { 85cb93a386Sopenharmony_ci uint32_t bgra = *bitmap.getAddr32(x, y); 86cb93a386Sopenharmony_ci dstRow[0] = (uint8_t) ((bgra >> 0) & 0xFF); 87cb93a386Sopenharmony_ci dstRow[1] = (uint8_t) ((bgra >> 8) & 0xFF); 88cb93a386Sopenharmony_ci dstRow[2] = (uint8_t) ((bgra >> 16) & 0xFF); 89cb93a386Sopenharmony_ci dstRow += 3; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci pixels = pixelStorage.get(); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci //Initialize COM. 98cb93a386Sopenharmony_ci SkAutoCoInitialize scopedCo; 99cb93a386Sopenharmony_ci if (!scopedCo.succeeded()) { 100cb93a386Sopenharmony_ci return false; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci HRESULT hr = S_OK; 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci //Create Windows Imaging Component ImagingFactory. 106cb93a386Sopenharmony_ci SkTScopedComPtr<IWICImagingFactory> piImagingFactory; 107cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 108cb93a386Sopenharmony_ci hr = CoCreateInstance( 109cb93a386Sopenharmony_ci CLSID_WICImagingFactory 110cb93a386Sopenharmony_ci , nullptr 111cb93a386Sopenharmony_ci , CLSCTX_INPROC_SERVER 112cb93a386Sopenharmony_ci , IID_PPV_ARGS(&piImagingFactory) 113cb93a386Sopenharmony_ci ); 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci //Convert the SkWStream to an IStream. 117cb93a386Sopenharmony_ci SkTScopedComPtr<IStream> piStream; 118cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 119cb93a386Sopenharmony_ci hr = SkWIStream::CreateFromSkWStream(stream, &piStream); 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci //Create an encode of the appropriate type. 123cb93a386Sopenharmony_ci SkTScopedComPtr<IWICBitmapEncoder> piEncoder; 124cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 125cb93a386Sopenharmony_ci hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder); 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 129cb93a386Sopenharmony_ci hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci //Create a the frame. 133cb93a386Sopenharmony_ci SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; 134cb93a386Sopenharmony_ci SkTScopedComPtr<IPropertyBag2> piPropertybag; 135cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 136cb93a386Sopenharmony_ci hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 140cb93a386Sopenharmony_ci PROPBAG2 name; 141cb93a386Sopenharmony_ci memset(&name, 0, sizeof(name)); 142cb93a386Sopenharmony_ci name.dwType = PROPBAG2_TYPE_DATA; 143cb93a386Sopenharmony_ci name.vt = VT_R4; 144cb93a386Sopenharmony_ci name.pstrName = const_cast<LPOLESTR>(L"ImageQuality"); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci VARIANT value; 147cb93a386Sopenharmony_ci VariantInit(&value); 148cb93a386Sopenharmony_ci value.vt = VT_R4; 149cb93a386Sopenharmony_ci value.fltVal = (FLOAT)(quality / 100.0); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci //Ignore result code. 152cb93a386Sopenharmony_ci // This returns E_FAIL if the named property is not in the bag. 153cb93a386Sopenharmony_ci //TODO(bungeman) enumerate the properties, 154cb93a386Sopenharmony_ci // write and set hr iff property exists. 155cb93a386Sopenharmony_ci piPropertybag->Write(1, &name, &value); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 158cb93a386Sopenharmony_ci hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci //Set the size of the frame. 162cb93a386Sopenharmony_ci const UINT width = bitmap.width(); 163cb93a386Sopenharmony_ci const UINT height = bitmap.height(); 164cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 165cb93a386Sopenharmony_ci hr = piBitmapFrameEncode->SetSize(width, height); 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci //Set the pixel format of the frame. If native encoded format cannot match BGRA, 169cb93a386Sopenharmony_ci //it will choose the closest pixel format that it supports. 170cb93a386Sopenharmony_ci WICPixelFormatGUID formatGUID = formatDesired; 171cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 172cb93a386Sopenharmony_ci hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 175cb93a386Sopenharmony_ci //Be sure the image format is the one requested. 176cb93a386Sopenharmony_ci hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci //Write the pixels into the frame. 180cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 181cb93a386Sopenharmony_ci hr = piBitmapFrameEncode->WritePixels(height, 182cb93a386Sopenharmony_ci (UINT) rowBytes, 183cb93a386Sopenharmony_ci (UINT) rowBytes * height, 184cb93a386Sopenharmony_ci reinterpret_cast<BYTE*>(pixels)); 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 188cb93a386Sopenharmony_ci hr = piBitmapFrameEncode->Commit(); 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 192cb93a386Sopenharmony_ci hr = piEncoder->Commit(); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci return SUCCEEDED(hr); 196cb93a386Sopenharmony_ci} 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci#endif // defined(SK_BUILD_FOR_WIN) 199