• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * 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.
7  */
8 
9 
10 #define WIN32_LEAN_AND_MEAN
11 #include <Windows.h>
12 #include <wincodec.h>
13 #include "SkAutoCoInitialize.h"
14 #include "SkImageDecoder.h"
15 #include "SkImageEncoder.h"
16 #include "SkIStream.h"
17 #include "SkMovie.h"
18 #include "SkStream.h"
19 #include "SkTScopedComPtr.h"
20 
21 class SkImageDecoder_WIC : public SkImageDecoder {
22 protected:
23     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
24 };
25 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)26 bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
27     //Initialize COM.
28     SkAutoCoInitialize scopedCo;
29     if (!scopedCo.succeeded()) {
30         return false;
31     }
32 
33     HRESULT hr = S_OK;
34 
35     //Create Windows Imaging Component ImagingFactory.
36     SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
37     if (SUCCEEDED(hr)) {
38         hr = CoCreateInstance(
39             CLSID_WICImagingFactory
40             , NULL
41             , CLSCTX_INPROC_SERVER
42             , IID_PPV_ARGS(&piImagingFactory)
43         );
44     }
45 
46     //Convert SkStream to IStream.
47     SkTScopedComPtr<IStream> piStream;
48     if (SUCCEEDED(hr)) {
49         hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
50     }
51 
52     //Make sure we're at the beginning of the stream.
53     if (SUCCEEDED(hr)) {
54         LARGE_INTEGER liBeginning = { 0 };
55         hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
56     }
57 
58     //Create the decoder from the stream content.
59     SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
60     if (SUCCEEDED(hr)) {
61         hr = piImagingFactory->CreateDecoderFromStream(
62             piStream.get()                    //Image to be decoded
63             , NULL                            //No particular vendor
64             , WICDecodeMetadataCacheOnDemand  //Cache metadata when needed
65             , &piBitmapDecoder                //Pointer to the decoder
66         );
67     }
68 
69     //Get the first frame from the decoder.
70     SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
71     if (SUCCEEDED(hr)) {
72         hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
73     }
74 
75     //Get the BitmapSource interface of the frame.
76     SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
77     if (SUCCEEDED(hr)) {
78         hr = piBitmapFrameDecode->QueryInterface(
79             IID_PPV_ARGS(&piBitmapSourceOriginal)
80         );
81     }
82 
83     //Get the size of the bitmap.
84     UINT width;
85     UINT height;
86     if (SUCCEEDED(hr)) {
87         hr = piBitmapSourceOriginal->GetSize(&width, &height);
88     }
89 
90     //Exit early if we're only looking for the bitmap bounds.
91     if (SUCCEEDED(hr)) {
92         bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
93         if (SkImageDecoder::kDecodeBounds_Mode == mode) {
94             return true;
95         }
96         if (!this->allocPixelRef(bm, NULL)) {
97             return false;
98         }
99     }
100 
101     //Create a format converter.
102     SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
103     if (SUCCEEDED(hr)) {
104         hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
105     }
106 
107     if (SUCCEEDED(hr)) {
108         hr = piFormatConverter->Initialize(
109             piBitmapSourceOriginal.get()      //Input bitmap to convert
110             , GUID_WICPixelFormat32bppPBGRA   //Destination pixel format
111             , WICBitmapDitherTypeNone         //Specified dither patterm
112             , NULL                            //Specify a particular palette
113             , 0.f                             //Alpha threshold
114             , WICBitmapPaletteTypeCustom      //Palette translation type
115         );
116     }
117 
118     //Get the BitmapSource interface of the format converter.
119     SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
120     if (SUCCEEDED(hr)) {
121         hr = piFormatConverter->QueryInterface(
122             IID_PPV_ARGS(&piBitmapSourceConverted)
123         );
124     }
125 
126     //Copy the pixels into the bitmap.
127     if (SUCCEEDED(hr)) {
128         SkAutoLockPixels alp(*bm);
129         bm->eraseColor(0);
130         const int stride = bm->rowBytes();
131         hr = piBitmapSourceConverted->CopyPixels(
132             NULL,                             //Get all the pixels
133             stride,
134             stride * height,
135             reinterpret_cast<BYTE *>(bm->getPixels())
136         );
137     }
138 
139     return SUCCEEDED(hr);
140 }
141 
142 /////////////////////////////////////////////////////////////////////////
143 
Factory(SkStream * stream)144 SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
145     return SkNEW(SkImageDecoder_WIC);
146 }
147 
148 /////////////////////////////////////////////////////////////////////////
149 
DecodeStream(SkStream * stream)150 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
151     return NULL;
152 }
153 
154 /////////////////////////////////////////////////////////////////////////
155 
156 class SkImageEncoder_WIC : public SkImageEncoder {
157 public:
SkImageEncoder_WIC(Type t)158     SkImageEncoder_WIC(Type t) : fType(t) {}
159 
160 protected:
161     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
162 
163 private:
164     Type fType;
165 };
166 
onEncode(SkWStream * stream,const SkBitmap & bitmapOrig,int quality)167 bool SkImageEncoder_WIC::onEncode(SkWStream* stream
168                                 , const SkBitmap& bitmapOrig
169                                 , int quality)
170 {
171     GUID type;
172     switch (fType) {
173         case kJPEG_Type:
174             type = GUID_ContainerFormatJpeg;
175             break;
176         case kPNG_Type:
177             type = GUID_ContainerFormatPng;
178             break;
179         default:
180             return false;
181     }
182 
183     //Convert to 8888 if needed.
184     const SkBitmap* bitmap;
185     SkBitmap bitmapCopy;
186     if (SkBitmap::kARGB_8888_Config == bitmapOrig.config()) {
187         bitmap = &bitmapOrig;
188     } else {
189         if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) {
190             return false;
191         }
192         bitmap = &bitmapCopy;
193     }
194 
195     //Initialize COM.
196     SkAutoCoInitialize scopedCo;
197     if (!scopedCo.succeeded()) {
198         return false;
199     }
200 
201     HRESULT hr = S_OK;
202 
203     //Create Windows Imaging Component ImagingFactory.
204     SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
205     if (SUCCEEDED(hr)) {
206         hr = CoCreateInstance(
207             CLSID_WICImagingFactory
208             , NULL
209             , CLSCTX_INPROC_SERVER
210             , IID_PPV_ARGS(&piImagingFactory)
211         );
212     }
213 
214     //Convert the SkWStream to an IStream.
215     SkTScopedComPtr<IStream> piStream;
216     if (SUCCEEDED(hr)) {
217         hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
218     }
219 
220     //Create an encode of the appropriate type.
221     SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
222     if (SUCCEEDED(hr)) {
223         hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
224     }
225 
226     if (SUCCEEDED(hr)) {
227         hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
228     }
229 
230     //Create a the frame.
231     SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
232     SkTScopedComPtr<IPropertyBag2> piPropertybag;
233     if (SUCCEEDED(hr)) {
234         hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
235     }
236 
237     if (SUCCEEDED(hr)) {
238         PROPBAG2 name = { 0 };
239         name.dwType = PROPBAG2_TYPE_DATA;
240         name.vt = VT_R4;
241         name.pstrName = L"ImageQuality";
242 
243         VARIANT value;
244         VariantInit(&value);
245         value.vt = VT_R4;
246         value.fltVal = (FLOAT)(quality / 100.0);
247 
248         //Ignore result code.
249         //  This returns E_FAIL if the named property is not in the bag.
250         //TODO(bungeman) enumerate the properties,
251         //  write and set hr iff property exists.
252         piPropertybag->Write(1, &name, &value);
253     }
254     if (SUCCEEDED(hr)) {
255         hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
256     }
257 
258     //Set the size of the frame.
259     const UINT width = bitmap->width();
260     const UINT height = bitmap->height();
261     if (SUCCEEDED(hr)) {
262         hr = piBitmapFrameEncode->SetSize(width, height);
263     }
264 
265     //Set the pixel format of the frame.
266     const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
267     WICPixelFormatGUID formatGUID = formatDesired;
268     if (SUCCEEDED(hr)) {
269         hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
270     }
271     if (SUCCEEDED(hr)) {
272         //Be sure the image format is the one requested.
273         hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
274     }
275 
276     //Write the pixels into the frame.
277     if (SUCCEEDED(hr)) {
278         SkAutoLockPixels alp(*bitmap);
279         hr = piBitmapFrameEncode->WritePixels(
280             height
281             , bitmap->rowBytes()
282             , bitmap->rowBytes()*height
283             , reinterpret_cast<BYTE*>(bitmap->getPixels()));
284     }
285 
286     if (SUCCEEDED(hr)) {
287         hr = piBitmapFrameEncode->Commit();
288     }
289 
290     if (SUCCEEDED(hr)) {
291         hr = piEncoder->Commit();
292     }
293 
294     return SUCCEEDED(hr);
295 }
296 
Create(Type t)297 SkImageEncoder* SkImageEncoder::Create(Type t) {
298     switch (t) {
299         case kJPEG_Type:
300         case kPNG_Type:
301             break;
302         default:
303             return NULL;
304     }
305     return SkNEW_ARGS(SkImageEncoder_WIC, (t));
306 }
307 
308