blob: 74b2c391959a7a0b3456702c1e41ca27a4ad8a93 [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
bungeman@google.com85302962013-10-11 20:04:08 +000011// Workaround for:
12// http://connect.microsoft.com/VisualStudio/feedback/details/621653/
13// http://crbug.com/225822
14// In VS2010 both intsafe.h and stdint.h define the following without guards.
15// SkTypes brought in windows.h and stdint.h and the following defines are
16// not used by this file. However, they may be re-introduced by wincodec.h.
17#undef INT8_MIN
18#undef INT16_MIN
19#undef INT32_MIN
20#undef INT64_MIN
21#undef INT8_MAX
22#undef UINT8_MAX
23#undef INT16_MAX
24#undef UINT16_MAX
25#undef INT32_MAX
26#undef UINT32_MAX
27#undef INT64_MAX
28#undef UINT64_MAX
29
bungeman@google.com242bb892011-06-22 20:42:34 +000030#include <wincodec.h>
bungeman@google.com9df621d2011-06-23 21:43:52 +000031#include "SkAutoCoInitialize.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000032#include "SkImageDecoder.h"
33#include "SkImageEncoder.h"
bungeman@google.com9df621d2011-06-23 21:43:52 +000034#include "SkIStream.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000035#include "SkMovie.h"
36#include "SkStream.h"
bungeman@google.com9df621d2011-06-23 21:43:52 +000037#include "SkTScopedComPtr.h"
robertphillips@google.com59bfb122012-11-08 15:06:52 +000038#include "SkUnPreMultiply.h"
bungeman@google.com242bb892011-06-22 20:42:34 +000039
bungeman@google.comc18143e2013-01-11 20:02:32 +000040//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
41//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
42//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
43//Undo this #define if it has been done so that we link against the symbols
44//we intended to link against on all SDKs.
45#if defined(CLSID_WICImagingFactory)
46#undef CLSID_WICImagingFactory
47#endif
48
bungeman@google.com242bb892011-06-22 20:42:34 +000049class SkImageDecoder_WIC : public SkImageDecoder {
scroggo@google.com39edf4c2013-04-25 17:33:51 +000050public:
51 // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding
52 // only the format.
53 enum WICModes {
54 kDecodeFormat_WICMode,
55 kDecodeBounds_WICMode,
56 kDecodePixels_WICMode,
57 };
58
59 /**
60 * Helper function to decode an SkStream.
61 * @param stream SkStream to decode. Must be at the beginning.
62 * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or
63 * kDecodePixels_WICMode, in which case it must not be NULL.
64 * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if
65 * wicMode is kDecodeFormat_WICMode.
66 */
67 bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
68
bungeman@google.com242bb892011-06-22 20:42:34 +000069protected:
scroggo@google.com39edf4c2013-04-25 17:33:51 +000070 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
bungeman@google.com242bb892011-06-22 20:42:34 +000071};
72
scroggo@google.com39edf4c2013-04-25 17:33:51 +000073struct FormatConversion {
74 GUID fGuidFormat;
75 SkImageDecoder::Format fFormat;
76};
77
78static const FormatConversion gFormatConversions[] = {
79 { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format },
80 { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format },
81 { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format },
82 { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format },
83 { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format },
84};
85
86static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) {
87 for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
88 if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) {
89 return gFormatConversions[i].fFormat;
90 }
91 }
92 return SkImageDecoder::kUnknown_Format;
93}
94
bungeman@google.com242bb892011-06-22 20:42:34 +000095bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
scroggo@google.com39edf4c2013-04-25 17:33:51 +000096 WICModes wicMode;
97 switch (mode) {
98 case SkImageDecoder::kDecodeBounds_Mode:
99 wicMode = kDecodeBounds_WICMode;
100 break;
101 case SkImageDecoder::kDecodePixels_Mode:
102 wicMode = kDecodePixels_WICMode;
103 break;
104 }
105 return this->decodeStream(stream, bm, wicMode, NULL);
106}
107
108bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
109 Format* format) const {
bungeman@google.com242bb892011-06-22 20:42:34 +0000110 //Initialize COM.
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000111 SkAutoCoInitialize scopedCo;
112 if (!scopedCo.succeeded()) {
113 return false;
114 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000116 HRESULT hr = S_OK;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000117
bungeman@google.com242bb892011-06-22 20:42:34 +0000118 //Create Windows Imaging Component ImagingFactory.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000119 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
bungeman@google.com242bb892011-06-22 20:42:34 +0000120 if (SUCCEEDED(hr)) {
121 hr = CoCreateInstance(
122 CLSID_WICImagingFactory
123 , NULL
124 , CLSCTX_INPROC_SERVER
125 , IID_PPV_ARGS(&piImagingFactory)
126 );
127 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000128
bungeman@google.com242bb892011-06-22 20:42:34 +0000129 //Convert SkStream to IStream.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000130 SkTScopedComPtr<IStream> piStream;
bungeman@google.com242bb892011-06-22 20:42:34 +0000131 if (SUCCEEDED(hr)) {
bungeman@google.com9df621d2011-06-23 21:43:52 +0000132 hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
bungeman@google.com242bb892011-06-22 20:42:34 +0000133 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000134
bungeman@google.com242bb892011-06-22 20:42:34 +0000135 //Make sure we're at the beginning of the stream.
136 if (SUCCEEDED(hr)) {
137 LARGE_INTEGER liBeginning = { 0 };
138 hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
139 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000140
bungeman@google.com242bb892011-06-22 20:42:34 +0000141 //Create the decoder from the stream content.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000142 SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
bungeman@google.com242bb892011-06-22 20:42:34 +0000143 if (SUCCEEDED(hr)) {
144 hr = piImagingFactory->CreateDecoderFromStream(
145 piStream.get() //Image to be decoded
146 , NULL //No particular vendor
147 , WICDecodeMetadataCacheOnDemand //Cache metadata when needed
148 , &piBitmapDecoder //Pointer to the decoder
149 );
150 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000151
scroggo@google.com39edf4c2013-04-25 17:33:51 +0000152 if (kDecodeFormat_WICMode == wicMode) {
153 SkASSERT(format != NULL);
154 //Get the format
155 if (SUCCEEDED(hr)) {
156 GUID guidFormat;
157 hr = piBitmapDecoder->GetContainerFormat(&guidFormat);
158 if (SUCCEEDED(hr)) {
159 *format = GuidContainerFormat_to_Format(guidFormat);
160 return true;
161 }
162 }
163 return false;
164 }
165
bungeman@google.com242bb892011-06-22 20:42:34 +0000166 //Get the first frame from the decoder.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000167 SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
bungeman@google.com242bb892011-06-22 20:42:34 +0000168 if (SUCCEEDED(hr)) {
169 hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
170 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000171
bungeman@google.com242bb892011-06-22 20:42:34 +0000172 //Get the BitmapSource interface of the frame.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000173 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
bungeman@google.com242bb892011-06-22 20:42:34 +0000174 if (SUCCEEDED(hr)) {
175 hr = piBitmapFrameDecode->QueryInterface(
176 IID_PPV_ARGS(&piBitmapSourceOriginal)
177 );
178 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000179
bungeman@google.com242bb892011-06-22 20:42:34 +0000180 //Get the size of the bitmap.
181 UINT width;
182 UINT height;
183 if (SUCCEEDED(hr)) {
184 hr = piBitmapSourceOriginal->GetSize(&width, &height);
185 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000186
bungeman@google.com242bb892011-06-22 20:42:34 +0000187 //Exit early if we're only looking for the bitmap bounds.
188 if (SUCCEEDED(hr)) {
reed@google.come9336aa2014-02-24 13:13:26 +0000189 bm->setConfig(SkImageInfo::MakeN32Premul(width, height));
scroggo@google.com39edf4c2013-04-25 17:33:51 +0000190 if (kDecodeBounds_WICMode == wicMode) {
bungeman@google.com242bb892011-06-22 20:42:34 +0000191 return true;
192 }
193 if (!this->allocPixelRef(bm, NULL)) {
194 return false;
195 }
196 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000197
bungeman@google.com242bb892011-06-22 20:42:34 +0000198 //Create a format converter.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000199 SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
bungeman@google.com242bb892011-06-22 20:42:34 +0000200 if (SUCCEEDED(hr)) {
201 hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
202 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000203
scroggo@google.com2bbc2c92013-06-14 15:33:20 +0000204 GUID destinationPixelFormat;
205 if (this->getRequireUnpremultipliedColors()) {
206 destinationPixelFormat = GUID_WICPixelFormat32bppBGRA;
207 } else {
208 destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA;
209 }
210
bungeman@google.com242bb892011-06-22 20:42:34 +0000211 if (SUCCEEDED(hr)) {
212 hr = piFormatConverter->Initialize(
213 piBitmapSourceOriginal.get() //Input bitmap to convert
scroggo@google.com2bbc2c92013-06-14 15:33:20 +0000214 , destinationPixelFormat //Destination pixel format
bungeman@google.com242bb892011-06-22 20:42:34 +0000215 , WICBitmapDitherTypeNone //Specified dither patterm
216 , NULL //Specify a particular palette
217 , 0.f //Alpha threshold
218 , WICBitmapPaletteTypeCustom //Palette translation type
219 );
220 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000221
bungeman@google.com242bb892011-06-22 20:42:34 +0000222 //Get the BitmapSource interface of the format converter.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000223 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
bungeman@google.com242bb892011-06-22 20:42:34 +0000224 if (SUCCEEDED(hr)) {
225 hr = piFormatConverter->QueryInterface(
226 IID_PPV_ARGS(&piBitmapSourceConverted)
227 );
228 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000229
bungeman@google.com242bb892011-06-22 20:42:34 +0000230 //Copy the pixels into the bitmap.
231 if (SUCCEEDED(hr)) {
bungeman@google.com955bb072011-08-01 20:18:45 +0000232 SkAutoLockPixels alp(*bm);
junov@google.comdbfac8a2012-12-06 21:47:40 +0000233 bm->eraseColor(SK_ColorTRANSPARENT);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000234 const UINT stride = (UINT) bm->rowBytes();
bungeman@google.com242bb892011-06-22 20:42:34 +0000235 hr = piBitmapSourceConverted->CopyPixels(
236 NULL, //Get all the pixels
237 stride,
238 stride * height,
239 reinterpret_cast<BYTE *>(bm->getPixels())
240 );
robertphillips@google.com59bfb122012-11-08 15:06:52 +0000241
242 // Note: we don't need to premultiply here since we specified PBGRA
reed@google.come7e29b72013-10-21 14:31:20 +0000243 if (SkBitmap::ComputeIsOpaque(*bm)) {
reed@google.com383a6972013-10-21 14:00:07 +0000244 bm->setAlphaType(kOpaque_SkAlphaType);
245 }
bungeman@google.com242bb892011-06-22 20:42:34 +0000246 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000247
bungeman@google.com242bb892011-06-22 20:42:34 +0000248 return SUCCEEDED(hr);
249}
250
251/////////////////////////////////////////////////////////////////////////
252
scroggo@google.comb5571b32013-09-25 21:34:24 +0000253extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000254
scroggo@google.comb5571b32013-09-25 21:34:24 +0000255SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000256 SkImageDecoder* decoder = image_decoder_from_stream(stream);
257 if (NULL == decoder) {
258 // If no image decoder specific to the stream exists, use SkImageDecoder_WIC.
259 return SkNEW(SkImageDecoder_WIC);
260 } else {
261 return decoder;
262 }
bungeman@google.com242bb892011-06-22 20:42:34 +0000263}
264
265/////////////////////////////////////////////////////////////////////////
266
scroggo@google.comb5571b32013-09-25 21:34:24 +0000267SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
bungeman@google.com242bb892011-06-22 20:42:34 +0000268 return NULL;
269}
270
271/////////////////////////////////////////////////////////////////////////
272
273class SkImageEncoder_WIC : public SkImageEncoder {
274public:
275 SkImageEncoder_WIC(Type t) : fType(t) {}
276
277protected:
278 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
279
280private:
281 Type fType;
282};
283
284bool SkImageEncoder_WIC::onEncode(SkWStream* stream
bungeman@google.com22b49502011-08-01 19:37:43 +0000285 , const SkBitmap& bitmapOrig
bungeman@google.com242bb892011-06-22 20:42:34 +0000286 , int quality)
287{
288 GUID type;
289 switch (fType) {
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000290 case kBMP_Type:
291 type = GUID_ContainerFormatBmp;
292 break;
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000293 case kICO_Type:
294 type = GUID_ContainerFormatIco;
295 break;
bungeman@google.com242bb892011-06-22 20:42:34 +0000296 case kJPEG_Type:
297 type = GUID_ContainerFormatJpeg;
298 break;
299 case kPNG_Type:
300 type = GUID_ContainerFormatPng;
301 break;
302 default:
303 return false;
304 }
305
bungeman@google.com22b49502011-08-01 19:37:43 +0000306 //Convert to 8888 if needed.
307 const SkBitmap* bitmap;
308 SkBitmap bitmapCopy;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000309 if (kN32_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) {
bungeman@google.com22b49502011-08-01 19:37:43 +0000310 bitmap = &bitmapOrig;
311 } else {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000312 if (!bitmapOrig.copyTo(&bitmapCopy, kN32_SkColorType)) {
bungeman@google.com22b49502011-08-01 19:37:43 +0000313 return false;
314 }
315 bitmap = &bitmapCopy;
316 }
317
robertphillips@google.com59bfb122012-11-08 15:06:52 +0000318 // We cannot use PBGRA so we need to unpremultiply ourselves
319 if (!bitmap->isOpaque()) {
320 SkAutoLockPixels alp(*bitmap);
321
322 uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels());
323 for (int y = 0; y < bitmap->height(); ++y) {
324 for (int x = 0; x < bitmap->width(); ++x) {
325 uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel();
326
327 SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
328 SkColor* dst = reinterpret_cast<SkColor*>(bytes);
329
330 *dst = SkUnPreMultiply::PMColorToColor(*src);
331 }
332 }
333 }
334
bungeman@google.com242bb892011-06-22 20:42:34 +0000335 //Initialize COM.
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000336 SkAutoCoInitialize scopedCo;
337 if (!scopedCo.succeeded()) {
338 return false;
339 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000340
bungeman@google.com2e2f3f52011-09-16 15:37:20 +0000341 HRESULT hr = S_OK;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000342
bungeman@google.com242bb892011-06-22 20:42:34 +0000343 //Create Windows Imaging Component ImagingFactory.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000344 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
bungeman@google.com242bb892011-06-22 20:42:34 +0000345 if (SUCCEEDED(hr)) {
346 hr = CoCreateInstance(
347 CLSID_WICImagingFactory
348 , NULL
349 , CLSCTX_INPROC_SERVER
350 , IID_PPV_ARGS(&piImagingFactory)
351 );
352 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000353
bungeman@google.com9df621d2011-06-23 21:43:52 +0000354 //Convert the SkWStream to an IStream.
355 SkTScopedComPtr<IStream> piStream;
bungeman@google.com242bb892011-06-22 20:42:34 +0000356 if (SUCCEEDED(hr)) {
bungeman@google.com9df621d2011-06-23 21:43:52 +0000357 hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
bungeman@google.com242bb892011-06-22 20:42:34 +0000358 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000359
bungeman@google.com242bb892011-06-22 20:42:34 +0000360 //Create an encode of the appropriate type.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000361 SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
bungeman@google.com242bb892011-06-22 20:42:34 +0000362 if (SUCCEEDED(hr)) {
363 hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
364 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000365
bungeman@google.com242bb892011-06-22 20:42:34 +0000366 if (SUCCEEDED(hr)) {
367 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
368 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000369
bungeman@google.com242bb892011-06-22 20:42:34 +0000370 //Create a the frame.
bungeman@google.com9df621d2011-06-23 21:43:52 +0000371 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
372 SkTScopedComPtr<IPropertyBag2> piPropertybag;
bungeman@google.com242bb892011-06-22 20:42:34 +0000373 if (SUCCEEDED(hr)) {
374 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
375 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000376
bungeman@google.com242bb892011-06-22 20:42:34 +0000377 if (SUCCEEDED(hr)) {
378 PROPBAG2 name = { 0 };
379 name.dwType = PROPBAG2_TYPE_DATA;
380 name.vt = VT_R4;
381 name.pstrName = L"ImageQuality";
rmistry@google.comd6176b02012-08-23 18:14:13 +0000382
bungeman@google.com242bb892011-06-22 20:42:34 +0000383 VARIANT value;
384 VariantInit(&value);
385 value.vt = VT_R4;
386 value.fltVal = (FLOAT)(quality / 100.0);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000387
bungeman@google.com242bb892011-06-22 20:42:34 +0000388 //Ignore result code.
389 // This returns E_FAIL if the named property is not in the bag.
390 //TODO(bungeman) enumerate the properties,
391 // write and set hr iff property exists.
392 piPropertybag->Write(1, &name, &value);
393 }
394 if (SUCCEEDED(hr)) {
395 hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
396 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000397
bungeman@google.com242bb892011-06-22 20:42:34 +0000398 //Set the size of the frame.
bungeman@google.com22b49502011-08-01 19:37:43 +0000399 const UINT width = bitmap->width();
400 const UINT height = bitmap->height();
bungeman@google.com242bb892011-06-22 20:42:34 +0000401 if (SUCCEEDED(hr)) {
402 hr = piBitmapFrameEncode->SetSize(width, height);
403 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000404
bungeman@google.com242bb892011-06-22 20:42:34 +0000405 //Set the pixel format of the frame.
406 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
407 WICPixelFormatGUID formatGUID = formatDesired;
408 if (SUCCEEDED(hr)) {
409 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
410 }
411 if (SUCCEEDED(hr)) {
412 //Be sure the image format is the one requested.
413 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
414 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000415
bungeman@google.com242bb892011-06-22 20:42:34 +0000416 //Write the pixels into the frame.
417 if (SUCCEEDED(hr)) {
bungeman@google.com955bb072011-08-01 20:18:45 +0000418 SkAutoLockPixels alp(*bitmap);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000419 const UINT stride = (UINT) bitmap->rowBytes();
bungeman@google.com242bb892011-06-22 20:42:34 +0000420 hr = piBitmapFrameEncode->WritePixels(
421 height
bungeman@google.com4b18f572013-07-22 15:21:23 +0000422 , stride
423 , stride * height
bungeman@google.com22b49502011-08-01 19:37:43 +0000424 , reinterpret_cast<BYTE*>(bitmap->getPixels()));
bungeman@google.com242bb892011-06-22 20:42:34 +0000425 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000426
bungeman@google.com242bb892011-06-22 20:42:34 +0000427 if (SUCCEEDED(hr)) {
428 hr = piBitmapFrameEncode->Commit();
429 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000430
bungeman@google.com242bb892011-06-22 20:42:34 +0000431 if (SUCCEEDED(hr)) {
432 hr = piEncoder->Commit();
433 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000434
bungeman@google.com242bb892011-06-22 20:42:34 +0000435 return SUCCEEDED(hr);
436}
437
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000438///////////////////////////////////////////////////////////////////////////////
439
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000440static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
bungeman@google.com242bb892011-06-22 20:42:34 +0000441 switch (t) {
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000442 case SkImageEncoder::kBMP_Type:
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000443 case SkImageEncoder::kICO_Type:
444 case SkImageEncoder::kJPEG_Type:
445 case SkImageEncoder::kPNG_Type:
bungeman@google.com242bb892011-06-22 20:42:34 +0000446 break;
447 default:
448 return NULL;
449 }
450 return SkNEW_ARGS(SkImageEncoder_WIC, (t));
451}
scroggo@google.com4c6adf92013-04-17 21:07:55 +0000452
scroggo@google.comb5571b32013-09-25 21:34:24 +0000453static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory);
scroggo@google.com39edf4c2013-04-25 17:33:51 +0000454
scroggo@google.comb5571b32013-09-25 21:34:24 +0000455static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) {
scroggo@google.com39edf4c2013-04-25 17:33:51 +0000456 SkImageDecoder::Format format;
457 SkImageDecoder_WIC codec;
458 if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) {
459 format = SkImageDecoder::kUnknown_Format;
460 }
461 return format;
462}
463
scroggo@google.comb5571b32013-09-25 21:34:24 +0000464static SkImageDecoder_FormatReg gFormatReg(get_format_wic);