1

我有一种方法可以用来Byte[]从图像中获取缩略图。该方法接收图像的路径。

这个类运行得很好,直到你达到一个大小阈值,之后性能下降到可怜的低水平。不,我还没有确定门槛……主要是因为经过一些研究,我似乎使用了一种效率低下且可扩展性不强的方法。

我的情况似乎在这个 SO 线程中得到了证实。

这个问题正好说明了我正在经历的事情。它不是解决方案的原因是因为答案谈到了使用其他图形 API 和Paint覆盖,这显然不适用于这里。我尝试了其他一些东西,比如设置图形参数,但这并没有什么不同。

我正在处理的大图像的一个例子是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[] { };
}

PS我首先通过使用Visual Studio 2012分析器到达这里,它告诉我DrawImage()在加载图像时负责97.7%的CPU负载(我做了暂停/开始以隔离加载代码)。

4

0 回答 0