如何写一个(位图?)图像更快的GDI +显示缓冲区?(How to write to a (Bitm

2019-06-24 08:55发布

使用C ++和.NET我有数据流我想显示作为滚动图像。 每次我得到一些新的数据我想将其先前的内容添加为新行(128x1像素),并滚动到一边。

我当时的第一个问题涉及刺呈现整个数据的每个我得到了一个新的行时间设定。 这个工作,但速度太慢,所以我想它可能会更有意义写信给某种形式的缓冲区(可能是位图?)。 问题是,我不知道怎样才能做到这一点; Graphic对象让你很愉快地画,但我不能看到一个明显的方式来告诉我的控制使用Bitmap对象,因为它的缓冲? 同样的,我看不到的方式来画上一个位图,我可以再写入到屏幕上。

这必须是可能的,但我的谷歌,富失败我迄今...

[EDIT1]只是为了澄清,所述数据是频谱图。 下图显示的那种,我想实现的事情:

替代文字http://www.geekops.co.uk/photos/0000-00-02%20(Forum%20images)/ScrollingGraphicsAlgorithmExplanation.png

我绘制的有关资料在彩车的数组。 没有什么限制我多少会得到的,所以我只是想,因为它脱落情节的侧忘记的数据。

我目前正在从继承System::Windows::Forms::UserControl ,但可以切换到别的东西,如果有一个更好的变质?

Answer 1:

看看的滚屏 win32的方法。 您可以在屏幕上滚动的现有数据,然后只绘制新的数据。 这是非常快的。



Answer 2:

位图bmpImage =新位图(512512);

对(INT iRow = 0; iRow <512; iRow ++)

{

  for (int iCol = 0; iCol <512; iCol++)
                        {
                            Color clr;
                            bmpImage.SetPixel(iCol, iRow, clr);
                        }

}

(图像)bmpImage.save()



Answer 3:

一个可能的策略:

  • 借鉴从左至右后备缓冲到达终端时回绕。 仅执行绘画到屏幕(在一些指定的帧率)时滚动逻辑。 使用的DrawImage与源矩形和目标矩形来实现这一目标。

  • 使用bitmap.LockBits(...)和bitmap.UnlockBits(...)方法来修改原始位图数据。 要小心,只锁定你要修改的矩形,因为这些功能实际上使位图数据的副本从非托管到托管内存。 如何做到这一点的例子在这里描述的位图.. ::。LockBits方法(矩形,ImageLockMode,的PixelFormat) 。

  • 到LockBits另一种方法是在使用位图SetPixel。 但是SetPixel被称为是缓慢的。

  • 当块传输图像到屏幕上确保CompositingMode在图形实例设置为bmpg.CompositingMode = CompositingMode.SourceCopy,后缓冲器的该像素格式是PixelFormat.Format32bppPArgb。


Answer 4:

我不是很清楚你想画(某种程度的控制在对话框?),但在猜测它应该工作一样的东西到底是什么:

class Foo {
    ...
    Gdiplus::Bitmap* m_pBitmap;
};

void Foo::DrawItem(LPDRAWITEMSTRUCT lpDraw) {

   // update bitmap if needed
   if(some_condition_requiring_bitmap_redraw) {

       // do expensive drawing into bitmap
       Gdiplus::Graphics graphics(m_pBitmap);
   }


   // create a graphics object to draw the control from the bitmap
   Gdiplus::Graphics graphics(lpDraw->hDC);
   graphics.DrawImage(m_pBitmap, ...);
}

这是一个非常粗略的猜测也无妨。 该DRAWITEM通话可能看起来完全不同,如果你使用.NET(我不熟悉...),但基本的逻辑应该是大致相同的。

根据究竟是什么你的数据是,它可能不是高效的同时绘制1个像素行。 你可能会更好拉大面积只显示所需的它位 - 尽管这显然将取决于您的数据是如何的用武之地。

你也可能需要做一些更新到您的位图“滚动”的内容。 我会离开,你:-)



Answer 5:

尝试以下方法:

  • 启动一个新的VC ++ WinForms应用程序。
  • 添加一个名为“频谱”该项目的用户控件
  • 计时器控件添加到“频谱”的用户控制和设置的“已启用”属性设置为true
  • 以下私有变量添加到“频谱”用户控制
private:
Graphics ^m_gfxBuffer;
Graphics ^m_gfxOriginal;
Bitmap ^m_bmpBuffer;
Bitmap ^m_bmpOriginal;
  • 下面的代码添加到“频谱”的构造函数:

m_bmpBuffer = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxBuffer = Graphics::FromImage(m_bmpBuffer);
m_bmpOriginal = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxOriginal = Graphics::FromImage(m_bmpOriginal);
this->SetStyle(::ControlStyles::AllPaintingInWmPaint | ::ControlStyles::DoubleBuffer | ::ControlStyles::UserPaint | ::ControlStyles::OptimizedDoubleBuffer, true);
this->UpdateStyles();
  • 下面的代码添加到“频谱”油漆事件:

array<unsigned char, 1> ^bytes = gcnew array<unsigned char, 1>(m_bmpBuffer->Height * 3);
Random ^r = gcnew Random();
r->NextBytes(bytes);

m_gfxOriginal->DrawImage(m_bmpBuffer, -1, 0);

int y = 0;
for (int i = 0; i < m_bmpOriginal->Height * 3; i += 3)
{
  m_bmpOriginal->SetPixel(m_bmpOriginal->Width - 1, y++, ::Drawing::Color::FromArgb(255, bytes[i], bytes[i + 1], bytes[i + 2]));
}

m_gfxBuffer->DrawImage(m_bmpOriginal, 0, 0);
e->Graphics->DrawImage(m_bmpOriginal, 0, 0);    
  • 添加以下代码的“频谱”计时器滴答事件

this->Invalidate(false);
  • 保存项目
  • 清洁和重建
  • 运行项目
  • 关闭正在运行的表
  • 频谱用户控件现在应该在“工具箱”
  • 从“工具箱”拖到窗体它,你应该看到了各种各样的滚动随机颜色的光谱图。

这应该给你一个位图缓存控制的总体思路。 这里的关键是在构造函数中“的SetStyle”通话并以-1的油漆事件的偏移位图。

你必须妥善处理图形和位图对象以及处理销毁,并在resize事件重建他们。

希望这可以帮助。 让我知道事情的后续。



文章来源: How to write to a (Bitmap?) image buffer for faster GDI+ displays?