将 SlimDX.Direct3D11 Texture2D 转换为 .Net 位图
Convert SlimDX.Direct3D11 Texture2D to .Net Bitmap
将 .Net 位图转换为 SlimDx Texture2D 的速度非常快,如下所示:
http://www.rolandk.de/index.php?option=com_content&view=article&id=65:bitmap-from-texture-d3d11&catid=16:blog&Itemid=10
private Texture2D TextureFromBitmap(FastBitmapSingle fastBitmap)
{
Texture2D result = null;
DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, true, false);
DataRectangle dataRectangle = new DataRectangle(fastBitmap.BitmapData.Stride, dataStream);
try
{
Texture2DDescription dt = new Texture2DDescription
{
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.None,
Format = Format.B8G8R8A8_UNorm,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
Usage = ResourceUsage.Immutable,
Width = fastBitmap.Size.X,
Height = fastBitmap.Size.Y,
ArraySize = 1,
SampleDescription = new SampleDescription(1, 0),
};
result = new Texture2D(device, dt, dataRectangle);
}
finally
{
dataStream.Dispose();
}
return result;
}
为了以正确的格式将纹理转换回 .Net 位图,我使用了它,但速度很慢:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture)
{
using (MemoryStream ms = new MemoryStream())
{
Texture2D.ToStream(device.ImmediateContext, texture, ImageFileFormat.Bmp, ms);
ms.Position = 0;
using (Bitmap temp1 = (Bitmap)Bitmap.FromStream(ms))
{
Rectangle bounds = new Rectangle(0, 0, temp1.Width, temp1.Height);
BitmapData BitmapDataIn = temp1.LockBits(bounds, ImageLockMode.ReadWrite, temp1.PixelFormat);
using (DataStream dataStreamIn = new DataStream(BitmapDataIn.Scan0, BitmapDataIn.Stride * BitmapDataIn.Height, true, false))
using (DataStream dataStreamOut = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true))
{
dataStreamIn.CopyTo(dataStreamOut);
}
temp1.UnlockBits(BitmapDataIn);
BitmapDataIn = null;
}
}
return true;
}
有没有更快的方法???我尝试了很多,例如:
但是 DataRectangle 的数据正好是我的 DataStream 中需要的数据的 8 倍:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture)
{
using (Texture2D buff = Helper.CreateTexture2D(device, texture.Description.Width, texture.Description.Height, Format.B8G8R8A8_UNorm, BindFlags.None, ResourceUsage.Staging, CpuAccessFlags.Read | CpuAccessFlags.Write))
{
device.ImmediateContext.CopyResource(texture, buff);
using (Surface surface = buff.AsSurface())
using (DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true))
{
DataRectangle rect = surface.Map(SlimDX.DXGI.MapFlags.Read);
rect.Data.CopyTo(dataStream);
surface.Unmap();
}
}
return true;
}
有人可以帮忙吗?
复制回我的数据大约需要整个计算时间的 50%。
如果能解决这个问题,我的应用程序会更快...
我使用的转换器是这样的:
public static BitmapSource Texture2DToBitmapSource(Texture2D texture2D)
{
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
Texture2D.ToStream(App.device.ImmediateContext, texture2D, ImageFileFormat.Png, memoryStream);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
return BitmapFrame.Create(memoryStream, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad);
}
}
但是我遇到了一个问题,dpi 是 72 而不是 96,就像我在我的程序中使用的 BitmapSource。希望对大家有所帮助。
我也在用 SlimDX。
WPF 位图转换从一开始就令人头疼。通过进入不安全代码和 lockbits 获得最大速度可能需要从 Pbgra 和 bgra 到 rgba 等的转换。我通常最终回到旧的绘图位图以在许多程序中转换为 BitmapSource。这个片段是我一直在使用的,直到我可以从我的计算着色器中获取正确的 PixelFormat。
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
Texture2D.ToStream(App.device.ImmediateContext, texture, ImageFileFormat.Png, memoryStream);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
//Create an image from a stream.
System.Drawing.Image bitmap = System.Drawing.Bitmap.FromStream(memoryStream); memoryStream.Close();
var hBitmap = ((System.Drawing.Bitmap)bitmap).GetHbitmap();
BitmapSource source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
if (!(source.Width == pixelWidth)) { }
if (!(source.Height == pixelHeight)) { }
return source;
}
使用来自 System.Drawing.Image 或 System.drawing.Bitmap 的 HBITMAP 可以更好地控制锁定位和不同像素格式的转换。较旧的 CreateBitmap 函数和 DIB 也使用 HBITMAP 进行转换。
另一个速度瓶颈我想是在 Texture2D.ToStream() 例程中。这些ImageFileFormat.Png、ImageFileFormat.Bmp、ImageFileFormat.Jpg等。SlimDX没有在Texture2D中添加一些Copy功能,而DX11在某处有。
我找到了解决方案,感谢:http://www.rolandk.de/wp/2013/06/inhalt-der-rendertarget-textur-in-ein-bitmap-kopieren/
但是这个故事有点复杂,因为Texture Pitch与Bitmap Stride不匹配,所以这是我的解决方案,比我的问题快10倍:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture, int row, int col)
{
using (Texture2D stage = Helper.CreateStagingTexture(device, fastBitmap.BitmapWidths[col], fastBitmap.BitmapHeights[row]))
{
device.ImmediateContext.CopyResource(texture, stage);
DataStream dsIn;
DataBox dataBox = device.ImmediateContext.MapSubresource(stage, 0, 0, MapMode.Read, D3D.MapFlags.None, out dsIn);
int dx = dataBox.RowPitch - fastBitmap.BitmapData[row][col].Stride;
try
{
using (DataStream dsOut = new DataStream(fastBitmap.BitmapData[row][col].Scan0, fastBitmap.BitmapData[row][col].Stride * fastBitmap.BitmapData[row][col].Height, false, true))
{
for (int r = 0; r < fastBitmap.BitmapData[row][col].Height; r++)
{
dsOut.WriteRange<byte>(dsIn.ReadRange<byte>(fastBitmap.BitmapData[row][col].Stride));
dsIn.Position += dx;
}
}
}
finally
{
device.ImmediateContext.UnmapSubresource(stage, 0);
}
dsIn.Dispose();
}
return true;
}
将 .Net 位图转换为 SlimDx Texture2D 的速度非常快,如下所示: http://www.rolandk.de/index.php?option=com_content&view=article&id=65:bitmap-from-texture-d3d11&catid=16:blog&Itemid=10
private Texture2D TextureFromBitmap(FastBitmapSingle fastBitmap)
{
Texture2D result = null;
DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, true, false);
DataRectangle dataRectangle = new DataRectangle(fastBitmap.BitmapData.Stride, dataStream);
try
{
Texture2DDescription dt = new Texture2DDescription
{
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.None,
Format = Format.B8G8R8A8_UNorm,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
Usage = ResourceUsage.Immutable,
Width = fastBitmap.Size.X,
Height = fastBitmap.Size.Y,
ArraySize = 1,
SampleDescription = new SampleDescription(1, 0),
};
result = new Texture2D(device, dt, dataRectangle);
}
finally
{
dataStream.Dispose();
}
return result;
}
为了以正确的格式将纹理转换回 .Net 位图,我使用了它,但速度很慢:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture)
{
using (MemoryStream ms = new MemoryStream())
{
Texture2D.ToStream(device.ImmediateContext, texture, ImageFileFormat.Bmp, ms);
ms.Position = 0;
using (Bitmap temp1 = (Bitmap)Bitmap.FromStream(ms))
{
Rectangle bounds = new Rectangle(0, 0, temp1.Width, temp1.Height);
BitmapData BitmapDataIn = temp1.LockBits(bounds, ImageLockMode.ReadWrite, temp1.PixelFormat);
using (DataStream dataStreamIn = new DataStream(BitmapDataIn.Scan0, BitmapDataIn.Stride * BitmapDataIn.Height, true, false))
using (DataStream dataStreamOut = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true))
{
dataStreamIn.CopyTo(dataStreamOut);
}
temp1.UnlockBits(BitmapDataIn);
BitmapDataIn = null;
}
}
return true;
}
有没有更快的方法???我尝试了很多,例如:
但是 DataRectangle 的数据正好是我的 DataStream 中需要的数据的 8 倍:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture)
{
using (Texture2D buff = Helper.CreateTexture2D(device, texture.Description.Width, texture.Description.Height, Format.B8G8R8A8_UNorm, BindFlags.None, ResourceUsage.Staging, CpuAccessFlags.Read | CpuAccessFlags.Write))
{
device.ImmediateContext.CopyResource(texture, buff);
using (Surface surface = buff.AsSurface())
using (DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true))
{
DataRectangle rect = surface.Map(SlimDX.DXGI.MapFlags.Read);
rect.Data.CopyTo(dataStream);
surface.Unmap();
}
}
return true;
}
有人可以帮忙吗? 复制回我的数据大约需要整个计算时间的 50%。 如果能解决这个问题,我的应用程序会更快...
我使用的转换器是这样的:
public static BitmapSource Texture2DToBitmapSource(Texture2D texture2D)
{
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
Texture2D.ToStream(App.device.ImmediateContext, texture2D, ImageFileFormat.Png, memoryStream);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
return BitmapFrame.Create(memoryStream, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad);
}
}
但是我遇到了一个问题,dpi 是 72 而不是 96,就像我在我的程序中使用的 BitmapSource。希望对大家有所帮助。
我也在用 SlimDX。
WPF 位图转换从一开始就令人头疼。通过进入不安全代码和 lockbits 获得最大速度可能需要从 Pbgra 和 bgra 到 rgba 等的转换。我通常最终回到旧的绘图位图以在许多程序中转换为 BitmapSource。这个片段是我一直在使用的,直到我可以从我的计算着色器中获取正确的 PixelFormat。
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
Texture2D.ToStream(App.device.ImmediateContext, texture, ImageFileFormat.Png, memoryStream);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
//Create an image from a stream.
System.Drawing.Image bitmap = System.Drawing.Bitmap.FromStream(memoryStream); memoryStream.Close();
var hBitmap = ((System.Drawing.Bitmap)bitmap).GetHbitmap();
BitmapSource source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
if (!(source.Width == pixelWidth)) { }
if (!(source.Height == pixelHeight)) { }
return source;
}
使用来自 System.Drawing.Image 或 System.drawing.Bitmap 的 HBITMAP 可以更好地控制锁定位和不同像素格式的转换。较旧的 CreateBitmap 函数和 DIB 也使用 HBITMAP 进行转换。
另一个速度瓶颈我想是在 Texture2D.ToStream() 例程中。这些ImageFileFormat.Png、ImageFileFormat.Bmp、ImageFileFormat.Jpg等。SlimDX没有在Texture2D中添加一些Copy功能,而DX11在某处有。
我找到了解决方案,感谢:http://www.rolandk.de/wp/2013/06/inhalt-der-rendertarget-textur-in-ein-bitmap-kopieren/
但是这个故事有点复杂,因为Texture Pitch与Bitmap Stride不匹配,所以这是我的解决方案,比我的问题快10倍:
private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture, int row, int col)
{
using (Texture2D stage = Helper.CreateStagingTexture(device, fastBitmap.BitmapWidths[col], fastBitmap.BitmapHeights[row]))
{
device.ImmediateContext.CopyResource(texture, stage);
DataStream dsIn;
DataBox dataBox = device.ImmediateContext.MapSubresource(stage, 0, 0, MapMode.Read, D3D.MapFlags.None, out dsIn);
int dx = dataBox.RowPitch - fastBitmap.BitmapData[row][col].Stride;
try
{
using (DataStream dsOut = new DataStream(fastBitmap.BitmapData[row][col].Scan0, fastBitmap.BitmapData[row][col].Stride * fastBitmap.BitmapData[row][col].Height, false, true))
{
for (int r = 0; r < fastBitmap.BitmapData[row][col].Height; r++)
{
dsOut.WriteRange<byte>(dsIn.ReadRange<byte>(fastBitmap.BitmapData[row][col].Stride));
dsIn.Position += dx;
}
}
}
finally
{
device.ImmediateContext.UnmapSubresource(stage, 0);
}
dsIn.Dispose();
}
return true;
}