在我的用户控件的绘图处理程序中,我遍历一组预定义的Bitmap对象,并将它们绘制到客户区:
C#版本:
private void Control_Paint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
foreach (BitmapObj bmpObj in _bitmapObjCollection) {
g.DrawImageUnscaled(bmpObj.Bitmap, bmpObj.Location);
}
}
Run Code Online (Sandbox Code Playgroud)
VB.NET版本:
Private Sub Control_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
Dim g As Graphics = e.Graphics
For Each bmpObj As BitmapObj In _bitmapObjCollection
g.DrawImageUnscaled(bmpObj.Bitmap, bmpObj.Location)
Next
End Sub
Run Code Online (Sandbox Code Playgroud)
代码工作正常但是当十几个对象添加到集合时开始陷入困境.我的问题是:有没有办法加快速度?是否可以使用Win32 bitblt函数替换DrawImageUnscaled?如果是这样怎么样?
谢谢!
注意:到目前为止,谷歌搜索BitBlt的使用仅产生了我的屏幕截图样本......
在Qt4的特定位置将一个QImage复制到另一个QImage的推荐方法是什么?
在Qt4中删除了QImage :: bitblt.
QImage现在是否需要转换为PixMap并返回?
是否可以使用BitBlt直接从GDI +位图复制而不使用GetHBitmap?
GetHBitmap很慢,因为它创建了整个图像的新副本,除了比BitBlt副本慢,并且必须处理给定的HBITMAP.图像很大.
有没有办法指向BitBlt使用原始GDI +图像的像素数据?
编辑: 我可以获得指向GDI +位图像素数据在内存中的位置的指针.我可以创建一个指向GDI +位图像素数据的HBITMAP以避免额外的复制,并从中创建BitBlt吗?
我尝试将图形对象的内容复制到位图.我正在使用此代码
public static class GraphicsBitmapConverter
{
[DllImport("gdi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
public static Bitmap GraphicsToBitmap(Graphics g, Rectangle bounds)
{
Bitmap bmp = new Bitmap(bounds.Width, bounds.Height);
using (Graphics bmpGrf = Graphics.FromImage(bmp))
{
IntPtr hdc1 = g.GetHdc();
IntPtr hdc2 = bmpGrf.GetHdc();
BitBlt(hdc2, 0, 0, bmp.Width, bmp.Height, hdc1, 0, 0, TernaryRasterOperations.SRCCOPY);
g.ReleaseHdc(hdc1);
bmpGrf.ReleaseHdc(hdc2);
}
return bmp;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我像这样使用这种方法
Graphics …
Run Code Online (Sandbox Code Playgroud) 我使用以下代码来捕获具有GDI函数的屏幕:
// Prologue:
int iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int iScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HDC hScreenDC = GetDC(0);
HDC hCaptureDC = CreateCompatibleDC(hScreenDC);
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hScreenDC, iScreenWidth, iScreenHeight);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCaptureDC, hCaptureBitmap);
// Capture:
BitBlt(hCaptureDC, 0, 0, iScreenWidth, iScreenHeight, hScreenDC, 0, 0, SRCCOPY);
// --- ... --- //
// Epilogue:
SelectObject(hCaptureDC, hOldBitmap);
DeleteObject(hCaptureBitmap);
DeleteDC(hCaptureDC);
ReleaseDC(0, hScreenDC);
Run Code Online (Sandbox Code Playgroud)
问题是:BitBlt函数是WAY当Aero是打开慢-它需要近50毫秒(这对我来说是不可接受的,因为我需要捕捉多次排在第二).
BitBlt直接从视频硬件获取像素数据.但是在我的测试机器(即Radeon 5470和Radeon 4850)中显卡非常好,所以我不明白什么是错的.我知道这些卡(任何现代卡)在2D中并不像3D那样好,但是我认为简单的blit操作不应该花费50ms.
那么,请你建议做什么?在我的情况下,任何一种"hackish"解决方案(只要它稳定工作)都可以.
目标系统是Win7 x64,32位代码.
提前致谢!
我目前正在从Qt3到Qt5 移植一个开源解决方案(Albatross ATM解决方案http://www.albatross.aero/).信天翁是一个空中交通观众,需要非常好的表现.我可以管理各种问题,但不能显示部分.
显示架构依赖于一个bitblt
命令,该命令首先将一个像素图复制到另一个像素图中,最后将像素图复制到屏幕上.
这是Qt3显示代码(工作和性能):
void CAsdView::paintEvent ( QPaintEvent * Event)
{
QRect rcBounds=Event->rect();
QPainter tmp;
for (int lay=0;lay<(int)m_RectTable.size();lay++) //For each drawing layer (there are 3)
{
if (!m_RectTable[lay].isEmpty())
{
if (lay!=0)
bitBlt(m_BitmapTable[lay],m_RectTable[lay].left(),m_RectTable[lay].top(),m_BitmapTable[lay-1],m_RectTable[lay].left(),m_RectTable[lay].top(),m_RectTable[lay].width(),m_RectTable[lay].height(),CopyROP); //m_BitmapTable is a QVector< QPixmap* >, m_RectTable is a QVector<QRect>
tmp.begin(m_BitmapTable[lay]);
if (lay==0)
tmp.fillRect(m_RectTable[lay], *m_pBrush);
OnDraw(&tmp,lay);
tmp.end();
m_RectTable[lay].setRect(0,0,-1,-1);
}
}
bitBlt(this, rcBounds.left(), rcBounds.top(),m_BitmapTable[m_LayerNb-1],rcBounds.left(), rcBounds.top(),rcBounds.width(), rcBounds.height(), CopyROP);
}
Run Code Online (Sandbox Code Playgroud)
我试过替换bitblt
,drawPixmap
但性能非常差,因为我必须经常显示屏幕.
这是新的Qt5代码:
void CAsdView::paintEvent ( QPaintEvent * Event)
{
QRect rcBounds=Event->rect(); …
Run Code Online (Sandbox Code Playgroud) 我正在使用GDI32.dll捕获窗口快照,虽然我遇到了硬件加速Windows的问题,我想知道是否有办法规避.
我在这里找到了这个惊人的代码:
public static Image CaptureWindow(IntPtr handle)
{
IntPtr hdcSrc = User32.GetWindowDC(handle);
Rect windowRect = new Rect();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.Right - windowRect.Left;
int height = windowRect.Bottom - windowRect.Top;
IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);
IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap);
Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);
Gdi32.SelectObject(hdcDest, hOld);
Gdi32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
Image image = Image.FromHbitmap(hBitmap);
Gdi32.DeleteObject(hBitmap);
return image;
}
Run Code Online (Sandbox Code Playgroud)
适用于所有窗户,除了我的镀铬窗户.在chrome中禁用硬件加速修复了这个问题虽然我不想这样做.
任何人对此问题有任何建议/解决方案吗?
感谢您的帮助,
- 保罗
我正在尝试使用此代码Bitmap
直接绘制到PictureBox
:
Bitmap bmp = (Bitmap)Bitmap.FromFile(@"C:\Users\Ken\Desktop\Load2.bmp");
Graphics grDest = Graphics.FromHwnd(pictureBox1.Handle);
Graphics grSrc = Graphics.FromImage(bmp);
IntPtr hdcDest = grDest.GetHdc();
IntPtr hdcSrc = grSrc.GetHdc();
BitBlt(hdcDest, 0, 0, pictureBox1.Width, pictureBox1.Height,
hdcSrc, 0, 0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020
grDest.ReleaseHdc(hdcDest);
grSrc.ReleaseHdc(hdcSrc);
Run Code Online (Sandbox Code Playgroud)
但是不是渲染Bitmap
它的内容,而是绘制一个近乎黑色的固体块.我很确定问题出在源hDC上,因为如果我在上面的代码中将SRCCOPY更改为WHITENESS,它会按预期绘制一个纯白色块.
注意:这个下一个片段工作正常,所以位图本身没有任何问题:
Bitmap bmp = (Bitmap)Bitmap.FromFile(@"C:\Users\Ken\Desktop\Load2.bmp");
pictureBox1.Image = bmp;
Run Code Online (Sandbox Code Playgroud) 我曾经使用 BitBlt 将屏幕截图保存到图像文件(.Net Compact Framework V3.5、Windows Mobile 2003 及更高版本)。工作得很好。现在我想在表单上绘制位图。我可以使用this.CreateGraphics().DrawImage(mybitmap, 0, 0)
,但我想知道它是否可以像以前一样与 BitBlt 一起使用并且只是交换参数。所以我写道:
[DllImport("coredll.dll")]
public static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
Run Code Online (Sandbox Code Playgroud)
(再往下走:)
IntPtr hb = mybitmap.GetHbitmap();
BitBlt(this.Handle, 0, 0, mybitmap.Width, mybitmap.Height, hb, 0, 0, 0x00CC0020);
Run Code Online (Sandbox Code Playgroud)
但形式保持纯白色。这是为什么?我犯的错误在哪里?谢谢你的意见。干杯,大卫
我最近问了一个关于这个的问题,并理解了答案,但无法将其翻译成代码。经过一天的乱搞东西,并修复泄漏。不过,我一生都无法弄清楚这一点。
这有点不同,我需要做的就是在地图位图下获取背景位图。
HDC hdc = GetDC(hWnd);
HDC hdcMem = CreateCompatibleDC(hdc);
HDC hdcMem2 = CreateCompatibleDC(hdc);
ReleaseDC(hWnd, hdc);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap.hbmBackground);
BitBlt(buffer.getBufferDC(), 1, 1, WINDOW_WIDTH, WINDOW_HEIGHT, hdcMem, 0, 0, SRCCOPY);
HBITMAP hbmOld2 = (HBITMAP)SelectObject(hdcMem2, bitmap.hbmMap);
BitBlt(buffer.getBufferDC(), 1, 1, WINDOW_WIDTH, WINDOW_HEIGHT, hdcMem2, 0, 0, SRCPAINT);
SelectObject(hdcMem2, hbmOld2);
Run Code Online (Sandbox Code Playgroud)
我的问题是结合...创建内存 dcs 以保留光栅操作的结果。我根本无法解决这个问题,任何帮助都会很棒。
谢谢。
我有一个位图存储为BGRA字节数组.这是我用来绘制位图的代码:
CDC *dispDC = new CDC();
dispDC->CreateCompatibleDC(pDC);
CBitmap *dispBMP = new CBitmap();
dispBMP->CreateCompatibleBitmap(pDC, sourceImage->GetWidth(), sourceImage->GetHeight());
dispDC->SelectObject(this->dispBMP);
Run Code Online (Sandbox Code Playgroud)
实际复制translatedImage
数组中的像素时会发生以下情况:
dispBMP->SetBitmapBits(sourceImage->GetArea() * 4, translatedImage);
Run Code Online (Sandbox Code Playgroud)
经过一些处理之后,我打电话pDC->StretchBlt
给dispDC
作为源CDC.这在本地登录时工作正常,因为显示也设置为32bpp.
一旦我使用远程桌面登录,显示屏将变为16bpp并且图像被破坏.罪魁祸首是SetBitmapBits
; 即为了它的工作,我必须正确填写translatedImage
我想要显示的16bpp版本.我没有自己这样做,而是搜索了文档,发现SetDIBits
它听起来像我想要的那样:
SetDIBits函数使用在指定DIB中找到的颜色数据设置兼容位图(DDB)中的像素.
在我的例子中,DIB是32bpp RGBA数组,而DDB是dispBMP
我创建的CreateCompatibleBitmap
.
所以不是我的号召SetBitmapBits
,这就是我所做的:
BITMAPINFO info;
ZeroMemory(&info, sizeof(BITMAPINFO));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = sourceImage->GetArea()*4;
info.bmiHeader.biWidth = sourceImage->GetWidth();
info.bmiHeader.biHeight = sourceImage->GetHeight();
info.bmiHeader.biClrUsed = 0;
int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
0, …
Run Code Online (Sandbox Code Playgroud) > case WM_PAINT:
{
> hdc = BeginPaint(hWnd, &ps);
> // TODO: Add any drawing code here...
> RECT rt;
> GetClientRect(hWnd, &rt);
> HDC myHdc = CreateCompatibleDC(hdc);
>
> DrawText(myHdc, szHello, strlen(szHello), &rt, DT_CENTER);
> BitBlt(hdc,0,0,rt.right-rt.left,rt.bottom-rt.top,myHdc,0,0,SRCCOPY);
>
> EndPaint(hWnd, &ps);
}
>
> break;
Run Code Online (Sandbox Code Playgroud)
为什么文字无法在窗口显示?
我正在使用BitBlt在我的按钮上显示位图.对于大多数情况,它很好,但有一个内存泄漏导致程序在一段时间后崩溃.我做错了什么?
int Springboard::DrawBasicButtons(DRAWITEMSTRUCT* pdis, HINSTANCE hInstance){
RECT rect;
static HBITMAP hCurrIcon, hIconoff, hIconon;
rect = pdis->rcItem;
HFONT font = CreateFont(13, 0, 0, 0, 300, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, L"Arial");
TCHAR Txtstr[MAX_PATH];
BOOL isText = FALSE;
int textsize;
if (IDC_HOLD == pdis->CtlID) {
hIconoff = (HBITMAP) LoadBitmap(hInstance, MAKEINTRESOURCE(BASIC_HOLDOFF));
hIconon = (HBITMAP) LoadBitmap(hInstance, MAKEINTRESOURCE(BASIC_HOLDON));
_tcscpy( Txtstr, _T("Hold "));
isText = TRUE;
if (pdis->itemState & ODS_SELECTED) hCurrIcon = hIconon;
else hCurrIcon = hIconoff;
}
HDC hdc = CreateCompatibleDC(pdis->hDC);
SelectObject(hdc, …
Run Code Online (Sandbox Code Playgroud)