在列表框中显示所选项目的图像很慢c#

时间:2014-07-25 19:28:38

标签: c# image listbox picturebox

我创建了一个简单的程序,它将Listbox1中所选项目的图像显示到pictureBox1。它工作正常,但显示下一张图像大约需要200毫秒。我的电脑使用的是英特尔i7处理器和Windows 7 64位。请告知我如何加快这个过程。以下是我的代码。谢谢!

private void openToolStripMenuItem_Click(object sender, EventArgs e)
    {           
        folderBrowserDlg.SelectedPath = folderpath;
        this.folderBrowserDlg.ShowNewFolderButton = false; //Disable New Folder button
        DialogResult result = this.folderBrowserDlg.ShowDialog();
        if (result == DialogResult.OK)
        {

                folderpath = this.folderBrowserDlg.SelectedPath;
                string ImagePath = folderpath.Substring(0, folderpath.LastIndexOf(("\\")));
                folderName = folderpath.Substring(folderpath.LastIndexOf(("\\")) + 1);
                PathLength = ImagePath.Length; //Use for Substring later
                txtBrowse.Text = folderpath; //Get folder path and display to textbox


                var filearray = Directory.EnumerateFiles(folderpath, "*.*", SearchOption.AllDirectories).Where(a => a.EndsWith(".tif") || a.EndsWith(".tiff"));
                array = filearray.ToArray();                   

                var filenames = Directory.EnumerateFiles(folderpath, "*.*", SearchOption.AllDirectories).Where(a => a.EndsWith(".tif") || a.EndsWith(".tiff")).Select(Path.GetFileName); // Get all image file names

                foreach (string fn in filenames)
                {
                    listBox1.Items.Add(fn); // Add all image file names to listbox 
                }               

        }
    }

 private void Form1_KeyDown(object sender, KeyEventArgs e)
    {           
        if (e.KeyCode == Keys.Enter) //Go to next image after press Enter key
        {            
            if (listBox1.SelectedIndex != listBox1.Items.Count - 1)
            {
                listBox1.SelectedIndex = listBox1.SelectedIndex + 1;
            }

            e.SuppressKeyPress = true;
        }
     }

 private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
         Index = listBox1.SelectedIndex; //Get selected item from listbox
         pictureBox1.Image = Image.FromFile(array[Index].ToString()); // display image to picturebox 
    }

3 个答案:

答案 0 :(得分:0)

您正在使用Image.FromFile,它会从磁盘加载图像。像这样的IO操作通常会很慢,因为它们依赖于磁盘速度来完成。

我建议在将文件夹添加到列表框时,通过另一个线程从文件夹加载所有.tif个图像。

这将有一些初始加载时间来加载所有图像,但之后你可以点击任何列表项,它们将立即出现。

示例:将图像名称添加到列表框后,将此代码作为新线程运行:(确保您有一个包含所有已加载图像的全局变量List<Bitmap> Images

Images = new List<Bitmap>(); //Or use an array, your choice.
foreach (string file in filearray)
{
     Images.Add(Image.FromFile(file));
}

然后,当您从列表框中选择一个项目时,请设置图像:

pictureBox1.Image = Images.ElementAt[Index];

请注意,如果图像非常大,这可能无效,因为一次加载所有图像可能会导致内存不足错误。

如果是这种情况,您需要在点击它们时加载它们,然后加载加载时间。因为你有一个i7,许多最终用户的计算机速度可能会慢一些。这就是为什么我建议使用线程操作在后台加载它们,并提供加载栏或动画,因为加载大型tiff文件不会是即时的。

我不会在这篇文章中讨论有关线程的信息,因为答案是this S.O.问题显示了在后台处理操作的好方法,同时向用户报告进度(例如:加载栏)。

简而言之:要么一次加载它们,如果足够小,或者需要时加载它们会更好。没有办法绕过加载时间,所以你需要忍受一个小的等待,或者(推荐),在新线程中运行加载并在图像正在为用户提供加载图像加载。

答案 1 :(得分:0)

Image Loader测试结果: ImageFromFileFast() ImageFromFileSlow() 快800%(请记住 ImageFromFileFast()是不安全的代码)

Image Loaded time using the ImageFromFileSlow() is 4351.1889 milliseconds
Image Loaded time using the ImageFromFileFast() is 541.965 milliseconds
ImageFromFileFast() is 802.85% faster than ImageFromFileSlow()

Image Loader Test:

        string BigImage19MBpath = @"H:\Earth's_Location_in_the_Universe_(JPEG).jpg";
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Bitmap LoadedImage = (Bitmap)ImageFromFileSlow(BigImage19MBpath);
        double TotalMillisecondsSlow = sw.Elapsed.TotalMilliseconds;
        Debug.WriteLine(string.Format("Image Loaded time using the ImageFromFileSlow() is {0} milliseconds", TotalMillisecondsSlow.ToString()));

        sw.Restart();                       
        Bitmap LoadedImage1 = (Bitmap)ImageFromFileFast(BigImage19MBpath);
        double TotalMillisecondsFast = sw.Elapsed.TotalMilliseconds;
        Debug.WriteLine(string.Format("Image Loaded time using the ImageFromFileFast() is {0} milliseconds", TotalMillisecondsFast.ToString()));
        Debug.WriteLine(string.Format("ImageFromFileFast() is {0}% faster then ImageFromFileSlow()", (100*TotalMillisecondsSlow/TotalMillisecondsFast).ToString("0.00")));

图像加载器功能:

    [DllImport("Kernel32.dll", EntryPoint = "CopyMemory")]
    private static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
    /// <summary>
    /// loads image fast but UNSAFE
    /// </summary>
    /// <param name="iPath"></param>
    /// <returns></returns>
    public static Image ImageFromFileFast(string iPath)
    {
        using (Bitmap sourceImage = (Bitmap)Image.FromFile(iPath))
        {
            Bitmap targetImage = new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
            BitmapData sourceBitmapData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
            BitmapData targetBitmapData = targetImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.WriteOnly, targetImage.PixelFormat);
            CopyMemory(targetBitmapData.Scan0, sourceBitmapData.Scan0, Convert.ToUInt32(sourceBitmapData.Stride) * Convert.ToUInt32(sourceBitmapData.Height));
            sourceImage.UnlockBits(sourceBitmapData);
            targetImage.UnlockBits(targetBitmapData);
            return targetImage;
        }
    }

    public static Image ImageFromFileSlow(string iPath)
    {
        using (Bitmap sourceImage = (Bitmap)Image.FromFile(iPath))
        {
            Bitmap targetImage = new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
            using (Graphics g = Graphics.FromImage(targetImage))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                g.DrawImage(sourceImage, 0, 0, sourceImage.Width, sourceImage.Height);
            }
            return targetImage;
        }
    }

答案 2 :(得分:0)

3184x4208的图像(来自您的评论)需要大约40 Mb的内存

如果用户快速浏览/打开这些图像,让我们说每秒1次,应用程序将在一分钟内声明2.4千兆字节(通过打开/浏览60张图像)。

如果您没有释放声明的内存,这将导致应用程序内存不足并显着减慢速度。 阅读此问题并回答有关清理的问题:.NET Memory issues loading ~40 images, memory not reclaimed, potentially due to LOH fragmentation

根据程序的实际功能,您可能需要创建缩略图并加载这些缩略图。这将占用更少的内存(你仍然需要释放它)并且将加载更快。请参阅此问题,并提供有关如何创建缩略图的多项建议:Generating image thumbnails in ASP.NET?(问题与Web应用程序有关,但仍在讨论同一问题)