private static unsafe void EncodeImage(PixelBuffer image, WICFlags flags, IWICBitmapFrameEncode frame) { Guid pfGuid; if (!ToWIC(image.Format, out pfGuid)) { throw new NotSupportedException("Format not supported"); } frame.Initialize(); frame.SetSize(image.Width, image.Height); frame.SetResolution(72, 72); var targetGuid = pfGuid; frame.SetPixelFormat(ref targetGuid); if (targetGuid != pfGuid) { using (var source = Factory.CreateBitmapFromMemory(image.Width, image.Height, pfGuid, image.RowStride, image.BufferStride, image.DataPointer.ToPointer())) { using (var converter = Factory.CreateFormatConverter()) { using (var palette = Factory.CreatePalette()) { palette.InitializeFromBitmap(source, 256, true); converter.Initialize(source, targetGuid, GetWICDither(flags), palette, 0, BitmapPaletteType.Custom); var bpp = GetBitsPerPixel(targetGuid); if (bpp == 0) { throw new NotSupportedException("Unable to determine the Bpp for the target format"); } var rowPitch = (image.Width * bpp + 7) / 8; var slicePitch = rowPitch * image.Height; var temp = SdxUtilities.AllocateMemory(slicePitch); try { converter.CopyPixels(rowPitch, slicePitch, temp); frame.SetPalette(palette); frame.WritePixels(image.Height, temp, rowPitch, slicePitch); } finally { SdxUtilities.FreeMemory(temp); } } } } } else { // No conversion required frame.WritePixels(image.Height, image.DataPointer, image.RowStride, image.BufferStride); } frame.Commit(); }
public static void WritePixels(this IWICBitmapFrameEncode frame, uint lineCount, uint stride, byte[] pixels) { if (frame == null) { throw new ArgumentNullException(nameof(frame)); } if (pixels == null) { throw new ArgumentNullException(nameof(pixels)); } frame.WritePixels(lineCount, stride, pixels.Length, pixels).ThrowOnError(); }
protected override bool ProcessEncoder(MainForm form, IWICBitmapEncoder encoder, object tag) { Tag t = (Tag)tag; IWICImagingFactory factory = (IWICImagingFactory) new WICImagingFactory(); IWICPalette palette = factory.CreatePalette(); palette.InitializePredefined(WICBitmapPaletteType.WICBitmapPaletteTypeFixedBW, false); IWICBitmapFrameEncode frame = null; IWICBitmapFrameEncode frame2 = null; IPropertyBag2[] bag = new IPropertyBag2[1]; try { MethodInfo mi = typeof(IWICBitmapEncoder).GetMethod("CreateNewFrame"); try { encoder.CreateNewFrame(out frame, bag); } catch (Exception e) { form.Add(this, mi.ToString(Resources._0_Failed), new DataEntry(Resources.FrameIndex, 0), new DataEntry(e)); } if (frame == null) { form.Add(this, mi.ToString(Resources._0_NULL), new DataEntry(Resources.Parameter, mi.GetParameters()[0].Name)); } else { if (bag[0] == null) { form.Add(this, mi.ToString(Resources._0_NULL), new DataEntry(Resources.Parameter, mi.GetParameters()[1].Name)); } try { frame.Initialize(bag[0]); frame.SetSize(1, 1); frame.SetPalette(palette); Guid pixelFormat = Guid.Empty; List <Guid> allPixelFormats = new List <Guid>(PixelFormatInfoRule.AllPixelFormats); allPixelFormats.Add(Consts.GUID_WICPixelFormatDontCare); foreach (Guid g in allPixelFormats) { pixelFormat = g; frame.SetPixelFormat(ref pixelFormat); if (g == pixelFormat) { if (Array.IndexOf(t.PixelFormats, g) < 0) { form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources.DidNotChangeUnsupportedPixelFormat, "IWICBitmapFrameEncode::SetPixelFormat(...)"), new DataEntry(Resources.PixelFormat, g), new DataEntry(Resources.SupportedPixelFormats, t.PixelFormats)); } } else { if (Array.IndexOf(t.PixelFormats, g) >= 0) { form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources.ChangedSupportedPixelFormat, "IWICBitmapFrameEncode::SetPixelFormat(...)"), new DataEntry(Resources.Expected, g), new DataEntry(Resources.Actual, pixelFormat)); } } } pixelFormat = Consts.GUID_WICPixelFormat32bppBGRA; frame.SetPixelFormat(ref pixelFormat); byte[] buffer = new byte[(PixelFormatInfoRule.GetBitPerPixel(pixelFormat) + 7) / 8]; frame.WritePixels(1, (uint)buffer.Length, (uint)buffer.Length, buffer); frame.Commit(); try { encoder.CreateNewFrame(out frame2, null); if (!t.SupportsMultiframe) { form.Add(this, mi.ToString(Resources._0_ShouldFail), new DataEntry(WinCodecError.WINCODEC_ERR_UNSUPPORTEDOPERATION)); } } catch (Exception e) { if (t.SupportsMultiframe) { form.Add(this, e.TargetSite.ToString(Resources._0_Failed), new DataEntry(Resources.FrameIndex, 1), new DataEntry(e)); } else { form.CheckHRESULT(this, WinCodecError.WINCODEC_ERR_UNSUPPORTEDOPERATION, e, new DataEntry(Resources.FrameIndex, 1)); } } } catch (Exception e) { form.Add(this, e.TargetSite.ToString(Resources._0_Failed), new DataEntry(e)); } } } finally { frame2.ReleaseComObject(); encoder.ReleaseComObject(); bag.ReleaseComObject(); factory.ReleaseComObject(); palette.ReleaseComObject(); } return(base.ProcessEncoder(form, encoder, tag)); }
private unsafe void SaveScreenshot(string path, ContainerFormat format = ContainerFormat.Jpeg) { var d3d11GraphicsDevice = ((D3D11GraphicsDevice)_graphicsDevice !); ID3D11Texture2D source = Headless ? d3d11GraphicsDevice !.OffscreenTexture : d3d11GraphicsDevice !.BackBufferTexture; path = Path.Combine(AppContext.BaseDirectory, path); using (ID3D11Texture2D staging = d3d11GraphicsDevice !.CaptureTexture(source)) { staging.DebugName = "STAGING"; var textureDesc = staging !.Description; // Determine source format's WIC equivalent Guid pfGuid = default; bool sRGB = false; switch (textureDesc.Format) { case Format.R32G32B32A32_Float: pfGuid = WICPixelFormat.Format128bppRGBAFloat; break; case Format.R16G16B16A16_Float: pfGuid = WICPixelFormat.Format64bppRGBAHalf; break; case Format.R16G16B16A16_UNorm: pfGuid = WICPixelFormat.Format64bppRGBA; break; // DXGI 1.1 case Format.R10G10B10_Xr_Bias_A2_UNorm: pfGuid = WICPixelFormat.Format32bppRGBA1010102XR; break; case Format.R10G10B10A2_UNorm: pfGuid = WICPixelFormat.Format32bppRGBA1010102; break; case Format.B5G5R5A1_UNorm: pfGuid = WICPixelFormat.Format16bppBGRA5551; break; case Format.B5G6R5_UNorm: pfGuid = WICPixelFormat.Format16bppBGR565; break; case Format.R32_Float: pfGuid = WICPixelFormat.Format32bppGrayFloat; break; case Format.R16_Float: pfGuid = WICPixelFormat.Format16bppGrayHalf; break; case Format.R16_UNorm: pfGuid = WICPixelFormat.Format16bppGray; break; case Format.R8_UNorm: pfGuid = WICPixelFormat.Format8bppGray; break; case Format.A8_UNorm: pfGuid = WICPixelFormat.Format8bppAlpha; break; case Format.R8G8B8A8_UNorm: pfGuid = WICPixelFormat.Format32bppRGBA; break; case Format.R8G8B8A8_UNorm_SRgb: pfGuid = WICPixelFormat.Format32bppRGBA; sRGB = true; break; case Format.B8G8R8A8_UNorm: // DXGI 1.1 pfGuid = WICPixelFormat.Format32bppBGRA; break; case Format.B8G8R8A8_UNorm_SRgb: // DXGI 1.1 pfGuid = WICPixelFormat.Format32bppBGRA; sRGB = true; break; case Format.B8G8R8X8_UNorm: // DXGI 1.1 pfGuid = WICPixelFormat.Format32bppBGR; break; case Format.B8G8R8X8_UNorm_SRgb: // DXGI 1.1 pfGuid = WICPixelFormat.Format32bppBGR; sRGB = true; break; default: Console.WriteLine($"ERROR: ScreenGrab does not support all DXGI formats ({textureDesc.Format})"); return; } using var wicFactory = new IWICImagingFactory2(); //using IWICBitmapDecoder decoder = wicFactory.CreateDecoderFromFileName(path); //using Stream stream = File.OpenWrite(path); //using IWICStream wicStream = wicFactory.CreateStream(stream); using IWICStream wicStream = wicFactory.CreateStream(path, FileAccess.Write); using IWICBitmapEncoder encoder = wicFactory.CreateEncoder(format, wicStream); // Create a Frame encoder using IWICBitmapFrameEncode frame = encoder.CreateNewFrame(out SharpGen.Runtime.Win32.IPropertyBag2? props); frame.Initialize(props); frame.SetSize(textureDesc.Width, textureDesc.Height); frame.SetResolution(72, 72); // Screenshots don't typically include the alpha channel of the render target Guid targetGuid; switch (textureDesc.Format) { case Format.R32G32B32A32_Float: case Format.R16G16B16A16_Float: //if (IsWIC2()) { targetGuid = WICPixelFormat.Format96bppRGBFloat; } //else //{ // targetGuid = WICPixelFormat.Format24bppBGR; //} break; case Format.R16G16B16A16_UNorm: targetGuid = WICPixelFormat.Format48bppBGR; break; case Format.B5G5R5A1_UNorm: targetGuid = WICPixelFormat.Format16bppBGR555; break; case Format.B5G6R5_UNorm: targetGuid = WICPixelFormat.Format16bppBGR565; break; case Format.R32_Float: case Format.R16_Float: case Format.R16_UNorm: case Format.R8_UNorm: case Format.A8_UNorm: targetGuid = WICPixelFormat.Format8bppGray; break; default: targetGuid = WICPixelFormat.Format24bppBGR; break; } frame.SetPixelFormat(targetGuid); ID3D11DeviceContext1 context = d3d11GraphicsDevice !.DeviceContext; const bool native = false; if (native) { MappedSubresource mappedSubresource = context.Map(staging, 0, MapMode.Read); int imageSize = mappedSubresource.RowPitch * textureDesc.Height; if (targetGuid != pfGuid) { // Conversion required to write using (IWICBitmap bitmapSource = wicFactory.CreateBitmapFromMemory( textureDesc.Width, textureDesc.Height, pfGuid, mappedSubresource.RowPitch, imageSize, mappedSubresource.DataPointer)) { using (IWICFormatConverter formatConverter = wicFactory.CreateFormatConverter()) { if (!formatConverter.CanConvert(pfGuid, targetGuid)) { context.Unmap(staging, 0); return; } formatConverter.Initialize(bitmapSource, targetGuid, BitmapDitherType.None, null, 0, BitmapPaletteType.MedianCut); frame.WriteSource(formatConverter, new RectI(textureDesc.Width, textureDesc.Height)); } } } else { // No conversion required frame.WritePixels(textureDesc.Height, mappedSubresource.RowPitch, imageSize, mappedSubresource.DataPointer); } } else { int stride = WICPixelFormat.GetStride(pfGuid, textureDesc.Width); ReadOnlySpan <Color> colors = context.MapReadOnly <Color>(staging); if (targetGuid != pfGuid) { // Conversion required to write using (IWICBitmap bitmapSource = wicFactory.CreateBitmapFromMemory( textureDesc.Width, textureDesc.Height, pfGuid, colors, stride)) { using (IWICFormatConverter formatConverter = wicFactory.CreateFormatConverter()) { if (!formatConverter.CanConvert(pfGuid, targetGuid)) { context.Unmap(staging, 0); return; } formatConverter.Initialize(bitmapSource, targetGuid, BitmapDitherType.None, null, 0, BitmapPaletteType.MedianCut); frame.WriteSource(formatConverter, new RectI(textureDesc.Width, textureDesc.Height)); } } } else { // No conversion required frame.WritePixels(textureDesc.Height, stride, colors); } } context.Unmap(staging, 0); frame.Commit(); encoder.Commit(); } }
public static void WritePixels(this IWICBitmapFrameEncode bitmapFrameEncode, int lineCount, int cbStride, byte[] pbPixels) { bitmapFrameEncode.WritePixels(lineCount, cbStride, pbPixels.Length, pbPixels); }