C# 如何在没有DrawImage的情况下生成高质量的图像缩略图

C# 如何在没有DrawImage的情况下生成高质量的图像缩略图,c#,winforms,image-processing,thumbnails,drawimage,C#,Winforms,Image Processing,Thumbnails,Drawimage,我有一个方法,我使用它从图像中获取一个缩略图作为字节[]。该方法接收图像的路径 该类工作得非常好,直到达到一个大小阈值,之后性能下降到可怜的低水平。不,我还没有确定阈值…主要是因为经过一些研究,我似乎使用了一种低效且不太可扩展的方法 我的设想似乎已得到证实 这个问题正是我所经历的。它不是解决方案的原因是因为答案谈到了使用其他图形API和绘制覆盖,这显然不适用于这里。我尝试了各种各样的事情,比如设置图形参数,但是没有什么不同 我正在处理的一个大图像示例是3872 x 2592,大小约为3.5Mb。

我有一个方法,我使用它从图像中获取一个缩略图作为字节[]。该方法接收图像的路径

该类工作得非常好,直到达到一个大小阈值,之后性能下降到可怜的低水平。不,我还没有确定阈值…主要是因为经过一些研究,我似乎使用了一种低效且不太可扩展的方法

我的设想似乎已得到证实

这个问题正是我所经历的。它不是解决方案的原因是因为答案谈到了使用其他图形API和绘制覆盖,这显然不适用于这里。我尝试了各种各样的事情,比如设置图形参数,但是没有什么不同

我正在处理的一个大图像示例是3872 x 2592,大小约为3.5Mb。有些要大得多,许多要小得多

我的搜寻并没有取得多少成果。事实上,我似乎只能找到包括System.Drawing.Graphics.DrawImage使用在内的建议。在一个例外情况下,有人建议包括试图使用PresentationFramework的程序集。这是一个WinForms应用程序,所以仅仅为了抓取一个缩略图似乎有点过分

我遇到的另一个建议是从文件中提取Exif信息(如果我记得的话),并试图仅获取该数据而不是整个图像。我并不反对,但我还没有找到一个足够完整的例子来说明这是如何实现的

我想知道p/Invoke选项。比GDI+显然能够提供的性能更好。但是,无论如何,如果我在这段代码中缺少一个优化,请指出它

以下是我目前的方法:

public static Byte[] GetImageThumbnailAsBytes(String FilePath)
{
    if (File.Exists(FilePath))
    {
        Byte[] ba = File.ReadAllBytes(FilePath);
        if (ba != null)
        {
            using (MemoryStream ms = new MemoryStream(ba, false))
            {
                Int32 thWidth = _MaxThumbWidth;
                Int32 thHeight = _MaxThumbHeight;
                Image i = Image.FromStream(ms, true, false);
                ImageFormat imf = i.RawFormat;
                Int32 w = i.Width;
                Int32 h = i.Height;
                Int32 th = thWidth;
                Int32 tw = thWidth;
                if (h > w)
                {
                    Double ratio = (Double)w / (Double)h;
                    th = thHeight < h ? thHeight : h;
                    tw = thWidth < w ? (Int32)(ratio * thWidth) : w;
                }
                else
                {
                    Double ratio = (Double)h / (Double)w;
                    th = thHeight < h ? (Int32)(ratio * thHeight) : h;
                    tw = thWidth < w ? thWidth : w;
                }
                Bitmap target = new Bitmap(tw, th);
                Graphics g = Graphics.FromImage(target);
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.InterpolationMode = InterpolationMode.Bilinear; //NearestNeighbor
                g.CompositingMode = CompositingMode.SourceCopy;
                Rectangle rect = new Rectangle(0, 0, tw, th);
                g.DrawImage(i, rect, 0, 0, w, h, GraphicsUnit.Pixel);
                using (MemoryStream ms2 = new MemoryStream())
                {
                    target.Save(ms2, imf);
                    target.Dispose();
                    i.Dispose();
                    return ms2.ToArray();
                }
            }
        }
    }
    return new Byte[] { };
}

另外,我首先使用Visual Studio 2012 profiler来到这里,它告诉我DrawImage负责加载图像时97.7%的CPU负载。我暂停/开始隔离加载代码。

你不能使用Image.GetThumbnailImage?@flyingstrudel这是此方法的前身,性能差得多。无论在质量还是速度上,gdi+都比其他产品慢。尝试一下gdii如果你愿意为了性能而放弃一些质量,我建议你编写自己的降尺度算法。我自己在机器视觉应用程序中处理大于80mpx的海量图像时也必须这样做。在我的例子中,我只是在两个方向上每16个像素获取一个缩略图,或者更确切地说是一个适合在屏幕上显示的东西。如果你需要一个特定的大小,这有点棘手。如果你对内置的性能不满意,你应该考虑在一个不安全的块内实现你自己的缩放算法,或者使用DirectX来代替GCPU在GPU上进行计算。