程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> GDI+中常見的幾個問題(3)

GDI+中常見的幾個問題(3)

編輯:關於.NET

4. 為啥讀個圖那麼慢?

一般來說,讀圖可以用以下幾種方法:

1 public static Image FromFile(string filename);
2 public static Image FromFile(string filename, bool useEmbeddedColorManagement);
3 public static Bitmap FromHbitmap(IntPtr hbitmap);
4 public static Bitmap FromHbitmap (IntPtr hbitmap, IntPtr hpalette);
5 public static Image FromStream(Stream stream);
6 public static Image FromStream(Stream stream, bool useEmbeddedColorManagement);
7 public static Image FromStream(Stream stream, bool useEmbeddedColorManagement, bool validateImageData);

其中3,4兩種方法主要用在從Windows句柄中拿到原來DIB的Bitmap,經常是用在需要讀取 資源圖像啊,或者GDI圖像的時候。最經常用的,無非是1,2和5,6,7,其中1和5類似,2和 6類似,方法5,6會使用不同的參數調用7。我們可以做一個簡單的性能測試。拿一張 8000*7000大的TIF圖像,這樣的圖像一般大小都在100M以上,用不同的參數調用方法7, 看 到以下結果。

1             {
2                 Stopwatch watch = new Stopwatch();
3                 watch.Start();
4                 FileStream fs = new FileStream(image, FileMode.Open, FileAccess.Read);
5                  Image img = Image.FromStream(fs, true, true);
6                  Console.WriteLine("Use ICM: {0}. Validate: {1}, ElapsedTicks:{2}.", true, true, watch.ElapsedTicks);
7                 watch.Stop ();
8                 fs.Close();
9             }
10
11             {
12                 Stopwatch watch = new Stopwatch();
13                 watch.Start();
14                 FileStream fs = new FileStream(image, FileMode.Open, FileAccess.Read);
15                  Image img = Image.FromStream(fs, false, true);
16                  Console.WriteLine("Use ICM: {0}. Validate: {1}, ElapsedTicks:{2}.", false, true, watch.ElapsedTicks);
17                 watch.Stop();
18                 fs.Close();
19              }
20
21             {
22                  Stopwatch watch = new Stopwatch();
23                  watch.Start();
24                 FileStream fs = new FileStream(image, FileMode.Open, FileAccess.Read);
25                  Image img = Image.FromStream(fs, true, false);
26                  Console.WriteLine("Use ICM: {0}. Validate: {1}, ElapsedTicks:{2}.", true, false, watch.ElapsedTicks);
27                 watch.Stop();
28                 fs.Close();
29              }
30
31             {
32                  Stopwatch watch = new Stopwatch();
33                  watch.Start();
34                 FileStream fs = new FileStream(image, FileMode.Open, FileAccess.Read);
35                  Image img = Image.FromStream(fs, false, false);
36                  Console.WriteLine("Use ICM: {0}. Validate: {1}, ElapsedTicks: {2}.", false, false, watch.ElapsedTicks);
37                 watch.Stop();
38                 fs.Close();
39              }

我們來看看執行結果:

Use ICM: True. Validate: True, ElapsedTicks:51853544.
Use ICM: False. Validate: True, ElapsedTicks:52507953.
Use ICM: True. Validate: False, ElapsedTicks:6880.
Use ICM: False. Validate: False, ElapsedTicks:5187.

所以你看到,罪魁禍首是Validate。當然Validate其實是有用的,圖像的格式各種各樣, 就單BMP就有好多種不同的放法,更不要說JPEG, PNG, GIF了。JPEG有普通的用離散余弦變換 生成的最早的,還有用小波生成的JPEG 2000。 PNG沒啥研究,不知道裡面什麼名堂。GIF有 靜態的和能動的GIF 98.所以後面的數據流出問題是很正常的事情,驗證在很多情況下是需要 的,但是造成的性能損失實在是很大。 如果你確定這些照片一般不會錯,而且讀圖又需要很 好的性能,比如獲得一個目錄裡面所有圖像的縮略圖,那還是用最後一種方法吧。

這裡再提一下ICM. ICM是色彩管理中的一個概念,對於相同圖像不同設備而言,呈現的色 彩可能是不同的。比如一個液晶顯示器和一個CRT顯示器,先是一張相同的圖片,色彩可能相 差十萬八千裡。這主要是因為不同設備能夠顯示的色彩空間是不同的。色彩空間又是個值得 研究的話題,這裡就不多說了。對於色彩的研究可以寫一本好厚的書。這個世界上最權威的 一個網站http://www.color.org/ 可以告訴你很多有用的信息和數學公式,包括Gamma,色彩 密度的概念,等等諸如此類。有些圖像格式是可以把ICM的信息寫在文件中的,比如JPEG,所 以這個參數是說是否使用文件內嵌的ICM信息還是用設備默認的信息。

其實第7個函數是在.NET 2.0以後才出現的。1.1出來以後讀圖慢的這個問題被別人罵得要 死,所以新版本中加了一個函數解決了這個問題。當時有個叫Justin Rogers的人寫了個類叫 ImageFast (http://weblogs.asp.net/justin_rogers/articles/131704.aspx),自己用 Interop去調用GDI+的方法,跳過了icm和validation。在.NET 2.0之後,這個問題才算是被 解決了。這又是.NET Framework對GDI+封裝不完善的一個例子。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved