c# - Image/Bitmap 和 PictureBox 的正确处理方式

标签 c# image graphics dispose picturebox

我正在尝试开发 Windows Mobile 6(在 WF/C# 中)应用程序。只有一种形式,并且在形式上只有一个 PictureBox 对象。我在上面绘制所有需要的控件或任何我想要的东西。

我正在做两件事。从 .png 文件绘制自定义形状和加载位图。

下一行在加载时锁定文件(这是一种不希望出现的情况):

Bitmap bmp = new Bitmap("file.png");

所以我使用另一种方式加载位图。

public static Bitmap LoadBitmap(string path) {
    using (Bitmap original = new Bitmap(path))
    {
        return new Bitmap(original);
    }
}

我猜这要慢得多,但我不知道有什么更好的方法来加载图像,同时快速释放文件锁。

现在,在绘制图像时,我使用的方法是:

public void Draw() {
    Bitmap bmp = new Bitmap(240,320);
    Graphics g = Graphics.FromImage(bmp);

    // draw something with Graphics here.
    g.Clear(Color.Black);
    g.DrawImage(Images.CloseIcon, 16, 48);
    g.DrawImage(Images.RefreshIcon, 46, 48);
    g.FillRectangle(new SolidBrush(Color.Black), 0, 100, 240, 103);

    pictureBox.Image = bmp; 
}

但这似乎是某种内存泄漏。如果我继续这样做太久,应用程序最终会崩溃。

因此,我有3个问题:

1.)在不锁定文件的情况下从文件加载位图的更好方法是什么?

2.)哪些对象需要在 Draw() 函数中手动处理(以何种顺序),这样才不会发生内存泄漏和 ObjectDisposedException 抛出?

3.) 如果 pictureBox.Image 设置为 bmp,就像在代码的最后一行中一样,pictureBox.Image.Dispose() 将仅处理与维护 pictureBox.Image 或相关的资源底层位图设置为它?

最佳答案

我不认为存在真正的内存泄漏。问题是你不处理旧位图,由 GC 来清理这些东西。但是没有确定性的方式来说明何时这会发生。

所以我认为如果你要遍历很多图片,你会看到一些内存增加,而在其他一些点它会下降或抵抗在一个位置。

我没有测试它,但也许这会有助于使其更具确定性:

public void Draw() {
    Bitmap bmp = new Bitmap(240,320);
    using(var g = Graphics.FromImage(bmp))
    using(var solidBrush = SolidBrush(Color.Black))
    {
        // draw something with Graphics here.
        g.Clear(Color.Black);
        g.DrawImage(Images.CloseIcon, 16, 48);
        g.DrawImage(Images.RefreshIcon, 46, 48);
        g.FillRectangle(solidBrush, 0, 100, 240, 103);

        //Backup old image in pictureBox
        var oldImage = pictureBox.Image;
        pictureBox.Image = bmp; 
        //Release resources from old image
        if(oldImage != null)
            ((IDisposable)oldImage).Dispose();            
    }
}

更新

还有另一个灵感来自 jack30lena 的想法:

public static Bitmap LoadBitmap(string path)
{
    //Open file in read only mode
    using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
    //Get a binary reader for the file stream
    using (BinaryReader reader = new BinaryReader(stream))
    {
        //copy the content of the file into a memory stream
        var memoryStream = new MemoryStream(reader.ReadBytes((int)stream.Length));
        //make a new Bitmap object the owner of the MemoryStream
        return new Bitmap(memoryStream);
    }
}

我的第二个代码示例背后的想法是摆脱文件句柄并将文件内容复制到内存中。之后,Bitmap 将获得 MemoryStream 的所有权,该 MemoryStream 将通过调用 oldImage.Dispose() 在我的第一个示例中进行处理。

通过使用这种方法,内存中的图像永远不会超过两张,这只会导致非常大的图片或少量 RAM 导致 OutOfMemoryExceptions。

关于c# - Image/Bitmap 和 PictureBox 的正确处理方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2808753/

相关文章:

actionscript-3 - 为什么 drawRoundRectComplex() 没有记录在 ActionScript 中?

C# 静态类与 VB.NET 模块使用

c# - 使用 Entity Framework 从嵌套表中获取数据

python - 两个图像的 OpenCV 'BackgroundSubtractorMOG2'

python - 使用 Python 将电子邮件发送到带有内联图像的 Gmail

java - 如何创建 Ellipse2D 数组?

c++ - 清除图形的替代方法

javascript - 使用 ASP.Net MVC 的回调在弹出窗口中加载选定的 GridView 项目

c# - 如何为我的项目执行代码覆盖率。我在specflow中编写了单元测试

xml - 从 .msc 文件中提取图标?