如何在C#中快速生成缩略图

3

我正在尝试以最快的速度拇指图像,而不考虑在我的ImageList和listview中使用的资源,目前我是这样做的,但它似乎很慢:

public Image toThumbs(string file, int width, int height)
        {
            image = null;
            aspectRatio = 1;
            fullSizeImg = null;
            try
            {
                fullSizeImg = Image.FromFile(file);
                float w = fullSizeImg.Width;
                float h = fullSizeImg.Height;
                aspectRatio = w / h;

                int xp = width;
                int yp = height;

                if (fullSizeImg.Width > width && fullSizeImg.Height > height)
                {
                    if ((float)xp / yp > aspectRatio)
                    {
                        xp = (int)(yp * aspectRatio);
                    }
                    else
                    {
                        yp = (int)(xp / aspectRatio);
                    }
                }
                else if (fullSizeImg.Width != 0 && fullSizeImg.Height != 0)
                {
                    xp = fullSizeImg.Width;
                    yp = fullSizeImg.Height;
                }

                image = new Bitmap(width, height);
                graphics = Graphics.FromImage(image);
                graphics.FillRectangle(Brushes.White, ((width - xp) / 2), (height - yp), xp, yp);
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.DrawImage(fullSizeImg, new Rectangle(((width - xp) / 2), (height - yp), xp, yp));
                graphics.Dispose();
                fullSizeImg.Dispose();
            }
            catch (Exception)
            {
                image = null;
            }
            return image;
        }

我不确定是计算导致缩略图变慢,还是使用的类本身很慢。如果是后者,那么有哪些其他替代方案可以使用?也许可以使用不同的计算方法,或者导入其他类,或者使用第三方库,或者进行dll导入等等。请帮忙解决。

编辑:在这里找到了一个解决方案http://www.vbforums.com/showthread.php?t=342386,它可以从文件中提取缩略图而无需读取整个文件。当我使用它时,能够将时间缩短约40%。


你有进行过任何性能分析来查看程序运行时花费时间的位置吗?例如,Visual Studio 2010 自带了一个分析器。 - bzlm
我在我的代码中添加了时间戳,似乎 GetThumbnailImage 函数变慢了。 - murasaki5
你可以创建异步线程以防止GUI在此操作上“冻结”。 - Stormenet
5个回答

3
你的计算在几分之一秒内完成。调用DrawImage可能是最慢的部分(因为它正在进行缩放)。
如果你只需要这个缩略图图像一次,那么我认为在这里没有太多改进的空间。如果你对同一张图片调用该方法超过一次,你应该缓存这些缩略图。

嗯,你说得对。由于我只缩略图一次,所以似乎没有其他办法。 - murasaki5
如果您每次启动应用程序时都这样做,那么您仍然可以通过将缩略图存储在文件中来缓存它们。图像重采样,特别是对于大型图像而言,成本非常高昂。 - Joey
但是如果图像被编辑了呢?我该如何确定需要重建缩略图,因为缓存是旧版本的? - murasaki5
通常情况下,这是通过比较缩略图和图像的最后修改日期来完成的。但是,缓存始终容易受到数据更改的影响。 - Joey

2

我使用这种机制,它似乎非常快速。

               BitmapFrame bi = BitmapFrame.Create(new Uri(value.ToString()), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);

            // If this is a photo there should be a thumbnail image, this is VERY fast
            if (bi.Thumbnail != null)
            {
                return bi.Thumbnail;
            }
            else
            {
                // No thumbnail so make our own (Not so fast)
                BitmapImage bi2 = new BitmapImage();
                bi2.BeginInit();
                bi2.DecodePixelWidth = 100;
                bi2.CacheOption = BitmapCacheOption.OnLoad;
                bi2.UriSource = new Uri(value.ToString());
                bi2.EndInit();
                return bi2;
            }

希望这能有所帮助。

我认为这是一个误导性的答案,因为我正在处理一个文件而不是一个URL。 - murasaki5
这是使用URI,它可以是文件的路径。 - user217748

1

出于好奇,您尝试过System.Drawing.Bitmap上的GetThumbnailImage方法吗?与您当前的实现进行比较可能至少是值得的。


0

你的缩略图提取依赖于图像已经嵌入了缩略图,从而使你获得更快的速度。

为了加速原始图像,你可能会发现需要改变:

graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;

可能有帮助。


0
这可能看起来是一个非常明显的答案,但你尝试过使用Image.GetThumbnailImage()吗?
虽然你不能控制结果的质量,但如果速度是你的主要关注点呢?

但我需要用白色填充图像的透明度,因此我仍需要使用图形类。 - murasaki5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接