//保存目錄 string dir = "/upload/user/head"; //站點文件目錄 string fileDir = HttpContext.Current.Server.MapPath("~" + dir); //文件名稱 string fileName = "headdemo" + DateTime.Now.ToString("yyyyMMddHHmmssff"); //保存文件所在站點位置 string filePath = Path.Combine(fileDir, fileName); if (!System.IO.Directory.Exists(fileDir)) System.IO.Directory.CreateDirectory(fileDir); //讀圖片轉為Base64String System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(Path.Combine(fileDir, "default.jpg")); using (MemoryStream ms1 = new MemoryStream()) { bmp1.Save(ms1, System.Drawing.Imaging.ImageFormat.Jpeg); byte[] arr1 = new byte[ms1.Length]; ms1.Position = 0; ms1.Read(arr1, 0, (int)ms1.Length); ms1.Close(); UserPhoto = Convert.ToBase64String(arr1); } //將Base64String轉為圖片並保存 byte[] arr2 = Convert.FromBase64String(UserPhoto); using (MemoryStream ms2 = new MemoryStream(arr2)) { System.Drawing.Bitmap bmp2 = new System.Drawing.Bitmap(ms2); bmp2.Save(filePath + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg); //bmp2.Save(filePath + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp); //bmp2.Save(filePath + ".gif", System.Drawing.Imaging.ImageFormat.Gif); //bmp2.Save(filePath + ".png", System.Drawing.Imaging.ImageFormat.Png); }
//將Base64String轉為圖片並保存 byte[] arr2 = Convert.FromBase64String(UserPhoto); using (MemoryStream ms2 = new MemoryStream(arr2)) { System.Drawing.Bitmap bmp2 = new System.Drawing.Bitmap(ms2); ////只有把當前的圖像復制一份,然后把舊的Dispose掉,那個文件就不被鎖住了, ////這樣就可以放心覆蓋原始文件,否則GDI+一般性錯誤(A generic error occurred in GDI+) //System.Drawing.Bitmap bmpNew = new System.Drawing.Bitmap(bmp2); //bmp2.Dispose(); //bmp2 = null; bmp2.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg); //bmp2.Save(filePath + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg); //bmp2.Save(filePath + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp); //bmp2.Save(filePath + ".gif", System.Drawing.Imaging.ImageFormat.Gif); //bmp2.Save(filePath + ".png", System.Drawing.Imaging.ImageFormat.Png); bmp2.Dispose(); }
GDI+一般性錯誤(A generic error occurred in GDI+)
1.GDI+的前世今生
GDI+全稱圖形設備接口,Graphics Device Interface (GDI) ,他的爸爸叫做GDI, 用C寫的。Windows XP出來以后用C++重新寫了一下,變成了GDI+。從.NET Framework 1.0開始,GDI+就被正式封裝在了.NET Framework里面,並被廣泛地應用到了所有和圖形圖像相關的程序中。不幸的是,這個GDI+引入了微軟有史以來最大的2個patch,造成了Microsoft IT, Support, Developer, Tester的無數麻煩。[1][2]
GDI+沒有用顯卡加速,所以Windows Vista推薦用Windows Display Driver Model (WDDM)了,支持渲染,3D加速。不過普通的應用程序,用GDI/GDI+其實是完全足夠了,所以GDI+是在微軟平台上開發圖形圖像程序的最好選擇了。至少現在沒有聽說微軟准備重新寫GDI。
GDI+ 可以用來做圖形處理,也可以做圖像處理。這里只分析幾個使用.NET Framework容易出錯的地方。
2. GDI+一般性錯誤(A generic error occurred in GDI+)
這是使用GDI+的時候最滑稽的一個Exception,里面啥信息都沒有。對於剛剛開始使用.NET Framework開發者來說,很難發現這個問題到底是為什么。
我們先來看看下面一段代碼
Bitmap bmp = new Bitmap(fileName);
bmp.Save(fileName, ImageFormat.Jpeg);
這段代碼的目的是要打開一個Bitmap,然后保存。可惜這段代碼一定會給你一個GDI+一般性錯誤:
其中的Error Code是0x80004005, innerException是空。如果你查Windows的Error Code表,會發現這個錯誤原因是“Unspecified Error”,還是什么都不知道。這其實是.NET Framework封裝不好的問題,我們可以調用
拿到Win32的Error, 32。這個錯誤代碼就有點信息量了,在winerror.h里面,我們可以找到下面的定義:
// MessageId: ERROR_SHARING_VIOLATION
//
// MessageText:
//
// The process cannot access the file because it is being used by another process.
//
#define ERROR_SHARING_VIOLATION 32L
原來是文件不能寫。其實MSDN里面有一句話,The file remains locked until the Bitmap is disposed。所以文件讀取以后是鎖着的,沒有辦法寫。那如果我想做點改動然后再保存原來的文件怎么辦呢?
這里有個土辦法可以搞定這個問題
Bitmap bmp = new Bitmap(bmpTemp);
bmpTemp.Dispose();
bmp.Save(image, ImageFormat.Jpeg);
只要把當前的圖像復制一份,然后把舊的Dispose掉,那個文件就不被鎖住了,這樣就可以放心覆蓋原始文件了。
想想如果你要用GDI+寫一個Painter,很容易你就會遇到這個問題。