【问题标题】:c# Drawing bitmap over another onec# 在另一个上绘制位图
【发布时间】:2016-07-06 07:58:58
【问题描述】:

我正在做一个项目,我需要在已经存在的图像(我在程序的开头定义)上绘制从套接字接收的图像块(作为位图),并显示它在PictureBox-换句话说,每次我收到一个新块时更新图像。

为了异步执行此操作,我使用ThreadSocket 读取数据并进行处理。

这是我的代码:

private void MainScreenThread() {

ReadData();
initial = bufferToJpeg(); //full screen first shot.
pictureBox1.Image = initial;

while (true) {
 int pos = ReadData();
 int x = BlockX();
 int y = BlockY();
 Bitmap block = bufferToJpeg(); //retrieveing the new block.

 Graphics g = Graphics.FromImage(initial);
 g.DrawImage(block, x, y); //drawing the new block over the inital image.
 this.Invoke(new Action(() => pictureBox1.Refresh())); //refreshing the picturebox-will update the intial;

 }
}
  private Bitmap bufferToJpeg()
    {
      return (Bitmap)Image.FromStream(ms);        
    }

我遇到了一个错误

对象当前正在其他地方使用

Graphics 创建线上

Graphics g = Graphics.FromImage(initial);

我没有使用任何其他线程或其他东西来访问位图..所以我不确定这里有什么问题..

如果有人能启发我,我将非常感激。

谢谢。

【问题讨论】:

  • 您刚刚发现 PictureBox 和 Bitmap 类都不是线程安全的。幸运的是,Bitmap 类有一个内置的诊断功能,当您在 PictureBox 重新绘制自身的同时使用 Graphics.FromImage() 时会出现 kaboom。非常随机,就像线程竞赛错误总是如此。您需要调用更多代码,包括 Graphics.FromImage 和 DrawImage。或者创建你自己的线程安全的 PictureBox 类,它的 OnPaint() 覆盖需要获取一个你也在这个方法中获取的锁。
  • 你可能会很快遇到OutOfMemoryException,你需要在每个循环中处理block,并在完成后处理g

标签: c# multithreading sockets bitmap


【解决方案1】:

尝试在循环之前分配图形:

private void MainScreenThread() {

  ReadData();
  initial = bufferToJpeg(); 
  pictureBox1.Image = initial;
  Graphics g = Graphics.FromImage(initial);

  while (true) {
    int pos = ReadData();
    int x = BlockX();
    int y = BlockY();
    Bitmap block = bufferToJpeg(); 

    g.DrawImage(block, x, y); 
    this.Invoke(new Action(() => pictureBox1.Refresh())); 

  }
}

【讨论】:

    【解决方案2】:

    这是因为图形对象在使用后从不处置。

    如果您查看图形组件,当您创建它时。您使用“初始”位图。图形现在指向这个“初始”对象,第一次它会成功创建图形,但第二次(因为“g”尚未被释放/释放)“初始”对象仍在使用中在创建新图形之前使用旧图形。

    你可以做的是:

    private void MainScreenThread() {
    
       ReadData();
       initial = bufferToJpeg(); //full screen first shot.
       pictureBox1.Image = initial;
    
       while (true) {
        int pos = ReadData();
        int x = BlockX();
        int y = BlockY();
        Bitmap block = bufferToJpeg(); //retrieveing the new block.
    
        using(Graphics g = Graphics.FromImage(initial)) {
           g.DrawImage(block, x, y); //drawing the new block over the inital image.
           this.Invoke(new Action(() => pictureBox1.Refresh())); //refreshing the picturebox-will update the intial;
       }
     }
    }
    

    会发生的是,'g'对象在使用后会被释放,以便您以后可以再次执行相同的操作。

    编辑:修复 - 没有正确地将整个代码包含为代码块。

    【讨论】:

    • 我也想过,所以我之前使用了Dispose,现在我使用了Using() 语句……不幸的是,我得到了完全相同的错误……在同一行。 ..object is currently in use elsewhere@Karl Patrik Johansson
    • 嗯,那一定是被图片框占用了?也许在创建图形之前尝试克隆初始位图并将克隆的位图指定为图片框上的新图像。例如:var img = (Bitmap)initial.Clone(); using(Graphics g = Graphics.FromImage(img)) 然后this.Invoke(new Action(() => pictureBox1.Image = img));
    • 现在我在这一行 var img= (Bitmap)initial.Clone();@Karl Patrik Johansson 中遇到了创建克隆的错误
    • 你能发布bufferToJpeg()方法吗?也许其中有什么东西会导致图像被“锁定”
    • 我很确定我们的问题不存在:)。更新了我在问题中的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2014-02-26
    相关资源
    最近更新 更多