MSW/GteWICFileIO.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #include <GTEnginePCH.h>
9 #include <LowLevel/GteLogger.h>
12 #include <memory>
13 // wincodec.h includes windows.h, so we must turn off min/max macros
14 #define NOMINMAX
15 #include <wincodec.h>
16 using namespace gte;
17 
18 std::shared_ptr<Texture2> WICFileIO::Load(std::string const& filename, bool wantMipmaps)
19 {
20  // Start COM and create WIC.
21  ComInitializer comInitializer;
22  if (!comInitializer.IsInitialized())
23  {
24  LogError("Unable to initialize COM for WIC.");
25  return nullptr;
26  }
27 
28  // Create a WIC imaging factory.
29  ComObject<IWICImagingFactory> wicFactory;
30  HRESULT hr = ::CoCreateInstance(CLSID_WICImagingFactory, nullptr,
31  CLSCTX_INPROC_SERVER, IID_IWICImagingFactory,
32  reinterpret_cast<LPVOID*>(&wicFactory));
33  if (FAILED(hr))
34  {
35  LogError("Unable to create WIC imaging factory.");
36  return nullptr;
37  }
38 
39  // Create a decoder based on the file name.
40  std::wstring wfilename(filename.begin(), filename.end());
41  ComObject<IWICBitmapDecoder> wicDecoder;
42  hr = wicFactory->CreateDecoderFromFilename(wfilename.c_str(),
43  nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &wicDecoder);
44  if (FAILED(hr))
45  {
46  LogError("wicFactory->CreateDecoderFromFilename failed (" +
47  filename + ").");
48  return nullptr;
49  }
50 
51  // Create a WIC decoder.
52  ComObject<IWICBitmapFrameDecode> wicFrameDecode;
53  hr = wicDecoder->GetFrame(0, &wicFrameDecode);
54  if (FAILED(hr))
55  {
56  LogError("wicDecoder->GetFrame failed.");
57  return nullptr;
58  }
59 
60  // Get the pixel format of the image.
61  WICPixelFormatGUID wicSourceGUID;
62  hr = wicFrameDecode->GetPixelFormat(&wicSourceGUID);
63  if (FAILED(hr))
64  {
65  LogError("wicFrameDecode->GetPixelFormat failed.");
66  return nullptr;
67  }
68 
69  // Find the supported WIC input pixel format that matches a Texture2
70  // format. If a matching format is not found, the returned texture
71  // is an R8G8B8A8 format with texels converted from the source format.
72  WICPixelFormatGUID wicConvertGUID = GUID_WICPixelFormat32bppRGBA;
73  DFType gtformat = DF_R8G8B8A8_UNORM;
74  for (int i = 0; i < NUM_LOAD_FORMATS; ++i)
75  {
76  if (IsEqualGUID(wicSourceGUID, *msLoadFormatMap[i].wicInputGUID))
77  {
78  // Determine whether there is a conversion format.
79  if (msLoadFormatMap[i].wicConvertGUID)
80  {
81  wicConvertGUID = *msLoadFormatMap[i].wicConvertGUID;
82  }
83  else
84  {
85  wicConvertGUID = *msLoadFormatMap[i].wicInputGUID;
86  }
87  gtformat = msLoadFormatMap[i].gtFormat;
88  break;
89  }
90  }
91 
92  // The wicFrameDecode value is used for no conversion. If the decoder
93  // does not support the format in the texture, then a conversion is
94  // required.
95  IWICBitmapSource* wicBitmapSource = wicFrameDecode;
96  ComObject<IWICFormatConverter> wicFormatConverter;
97  if (!IsEqualGUID(wicSourceGUID, wicConvertGUID))
98  {
99  // Create a WIC format converter.
100  hr = wicFactory->CreateFormatConverter(&wicFormatConverter);
101  if (FAILED(hr))
102  {
103  LogError("wicFactory->CreateFormatConverter failed.");
104  return nullptr;
105  }
106 
107  // Initialize format converter to convert the input texture format
108  // to the nearest format supported by the decoder.
109  hr = wicFormatConverter->Initialize(wicFrameDecode, wicConvertGUID,
110  WICBitmapDitherTypeNone, nullptr, 0.0,
111  WICBitmapPaletteTypeCustom);
112  if (FAILED(hr))
113  {
114  LogError("wicFormatConverter->Initialize failed.");
115  return nullptr;
116  }
117 
118  // Use the format converter.
119  wicBitmapSource = wicFormatConverter;
120  }
121 
122  // Get the image dimensions.
123  UINT width, height;
124  hr = wicBitmapSource->GetSize(&width, &height);
125  if (FAILED(hr))
126  {
127  LogError("wicBitmapSource->GetSize failed.");
128  return nullptr;
129  }
130 
131  // Create the 2D texture and compute the stride and image size.
132  std::shared_ptr<Texture2> texture = std::make_shared<Texture2>(
133  gtformat, width, height, wantMipmaps);
134  UINT const stride = width * texture->GetElementSize();
135  UINT const imageSize = stride * height;
136 
137  // Copy the pixels from the decoder to the texture.
138  hr = wicBitmapSource->CopyPixels(nullptr, stride, imageSize,
139  texture->Get<BYTE>());
140  if (FAILED(hr))
141  {
142  LogError("wicBitmapSource->CopyPixels failed.");
143  return nullptr;
144  }
145 
146  return texture;
147 }
148 
149 bool WICFileIO::SaveToPNG(std::string const& filename,
150  std::shared_ptr<Texture2> const& texture)
151 {
152  return SaveTo(filename, texture, -1.0f);
153 }
154 
155 bool WICFileIO::SaveToJPEG(std::string const& filename,
156  std::shared_ptr<Texture2> const& texture, float imageQuality)
157 {
158  imageQuality = std::min(std::max(imageQuality, 0.0f), 1.0f);
159  return SaveTo(filename, texture, imageQuality);
160 }
161 
162 bool WICFileIO::SaveTo(std::string const& filename,
163  std::shared_ptr<Texture2> const& texture, float imageQuality)
164 {
165  if (!texture || !texture->GetData())
166  {
167  LogError("The texture and its data must exist.");
168  return false;
169  }
170 
171  // Select the WIC format that matches the input texture format.
172  WICPixelFormatGUID wicSourceGUID = GUID_WICPixelFormatUndefined;
173  for (int i = 0; i < NUM_SAVE_FORMATS; ++i)
174  {
175  if (msSaveFormatMap[i].gtFormat == texture->GetFormat())
176  {
177  wicSourceGUID = *msSaveFormatMap[i].wicOutputGUID;
178  break;
179  }
180  }
181  if (IsEqualGUID(wicSourceGUID, GUID_WICPixelFormatUndefined))
182  {
183  LogError("Format " +
184  DataFormat::GetName(texture->GetFormat()) +
185  "is not supported for saving.");
186  return false;
187  }
188 
189  // Start COM and create WIC.
190  ComInitializer comInitializer;
191  if (!comInitializer.IsInitialized())
192  {
193  LogError("Unable to initialize COM for WIC.");
194  return false;
195  }
196 
197  // Create a WIC imaging factory.
199  HRESULT hr = ::CoCreateInstance(CLSID_WICImagingFactory, nullptr,
200  CLSCTX_INPROC_SERVER, IID_IWICImagingFactory,
201  reinterpret_cast<LPVOID*>(&wicFactory));
202  if (FAILED(hr))
203  {
204  LogError("Unable to create WIC imaging factory.");
205  return false;
206  }
207 
208  // Create a WIC stream for output.
209  ComObject<IWICStream> wicStream;
210  hr = wicFactory->CreateStream(&wicStream);
211  if (FAILED(hr))
212  {
213  LogError("wicFactory->CreateStream failed.");
214  return false;
215  }
216 
217  std::wstring wfilename(filename.begin(), filename.end());
218  hr = wicStream->InitializeFromFilename(wfilename.c_str(), GENERIC_WRITE);
219  if (FAILED(hr))
220  {
221  LogError("wicStream->InitializeFromFilename failed (" +
222  filename + ").");
223  return false;
224  }
225 
226  // Create a WIC JPEG encoder.
227  ComObject<IWICBitmapEncoder> wicEncoder;
228  if (imageQuality == -1.0f)
229  {
230  hr = wicFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &wicEncoder);
231  }
232  else
233  {
234  hr = wicFactory->CreateEncoder(GUID_ContainerFormatJpeg, nullptr, &wicEncoder);
235  }
236  if (FAILED(hr))
237  {
238  LogError("wicFactory->CreateEncoder failed.");
239  return false;
240  }
241 
242  hr = wicEncoder->Initialize(wicStream, WICBitmapEncoderNoCache);
243  if (FAILED(hr))
244  {
245  LogError("wicEncoder->Initialize failed.");
246  return false;
247  }
248 
249  // Create a new frame and a property bag for encoder options.
250  ComObject<IWICBitmapFrameEncode> wicFrameEncode;
251  ComObject<IPropertyBag2> wicPropertyBag;
252  hr = wicEncoder->CreateNewFrame(&wicFrameEncode, &wicPropertyBag);
253  if (FAILED(hr))
254  {
255  LogError("wicEncoder->CreateNewFrame failed.");
256  return false;
257  }
258 
259  if (imageQuality == -1.0f)
260  {
261  // Set the options for the PNG encoder.
262  PROPBAG2 option = { 0 };
263  VARIANT varValue;
264 
265  // Default subsampling.
266  option.pstrName = L"InterlaceOption";
267  VariantInit(&varValue);
268  varValue.vt = VT_BOOL;
269  varValue.boolVal = FALSE;
270  hr = wicPropertyBag->Write(1, &option, &varValue);
271  if (FAILED(hr))
272  {
273  LogError("wicPropertyBag->Write failed for InterlaceOption.");
274  return false;
275  }
276 
277  // Disable filtering.
278  option.pstrName = L"FilterOption";
279  VariantInit(&varValue);
280  varValue.vt = VT_UI1;
281  varValue.bVal = WICPngFilterNone;
282  hr = wicPropertyBag->Write(1, &option, &varValue);
283  if (FAILED(hr))
284  {
285  LogError("wicPropertyBag->Write failed for FilterOption.");
286  return false;
287  }
288  }
289  else
290  {
291  // Set the options for the PNG encoder.
292  PROPBAG2 option = { 0 };
293  VARIANT varValue;
294 
295  // Set image quality, a number in [0,1].
296  option.pstrName = L"ImageQuality";
297  VariantInit(&varValue);
298  varValue.vt = VT_R4;
299  varValue.fltVal = imageQuality;
300  hr = wicPropertyBag->Write(1, &option, &varValue);
301  if (FAILED(hr))
302  {
303  LogError("wicPropertyBag->Write failed for ImageQuality.");
304  return false;
305  }
306  }
307 
308  // Initialize the encoder.
309  hr = wicFrameEncode->Initialize(wicPropertyBag);
310  if (FAILED(hr))
311  {
312  LogError("wicFrameEncode->Initialize failed.");
313  return false;
314  }
315 
316  // Set the image size.
317  UINT width = texture->GetWidth();
318  UINT height = texture->GetHeight();
319  hr = wicFrameEncode->SetSize(width, height);
320  if (FAILED(hr))
321  {
322  LogError("wicFrameEncode->SetSize failed.");
323  return false;
324  }
325 
326  // Set the image format.
327  WICPixelFormatGUID wicTargetGUID = wicSourceGUID;
328  hr = wicFrameEncode->SetPixelFormat(&wicTargetGUID);
329  if (FAILED(hr))
330  {
331  LogError("wicFrameEncode->SetPixelFormat failed.");
332  return false;
333  }
334 
335  // Compute the stride and image size.
336  UINT const stride = width * texture->GetElementSize();
337  UINT const imageSize = stride * height;
338 
339  // Create a WIC bitmap to wrap the texture image data.
340  ComObject<IWICBitmap> wicTextureBitmap;
341  hr = wicFactory->CreateBitmapFromMemory(width, height,
342  wicSourceGUID, stride, imageSize, texture->Get<BYTE>(),
343  &wicTextureBitmap);
344  if (FAILED(hr))
345  {
346  LogError("wicFactory->CreateBitmapFromMemory failed.");
347  return false;
348  }
349 
350  // The wicTextureBitmap value is used for no conversion. If the encoder
351  // does not support the format in the texture, then a conversion is
352  // required.
353  IWICBitmapSource* wicBitmapSource = wicTextureBitmap;
354  ComObject<IWICFormatConverter> wicFormatConverter;
355  if (!IsEqualGUID(wicSourceGUID, wicTargetGUID))
356  {
357  // Create a WIC format converter.
358  hr = wicFactory->CreateFormatConverter(&wicFormatConverter);
359  if (FAILED(hr))
360  {
361  LogError("wicFactory->CreateFormatConverter failed.");
362  return false;
363  }
364 
365  // Initialize the format converter to convert to the nearest format
366  // supported by the encoder.
367  hr = wicFormatConverter->Initialize(wicTextureBitmap, wicTargetGUID,
368  WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom);
369  if (FAILED(hr))
370  {
371  LogError("wicFormatConverter->Initialize failed.");
372  return false;
373  }
374 
375  // Use the format converter.
376  wicBitmapSource = wicFormatConverter;
377  }
378 
379  // Send the pixels to the encoder.
380  hr = wicFrameEncode->WriteSource(wicBitmapSource, nullptr);
381  if (FAILED(hr))
382  {
383  LogError("wicFrameEncode->WriteSource failed.");
384  return false;
385  }
386 
387  // Commit the frame.
388  hr = wicFrameEncode->Commit();
389  if (FAILED(hr))
390  {
391  LogError("wicFrameEncode->Commit failed.");
392  return false;
393  }
394 
395  // Commit the encoder.
396  hr = wicEncoder->Commit();
397  if (FAILED(hr))
398  {
399  LogError("wicEncoder->Commit failed.");
400  return false;
401  }
402 
403  return true;
404 }
405 
407 {
408  if (mInitialized)
409  {
410  ::CoUninitialize();
411  }
412 }
413 
415 {
416  HRESULT hr = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
417  mInitialized = SUCCEEDED(hr);
418 }
419 
421 {
422  return mInitialized;
423 }
424 
425 template <typename T>
427  :
428  object(nullptr)
429 {
430 }
431 
432 template <typename T>
434  :
435  object(inObject)
436 {
437  if (object != nullptr)
438  {
439  object->AddRef();
440  }
441 }
442 
443 template <typename T>
445 {
446  if (object)
447  {
448  object->Release();
449  }
450 }
451 
452 template <typename T>
454 {
455  return object;
456 }
457 
458 template <typename T>
460 {
461  return *object;
462 }
463 
464 template <typename T>
466 {
467  return &object;
468 }
469 
470 template <typename T>
472 {
473  return object;
474 }
475 
476 
478 {
479  { DF_B5G6R5_UNORM, &GUID_WICPixelFormat16bppBGR565, nullptr },
480  { DF_B5G5R5A1_UNORM, &GUID_WICPixelFormat16bppBGR555, nullptr },
481  { DF_R10G10B10A2_UNORM, &GUID_WICPixelFormat32bppRGBA1010102, nullptr },
482  { DF_R10G10B10_XR_BIAS_A2_UNORM, &GUID_WICPixelFormat32bppRGBA1010102XR, nullptr },
483  { DF_R1_UNORM, &GUID_WICPixelFormatBlackWhite, &GUID_WICPixelFormat8bppGray },
484  { DF_R8_UNORM, &GUID_WICPixelFormat2bppGray, &GUID_WICPixelFormat8bppGray },
485  { DF_R8_UNORM, &GUID_WICPixelFormat4bppGray, &GUID_WICPixelFormat8bppGray },
486  { DF_R8_UNORM, &GUID_WICPixelFormat8bppGray, nullptr },
487  { DF_R16_UNORM, &GUID_WICPixelFormat16bppGray, nullptr },
488  { DF_R32_FLOAT, &GUID_WICPixelFormat32bppGrayFloat, nullptr },
489  { DF_R8G8B8A8_UNORM, &GUID_WICPixelFormat32bppRGBA, nullptr },
490  { DF_R8G8B8A8_UNORM, &GUID_WICPixelFormat32bppBGRA, &GUID_WICPixelFormat32bppRGBA },
491  { DF_R16G16B16A16_UNORM, &GUID_WICPixelFormat64bppRGBA, nullptr },
492  { DF_R16G16B16A16_UNORM, &GUID_WICPixelFormat64bppBGRA, &GUID_WICPixelFormat64bppRGBA }
493 
494  // B8G8R8A8 is not supported for Texture2 in DX11. We convert all
495  // unmatched formats to R8G8B8A8.
496  //{ DF_B8G8R8A8_UNORM, &GUID_WICPixelFormat32bppBGRA }
497 };
498 
500 {
501  { DF_B5G6R5_UNORM, &GUID_WICPixelFormat16bppBGR565 },
502  { DF_B5G5R5A1_UNORM, &GUID_WICPixelFormat16bppBGR555 },
503  { DF_R10G10B10A2_UNORM, &GUID_WICPixelFormat32bppRGBA1010102 },
504  { DF_R10G10B10_XR_BIAS_A2_UNORM, &GUID_WICPixelFormat32bppRGBA1010102XR },
505  { DF_R1_UNORM, &GUID_WICPixelFormatBlackWhite },
506  { DF_R8_UNORM, &GUID_WICPixelFormat8bppGray },
507  { DF_R16_UNORM, &GUID_WICPixelFormat16bppGray },
508  { DF_R32_FLOAT, &GUID_WICPixelFormat32bppGrayFloat },
509  { DF_R8G8B8A8_UNORM, &GUID_WICPixelFormat32bppRGBA },
510  { DF_B8G8R8A8_UNORM, &GUID_WICPixelFormat32bppBGRA },
511  { DF_R16G16B16A16_UNORM, &GUID_WICPixelFormat64bppRGBA }
512 };
DF_R32_FLOAT
Definition: GteDataFormat.h:20
GLint GLsizei width
Definition: glcorearb.h:98
DF_R10G10B10_XR_BIAS_A2_UNORM
Definition: GteDataFormat.h:20
static std::string const & GetName(DFType type)
static bool SaveTo(std::string const &filename, std::shared_ptr< Texture2 > const &texture, float imageQuality)
DF_R1_UNORM
Definition: GteDataFormat.h:20
DF_B5G6R5_UNORM
Definition: GteDataFormat.h:20
static LoadFormatMap const msLoadFormatMap[NUM_LOAD_FORMATS]
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
Definition: glcorearb.h:545
DF_R8_UNORM
Definition: GteDataFormat.h:20
GLuint GLenum option
Definition: glext.h:5581
DF_R10G10B10A2_UNORM
Definition: GteDataFormat.h:20
static bool SaveToJPEG(std::string const &filename, std::shared_ptr< Texture2 > const &texture, float imageQuality)
GLsizei const GLchar *const * string
Definition: glcorearb.h:809
#define LogError(message)
Definition: GteLogger.h:92
GLuint texture
Definition: glcorearb.h:410
DF_R16G16B16A16_UNORM
Definition: GteDataFormat.h:20
GLint GLsizei GLsizei height
Definition: glcorearb.h:98
DF_B8G8R8A8_UNORM
Definition: GteDataFormat.h:20
static SaveFormatMap const msSaveFormatMap[NUM_SAVE_FORMATS]
DF_R8G8B8A8_UNORM
Definition: GteDataFormat.h:20
static std::shared_ptr< Texture2 > Load(std::string const &filename, bool wantMipmaps)
GLfloat f
Definition: glcorearb.h:1921
DF_B5G5R5A1_UNORM
Definition: GteDataFormat.h:20
typedef UINT(WINAPI *PFNWGLGETGPUIDSAMDPROC)(UINT maxCount
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:867
GLuint object
Definition: glext.h:6426
static bool SaveToPNG(std::string const &filename, std::shared_ptr< Texture2 > const &texture)
DF_R16_UNORM
Definition: GteDataFormat.h:20


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:02