OLD | NEW |
| (Empty) |
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 #include "SkTypes.h" | |
10 | |
11 #if defined(SK_BUILD_FOR_WIN32) | |
12 | |
13 // 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 | |
32 #include <wincodec.h> | |
33 #include "SkAutoCoInitialize.h" | |
34 #include "SkImageEncoder.h" | |
35 #include "SkIStream.h" | |
36 #include "SkMovie.h" | |
37 #include "SkStream.h" | |
38 #include "SkTScopedComPtr.h" | |
39 #include "SkUnPreMultiply.h" | |
40 | |
41 //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 | |
50 ///////////////////////////////////////////////////////////////////////// | |
51 | |
52 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { | |
53 return nullptr; | |
54 } | |
55 | |
56 ///////////////////////////////////////////////////////////////////////// | |
57 | |
58 class SkImageEncoder_WIC : public SkImageEncoder { | |
59 public: | |
60 SkImageEncoder_WIC(Type t) : fType(t) {} | |
61 | |
62 // DO NOT USE this constructor. This exists only so SkForceLinking can | |
63 // link the WIC image encoder. | |
64 SkImageEncoder_WIC() {} | |
65 | |
66 protected: | |
67 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); | |
68 | |
69 private: | |
70 Type fType; | |
71 }; | |
72 | |
73 bool SkImageEncoder_WIC::onEncode(SkWStream* stream | |
74 , const SkBitmap& bitmapOrig | |
75 , int quality) | |
76 { | |
77 GUID type; | |
78 switch (fType) { | |
79 case kBMP_Type: | |
80 type = GUID_ContainerFormatBmp; | |
81 break; | |
82 case kICO_Type: | |
83 type = GUID_ContainerFormatIco; | |
84 break; | |
85 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 | |
95 //Convert to 8888 if needed. | |
96 const SkBitmap* bitmap; | |
97 SkBitmap bitmapCopy; | |
98 if (kN32_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) { | |
99 bitmap = &bitmapOrig; | |
100 } else { | |
101 if (!bitmapOrig.copyTo(&bitmapCopy, kN32_SkColorType)) { | |
102 return false; | |
103 } | |
104 bitmap = &bitmapCopy; | |
105 } | |
106 | |
107 // 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->b
ytesPerPixel(); | |
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 | |
124 //Initialize COM. | |
125 SkAutoCoInitialize scopedCo; | |
126 if (!scopedCo.succeeded()) { | |
127 return false; | |
128 } | |
129 | |
130 HRESULT hr = S_OK; | |
131 | |
132 //Create Windows Imaging Component ImagingFactory. | |
133 SkTScopedComPtr<IWICImagingFactory> piImagingFactory; | |
134 if (SUCCEEDED(hr)) { | |
135 hr = CoCreateInstance( | |
136 CLSID_WICImagingFactory | |
137 , nullptr | |
138 , CLSCTX_INPROC_SERVER | |
139 , IID_PPV_ARGS(&piImagingFactory) | |
140 ); | |
141 } | |
142 | |
143 //Convert the SkWStream to an IStream. | |
144 SkTScopedComPtr<IStream> piStream; | |
145 if (SUCCEEDED(hr)) { | |
146 hr = SkWIStream::CreateFromSkWStream(stream, &piStream); | |
147 } | |
148 | |
149 //Create an encode of the appropriate type. | |
150 SkTScopedComPtr<IWICBitmapEncoder> piEncoder; | |
151 if (SUCCEEDED(hr)) { | |
152 hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder); | |
153 } | |
154 | |
155 if (SUCCEEDED(hr)) { | |
156 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); | |
157 } | |
158 | |
159 //Create a the frame. | |
160 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; | |
161 SkTScopedComPtr<IPropertyBag2> piPropertybag; | |
162 if (SUCCEEDED(hr)) { | |
163 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); | |
164 } | |
165 | |
166 if (SUCCEEDED(hr)) { | |
167 PROPBAG2 name = { 0 }; | |
168 name.dwType = PROPBAG2_TYPE_DATA; | |
169 name.vt = VT_R4; | |
170 name.pstrName = L"ImageQuality"; | |
171 | |
172 VARIANT value; | |
173 VariantInit(&value); | |
174 value.vt = VT_R4; | |
175 value.fltVal = (FLOAT)(quality / 100.0); | |
176 | |
177 //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 } | |
186 | |
187 //Set the size of the frame. | |
188 const UINT width = bitmap->width(); | |
189 const UINT height = bitmap->height(); | |
190 if (SUCCEEDED(hr)) { | |
191 hr = piBitmapFrameEncode->SetSize(width, height); | |
192 } | |
193 | |
194 //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. | |
196 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; | |
197 WICPixelFormatGUID formatGUID = formatDesired; | |
198 if (SUCCEEDED(hr)) { | |
199 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); | |
200 } | |
201 if (SUCCEEDED(hr)) { | |
202 //Be sure the image format is the one requested. | |
203 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; | |
204 } | |
205 | |
206 //Write the pixels into the frame. | |
207 if (SUCCEEDED(hr)) { | |
208 SkAutoLockPixels alp(*bitmap); | |
209 const UINT stride = (UINT) bitmap->rowBytes(); | |
210 hr = piBitmapFrameEncode->WritePixels( | |
211 height | |
212 , stride | |
213 , stride * height | |
214 , reinterpret_cast<BYTE*>(bitmap->getPixels())); | |
215 } | |
216 | |
217 if (SUCCEEDED(hr)) { | |
218 hr = piBitmapFrameEncode->Commit(); | |
219 } | |
220 | |
221 if (SUCCEEDED(hr)) { | |
222 hr = piEncoder->Commit(); | |
223 } | |
224 | |
225 return SUCCEEDED(hr); | |
226 } | |
227 | |
228 /////////////////////////////////////////////////////////////////////////////// | |
229 | |
230 static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) { | |
231 switch (t) { | |
232 case SkImageEncoder::kBMP_Type: | |
233 case SkImageEncoder::kICO_Type: | |
234 case SkImageEncoder::kPNG_Type: | |
235 break; | |
236 default: | |
237 return nullptr; | |
238 } | |
239 return new SkImageEncoder_WIC(t); | |
240 } | |
241 | |
242 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory); | |
243 | |
244 DEFINE_ENCODER_CREATOR(ImageEncoder_WIC); | |
245 | |
246 #endif // defined(SK_BUILD_FOR_WIN32) | |
OLD | NEW |