76 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
78 using System.Diagnostics;
80 using System.Runtime.InteropServices;
82 using SiliconStudio.Core;
83 using WIC = SharpDX.WIC;
86 namespace SiliconStudio.
Paradox.Graphics
88 public class WICHelper
90 private static WIC.ImagingFactory _factory =
new ImagingFactory();
92 private static ImagingFactory
Factory {
get {
return _factory ?? (_factory =
new ImagingFactory()); } }
105 public readonly Guid WIC;
106 public readonly Format Format;
109 private static readonly
WICTranslate[] WICToDXGIFormats =
111 new WICTranslate(SharpDX.WIC.PixelFormat.Format128bppRGBAFloat, Format.R32G32B32A32_Float),
113 new WICTranslate(SharpDX.WIC.PixelFormat.Format64bppRGBAHalf, Format.R16G16B16A16_Float),
114 new WICTranslate(SharpDX.WIC.PixelFormat.Format64bppRGBA, Format.R16G16B16A16_UNorm),
116 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA, Format.R8G8B8A8_UNorm),
117 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppBGRA, Format.B8G8R8A8_UNorm),
118 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppBGR, Format.B8G8R8X8_UNorm),
120 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA1010102XR, Format.R10G10B10_Xr_Bias_A2_UNorm),
121 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBA1010102, Format.R10G10B10A2_UNorm),
122 new WICTranslate(SharpDX.WIC.PixelFormat.Format32bppRGBE, Format.R9G9B9E5_Sharedexp),
124 new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppBGRA5551, Format.B5G5R5A1_UNorm),
125 new WICTranslate(SharpDX.WIC.PixelFormat.Format16bppBGR565, Format.B5G6R5_UNorm),
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),
132 new WICTranslate(SharpDX.WIC.PixelFormat.Format8bppAlpha, Format.A8_UNorm),
134 new WICTranslate(SharpDX.WIC.PixelFormat.FormatBlackWhite, Format.R1_UNorm),
137 new WICTranslate(SharpDX.WIC.PixelFormat.Format96bppRGBFloat, Format.R32G32B32_Float ),
149 this.source = source;
150 this.target = target;
153 public readonly Guid source;
154 public readonly Guid target;
157 private static readonly
WICConvert[] WICConvertTable =
162 new WICConvert(WIC.PixelFormat.Format1bppIndexed, WIC.PixelFormat.Format32bppRGBA),
163 new WICConvert(WIC.PixelFormat.Format2bppIndexed, WIC.PixelFormat.Format32bppRGBA),
164 new WICConvert(WIC.PixelFormat.Format4bppIndexed, WIC.PixelFormat.Format32bppRGBA),
165 new WICConvert(WIC.PixelFormat.Format8bppIndexed, WIC.PixelFormat.Format32bppRGBA),
167 new WICConvert(WIC.PixelFormat.Format2bppGray, WIC.PixelFormat.Format8bppGray),
168 new WICConvert(WIC.PixelFormat.Format4bppGray, WIC.PixelFormat.Format8bppGray),
170 new WICConvert(WIC.PixelFormat.Format16bppGrayFixedPoint, WIC.PixelFormat.Format16bppGrayHalf),
171 new WICConvert(WIC.PixelFormat.Format32bppGrayFixedPoint, WIC.PixelFormat.Format32bppGrayFloat),
173 new WICConvert(WIC.PixelFormat.Format16bppBGR555, WIC.PixelFormat.Format16bppBGRA5551),
174 new WICConvert(WIC.PixelFormat.Format32bppBGR101010, WIC.PixelFormat.Format32bppRGBA1010102),
176 new WICConvert(WIC.PixelFormat.Format24bppBGR, WIC.PixelFormat.Format32bppRGBA),
177 new WICConvert(WIC.PixelFormat.Format24bppRGB, WIC.PixelFormat.Format32bppRGBA),
178 new WICConvert(WIC.PixelFormat.Format32bppPBGRA, WIC.PixelFormat.Format32bppRGBA),
179 new WICConvert(WIC.PixelFormat.Format32bppPRGBA, WIC.PixelFormat.Format32bppRGBA),
181 new WICConvert(WIC.PixelFormat.Format48bppRGB, WIC.PixelFormat.Format64bppRGBA),
182 new WICConvert(WIC.PixelFormat.Format48bppBGR, WIC.PixelFormat.Format64bppRGBA),
183 new WICConvert(WIC.PixelFormat.Format64bppBGRA, WIC.PixelFormat.Format64bppRGBA),
184 new WICConvert(WIC.PixelFormat.Format64bppPRGBA, WIC.PixelFormat.Format64bppRGBA),
185 new WICConvert(WIC.PixelFormat.Format64bppPBGRA, WIC.PixelFormat.Format64bppRGBA),
187 new WICConvert(WIC.PixelFormat.Format48bppRGBFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf),
188 new WICConvert(WIC.PixelFormat.Format48bppBGRFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf),
189 new WICConvert(WIC.PixelFormat.Format64bppRGBAFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf),
190 new WICConvert(WIC.PixelFormat.Format64bppBGRAFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf),
191 new WICConvert(WIC.PixelFormat.Format64bppRGBFixedPoint, WIC.PixelFormat.Format64bppRGBAHalf),
192 new WICConvert(WIC.PixelFormat.Format64bppRGBHalf, WIC.PixelFormat.Format64bppRGBAHalf),
193 new WICConvert(WIC.PixelFormat.Format48bppRGBHalf, WIC.PixelFormat.Format64bppRGBAHalf),
195 new WICConvert(WIC.PixelFormat.Format128bppPRGBAFloat, WIC.PixelFormat.Format128bppRGBAFloat),
196 new WICConvert(WIC.PixelFormat.Format128bppRGBFloat, WIC.PixelFormat.Format128bppRGBAFloat),
197 new WICConvert(WIC.PixelFormat.Format128bppRGBAFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat),
198 new WICConvert(WIC.PixelFormat.Format128bppRGBFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat),
200 new WICConvert(WIC.PixelFormat.Format32bppCMYK, WIC.PixelFormat.Format32bppRGBA),
201 new WICConvert(WIC.PixelFormat.Format64bppCMYK, WIC.PixelFormat.Format64bppRGBA),
202 new WICConvert(WIC.PixelFormat.Format40bppCMYKAlpha, WIC.PixelFormat.Format64bppRGBA),
203 new WICConvert(WIC.PixelFormat.Format80bppCMYKAlpha, WIC.PixelFormat.Format64bppRGBA),
206 new WICConvert( WIC.PixelFormat.Format32bppRGB, WIC.PixelFormat.Format32bppRGBA ),
207 new WICConvert( WIC.PixelFormat.Format64bppRGB, WIC.PixelFormat.Format64bppRGBA ),
208 new WICConvert( WIC.PixelFormat.Format64bppPRGBAHalf, WIC.PixelFormat.Format64bppRGBAHalf ),
209 new WICConvert( WIC.PixelFormat.Format96bppRGBFixedPoint, WIC.PixelFormat.Format96bppRGBFloat ),
211 new WICConvert(WIC.PixelFormat.Format96bppRGBFixedPoint, WIC.PixelFormat.Format128bppRGBAFloat),
222 private static Format ToDXGI(Guid guid)
224 for (
int i = 0; i < WICToDXGIFormats.Length; ++i)
226 if (WICToDXGIFormats[i].WIC == guid)
227 return WICToDXGIFormats[i].Format;
239 private static bool ToWIC(Format
format, out Guid guid)
241 for (
int i = 0; i < WICToDXGIFormats.Length; ++i)
243 if (WICToDXGIFormats[i].Format == format)
245 guid = WICToDXGIFormats[i].WIC;
253 case Format.R8G8B8A8_UNorm_SRgb:
254 guid = SharpDX.WIC.PixelFormat.Format32bppRGBA;
257 case Format.D32_Float:
258 guid = SharpDX.WIC.PixelFormat.Format32bppGrayFloat;
261 case Format.D16_UNorm:
262 guid = SharpDX.WIC.PixelFormat.Format16bppGray;
265 case Format.B8G8R8A8_UNorm_SRgb:
266 guid = SharpDX.WIC.PixelFormat.Format32bppBGRA;
269 case Format.B8G8R8X8_UNorm_SRgb:
270 guid = SharpDX.WIC.PixelFormat.Format32bppBGR;
283 private static int GetBitsPerPixel(Guid targetGuid)
285 using (var info =
new ComponentInfo(
Factory, targetGuid))
287 if (info.ComponentType != ComponentType.PixelFormat)
290 var pixelFormatInfo = info.QueryInterfaceOrNull<PixelFormatInfo>();
291 if (pixelFormatInfo == null)
295 pixelFormatInfo.Dispose();
304 private static Format DetermineFormat(Guid pixelFormat, WICFlags
flags, out Guid pixelFormatOut)
306 Format format = ToDXGI(pixelFormat);
307 pixelFormatOut = Guid.Empty;
309 if (format == Format.None)
311 for (
int i = 0; i < WICConvertTable.Length; ++i)
313 if (WICConvertTable[i].source == pixelFormat)
315 pixelFormatOut = WICConvertTable[i].target;
317 format = ToDXGI(WICConvertTable[i].target);
318 Debug.Assert(format != Format.None);
327 case Format.B8G8R8A8_UNorm:
328 case Format.B8G8R8X8_UNorm:
329 if ((flags & WICFlags.ForceRgb) != 0)
331 format = Format.R8G8B8A8_UNorm;
332 pixelFormatOut = WIC.PixelFormat.Format32bppRGBA;
336 case Format.R10G10B10_Xr_Bias_A2_UNorm:
337 if ((flags & WICFlags.NoX2Bias) != 0)
339 format = Format.R10G10B10A2_UNorm;
340 pixelFormatOut = WIC.PixelFormat.Format32bppRGBA1010102;
344 case Format.B5G5R5A1_UNorm:
345 case Format.B5G6R5_UNorm:
346 if ((flags & WICFlags.No16Bpp) != 0)
348 format = Format.R8G8B8A8_UNorm;
349 pixelFormatOut = WIC.PixelFormat.Format32bppRGBA;
353 case Format.R1_UNorm:
354 if ((flags & WICFlags.FlagsAllowMono) == 0)
357 format = Format.R8_UNorm;
358 pixelFormatOut = WIC.PixelFormat.Format8bppGray;
375 private static ImageDescription? DecodeMetadata(WICFlags flags, BitmapDecoder decoder, BitmapFrameDecode frame, out Guid pixelFormat)
377 var
size = frame.Size;
381 Dimension = TextureDimension.Texture2D,
383 Height = size.Height,
386 ArraySize = (flags & WICFlags.AllFrames) != 0 ? decoder.FrameCount : 1,
387 Format = DetermineFormat(frame.PixelFormat, flags, out pixelFormat)
390 if (metadata.Format == Format.None)
396 private static BitmapDitherType GetWICDither(WICFlags flags)
398 if ((flags & WICFlags.Dither) != 0)
399 return BitmapDitherType.Ordered4x4;
401 if ((flags & WICFlags.DitherDiffusion) != 0)
402 return BitmapDitherType.ErrorDiffusion;
404 return BitmapDitherType.None;
408 private static BitmapInterpolationMode GetWICInterp(WICFlags flags)
410 if ((flags & WICFlags.FilterPoint) != 0)
411 return BitmapInterpolationMode.NearestNeighbor;
413 if ((flags & WICFlags.FilterLinear) != 0)
414 return BitmapInterpolationMode.Linear;
416 if ((flags & WICFlags.FilterCubic) != 0)
417 return BitmapInterpolationMode.Cubic;
419 return BitmapInterpolationMode.Fant;
425 private static Image DecodeSingleFrame(WICFlags flags, ImageDescription metadata, Guid convertGUID, BitmapFrameDecode frame)
429 var pixelBuffer = image.PixelBuffer[0];
431 if (convertGUID == Guid.Empty)
433 frame.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
437 using (var converter =
new FormatConverter(
Factory))
439 converter.Initialize(frame, convertGUID, GetWICDither(flags), null, 0, BitmapPaletteType.Custom);
440 converter.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
450 private static Image DecodeMultiframe(WICFlags flags, ImageDescription metadata, BitmapDecoder decoder)
455 if (!ToWIC(metadata.Format, out sourceGuid))
458 for (
int index = 0; index < metadata.ArraySize; ++index)
460 var pixelBuffer = image.PixelBuffer[index, 0];
462 using (var frame = decoder.GetFrame(index))
465 var size = frame.Size;
467 if (pfGuid == sourceGuid)
469 if (size.Width == metadata.Width && size.Height == metadata.Height)
472 frame.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
477 using (var scaler =
new BitmapScaler(
Factory))
479 scaler.Initialize(frame, metadata.Width, metadata.Height, GetWICInterp(flags));
480 scaler.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
487 using (var converter =
new FormatConverter(
Factory))
489 converter.Initialize(frame, pfGuid, GetWICDither(flags), null, 0, BitmapPaletteType.Custom);
491 if (size.Width == metadata.Width && size.Height == metadata.Height)
493 converter.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
498 using (var scaler =
new BitmapScaler(
Factory))
500 scaler.Initialize(frame, metadata.Width, metadata.Height, GetWICInterp(flags));
501 scaler.CopyPixels(pixelBuffer.RowStride, pixelBuffer.DataPointer, pixelBuffer.BufferStride);
516 var flags = WICFlags.AllFrames;
520 using (var stream =
new WICStream(
Factory,
new SharpDX.DataPointer(pSource, size)))
523 BitmapDecoder decoder = null;
526 decoder =
new BitmapDecoder(
Factory, stream, DecodeOptions.CacheOnDemand);
527 using (var frame = decoder.GetFrame(0))
531 var tempDesc = DecodeMetadata(flags, decoder, frame, out convertGuid);
534 if (!tempDesc.HasValue)
537 var mdata = tempDesc.Value;
539 if ((mdata.ArraySize > 1) && (flags & WICFlags.AllFrames) != 0)
541 return DecodeMultiframe(flags, mdata, decoder);
544 image = DecodeSingleFrame(flags, mdata, convertGuid, frame);
559 if (image != null && !makeACopy)
567 Utilities.FreeMemory(pSource);
576 private static void EncodeImage(PixelBuffer image, WICFlags flags, BitmapFrameEncode frame)
579 if (!ToWIC(image.Format, out pfGuid))
580 throw new NotSupportedException(
"Format not supported");
583 frame.SetSize(image.Width, image.Height);
584 frame.SetResolution(72, 72);
585 Guid targetGuid = pfGuid;
586 frame.SetPixelFormat(ref targetGuid);
588 if (targetGuid != pfGuid)
590 using (var source =
new Bitmap(
Factory, image.Width, image.Height, pfGuid,
new SharpDX.DataRectangle(image.DataPointer, image.RowStride), image.BufferStride))
592 using (var converter =
new FormatConverter(
Factory))
594 using (var palette =
new Palette(
Factory))
596 palette.Initialize(source, 256,
true);
597 converter.Initialize(source, targetGuid, GetWICDither(flags), palette, 0, BitmapPaletteType.Custom);
599 int bpp = GetBitsPerPixel(targetGuid);
600 if (bpp == 0)
throw new NotSupportedException(
"Unable to determine the Bpp for the target format");
602 int rowPitch = (image.Width * bpp + 7) / 8;
603 int slicePitch = rowPitch * image.Height;
605 var temp = Utilities.AllocateMemory(slicePitch);
608 converter.CopyPixels(rowPitch, temp, slicePitch);
609 frame.Palette = palette;
610 frame.WritePixels(image.Height, temp, rowPitch, slicePitch);
614 Utilities.FreeMemory(temp);
623 frame.WritePixels(image.Height, image.DataPointer, image.RowStride, image.BufferStride);
629 private static void EncodeSingleFrame(PixelBuffer pixelBuffer, WICFlags flags, Guid guidContainerFormat, Stream stream)
631 using (var encoder =
new BitmapEncoder(
Factory, guidContainerFormat, stream))
633 using (var frame =
new BitmapFrameEncode(encoder))
635 if (guidContainerFormat == ContainerFormatGuids.Bmp)
639 frame.Options.Set(
"EnableV5Header32bppBGRA",
true);
645 EncodeImage(pixelBuffer, flags, frame);
654 private static void EncodeMultiframe(PixelBuffer[] images,
int count, WICFlags flags, Guid guidContainerFormat, Stream stream)
656 if (images.Length < 2)
657 throw new ArgumentException(
"Cannot encode to multiple frame. Image doesn't have multiple frame");
659 using (var encoder =
new BitmapEncoder(
Factory, guidContainerFormat))
661 using (var eInfo = encoder.EncoderInfo)
663 if (!eInfo.IsMultiframeSupported)
664 throw new NotSupportedException(
"Cannot encode to multiple frame. Format is not supporting multiple frame");
667 encoder.Initialize(stream);
669 for (
int i = 0; i < Math.Min(images.Length,
count); i++)
671 var pixelBuffer = images[i];
672 using (var frame =
new BitmapFrameEncode(encoder))
673 EncodeImage(pixelBuffer, flags, frame);
680 private static Guid GetContainerFormatFromFileType(
ImageFileType fileType)
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;
697 throw new NotSupportedException(
"Format not supported");
701 internal static void SaveGifToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
706 internal static void SaveTiffToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
711 internal static void SaveBmpToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
716 internal static void SaveJpgToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
721 internal static void SavePngToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
726 internal static void SaveWmpToWICMemory(PixelBuffer[] pixelBuffers,
int count, ImageDescription description, Stream imageStream)
734 EncodeMultiframe(pixelBuffer, count, flags, GetContainerFormatFromFileType(fileType), stream);
736 EncodeSingleFrame(pixelBuffer[0], flags, GetContainerFormatFromFileType(fileType), stream);
739 public static void Dispose()
741 Utilities.Dispose(ref _factory);
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
_In_ size_t _In_ const TexMetadata & metadata
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
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
PixelFormat
Defines various types of pixel formats.