1. 程式人生 > >C#開啟tif檔案時記憶體溢位(System.OutOfMemoryException)解決辦法

C#開啟tif檔案時記憶體溢位(System.OutOfMemoryException)解決辦法

前言

我在做一個統計圖片長和寬的軟體時遇到一個問題,本來是用的

 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();