2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/core/SkTypes.h"
10 #if defined(SK_BUILD_FOR_WIN)
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkImageEncoder.h"
14 #include "include/core/SkStream.h"
15 #include "include/core/SkUnPreMultiply.h"
16 #include "include/private/SkTemplates.h"
17 #include "src/core/SkAutoMalloc.h"
18 #include "src/images/SkImageEncoderPriv.h"
19 #include "src/utils/win/SkAutoCoInitialize.h"
20 #include "src/utils/win/SkIStream.h"
21 #include "src/utils/win/SkTScopedComPtr.h"
24 //All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
25 //In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
26 //but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
27 //Undo this #define if it has been done so that we link against the symbols
28 //we intended to link against on all SDKs.
29 #if defined(CLSID_WICImagingFactory)
30 #undef CLSID_WICImagingFactory
33 bool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap,
34 SkEncodedImageFormat format, int quality) {
37 case SkEncodedImageFormat::kJPEG:
38 type = GUID_ContainerFormatJpeg;
40 case SkEncodedImageFormat::kPNG:
41 type = GUID_ContainerFormatPng;
47 if (!bitmapOrig.installPixels(pixmap)) {
50 bitmapOrig.setImmutable();
52 // First convert to BGRA if necessary.
54 if (!bitmap.tryAllocPixels(bitmapOrig.info().makeColorType(kBGRA_8888_SkColorType)) ||
55 !bitmapOrig.readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0))
60 // WIC expects unpremultiplied pixels. Unpremultiply if necessary.
61 if (kPremul_SkAlphaType == bitmap.alphaType()) {
62 uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
63 for (int y = 0; y < bitmap.height(); ++y) {
64 for (int x = 0; x < bitmap.width(); ++x) {
65 uint8_t* bytes = pixels + y * bitmap.rowBytes() + x * bitmap.bytesPerPixel();
66 SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
67 SkColor* dst = reinterpret_cast<SkColor*>(bytes);
68 *dst = SkUnPreMultiply::PMColorToColor(*src);
73 // Finally, if we are performing a jpeg encode, we must convert to BGR.
74 void* pixels = bitmap.getPixels();
75 size_t rowBytes = bitmap.rowBytes();
76 SkAutoMalloc pixelStorage;
77 WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
78 if (SkEncodedImageFormat::kJPEG == format) {
79 formatDesired = GUID_WICPixelFormat24bppBGR;
80 rowBytes = SkAlign4(bitmap.width() * 3);
81 pixelStorage.reset(rowBytes * bitmap.height());
82 for (int y = 0; y < bitmap.height(); y++) {
83 uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes);
84 for (int x = 0; x < bitmap.width(); x++) {
85 uint32_t bgra = *bitmap.getAddr32(x, y);
86 dstRow[0] = (uint8_t) ((bgra >> 0) & 0xFF);
87 dstRow[1] = (uint8_t) ((bgra >> 8) & 0xFF);
88 dstRow[2] = (uint8_t) ((bgra >> 16) & 0xFF);
93 pixels = pixelStorage.get();
98 SkAutoCoInitialize scopedCo;
99 if (!scopedCo.succeeded()) {
105 //Create Windows Imaging Component ImagingFactory.
106 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
108 hr = CoCreateInstance(
109 CLSID_WICImagingFactory
111 , CLSCTX_INPROC_SERVER
112 , IID_PPV_ARGS(&piImagingFactory)
116 //Convert the SkWStream to an IStream.
117 SkTScopedComPtr<IStream> piStream;
119 hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
122 //Create an encode of the appropriate type.
123 SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
125 hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder);
129 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
132 //Create a the frame.
133 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
134 SkTScopedComPtr<IPropertyBag2> piPropertybag;
136 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
141 memset(&name, 0, sizeof(name));
142 name.dwType = PROPBAG2_TYPE_DATA;
144 name.pstrName = const_cast<LPOLESTR>(L"ImageQuality");
149 value.fltVal = (FLOAT)(quality / 100.0);
151 //Ignore result code.
152 // This returns E_FAIL if the named property is not in the bag.
153 //TODO(bungeman) enumerate the properties,
154 // write and set hr iff property exists.
155 piPropertybag->Write(1, &name, &value);
158 hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
161 //Set the size of the frame.
162 const UINT width = bitmap.width();
163 const UINT height = bitmap.height();
165 hr = piBitmapFrameEncode->SetSize(width, height);
168 //Set the pixel format of the frame. If native encoded format cannot match BGRA,
169 //it will choose the closest pixel format that it supports.
170 WICPixelFormatGUID formatGUID = formatDesired;
172 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
175 //Be sure the image format is the one requested.
176 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
179 //Write the pixels into the frame.
181 hr = piBitmapFrameEncode->WritePixels(height,
183 (UINT) rowBytes * height,
184 reinterpret_cast<BYTE*>(pixels));
188 hr = piBitmapFrameEncode->Commit();
192 hr = piEncoder->Commit();
195 return SUCCEEDED(hr);
198 #endif // defined(SK_BUILD_FOR_WIN)