C#開啟tif檔案時記憶體溢位(System.OutOfMemoryException)解決辦法
阿新 • • 發佈:2019-02-01
前言
我在做一個統計圖片長和寬的軟體時遇到一個問題,本來是用的
Image img = null;
img = Image.FromFile(f.FullName);
w = img.Width;
h = img.Height;
這段程式碼來獲取圖片的長和寬的,本來在我的win7下面 16G記憶體的機器上跑的完全沒問題,結果我把這個程式放在了xp系統上面執行,那麼問題就來了
錯誤問題
程式竟然在建立Image型別時出現記憶體溢位(System.OutOfMemoryException)
錯誤程式碼: System.Drawing.Image myimg=System.Drawing.Image.FromFile(file.FullName);
當開啟的檔案不是影象檔案時會引發的異常:
或者出現 Bitmap System.ArgumentException: 引數無效問題
這其實不是程式的問題,而是系統中記憶體的問題,或者圖片太大了,大於65535畫素了。
我測試 2G記憶體 BitMap最大 5000*5000,反正這個BitMap大小和機器配置有關。
win7 64位 16G記憶體最大 23200*23200
由於 GDI+ 解碼器的限制,如果使用單維大小大於 65,535 畫素的 .png 影象檔案構造點陣圖,將引發 System.ArgumentException。
獲取TIF圖片的長和寬
那麼我們既然不能通過方面的程式碼載入Image物件,那麼我們就沒法獲取圖片的長度和寬度,我們有沒有什麼方法可以獲取長度呢? 答案是肯定的,我們可以通過讀取TIF的檔案格式的內容獲取它的長度和寬度 TIF和其它格式都是一樣的檔案的開頭都有一段描述檔案的資訊 我們的方法就是獲取檔案中所包含長度的那段內容把它讀取出來using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.IO; namespace ImageSize { public class ReadTIF:IDisposable { #region 讀入TIF影象的變數設定 /// <summary> /// 儲存讀入的TIF影象的寬度 /// </summary> private int Width; /// <summary> /// 儲存讀入的TIF影象的高度 /// </summary> private int Heigth; /// <summary> /// 儲存讀入的TIF影象的Directory Entry Count(DE)的個數 /// </summary> private short NumOfDE; /// <summary> /// 儲存下一個Directory Entry的偏移值 /// </summary> private int NextOffsetFID; /// <summary> /// 宣告一個結構,儲存影象檔案頭Image File Header的資訊 /// </summary> struct IFH { public char[] ByteOrder; public short Version; public int OffsetToFirstFID; } /// <summary> /// 宣告一個結構,儲存Directory Entry /// </summary> struct DE { public short tag; public short type; public int length; public int valueOffset; } #endregion /* * 例項化一個IFH結構的物件 */ private IFH myIFH; /* * 初始化IFH影象檔案頭 */ public void DefineIFH() { myIFH.ByteOrder = new char[2]; myIFH.ByteOrder[0] = Convert.ToChar(0); myIFH.ByteOrder[1] = Convert.ToChar(0); myIFH.Version = 0; myIFH.OffsetToFirstFID = 0; } public void TifFile(string file) { FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read); BinaryReader TIFReader = new BinaryReader(stream); DefineIFH();//呼叫初始化IFH影象檔案頭 /* * 讀取影象檔案頭內容 */ myIFH.ByteOrder[0] = TIFReader.ReadChar();//1個位元組 myIFH.ByteOrder[1] = TIFReader.ReadChar();//1個位元組 myIFH.Version = TIFReader.ReadInt16();//2個位元組 myIFH.OffsetToFirstFID = TIFReader.ReadInt32();//4個位元組 stream.Seek(0, SeekOrigin.Begin);//將檔案的指標移到開始位置 stream.Seek(myIFH.OffsetToFirstFID, SeekOrigin.Begin);//將檔案的指標移動到第一個IFD的位置處 NumOfDE = TIFReader.ReadInt16();//獲取本IFD結構中目錄入口DE的個數,2個位元組 /* * 獲取各個目錄項DE的資訊 */ DE[] myDE = new DE[NumOfDE]; for (int i = 0; i < NumOfDE; i++) { myDE[i].tag = TIFReader.ReadInt16();//2個位元組 myDE[i].type = TIFReader.ReadInt16();//2個位元組 myDE[i].length = TIFReader.ReadInt32();//4個位元組 myDE[i].valueOffset = TIFReader.ReadInt32();//4個位元組 } /* * 讀取下一個Directory Entry的偏移值 */ NextOffsetFID = TIFReader.ReadInt32(); /* * 讀取影象的寬度、高度 */ for (int i = 0; i < NumOfDE; i++) { if (myDE[i].tag == 256)//影象的寬 { Width = myDE[i].valueOffset; } if (myDE[i].tag == 257)//影象的高 { Heigth = myDE[i].valueOffset; } } TIFReader.Close(); stream.Close(); } //返回寬度 public int GetW() { return Width; } //返回高度 public int GetH() { return Heigth; } public void Dispose() { } } }
使用方法
ReadTIF rt = new ReadTIF();
rt.TifFile(f.FullName);
w = rt.GetW();
h = rt.GetH();