private static void EncodeImage(ImagingFactory imagingFactory, Image image, WicFlags flags, Guid containerFormat, BitmapFrameEncode frame) { Guid pfGuid = ToWic(image.Format, false); frame.Initialize(); frame.SetSize(image.Width, image.Height); frame.SetResolution(72, 72); Guid targetGuid = pfGuid; frame.SetPixelFormat(ref targetGuid); EncodeMetadata(frame, containerFormat, image.Format); if (targetGuid != pfGuid) { // Conversion required to write. GCHandle handle = GCHandle.Alloc(image.Data, GCHandleType.Pinned); using (var source = new Bitmap(imagingFactory, image.Width, image.Height, pfGuid, new DataRectangle(handle.AddrOfPinnedObject(), image.RowPitch), image.Data.Length)) { using (var converter = new FormatConverter(imagingFactory)) { if (!converter.CanConvert(pfGuid, targetGuid)) throw new NotSupportedException("Format conversion is not supported."); converter.Initialize(source, targetGuid, GetWicDither(flags), null, 0, BitmapPaletteType.Custom); frame.WriteSource(converter, new Rectangle(0, 0, image.Width, image.Height)); } } handle.Free(); } else { // No conversion required. frame.WritePixels(image.Height, image.RowPitch, image.Data); } frame.Commit(); }
/// <summary> /// Function to perform conversion/transformation of a bitmap. /// </summary> /// <param name="sourceData">WIC bitmap to transform.</param> /// <param name="destData">Destination data buffer.</param> /// <param name="rowPitch">Number of bytes per row in the image.</param> /// <param name="slicePitch">Number of bytes in total for the image.</param> /// <param name="destFormat">Destination format for transformation.</param> /// <param name="isSourcesRGB">TRUE if the source format is sRGB.</param> /// <param name="isDestsRGB">TRUE if the destination format is sRGB.</param> /// <param name="dither">Dithering to apply to images that get converted to a lower bit depth.</param> /// <param name="destRect">Rectangle containing the area to scale or clip</param> /// <param name="clip">TRUE to perform clipping instead of scaling.</param> /// <param name="scaleFilter">Filter to apply to scaled data.</param> public void TransformImageData(WIC.BitmapSource sourceData, IntPtr destData, int rowPitch, int slicePitch, Guid destFormat, bool isSourcesRGB, bool isDestsRGB, ImageDithering dither, Rectangle destRect, bool clip, ImageFilter scaleFilter) { WIC.BitmapSource source = sourceData; WIC.FormatConverter converter = null; WIC.BitmapClipper clipper = null; WIC.BitmapScaler scaler = null; WIC.ColorContext sourceContext = null; WIC.ColorContext destContext = null; WIC.ColorTransform sRGBTransform = null; try { if (destFormat != Guid.Empty) { if (sourceData.PixelFormat != destFormat) { converter = new WIC.FormatConverter(Factory); if (!converter.CanConvert(sourceData.PixelFormat, destFormat)) { throw new GorgonException(GorgonResult.FormatNotSupported, string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, destFormat)); } converter.Initialize(source, destFormat, (WIC.BitmapDitherType)dither, null, 0, WIC.BitmapPaletteType.Custom); source = converter; } if ((isDestsRGB) || (isSourcesRGB)) { sRGBTransform = new WIC.ColorTransform(Factory); sourceContext = new WIC.ColorContext(Factory); destContext = new WIC.ColorContext(Factory); sourceContext.InitializeFromExifColorSpace(isSourcesRGB ? 1 : 2); destContext.InitializeFromExifColorSpace(isDestsRGB ? 1 : 2); sRGBTransform.Initialize(source, sourceContext, destContext, destFormat); source = sRGBTransform; } } if (destRect.IsEmpty) { source.CopyPixels(rowPitch, destData, slicePitch); return; } Guid pixelFormat = source.PixelFormat; if (!clip) { scaler = new WIC.BitmapScaler(Factory); scaler.Initialize(source, destRect.Width, destRect.Height, (WIC.BitmapInterpolationMode)scaleFilter); source = scaler; } else { destRect.Width = destRect.Width.Min(source.Size.Width); destRect.Height = destRect.Height.Min(source.Size.Height); if ((destRect.Width < source.Size.Width) || (destRect.Height < source.Size.Height)) { clipper = new WIC.BitmapClipper(Factory); clipper.Initialize(source, new DX.Rectangle(destRect.X, destRect.Y, destRect.Width, destRect.Height)); source = clipper; destRect.X = 0; destRect.Y = 0; } } // We have a change of format (probably due to the filter when scaling)... so we need to convert. if (source.PixelFormat != pixelFormat) { converter = new WIC.FormatConverter(Factory); if (!converter.CanConvert(source.PixelFormat, pixelFormat)) { throw new GorgonException(GorgonResult.FormatNotSupported, string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, pixelFormat)); } converter.Initialize(source, pixelFormat, WIC.BitmapDitherType.None, null, 0, WIC.BitmapPaletteType.Custom); source = converter; } source.CopyPixels(rowPitch, destData, slicePitch); } finally { if (converter != null) { converter.Dispose(); } if (sourceContext != null) { sourceContext.Dispose(); } if (destContext != null) { destContext.Dispose(); } if (sRGBTransform != null) { sRGBTransform.Dispose(); } if (scaler != null) { scaler.Dispose(); } if (clipper != null) { clipper.Dispose(); } } }
private Result SaveWICTextureToFileFix( DeviceContext context, Texture2D source, ref Guid guidContainerFormat, string fileName) { if (fileName == null) { return(Result.InvalidArg); } Result res = CaptureTextureFix(context, source, out Texture2DDescription desc, out Texture2D staging); if (res.Failure) { return(res); } Guid pfGuid; //bool sRGB = false; Guid targetGuid; switch (desc.Format) { case DXGI.Format.R32G32B32A32_Float: pfGuid = WIC.PixelFormat.Format128bppRGBAFloat; break; case DXGI.Format.R16G16B16A16_Float: pfGuid = WIC.PixelFormat.Format64bppRGBAHalf; break; case DXGI.Format.R16G16B16A16_UNorm: pfGuid = WIC.PixelFormat.Format64bppRGBA; break; case DXGI.Format.R10G10B10_Xr_Bias_A2_UNorm: pfGuid = WIC.PixelFormat.Format32bppRGBA1010102XR; break; // DXGI 1.1 case DXGI.Format.R10G10B10A2_UNorm: pfGuid = WIC.PixelFormat.Format32bppRGBA1010102; break; case DXGI.Format.B5G5R5A1_UNorm: pfGuid = WIC.PixelFormat.Format16bppBGRA5551; break; case DXGI.Format.B5G6R5_UNorm: pfGuid = WIC.PixelFormat.Format16bppBGR565; break; case DXGI.Format.R32_Float: pfGuid = WIC.PixelFormat.Format32bppGrayFloat; break; case DXGI.Format.R16_Float: pfGuid = WIC.PixelFormat.Format16bppGrayHalf; break; case DXGI.Format.R16_UNorm: pfGuid = WIC.PixelFormat.Format16bppGray; break; case DXGI.Format.R8_UNorm: pfGuid = WIC.PixelFormat.Format8bppGray; break; case DXGI.Format.A8_UNorm: pfGuid = WIC.PixelFormat.Format8bppAlpha; break; case DXGI.Format.R8G8B8A8_UNorm: pfGuid = WIC.PixelFormat.Format32bppRGBA; break; case DXGI.Format.R8G8B8A8_UNorm_SRgb: pfGuid = WIC.PixelFormat.Format32bppRGBA; //sRGB = true; break; case DXGI.Format.B8G8R8A8_UNorm: // DXGI 1.1 pfGuid = WIC.PixelFormat.Format32bppBGRA; break; case DXGI.Format.B8G8R8A8_UNorm_SRgb: // DXGI 1.1 pfGuid = WIC.PixelFormat.Format32bppBGRA; //sRGB = true; break; case DXGI.Format.B8G8R8X8_UNorm: // DXGI 1.1 pfGuid = WIC.PixelFormat.Format32bppBGR; break; case DXGI.Format.B8G8R8X8_UNorm_SRgb: // DXGI 1.1 pfGuid = WIC.PixelFormat.Format32bppBGR; //sRGB = true; break; default: return(Result.GetResultFromWin32Error(unchecked ((int)0x80070032))); } // Create file FileStream fs = new FileStream(fileName, FileMode.Create); WIC.BitmapEncoder encoder = new WIC.BitmapEncoder(DirectX.ImageFactory, guidContainerFormat); encoder.Initialize(fs); WIC.BitmapFrameEncode frameEncode = new WIC.BitmapFrameEncode(encoder); frameEncode.Initialize(); frameEncode.SetSize(desc.Width, desc.Height); frameEncode.SetResolution(72.0, 72.0); switch (desc.Format) { case DXGI.Format.R32G32B32A32_Float: case DXGI.Format.R16G16B16A16_Float: targetGuid = WIC.PixelFormat.Format24bppBGR; break; case DXGI.Format.R16G16B16A16_UNorm: targetGuid = WIC.PixelFormat.Format48bppBGR; break; case DXGI.Format.B5G5R5A1_UNorm: targetGuid = WIC.PixelFormat.Format16bppBGR555; break; case DXGI.Format.B5G6R5_UNorm: targetGuid = WIC.PixelFormat.Format16bppBGR565; break; case DXGI.Format.R32_Float: case DXGI.Format.R16_Float: case DXGI.Format.R16_UNorm: case DXGI.Format.R8_UNorm: case DXGI.Format.A8_UNorm: targetGuid = WIC.PixelFormat.Format8bppGray; break; default: targetGuid = WIC.PixelFormat.Format24bppBGR; break; } frameEncode.SetPixelFormat(ref targetGuid); #region Write DataBox db = context.MapSubresource(staging, 0, MapMode.Read, MapFlags.None, out DataStream stream); if (pfGuid != targetGuid) { WIC.FormatConverter formatCoverter = new WIC.FormatConverter(DirectX.ImageFactory); if (formatCoverter.CanConvert(pfGuid, targetGuid)) { WIC.Bitmap src = new WIC.Bitmap(DirectX.ImageFactory, desc.Width, desc.Height, pfGuid, new DataRectangle(db.DataPointer, db.RowPitch)); formatCoverter.Initialize(src, targetGuid, SharpDX.WIC.BitmapDitherType.None, null, 0, SharpDX.WIC.BitmapPaletteType.Custom); frameEncode.WriteSource(formatCoverter, new Rectangle(0, 0, desc.Width, desc.Height)); } } else { frameEncode.WritePixels(desc.Height, new DataRectangle(db.DataPointer, db.RowPitch)); } context.UnmapSubresource(staging, 0); frameEncode.Commit(); encoder.Commit(); #endregion frameEncode.Dispose(); encoder.Dispose(); fs.Close(); return(Result.Ok); }
/// <summary> /// Function to convert the format of a bitmap into the format of the buffer. /// </summary> /// <param name="sourceFormat">Format to convert from.</param> /// <param name="destFormat">Format to convert into.</param> /// <param name="dithering">Dithering to apply.</param> /// <param name="filter">Filtering to apply to scaled bitmaps.</param> /// <param name="bitmap">Bitmap to convert.</param> /// <param name="bitmapPalette">Palette for the bitmap.</param> /// <param name="alphaValue">Value of pixel to consider transparent.</param> /// <param name="buffer">Buffer holding the converted data.</param> /// <param name="scale">TRUE to scale when converting, FALSE to keep at original size.</param> /// <param name="clip">TRUE to perform clipping, FALSE to keep at original size.</param> private void ConvertFormat(Guid sourceFormat, Guid destFormat, WIC.BitmapDitherType dithering, WIC.BitmapInterpolationMode filter, WIC.BitmapSource bitmap, WIC.Palette bitmapPalette, int alphaValue, GorgonImageBuffer buffer, bool scale, bool clip) { WIC.BitmapSource source = bitmap; double alphaPercent = alphaValue / 255.0; var paletteType = WIC.BitmapPaletteType.Custom; // If we have a palette, then confirm that the dithering method is valid. if (bitmapPalette != null) { // Do not apply dithering if we're using // a custom palette and request ordered dithering. switch (dithering) { case WIC.BitmapDitherType.Ordered4x4: case WIC.BitmapDitherType.Ordered8x8: case WIC.BitmapDitherType.Ordered16x16: if (bitmapPalette.TypeInfo == WIC.BitmapPaletteType.Custom) { dithering = WIC.BitmapDitherType.None; } break; } paletteType = bitmapPalette.TypeInfo; } try { // Create a scaler if need one. if ((scale) && (!clip)) { var scaler = new WIC.BitmapScaler(Factory); scaler.Initialize(bitmap, buffer.Width, buffer.Height, filter); source = scaler; } // Create a clipper if we want to clip and the image needs resizing. if ((clip) && (scale) && ((buffer.Width < bitmap.Size.Width) || (buffer.Height < bitmap.Size.Height))) { var clipper = new WIC.BitmapClipper(Factory); clipper.Initialize(bitmap, new DX.Rectangle(0, 0, buffer.Width < bitmap.Size.Width ? buffer.Width : bitmap.Size.Width, buffer.Height < bitmap.Size.Height ? buffer.Height : bitmap.Size.Height)); source = clipper; } using (var converter = new WIC.FormatConverter(Factory)) { if (!converter.CanConvert(sourceFormat, destFormat)) { throw new GorgonException(GorgonResult.FormatNotSupported, string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, buffer.Format)); } converter.Initialize(source, destFormat, dithering, bitmapPalette, alphaPercent, paletteType); if (!scale) { int rowPitch = (GetBitsPerPixel(destFormat) * bitmap.Size.Width + 7) / 8; int slicePitch = rowPitch * bitmap.Size.Height; if ((rowPitch != buffer.PitchInformation.RowPitch) || (slicePitch != buffer.PitchInformation.SlicePitch)) { throw new GorgonException(GorgonResult.CannotWrite, Resources.GORGFX_IMAGE_PITCH_TOO_SMALL); } } converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch); } } finally { if (source != bitmap) { source.Dispose(); } } }