繁体   English   中英

处理 Image/Bitmap 和 PictureBox 的正确方法

[英]Right way to dispose Image/Bitmap and 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 或设置为它的底层Bitmap 相关的资源?

我不认为存在真正的内存泄漏 问题是你不处理旧的位图,由 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);
    }
}

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

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

1:我不知道它是否适用于 Windows Mobile 但试试这个:

FileStream bitmapFile = new FileStream("mybitmap.bmp", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Image loaded = new Bitmap(bitmapFile);

2:必须丢弃SolidBrush 处置有一个一般规则。 -->“每个对象,由你实例化,实现处置必须手动处置,除非对象返回/引用/输出值”

在这种情况下,最好使用using语句

using (new objecttodispose){ ..... } 

using语句将确保在任何情况下(例如例外Dispose()调用Dispose() )。

3: Dispose()将释放位图资源。

您可以从控制器中获取一个 Bitmap 对象,然后将其分配给 PictureBox 的 image 属性。 您还应该处置PictureBox 的当前图像以释放资源。

 var bmp = controller.GetBitmap();
 pictureBox1.Image.Dispose(); // this releases bitmap resources, required
 pictureBox1.Image = bmp;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM