• Bitmap使用注意事项


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

    System.Drawing.Bitmap如果跨线程使用,或者同时被多方调用,就会报错对象当前正在其他地方使用
    解决方案是新开线程就新建一个Bitmap副本,并且保证一个Bitmap对象同时只被一个地方使用
    复现这个问题的例子如下:

    string file="one image path";
    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(file);
    Task.Run(() =>
    {
        try
        {
            while (true)
            {
                for (int i = 0; i < bmp.Width; i++)
                    for (int j = 0; j < bmp.Height; j++)
                    {
                        var c1 = bmp.GetPixel(i, j);
                    }
                Thread.Sleep(100);
            }
    
        }
        catch (Exception ex)
        {
    
        }
    });
    
    Task.Run(() =>
    {
        try
        {
            while (true)
            {
                for (int i = 0; i < bmp.Width; i++)
                    for (int j = 0; j < bmp.Height; j++)
                    {
                        var c1 = bmp.GetPixel(i, j);
                    }
                Thread.Sleep(100);
            }
    
        }
        catch (Exception ex)
        {
    
        }
    });
    

    正确的使用方式是:

    string file="one image path";
    System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(file);
    Task.Run(() =>
    {
        try
        {
            var cpbmp1 = (Bitmap)bmp1.Clone();
            while (true)
            {
                for (int i = 0; i < cpbmp1.Width; i++)
                    for (int j = 0; j < cpbmp1.Height; j++)
                    {
                        var c1 = cpbmp1.GetPixel(i, j);
                    }
                Thread.Sleep(100);
    
            }
        }
        catch (Exception ex)
        {
    
        }
    });
    
    Task.Run(() =>
    {
        try
        {
            var cpbmp2 = (Bitmap)bmp1.Clone();
            while (true)
            {
                for (int i = 0; i < cpbmp2.Width; i++)
                    for (int j = 0; j < cpbmp2.Height; j++)
                    {
                        var c1 = cpbmp2.GetPixel(i, j);
                    }
                Thread.Sleep(100);
    
            }
        }
        catch (Exception ex)
        {
    
        }
    });
    

    使用byte[]也会遇到同样的问题

    GetPixel效率问题

    System.Drawing.Bitmap原生的GetPixel方法效率较低,可以使用C# Bitmap图片GetPixel 和 SetPixel 效率问题中的写法,经过测试,速度大概可以提高7倍。
    测试代码如下:

    int times = 10;
    
    //no. 2
    System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(file);
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int number = 0; number < times; number++)
        for (int i = 0; i < bmp1.Width; i++)
            for (int j = 0; j < bmp1.Height; j++)
            {
                var c1 = bmp1.GetPixel(i, j);
            }
    sw.Stop();
    Console.WriteLine($"{nameof(Bitmap)}:{sw.ElapsedMilliseconds}");
    
    //no. 1
    OldLockBitmap oldLockBitmap = new OldLockBitmap(bmp1);
    oldLockBitmap.LockBits();
    sw.Restart();
    for (int number = 0; number < times; number++)
        for (int i = 0; i < bmp1.Width; i++)
            for (int j = 0; j < bmp1.Height; j++)
            {
                var c1 = oldLockBitmap.GetPixel(i, j);
            }
    sw.Stop();
    oldLockBitmap.UnlockBits();
    Console.WriteLine($"{nameof(OldLockBitmap)}1:{sw.ElapsedMilliseconds}");
    

    关于速率问题的讨论:c# faster way of setting pixel colours

    示例代码

    BitmapConvertDemo

    学习技术最好的文档就是官方文档,没有之一。
    还有学习资料Microsoft LearnCSharp LearnMy Note
    如果,你认为阅读这篇博客让你有些收获,不妨点击一下右下角的推荐按钮。
    如果,你希望更容易地发现我的新博客,不妨点击一下关注

  • 相关阅读:
    717 汉诺塔的非递归实现 (25分)
    JSP入门[续]
    JSP运行原理和九大隐式对象
    JSP入门
    Mysql基本命令
    DataGridView数据导出为Excel
    sql server 2005中如何添加外键
    自定义配置文件的读取
    WinForm(C#)CheckedlistBox绑定数据,并获得选中的值(ValueMember)和显示文本(DisplayMember
    No CurrentSessionContext configured Hibernate
  • 原文地址:https://www.cnblogs.com/Lulus/p/15670444.html
Copyright © 2020-2023  润新知