blob: 43068fc8f6b74985e496dfb06acadf358b58d831 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bungeman@google.com242bb892011-06-22 20:42:34 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
bungeman@google.com242bb892011-06-22 20:42:34 +00007 */
8
bungeman@google.com85302962013-10-11 20:04:08 +00009#include "SkTypes.h"
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
mtklein1ee76512015-11-02 10:20:27 -080011#if defined(SK_BUILD_FOR_WIN32)
12
bungeman@google.com85302962013-10-11 20:04:08 +000013// 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
bungeman@google.com242bb892011-06-22 20:42:34 +000032#include <wincodec.h>
bungeman@google.com9df621d2011-06-23 21:43:52 +000033#include "SkAutoCoInitialize.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000034#include "SkImageEncoder.h"
bungeman@google.com9df621d2011-06-23 21:43:52 +000035#include "SkIStream.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000036#include "SkMovie.h"
37#include "SkStream.h"
bungeman@google.com9df621d2011-06-23 21:43:52 +000038#include "SkTScopedComPtr.h"
robertphillips@google.com59bfb122012-11-08 15:06:52 +000039#include "SkUnPreMultiply.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000040
bungeman@google.comc18143e2013-01-11 20:02:32 +000041//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
42//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
43//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
44//Undo this #define if it has been done so that we link against the symbols
45//we intended to link against on all SDKs.
46#if defined(CLSID_WICImagingFactory)
47#undef CLSID_WICImagingFactory
48#endif
49
bungeman@google.com242bb892011-06-22 20:42:34 +000050/////////////////////////////////////////////////////////////////////////
51
scroggo@google.comb5571b32013-09-25 21:34:24 +000052SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
halcanary96fcdcc2015-08-27 07:41:13 -070053 return nullptr;
bungeman@google.com242bb892011-06-22 20:42:34 +000054}
55
56/////////////////////////////////////////////////////////////////////////
57
58class SkImageEncoder_WIC : public SkImageEncoder {
59public:
60 SkImageEncoder_WIC(Type t) : fType(t) {}
msarette8597a42016-03-24 10:41:47 -070061
62 // DO NOT USE this constructor. This exists only so SkForceLinking can
63 // link the WIC image encoder.
64 SkImageEncoder_WIC() {}
bungeman@google.com242bb892011-06-22 20:42:34 +000065
66protected:
67 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
68
69private:
70 Type fType;
71};
72
73bool SkImageEncoder_WIC::onEncode(SkWStream* stream
bungeman@google.com22b49502011-08-01 19:37:43 +000074 , const SkBitmap& bitmapOrig
bungeman@google.com242bb892011-06-22 20:42:34 +000075 , int quality)
76{
77 GUID type;
78 switch (fType) {
scroggo@google.com4c6adf92013-04-17 21:07:55 +000079 case kBMP_Type:
80 type = GUID_ContainerFormatBmp;
81 break;
scroggo@google.com4c6adf92013-04-17 21:07:55 +000082 case kICO_Type:
83 type = GUID_ContainerFormatIco;
84 break;
bungeman@google.com242bb892011-06-22 20:42:34 +000085 case kJPEG_Type:
86 type = GUID_ContainerFormatJpeg;
87 break;
88 case kPNG_Type:
89 type = GUID_ContainerFormatPng;
90 break;
91 default:
92 return false;
93 }
94
bungeman@google.com22b49502011-08-01 19:37:43 +000095 //Convert to 8888 if needed.
96 const SkBitmap* bitmap;
97 SkBitmap bitmapCopy;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000098 if (kN32_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) {
bungeman@google.com22b49502011-08-01 19:37:43 +000099 bitmap = &bitmapOrig;
100 } else {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000101 if (!bitmapOrig.copyTo(&bitmapCopy, kN32_SkColorType)) {
bungeman@google.com22b49502011-08-01 19:37:43 +0000102 return false;
103 }
104 bitmap = &bitmapCopy;
105 }
106
robertphillips@google.com59bfb122012-11-08 15:06:52 +0000107 // We cannot use PBGRA so we need to unpremultiply ourselves
108 if (!bitmap->isOpaque()) {
109 SkAutoLockPixels alp(*bitmap);
110
111 uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels());
112 for (int y = 0; y < bitmap->height(); ++y) {
113 for (int x = 0; x < bitmap->width(); ++x) {
114 uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel();
115
116 SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
117 SkColor* dst = reinterpret_cast<SkColor*>(bytes);
118
119 *dst = SkUnPreMultiply::PMColorToColor(*src);
120 }
121 }
122 }
123
bungeman@google.com242bb892011-06-22 20:42:34 +0000124 //Initialize COM.
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000125 SkAutoCoInitialize scopedCo;
126 if (!scopedCo.succeeded()) {
127 return false;
128 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000129
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000130 HRESULT hr = S_OK;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000131
bungeman@google.com242bb892011-06-22 20:42:34 +0000132 //Create Windows Imaging Component ImagingFactory.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000133 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
bungeman@google.com242bb892011-06-22 20:42:34 +0000134 if (SUCCEEDED(hr)) {
135 hr = CoCreateInstance(
136 CLSID_WICImagingFactory
halcanary96fcdcc2015-08-27 07:41:13 -0700137 , nullptr
bungeman@google.com242bb892011-06-22 20:42:34 +0000138 , CLSCTX_INPROC_SERVER
139 , IID_PPV_ARGS(&piImagingFactory)
140 );
141 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000142
bungeman@google.com9df621d2011-06-23 21:43:52 +0000143 //Convert the SkWStream to an IStream.
144 SkTScopedComPtr<IStream> piStream;
bungeman@google.com242bb892011-06-22 20:42:34 +0000145 if (SUCCEEDED(hr)) {
bungeman@google.com9df621d2011-06-23 21:43:52 +0000146 hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
bungeman@google.com242bb892011-06-22 20:42:34 +0000147 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000148
bungeman@google.com242bb892011-06-22 20:42:34 +0000149 //Create an encode of the appropriate type.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000150 SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
bungeman@google.com242bb892011-06-22 20:42:34 +0000151 if (SUCCEEDED(hr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700152 hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder);
bungeman@google.com242bb892011-06-22 20:42:34 +0000153 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000154
bungeman@google.com242bb892011-06-22 20:42:34 +0000155 if (SUCCEEDED(hr)) {
156 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
157 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000158
bungeman@google.com242bb892011-06-22 20:42:34 +0000159 //Create a the frame.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000160 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
161 SkTScopedComPtr<IPropertyBag2> piPropertybag;
bungeman@google.com242bb892011-06-22 20:42:34 +0000162 if (SUCCEEDED(hr)) {
163 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
164 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000165
bungeman@google.com242bb892011-06-22 20:42:34 +0000166 if (SUCCEEDED(hr)) {
167 PROPBAG2 name = { 0 };
168 name.dwType = PROPBAG2_TYPE_DATA;
169 name.vt = VT_R4;
170 name.pstrName = L"ImageQuality";
rmistry@google.comd6176b02012-08-23 18:14:13 +0000171
bungeman@google.com242bb892011-06-22 20:42:34 +0000172 VARIANT value;
173 VariantInit(&value);
174 value.vt = VT_R4;
175 value.fltVal = (FLOAT)(quality / 100.0);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000176
bungeman@google.com242bb892011-06-22 20:42:34 +0000177 //Ignore result code.
178 // This returns E_FAIL if the named property is not in the bag.
179 //TODO(bungeman) enumerate the properties,
180 // write and set hr iff property exists.
181 piPropertybag->Write(1, &name, &value);
182 }
183 if (SUCCEEDED(hr)) {
184 hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
185 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000186
bungeman@google.com242bb892011-06-22 20:42:34 +0000187 //Set the size of the frame.
bungeman@google.com22b49502011-08-01 19:37:43 +0000188 const UINT width = bitmap->width();
189 const UINT height = bitmap->height();
bungeman@google.com242bb892011-06-22 20:42:34 +0000190 if (SUCCEEDED(hr)) {
191 hr = piBitmapFrameEncode->SetSize(width, height);
192 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000193
msarette820dfe2016-03-18 12:13:47 -0700194 //Set the pixel format of the frame. If native encoded format cannot match BGRA,
195 //it will choose the closest pixel format that it supports.
bungeman@google.com242bb892011-06-22 20:42:34 +0000196 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
197 WICPixelFormatGUID formatGUID = formatDesired;
198 if (SUCCEEDED(hr)) {
199 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
200 }
msarett60316a92016-03-21 13:35:43 -0700201 if (SUCCEEDED(hr)) {
202 //Be sure the image format is the one requested.
203 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
204 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000205
bungeman@google.com242bb892011-06-22 20:42:34 +0000206 //Write the pixels into the frame.
207 if (SUCCEEDED(hr)) {
bungeman@google.com955bb072011-08-01 20:18:45 +0000208 SkAutoLockPixels alp(*bitmap);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000209 const UINT stride = (UINT) bitmap->rowBytes();
bungeman@google.com242bb892011-06-22 20:42:34 +0000210 hr = piBitmapFrameEncode->WritePixels(
211 height
bungeman@google.com4b18f572013-07-22 15:21:23 +0000212 , stride
213 , stride * height
bungeman@google.com22b49502011-08-01 19:37:43 +0000214 , reinterpret_cast<BYTE*>(bitmap->getPixels()));
bungeman@google.com242bb892011-06-22 20:42:34 +0000215 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000216
bungeman@google.com242bb892011-06-22 20:42:34 +0000217 if (SUCCEEDED(hr)) {
218 hr = piBitmapFrameEncode->Commit();
219 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000220
bungeman@google.com242bb892011-06-22 20:42:34 +0000221 if (SUCCEEDED(hr)) {
222 hr = piEncoder->Commit();
223 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000224
bungeman@google.com242bb892011-06-22 20:42:34 +0000225 return SUCCEEDED(hr);
226}
227
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000228///////////////////////////////////////////////////////////////////////////////
229
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000230static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
bungeman@google.com242bb892011-06-22 20:42:34 +0000231 switch (t) {
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000232 case SkImageEncoder::kBMP_Type:
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000233 case SkImageEncoder::kICO_Type:
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000234 case SkImageEncoder::kPNG_Type:
bungeman@google.com242bb892011-06-22 20:42:34 +0000235 break;
236 default:
halcanary96fcdcc2015-08-27 07:41:13 -0700237 return nullptr;
bungeman@google.com242bb892011-06-22 20:42:34 +0000238 }
halcanary385fe4d2015-08-26 13:07:48 -0700239 return new SkImageEncoder_WIC(t);
bungeman@google.com242bb892011-06-22 20:42:34 +0000240}
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000241
scroggo@google.comb5571b32013-09-25 21:34:24 +0000242static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory);
scroggo@google.com39edf4c2013-04-25 17:33:51 +0000243
msarette8597a42016-03-24 10:41:47 -0700244DEFINE_ENCODER_CREATOR(ImageEncoder_WIC);
msarett39b54952016-03-23 12:26:29 -0700245
mtklein1ee76512015-11-02 10:20:27 -0800246#endif // defined(SK_BUILD_FOR_WIN32)