為什麼有第二版
首先感謝 jenlynn 同學的留言“DATA URL兩種產生方式,C#和HTML5 兩者同一張產生的base64編碼貌似不一樣,能有什麼方法讓他們達成一致嗎”。
其次,在研究這個問題時發現了Bug和異常。
Bug:圖片編碼判斷問題,不管什麼副檔名的都預設使用了PNG編碼。
異常:檢測到 ContextSwitchDeadlock
介面預覽
針對相關問題的改進方法
圖片編碼判斷問題
之前主要是忘記了擷取的副檔名前面是帶點.的
相關代碼:
string ext = Path.GetExtension(path).ToLower(); //根據檔案的副檔名確定使用的編碼格式 //注意副檔名是帶點的! switch (ext) { case ".gif": fmt = System.Drawing.Imaging.ImageFormat.Gif; break; case ".jpg": case ".jpeg": fmt = System.Drawing.Imaging.ImageFormat.Jpeg; break; case ".ico": fmt = System.Drawing.Imaging.ImageFormat.Icon; break; default: ext = "png"; break; }
檢測到 ContextSwitchDeadlock
解決方案說明
StackOverflow提到使用BackgroundWorker,我這裡使用線程;但是經過測試發現:由於TextBox顯示大文本時的效能問題,線程與TextBox互動時,如果使用者不操作的話,視窗不會死;一旦有任何操作,視窗就是不響應!
所以只能改變解決方案,使用折中的辦法,不讓TextBox顯示全部的DataUrl字串,只顯示其中的一部分;使用一個變數“”來儲存完整的DataUrl字串,點擊複製按鈕時將其Copy到Windows剪貼簿中。
相關代碼
/// <summary> /// 用於儲存完整的DataUrl /// </summary> private string fullDataUrl = string.Empty;
使用線程
//建立線程來產生DataUrl System.Threading.Thread thd = new System.Threading.Thread(new ParameterizedThreadStart(buildDataUrl)); thd.Start(textBox_saveDir.Text);
使用委託
/// <summary> /// TextBox委託,用於實現線程中訪問表單、組件等的執行緒安全性 /// </summary> /// <param name="msg"></param> public delegate void textbox_delegate(string msg); /// <summary> /// TextBox委託實現,用於實現線程中訪問表單、組件等的執行緒安全性 /// </summary> /// <param name="msg"></param> public void textboxset(string msg) { if (textBox1 == null) return; if (textBox1.InvokeRequired) { textbox_delegate dt = new textbox_delegate(textboxset); textBox1.Invoke(dt, new object[] { msg }); } else { int strLen = msg.Length; int step = 100; while (strLen > step) { textBox1.AppendText(msg.Substring(msg.Length - strLen, step)); strLen -= step; } textBox1.AppendText(msg.Substring(msg.Length - strLen, strLen)); } }
最佳化Base64編碼
//計算Base64編碼的字串後部分有多少可以省略的字元 int strLen = str.Length; string dyzf = str.Substring(strLen - 1, 1); while ((dyzf == "A" || dyzf == "=") && strLen > 0) { strLen -= 1; dyzf = str.Substring(strLen - 1, 1); } //組合完整的Data Url fullDataUrl = "<img src=\"data:image/" + ext + ";base64," + str.Substring(0, strLen) + "\" width=\"" + img.Width + "\" height=\"" + img.Height + "\" />"; //這裡定義TextBox最多隻顯示20000個字元,多餘的裁掉不顯示了,不然效能太差。 int showLen = 20000; if (showLen > fullDataUrl.Length) { showLen = fullDataUrl.Length; } textboxset(fullDataUrl.Substring(0, showLen));
/// <summary> /// 將完整的Data Url複製到Windows剪貼簿中。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button_copy_Click(object sender, EventArgs e) { Clipboard.SetText(fullDataUrl); }
/// <summary> /// 清空文字框 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button_clear_Click(object sender, EventArgs e) { textBox1.Clear(); fullDataUrl = string.Empty; }