Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
WICHelper.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 // -----------------------------------------------------------------------------
24 // The following code is a port of DirectXTex http://directxtex.codeplex.com
25 // -----------------------------------------------------------------------------
26 // Microsoft Public License (Ms-PL)
27 //
28 // This license governs use of the accompanying software. If you use the
29 // software, you accept this license. If you do not accept the license, do not
30 // use the software.
31 //
32 // 1. Definitions
33 // The terms "reproduce," "reproduction," "derivative works," and
34 // "distribution" have the same meaning here as under U.S. copyright law.
35 // A "contribution" is the original software, or any additions or changes to
36 // the software.
37 // A "contributor" is any person that distributes its contribution under this
38 // license.
39 // "Licensed patents" are a contributor's patent claims that read directly on
40 // its contribution.
41 //
42 // 2. Grant of Rights
43 // (A) Copyright Grant- Subject to the terms of this license, including the
44 // license conditions and limitations in section 3, each contributor grants
45 // you a non-exclusive, worldwide, royalty-free copyright license to reproduce
46 // its contribution, prepare derivative works of its contribution, and
47 // distribute its contribution or any derivative works that you create.
48 // (B) Patent Grant- Subject to the terms of this license, including the license
49 // conditions and limitations in section 3, each contributor grants you a
50 // non-exclusive, worldwide, royalty-free license under its licensed patents to
51 // make, have made, use, sell, offer for sale, import, and/or otherwise dispose
52 // of its contribution in the software or derivative works of the contribution
53 // in the software.
54 //
55 // 3. Conditions and Limitations
56 // (A) No Trademark License- This license does not grant you rights to use any
57 // contributors' name, logo, or trademarks.
58 // (B) If you bring a patent claim against any contributor over patents that
59 // you claim are infringed by the software, your patent license from such
60 // contributor to the software ends automatically.
61 // (C) If you distribute any portion of the software, you must retain all
62 // copyright, patent, trademark, and attribution notices that are present in the
63 // software.
64 // (D) If you distribute any portion of the software in source code form, you
65 // may do so only under this license by including a complete copy of this
66 // license with your distribution. If you distribute any portion of the software
67 // in compiled or object code form, you may only do so under a license that
68 // complies with this license.
69 // (E) The software is licensed "as-is." You bear the risk of using it. The
70 // contributors give no express warranties, guarantees or conditions. You may
71 // have additional consumer rights under your local laws which this license
72 // cannot change. To the extent permitted under your local laws, the
73 // contributors exclude the implied warranties of merchantability, fitness for a
74 // particular purpose and non-infringement.
75 
76 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
77 using System;
78 using System.Diagnostics;
79 using System.IO;
80 using System.Runtime.InteropServices;
81 using SharpDX.WIC;
82 using SiliconStudio.Core;
83 using WIC = SharpDX.WIC;
85 
86 namespace SiliconStudio.Paradox.Graphics
87 {
88  public class WICHelper
89  {
90  private static WIC.ImagingFactory _factory = new ImagingFactory();
91 
92  private static ImagingFactory Factory { get { return _factory ?? (_factory = new ImagingFactory()); } }
93 
94  //-------------------------------------------------------------------------------------
95  // WIC Pixel Format Translation Data
96  //-------------------------------------------------------------------------------------
97  private struct WICTranslate
98  {
99  public WICTranslate(Guid wic, Format format)
100  {
101  this.WIC = wic;
102  this.Format = format;
103  }
104 
105  public readonly Guid WIC;
106  public readonly Format Format;
107  };
108 
109  private static readonly WICTranslate[] WICToDXGIFormats =
110  {
111  new WICTranslate(SharpDX.WIC.PixelFormat.Format128bppRGBAFloat, Format.R32G32B32A32_Float),
112 
113  new WICTranslate(SharpDX.WIC.PixelFormat.Format64bppRGBAHalf, Format.R16G16B16A16_Float),
114  new WICTranslate(SharpDX.WIC.PixelFormat.Format64bppRGBA, Format.R16G16B16A16_UNorm),
115 
116  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA, Format.R8G8B8A8_UNorm),
117  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppBGRA, Format.B8G8R8A8_UNorm), // DXGI 1.1
118  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppBGR, Format.B8G8R8X8_UNorm), // DXGI 1.1
119 
120  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA1010102XR, Format.R10G10B10_Xr_Bias_A2_UNorm), // DXGI 1.1
121  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA1010102, Format.R10G10B10A2_UNorm),
122  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBE, Format.R9G9B9E5_Sharedexp),
123 
124  new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppBGRA5551, Format.B5G5R5A1_UNorm),
125  new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppBGR565, Format.B5G6R5_UNorm),
126 
127  new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppGrayFloat, Format.R32_Float),
128  new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppGrayHalf, Format.R16_Float),
129  new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppGray, Format.R16_UNorm),
130  new WICTranslate(SharpDX.WIC.PixelFormat.Format8bppGray, Format.R8_UNorm),
131 
132  new WICTranslate(SharpDX.WIC.PixelFormat.Format8bppAlpha, Format.A8_UNorm),
133 
134  new WICTranslate(SharpDX.WIC.PixelFormat.FormatBlackWhite, Format.R1_UNorm),
135 
136 #if DIRECTX11_1
137  new WICTranslate(SharpDX.WIC.PixelFormat.Format96bppRGBFloat, Format.R32G32B32_Float ),
138  #endif
139  };
140 
141  //-------------------------------------------------------------------------------------
142  // WIC Pixel Format nearest conversion table
143  //-------------------------------------------------------------------------------------
144 
145  private struct WICConvert
146  {
147  public WICConvert(Guid source, Guid target)
148  {
149  this.source = source;
150  this.target = target;
151  }
152 
153  public readonly Guid source;
154  public readonly Guid target;
155  };
156 
157  private static readonly WICConvert[] WICConvertTable =
158  {
159  // Directly support the formats listed in XnaTexUtil::g_WICFormats, so no conversion required
160  // Note target Guid in this conversion table must be one of those directly supported formats.
161 
162  new WICConvert(WIC.PixelFormat.Format1bppIndexed, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
163  new WICConvert(WIC.PixelFormat.Format2bppIndexed, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
164  new WICConvert(WIC.PixelFormat.Format4bppIndexed, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
165  new WICConvert(WIC.PixelFormat.Format8bppIndexed, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
166 
167  new WICConvert(WIC.PixelFormat.Format2bppGray, WIC.PixelFormat.Format8bppGray), // Format.R8_UNorm
168  new WICConvert(WIC.PixelFormat.Format4bppGray, WIC.PixelFormat.Format8bppGray), // Format.R8_UNorm
169 
170  new WICConvert(WIC.PixelFormat.Format16bppGrayFixedPoint, WIC.PixelFormat.Format16bppGrayHalf), // Format.R16_FLOAT
171  new WICConvert(WIC.PixelFormat.Format32bppGrayFixedPoint, WIC.PixelFormat.Format32bppGrayFloat), // Format.R32_FLOAT
172 
173  new WICConvert(WIC.PixelFormat.Format16bppBGR555, WIC.PixelFormat.Format16bppBGRA5551), // Format.B5G5R5A1_UNorm
174  new WICConvert(WIC.PixelFormat.Format32bppBGR101010, WIC.PixelFormat.Format32bppRGBA1010102), // Format.R10G10B10A2_UNorm
175 
176  new WICConvert(WIC.PixelFormat.Format24bppBGR, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
177  new WICConvert(WIC.PixelFormat.Format24bppRGB, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
178  new WICConvert(WIC.PixelFormat.Format32bppPBGRA, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
179  new WICConvert(WIC.PixelFormat.Format32bppPRGBA, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
180 
181  new WICConvert(WIC.PixelFormat.Format48bppRGB, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
182  new WICConvert(WIC.PixelFormat.Format48bppBGR, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
183  new WICConvert(WIC.PixelFormat.Format64bppBGRA, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
184  new WICConvert(WIC.PixelFormat.Format64bppPRGBA, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
185  new WICConvert(WIC.PixelFormat.Format64bppPBGRA, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
186 
187  new WICConvert(WIC.PixelFormat.Format48bppRGBFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
188  new WICConvert(WIC.PixelFormat.Format48bppBGRFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
189  new WICConvert(WIC.PixelFormat.Format64bppRGBAFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
190  new WICConvert(WIC.PixelFormat.Format64bppBGRAFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
191  new WICConvert(WIC.PixelFormat.Format64bppRGBFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
192  new WICConvert(WIC.PixelFormat.Format64bppRGBHalf, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
193  new WICConvert(WIC.PixelFormat.Format48bppRGBHalf, WIC.PixelFormat.Format64bppRGBAHalf), // Format.R16G16B16A16_FLOAT
194 
195  new WICConvert(WIC.PixelFormat.Format128bppPRGBAFloat, WIC.PixelFormat.Format128bppRGBAFloat), // Format.R32G32B32A32_FLOAT
196  new WICConvert(WIC.PixelFormat.Format128bppRGBFloat, WIC.PixelFormat.Format128bppRGBAFloat), // Format.R32G32B32A32_FLOAT
197  new WICConvert(WIC.PixelFormat.Format128bppRGBAFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat), // Format.R32G32B32A32_FLOAT
198  new WICConvert(WIC.PixelFormat.Format128bppRGBFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat), // Format.R32G32B32A32_FLOAT
199 
200  new WICConvert(WIC.PixelFormat.Format32bppCMYK, WIC.PixelFormat.Format32bppRGBA), // Format.R8G8B8A8_UNorm
201  new WICConvert(WIC.PixelFormat.Format64bppCMYK, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
202  new WICConvert(WIC.PixelFormat.Format40bppCMYKAlpha, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
203  new WICConvert(WIC.PixelFormat.Format80bppCMYKAlpha, WIC.PixelFormat.Format64bppRGBA), // Format.R16G16B16A16_UNorm
204 
205 #if DIRECTX11_1
206  new WICConvert( WIC.PixelFormat.Format32bppRGB, WIC.PixelFormat.Format32bppRGBA ), // Format.R8G8B8A8_UNorm
207  new WICConvert( WIC.PixelFormat.Format64bppRGB, WIC.PixelFormat.Format64bppRGBA ), // Format.R16G16B16A16_UNorm
208  new WICConvert( WIC.PixelFormat.Format64bppPRGBAHalf, WIC.PixelFormat.Format64bppRGBAHalf ), // Format.R16G16B16A16_FLOAT
209  new WICConvert( WIC.PixelFormat.Format96bppRGBFixedPoint, WIC.PixelFormat.Format96bppRGBFloat ), // Format.R32G32B32_FLOAT
210 #else
211  new WICConvert(WIC.PixelFormat.Format96bppRGBFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat), // Format.R32G32B32A32_FLOAT
212 #endif
213 
214  // We don't support n-channel formats
215  };
216 
217  /// <summary>
218  /// Converts a WIC <see cref="WIC.PixelFormat"/> to a <see cref="Format"/>.
219  /// </summary>
220  /// <param name="guid">A WIC <see cref="WIC.PixelFormat"/> </param>
221  /// <returns>A <see cref="Format"/></returns>
222  private static Format ToDXGI(Guid guid)
223  {
224  for (int i = 0; i < WICToDXGIFormats.Length; ++i)
225  {
226  if (WICToDXGIFormats[i].WIC == guid)
227  return WICToDXGIFormats[i].Format;
228  }
229 
230  return Format.None;
231  }
232 
233  /// <summary>
234  /// Converts a <see cref="Format"/> to a a WIC <see cref="WIC.PixelFormat"/>.
235  /// </summary>
236  /// <param name="format">A <see cref="Format"/></param>
237  /// <param name="guid">A WIC <see cref="WIC.PixelFormat"/> Guid.</param>
238  /// <returns>True if conversion succeed, false otherwise.</returns>
239  private static bool ToWIC(Format format, out Guid guid)
240  {
241  for (int i = 0; i < WICToDXGIFormats.Length; ++i)
242  {
243  if (WICToDXGIFormats[i].Format == format)
244  {
245  guid = WICToDXGIFormats[i].WIC;
246  return true;
247  }
248  }
249 
250  // Special cases
251  switch (format)
252  {
253  case Format.R8G8B8A8_UNorm_SRgb:
254  guid = SharpDX.WIC.PixelFormat.Format32bppRGBA;
255  return true;
256 
257  case Format.D32_Float:
258  guid = SharpDX.WIC.PixelFormat.Format32bppGrayFloat;
259  return true;
260 
261  case Format.D16_UNorm:
262  guid = SharpDX.WIC.PixelFormat.Format16bppGray;
263  return true;
264 
265  case Format.B8G8R8A8_UNorm_SRgb:
266  guid = SharpDX.WIC.PixelFormat.Format32bppBGRA;
267  return true;
268 
269  case Format.B8G8R8X8_UNorm_SRgb:
270  guid = SharpDX.WIC.PixelFormat.Format32bppBGR;
271  return true;
272  }
273 
274  guid = Guid.Empty;
275  return false;
276  }
277 
278  /// <summary>
279  /// Gets the number of bits per pixels for a WIC <see cref="WIC.PixelFormat"/> Guid.
280  /// </summary>
281  /// <param name="targetGuid">A WIC <see cref="WIC.PixelFormat"/> Guid.</param>
282  /// <returns>The number of bits per pixels for a WIC. If this method is failing to calculate the number of pixels, return 0.</returns>
283  private static int GetBitsPerPixel(Guid targetGuid)
284  {
285  using (var info = new ComponentInfo(Factory, targetGuid))
286  {
287  if (info.ComponentType != ComponentType.PixelFormat)
288  return 0;
289 
290  var pixelFormatInfo = info.QueryInterfaceOrNull<PixelFormatInfo>();
291  if (pixelFormatInfo == null)
292  return 0;
293 
295  pixelFormatInfo.Dispose();
296  return bpp;
297  }
298  }
299 
300 
301  //-------------------------------------------------------------------------------------
302  // Returns the DXGI format and optionally the WIC pixel Guid to convert to
303  //-------------------------------------------------------------------------------------
304  private static Format DetermineFormat(Guid pixelFormat, WICFlags flags, out Guid pixelFormatOut)
305  {
306  Format format = ToDXGI(pixelFormat);
307  pixelFormatOut = Guid.Empty;
308 
309  if (format == Format.None)
310  {
311  for (int i = 0; i < WICConvertTable.Length; ++i)
312  {
313  if (WICConvertTable[i].source == pixelFormat)
314  {
315  pixelFormatOut = WICConvertTable[i].target;
316 
317  format = ToDXGI(WICConvertTable[i].target);
318  Debug.Assert(format != Format.None);
319  break;
320  }
321  }
322  }
323 
324  // Handle special cases based on flags
325  switch (format)
326  {
327  case Format.B8G8R8A8_UNorm: // BGRA
328  case Format.B8G8R8X8_UNorm: // BGRX
329  if ((flags & WICFlags.ForceRgb) != 0)
330  {
331  format = Format.R8G8B8A8_UNorm;
332  pixelFormatOut = WIC.PixelFormat.Format32bppRGBA;
333  }
334  break;
335 
336  case Format.R10G10B10_Xr_Bias_A2_UNorm:
337  if ((flags & WICFlags.NoX2Bias) != 0)
338  {
339  format = Format.R10G10B10A2_UNorm;
340  pixelFormatOut = WIC.PixelFormat.Format32bppRGBA1010102;
341  }
342  break;
343 
344  case Format.B5G5R5A1_UNorm:
345  case Format.B5G6R5_UNorm:
346  if ((flags & WICFlags.No16Bpp) != 0)
347  {
348  format = Format.R8G8B8A8_UNorm;
349  pixelFormatOut = WIC.PixelFormat.Format32bppRGBA;
350  }
351  break;
352 
353  case Format.R1_UNorm:
354  if ((flags & WICFlags.FlagsAllowMono) == 0)
355  {
356  // By default we want to promote a black & white to greyscale since R1 is not a generally supported D3D format
357  format = Format.R8_UNorm;
358  pixelFormatOut = WIC.PixelFormat.Format8bppGray;
359  }
360  break;
361  }
362 
363  return format;
364  }
365 
366  /// <summary>
367  /// Determines metadata for image
368  /// </summary>
369  /// <param name="flags">The flags.</param>
370  /// <param name="decoder">The decoder.</param>
371  /// <param name="frame">The frame.</param>
372  /// <param name="pixelFormat">The pixel format.</param>
373  /// <returns></returns>
374  /// <exception cref="System.InvalidOperationException">If pixel format is not supported.</exception>
375  private static ImageDescription? DecodeMetadata(WICFlags flags, BitmapDecoder decoder, BitmapFrameDecode frame, out Guid pixelFormat)
376  {
377  var size = frame.Size;
378 
379  var metadata = new ImageDescription
380  {
381  Dimension = TextureDimension.Texture2D,
382  Width = size.Width,
383  Height = size.Height,
384  Depth = 1,
385  MipLevels = 1,
386  ArraySize = (flags & WICFlags.AllFrames) != 0 ? decoder.FrameCount : 1,
387  Format = DetermineFormat(frame.PixelFormat, flags, out pixelFormat)
388  };
389 
390  if (metadata.Format == Format.None)
391  return null;
392 
393  return metadata;
394  }
395 
396  private static BitmapDitherType GetWICDither(WICFlags flags)
397  {
398  if ((flags & WICFlags.Dither) != 0)
399  return BitmapDitherType.Ordered4x4;
400 
401  if ((flags & WICFlags.DitherDiffusion) != 0)
402  return BitmapDitherType.ErrorDiffusion;
403 
404  return BitmapDitherType.None;
405  }
406 
407 
408  private static BitmapInterpolationMode GetWICInterp(WICFlags flags)
409  {
410  if ((flags & WICFlags.FilterPoint) != 0)
411  return BitmapInterpolationMode.NearestNeighbor;
412 
413  if ((flags & WICFlags.FilterLinear) != 0)
414  return BitmapInterpolationMode.Linear;
415 
416  if ((flags & WICFlags.FilterCubic) != 0)
417  return BitmapInterpolationMode.Cubic;
418 
419  return BitmapInterpolationMode.Fant;
420  }
421 
422  //-------------------------------------------------------------------------------------
423  // Decodes a single frame
424  //-------------------------------------------------------------------------------------
425  private static Image DecodeSingleFrame(WICFlags flags, ImageDescription metadata, Guid convertGUID, BitmapFrameDecode frame)
426  {
427  var image = Image.New(metadata);
428 
429  var pixelBuffer = image.PixelBuffer[0];
430 
431  if (convertGUID == Guid.Empty)
432  {
433  frame.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
434  }
435  else
436  {
437  using (var converter = new FormatConverter(Factory))
438  {
439  converter.Initialize(frame, convertGUID, GetWICDither(flags), null, 0, BitmapPaletteType.Custom);
440  converter.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
441  }
442  }
443 
444  return image;
445  }
446 
447  //-------------------------------------------------------------------------------------
448  // Decodes an image array, resizing/format converting as needed
449  //-------------------------------------------------------------------------------------
450  private static Image DecodeMultiframe(WICFlags flags, ImageDescription metadata, BitmapDecoder decoder)
451  {
452  var image = Image.New(metadata);
453 
454  Guid sourceGuid;
455  if (!ToWIC(metadata.Format, out sourceGuid))
456  return null;
457 
458  for (int index = 0; index < metadata.ArraySize; ++index)
459  {
460  var pixelBuffer = image.PixelBuffer[index, 0];
461 
462  using (var frame = decoder.GetFrame(index))
463  {
464  var pfGuid = frame.PixelFormat;
465  var size = frame.Size;
466 
467  if (pfGuid == sourceGuid)
468  {
469  if (size.Width == metadata.Width && size.Height == metadata.Height)
470  {
471  // This frame does not need resized or format converted, just copy...
472  frame.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
473  }
474  else
475  {
476  // This frame needs resizing, but not format converted
477  using (var scaler = new BitmapScaler(Factory))
478  {
479  scaler.Initialize(frame, metadata.Width, metadata.Height, GetWICInterp(flags));
480  scaler.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
481  }
482  }
483  }
484  else
485  {
486  // This frame required format conversion
487  using (var converter = new FormatConverter(Factory))
488  {
489  converter.Initialize(frame, pfGuid, GetWICDither(flags), null, 0, BitmapPaletteType.Custom);
490 
491  if (size.Width == metadata.Width && size.Height == metadata.Height)
492  {
493  converter.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
494  }
495  else
496  {
497  // This frame needs resizing, but not format converted
498  using (var scaler = new BitmapScaler(Factory))
499  {
500  scaler.Initialize(frame, metadata.Width, metadata.Height, GetWICInterp(flags));
501  scaler.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
502  }
503  }
504  }
505  }
506  }
507  }
508  return image;
509  }
510 
511  //-------------------------------------------------------------------------------------
512  // Load a WIC-supported file in memory
513  //-------------------------------------------------------------------------------------
514  internal static Image LoadFromWICMemory(IntPtr pSource, int size, bool makeACopy, GCHandle? handle)
515  {
516  var flags = WICFlags.AllFrames;
517 
518  Image image = null;
519  // Create input stream for memory
520  using (var stream = new WICStream(Factory, new SharpDX.DataPointer(pSource, size)))
521  {
522  // If the decoder is unable to decode the image, than return null
523  BitmapDecoder decoder = null;
524  try
525  {
526  decoder = new BitmapDecoder(Factory, stream, DecodeOptions.CacheOnDemand);
527  using (var frame = decoder.GetFrame(0))
528  {
529  // Get metadata
530  Guid convertGuid;
531  var tempDesc = DecodeMetadata(flags, decoder, frame, out convertGuid);
532 
533  // If not supported.
534  if (!tempDesc.HasValue)
535  return null;
536 
537  var mdata = tempDesc.Value;
538 
539  if ((mdata.ArraySize > 1) && (flags & WICFlags.AllFrames) != 0)
540  {
541  return DecodeMultiframe(flags, mdata, decoder);
542  }
543 
544  image = DecodeSingleFrame(flags, mdata, convertGuid, frame);
545  }
546  }
547  catch
548  {
549  image = null;
550  }
551  finally
552  {
553  if (decoder != null)
554  decoder.Dispose();
555  }
556  }
557 
558  // For WIC, we are not keeping the original buffer.
559  if (image != null && !makeACopy)
560  {
561  if (handle.HasValue)
562  {
563  handle.Value.Free();
564  }
565  else
566  {
567  Utilities.FreeMemory(pSource);
568  }
569  }
570  return image;
571  }
572 
573  //-------------------------------------------------------------------------------------
574  // Encodes a single frame
575  //-------------------------------------------------------------------------------------
576  private static void EncodeImage(PixelBuffer image, WICFlags flags, BitmapFrameEncode frame)
577  {
578  Guid pfGuid;
579  if (!ToWIC(image.Format, out pfGuid))
580  throw new NotSupportedException("Format not supported");
581 
582  frame.Initialize();
583  frame.SetSize(image.Width, image.Height);
584  frame.SetResolution(72, 72);
585  Guid targetGuid = pfGuid;
586  frame.SetPixelFormat(ref targetGuid);
587 
588  if (targetGuid != pfGuid)
589  {
590  using (var source = new Bitmap(Factory, image.Width, image.Height, pfGuid, new SharpDX.DataRectangle(image.DataPointer, image.RowStride), image.BufferStride))
591  {
592  using (var converter = new FormatConverter(Factory))
593  {
594  using (var palette = new Palette(Factory))
595  {
596  palette.Initialize(source, 256, true);
597  converter.Initialize(source, targetGuid, GetWICDither(flags), palette, 0, BitmapPaletteType.Custom);
598 
599  int bpp = GetBitsPerPixel(targetGuid);
600  if (bpp == 0) throw new NotSupportedException("Unable to determine the Bpp for the target format");
601 
602  int rowPitch = (image.Width * bpp + 7) / 8;
603  int slicePitch = rowPitch * image.Height;
604 
605  var temp = Utilities.AllocateMemory(slicePitch);
606  try
607  {
608  converter.CopyPixels(rowPitch, temp, slicePitch);
609  frame.Palette = palette;
610  frame.WritePixels(image.Height, temp, rowPitch, slicePitch);
611  }
612  finally
613  {
614  Utilities.FreeMemory(temp);
615  }
616  }
617  }
618  }
619  }
620  else
621  {
622  // No conversion required
623  frame.WritePixels(image.Height, image.DataPointer, image.RowStride, image.BufferStride);
624  }
625 
626  frame.Commit();
627  }
628 
629  private static void EncodeSingleFrame(PixelBuffer pixelBuffer, WICFlags flags, Guid guidContainerFormat, Stream stream)
630  {
631  using (var encoder = new BitmapEncoder(Factory, guidContainerFormat, stream))
632  {
633  using (var frame = new BitmapFrameEncode(encoder))
634  {
635  if (guidContainerFormat == ContainerFormatGuids.Bmp)
636  {
637  try
638  {
639  frame.Options.Set("EnableV5Header32bppBGRA", true);
640  }
641  catch
642  {
643  }
644  }
645  EncodeImage(pixelBuffer, flags, frame);
646  encoder.Commit();
647  }
648  }
649  }
650 
651  //-------------------------------------------------------------------------------------
652  // Encodes an image array
653  //-------------------------------------------------------------------------------------
654  private static void EncodeMultiframe(PixelBuffer[] images, int count, WICFlags flags, Guid guidContainerFormat, Stream stream)
655  {
656  if (images.Length < 2)
657  throw new ArgumentException("Cannot encode to multiple frame. Image doesn't have multiple frame");
658 
659  using (var encoder = new BitmapEncoder(Factory, guidContainerFormat))
660  {
661  using (var eInfo = encoder.EncoderInfo)
662  {
663  if (!eInfo.IsMultiframeSupported)
664  throw new NotSupportedException("Cannot encode to multiple frame. Format is not supporting multiple frame");
665  }
666 
667  encoder.Initialize(stream);
668 
669  for (int i = 0; i < Math.Min(images.Length, count); i++)
670  {
671  var pixelBuffer = images[i];
672  using (var frame = new BitmapFrameEncode(encoder))
673  EncodeImage(pixelBuffer, flags, frame);
674  }
675 
676  encoder.Commit();
677  }
678  }
679 
680  private static Guid GetContainerFormatFromFileType(ImageFileType fileType)
681  {
682  switch (fileType)
683  {
684  case ImageFileType.Bmp:
685  return ContainerFormatGuids.Bmp;
686  case ImageFileType.Jpg:
687  return ContainerFormatGuids.Jpeg;
688  case ImageFileType.Gif:
689  return ContainerFormatGuids.Gif;
690  case ImageFileType.Png:
691  return ContainerFormatGuids.Png;
692  case ImageFileType.Tiff:
693  return ContainerFormatGuids.Tiff;
694  case ImageFileType.Wmp:
695  return ContainerFormatGuids.Wmp;
696  default:
697  throw new NotSupportedException("Format not supported");
698  }
699  }
700 
701  internal static void SaveGifToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
702  {
703  SaveToWICMemory(pixelBuffers, count, WICFlags.AllFrames, ImageFileType.Gif, imageStream);
704  }
705 
706  internal static void SaveTiffToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
707  {
708  SaveToWICMemory(pixelBuffers, count, WICFlags.AllFrames, ImageFileType.Tiff, imageStream);
709  }
710 
711  internal static void SaveBmpToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
712  {
713  SaveToWICMemory(pixelBuffers, 1, WICFlags.None, ImageFileType.Bmp, imageStream);
714  }
715 
716  internal static void SaveJpgToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
717  {
718  SaveToWICMemory(pixelBuffers, 1, WICFlags.None, ImageFileType.Jpg, imageStream);
719  }
720 
721  internal static void SavePngToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
722  {
723  SaveToWICMemory(pixelBuffers, 1, WICFlags.None, ImageFileType.Png, imageStream);
724  }
725 
726  internal static void SaveWmpToWICMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
727  {
728  SaveToWICMemory(pixelBuffers, 1, WICFlags.None, ImageFileType.Wmp, imageStream);
729  }
730 
731  private static void SaveToWICMemory(PixelBuffer[] pixelBuffer, int count, WICFlags flags, ImageFileType fileType, Stream stream)
732  {
733  if (count > 1)
734  EncodeMultiframe(pixelBuffer, count, flags, GetContainerFormatFromFileType(fileType), stream);
735  else
736  EncodeSingleFrame(pixelBuffer[0], flags, GetContainerFormatFromFileType(fileType), stream);
737  }
738 
739  public static void Dispose()
740  {
741  Utilities.Dispose(ref _factory);
742  }
743  }
744 }
745 #endif
ImageFileType
Image file format used by Image.Save(string,SiliconStudio.Paradox.Graphics.ImageFileType) ...
SharpDX.DirectWrite.Factory Factory
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
_In_ size_t _In_ const TexMetadata & metadata
Definition: DirectXTexP.h:116
_In_ size_t count
Definition: DirectXTexP.h:174
HRESULT LoadFromWICMemory(_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata *metadata, _Out_ ScratchImage &image)
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
size_t BitsPerPixel(_In_ DXGI_FORMAT fmt)
HRESULT SaveToWICMemory(_In_ const Image &image, _In_ DWORD flags, _In_ REFGUID guidContainerFormat, _Out_ Blob &blob, _In_opt_ const GUID *targetFormat=nullptr, _In_opt_ std::function< void(IPropertyBag2 *)> setCustomProps=nullptr)
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32