我有一种方法可以用来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负载(我做了暂停/开始以隔离加载代码)。