在 winforms 應用程式中,有沒有辦法直接繪制到視窗的像素緩沖區/位元組陣列?
我有一個帶有byte[] myimg = new byte[width x height x 4]ARGB 位圖格式的影像的位元組陣列,現在我想以這種形式顯示它,我知道的唯一方法是首先制作一個位圖,然后使用 lockbits 將我的像素寫入位圖,然后我將 picturebox.image 設定為我的位圖實體。但是我想跳過這一步直接寫到表格,如果可能的話甚至沒有圖片框,這可能嗎?
更新
為了澄清,我特別想避免視窗處理縮放/拉伸的開銷和緩慢。我只想要最有效的方式將我自己的像素放到表單的畫布區域,我自己的位元組陣列由我自己提前準備和相應地縮放。
更新 2
事實證明,較低的 windows api 確實提供了一種使用方式bitblt ,正如 jtxkopt 所示,這幾乎完全殺死了我的開銷
uj5u.com熱心網友回復:
您不能將原始影像資料直接繪制到Form. 沒有類似的功能DrawImageData(byte[] data, int width, int height, PixelFormat format);。我知道有兩種選擇。您可以嘗試其中一種最適合您的需求。
選項1
您可以使用建構式Bitmap從影像資料創建一個類,根據需要填充資料并將位圖繪制到螢屏上。但是,正如其他人所說,只要您留在托管代碼中,這樣做就不會獲得太多的性能提升。
對于簡單的實作,您可以查看示例代碼。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace CustomRendering
{
public unsafe partial class MainForm : Form
{
public MainForm()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
InitializeComponent();
}
private Bitmap m_surfaceBitmap;
private byte* m_surfaceData;
private int m_stride;
private int m_width, m_height;
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.DrawImage(m_surfaceBitmap, Point.Empty);
}
protected override void OnHandleCreated(EventArgs e)
{
this.FormBorderStyle = FormBorderStyle.FixedSingle;
m_width = ClientSize.Width;
m_height = ClientSize.Height;
m_stride = (32 * m_width 31) / 32 * 4; // Calculate the stride.
m_surfaceData = (byte*)Marshal.AllocHGlobal(m_stride * m_height);
m_surfaceBitmap = new Bitmap(m_width, m_height, m_stride, PixelFormat.Format32bppArgb, (IntPtr)m_surfaceData);
}
protected unsafe override void OnMouseMove(MouseEventArgs e)
{
Clear(Color.White);
FillRectangle(e.X, e.Y, 100, 100, Color.Black);
Invalidate();
base.OnMouseMove(e);
}
private void Clear(Color color)
{
int argb = color.ToArgb();
for (int i = 0; i < m_stride * m_height; i = 4)
*(int*)(m_surfaceData i) = argb;
}
private void FillRectangle(int x0, int y0, int width, int height, Color color)
{
int argb = color.ToArgb();
for (int y = y0; y < y0 height; y )
for (int x = x0; x < x0 width; x )
SetPixel(x, y, argb);
}
private void SetPixel(int x, int y, int argb)
{
if (x >= m_width || x < 0 || y >= m_height || y < 0)
return;
m_surfaceData[y * m_stride 4 * x 0] = (byte)((argb >> 0) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 1] = (byte)((argb >> 8) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 2] = (byte)((argb >> 16) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 3] = (byte)((argb >> 24) & 0x000000FF);
}
}
}
選項 2
這是一個使用 API 的較低級別的解決方案,Win32但我認為這個解決方案比以前的解決方案更快,因為它自己處理WM_PAINT訊息并使用該bitblt函式來顯示DIB(Device Independent Bitmap) 而不是繪制 Gdiplus Bitmap。我不解釋如何DIB創建 a 和其他Win32相關代碼的作業方式。示例代碼如下。比較它們并選擇其中之一。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace CustomRendering
{
public unsafe partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private byte* m_surfaceData;
private int m_stride;
private int m_width, m_height;
private IntPtr m_hdcWindow;
private IntPtr m_surfaceDC;
private IntPtr m_surfaceBitmap;
private IntPtr m_oldObject;
private Point m_mouseLocation;
protected override void WndProc(ref Message m)
{
// Process WM_PAINT ourself.
if(m.Msg == 0x000F)
{
Clear(Color.White);
FillRectangle(m_mouseLocation.X, m_mouseLocation.Y, 100, 100, Color.Black);
PAINTSTRUCT ps;
IntPtr hdc = BeginPaint(Handle, out ps);
BitBlt(m_hdcWindow, 0, 0, m_width, m_height, m_surfaceDC, 0, 0, RasterOperations.SRCCOPY);
EndPaint(Handle, ref ps);base.WndProc(ref m);
}
// Process WM_ERASEBKGND to prevent flickering.
else if(m.Msg == 0x0014)
m.Result = (IntPtr)1;
else
base.WndProc(ref m);
}
protected override void OnHandleCreated(EventArgs e)
{
m_width = Screen.PrimaryScreen.WorkingArea.Width;
m_height = Screen.PrimaryScreen.WorkingArea.Height;
m_stride = (32 * m_width 31) / 32 * 4; // Calculate the stride.
CreateSurface(m_width, m_height);
}
protected unsafe override void OnMouseMove(MouseEventArgs e)
{
m_mouseLocation = e.Location;
Invalidate(ClientRectangle); // Invalidate the only visible area.
}
private void CreateSurface(int width, int height)
{
BITMAPINFO bi = new BITMAPINFO();
m_hdcWindow = GetDC(Handle);
m_surfaceDC = CreateCompatibleDC(m_hdcWindow);
bi.bmiHeader.biSize = (uint)Marshal.SizeOf<BITMAPINFOHEADER>();
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = -height;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BitmapCompressionMode.BI_RGB; // No compression
bi.bmiHeader.biSizeImage = (uint)(width * height * 4);
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
IntPtr ppvBits;
m_surfaceBitmap = CreateDIBSection(m_surfaceDC, ref bi, DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0);
m_surfaceData = (byte*)ppvBits.ToPointer();
m_oldObject = SelectObject(m_surfaceDC, m_surfaceBitmap);
}
private void Clear(Color color)
{
int argb = color.ToArgb();
for (int i = 0; i < m_stride * m_height; i = 4)
*(int*)(m_surfaceData i) = argb;
}
private void FillRectangle(int x0, int y0, int width, int height, Color color)
{
int argb = color.ToArgb();
for (int y = y0; y < y0 height; y )
for (int x = x0; x < x0 width; x )
SetPixel(x, y, argb);
}
private void SetPixel(int x, int y, int argb)
{
m_surfaceData[y * m_stride 4 * x 0] = (byte)((argb >> 0) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 1] = (byte)((argb >> 8) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 2] = (byte)((argb >> 16) & 0x000000FF);
m_surfaceData[y * m_stride 4 * x 3] = (byte)((argb >> 24) & 0x000000FF);
}
private enum RasterOperations : uint
{
SRCCOPY = 0x00CC0020,
SRCPAINT = 0x00EE0086,
SRCAND = 0x008800C6,
SRCINVERT = 0x00660046,
SRCERASE = 0x00440328,
NOTSRCCOPY = 0x00330008,
NOTSRCERASE = 0x001100A6,
MERGECOPY = 0x00C000CA,
MERGEPAINT = 0x00BB0226,
PATCOPY = 0x00F00021,
PATPAINT = 0x00FB0A09,
PATINVERT = 0x005A0049,
DSTINVERT = 0x00550009,
BLACKNESS = 0x00000042,
WHITENESS = 0x00FF0062,
CAPTUREBLT = 0x40000000
}
private enum BitmapCompressionMode : uint
{
BI_RGB = 0,
BI_RLE8 = 1,
BI_RLE4 = 2,
BI_BITFIELDS = 3,
BI_JPEG = 4,
BI_PNG = 5
}
[StructLayout(LayoutKind.Sequential)]
private struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public BitmapCompressionMode biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct BITMAPINFO
{
public BITMAPINFOHEADER bmiHeader;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)]
public int[] bmiColors;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left, Top, Right, Bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct PAINTSTRUCT
{
public IntPtr hdc;
public bool fErase;
public RECT rcPaint;
public bool fRestore;
public bool fIncUpdate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rgbReserved;
}
private const int DIB_RGB_COLORS = 0;
private const int DIB_PAL_COLORS = 1;
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO pbmi, uint usage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, RasterOperations dwRop);
[DllImport("gdi32.dll")]
private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hNewObj);
[DllImport("user32.dll")]
static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);
[DllImport("user32.dll")]
static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/509997.html
標籤:C#表格比特币
