最近一段時間有用markdown作筆記,其餘都好,可是markdown插入圖片挺麻煩的,特別是想截圖以後直接插入的時候。須要首先把圖片保存了,而後還要上傳到一個地方生成連接才能插入。若是有個工具能夠直接上傳圖片或者截圖生成markdown能夠用的連接就行了。因此決定本身下班後寫一個,不過本身挺菜的,也就能用,代碼徹底是渣不能看。。。在這裏把本身的思路還有其中遇到的問題記錄一下。html
首先須要選一個圖牀,我選了七牛,主要是一個是有免費的空間,加上提供了SDK,這樣就能寫程序上傳了。語言挑了C#,由於感受WPF寫界面還算方便吧。根據七牛文檔寫得,首先要用nuget下載官方的SDK,這個能夠參考http://developer.qiniu.com/code/v6/sdk/csharp.html。git
所要完成的功能:可以選擇圖片上傳,可以自動上傳截圖,生成markdown可用的連接github
一、界面api
主界面:微信
設置帳號界面:markdown
2. 選擇圖片上傳功能ide
點擊中間區域彈出文件瀏覽框,選擇圖片後上傳。這個經過綁定控件的鼠標事件來完成,上傳圖片用到了七牛提供的API。主體函數以下,首先是經過比對文件的hash值來判斷是否本地以及遠程已經有過上傳,若是沒有上傳過,就經過七牛提供的上傳API進行上傳,並在預覽區顯示圖片。函數
1 private bool UpLoadFile(string filepath) 2 { 3 string filename = System.IO.Path.GetFileName(filepath); 4 Qiniu.Util.Mac lMac = new Qiniu.Util.Mac(UserAccount.AccessKey, UserAccount.SecretKey); 5 string lRemoteHash = RemoteFileInfo.RemoteFileStat(lMac, UserAccount.SpaceName, filename); 6 bool lSkip = false; 7 bool lUpLoadSuccess = false; 8 //check local 9 string lLocalHash = String.Empty; 10 if (!string.IsNullOrEmpty(lRemoteHash)) 11 { 12 lLocalHash = QETag.hash(filepath); 13 14 if (historyLog.ContainsKey(lLocalHash)) 15 { 16 if(historyLog[lLocalHash].Contains(filename)) 17 { 18 lSkip = true; 19 URL = CreateURL(filename); 20 lUpLoadSuccess = true; 21 } 22 } 23 else if (string.Equals(lLocalHash, lRemoteHash)) 24 { 25 lSkip = true; 26 URL = CreateURL(filename); 27 lUpLoadSuccess = true; 28 } 29 } 30 if (!lSkip) 31 { 32 putPolicy.Scope = UserAccount.SpaceName; 33 putPolicy.SetExpires(3600 * 24 * 30); 34 string lUploadToken = Auth.createUploadToken(putPolicy, lMac); 35 UploadManager lUploadMgr = new UploadManager(); 36 lUploadMgr.uploadFile(filepath, filename, lUploadToken, null, new UpCompletionHandler(delegate (string key, ResponseInfo responseinfo, string response) 37 { 38 if (responseinfo.StatusCode != 200) 39 { 40 MessageStr = Properties.Resources.ErrorMessage; 41 } 42 else 43 { 44 MessageStr = Properties.Resources.SuccessMessage; 45 if (historyLog.ContainsKey(lLocalHash)) 46 { 47 historyLog[lLocalHash].Add(filename); 48 } 49 URL = CreateURL(filename); 50 lUpLoadSuccess = true; 51 } 52 })); 53 } 54 55 if (lUpLoadSuccess) 56 { 57 DisplayImage(filepath); 58 MessageStr = URL; 59 } 60 61 return lUpLoadSuccess; 62 }
3. 截圖上傳工具
爲了完成這個,搜了下資料,須要用到win32的兩個函數,分別是AddClipboardFormatListener以及RemoveClipboardFormatListener,而後檢查系統消息是不是WM_CLIPBOARDUPDATE。爲了給用戶提供選擇是否開啓這個,在主界面上添加了一個button來控制是否開啓。由於七牛SDK的上傳api的參數是一個文件路徑,因此這裏我首先會將截圖存儲到本地再上傳。this
1 private void CBViewerButton_Click(object sender, RoutedEventArgs e) 2 { 3 if(!IsViewing) 4 { 5 InitCBViewer(); 6 this.CBViewerButton.Content = "中止監控"; 7 } 8 else 9 { 10 StopCBViewer(); 11 this.CBViewerButton.Content = "監控剪切板"; 12 } 13 } 14 private void InitCBViewer() 15 { 16 WindowInteropHelper lwindowih = new WindowInteropHelper(this); 17 hWndSource = HwndSource.FromHwnd(lwindowih.Handle); 18 19 hWndSource.AddHook(this.WndProc); 20 Win32.AddClipboardFormatListener(hWndSource.Handle); 21 IsViewing = true; 22 } 23 24 private void StopCBViewer() 25 { 26 Win32.RemoveClipboardFormatListener(hWndSource.Handle); 27 hWndSource.RemoveHook(this.WndProc); 28 IsViewing = false; 29 } 30 31 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParm, ref bool handled) 32 { 33 if(msg == Win32.WM_CLIPBOARDUPDATE) 34 { 35 ProcessClipBoard(); 36 } 37 return IntPtr.Zero; 38 } 39 40 private void ProcessClipBoard() 41 { 42 if(System.Windows.Clipboard.ContainsImage()) 43 { 44 MessageStr = Properties.Resources.UpLoading; 45 46 BmpBitmapEncoder enc = new BmpBitmapEncoder(); 47 enc.Frames.Add(BitmapFrame.Create(System.Windows.Clipboard.GetImage())); 48 49 string lFileName = CreateFileName(); 50 string lSaveFilePath = System.IO.Path.Combine(Properties.Resources.ImageSavePathDir, lFileName); 51 using (FileStream fs = new FileStream(lSaveFilePath, FileMode.OpenOrCreate, FileAccess.Write)) 52 { 53 enc.Save(fs); 54 fs.Close(); 55 } 56 57 //because unkown reason, when use wechat snapshot hotkey, the message will process twice, to avoid this, check whether we save the same file 58 string lLocalHash = QETag.hash(lSaveFilePath); 59 if(historyLog.ContainsKey(lLocalHash)) 60 { 61 File.Delete(lSaveFilePath); 62 URL = CreateURL(historyLog[lLocalHash][0]); 63 lSaveFilePath = System.IO.Path.Combine(Properties.Resources.ImageSavePathDir, historyLog[lLocalHash][0]); 64 } 65 else 66 { 67 if(!UpLoadFile(lSaveFilePath)) 68 { 69 File.Delete(lSaveFilePath); 70 } 71 } 72 } 73 }
PS:在作這個的時候我碰到一個問題就是當我用微信的截圖快捷鍵的時候,這個Clipboard事件會被觸發兩次,爲了解決這個,個人作法是判斷本地的上傳記錄,比對文件的hash值。若是已經上傳過,就把後來又存儲的文件給刪除掉。目前我也想不到其餘方式,暫且這樣處理吧。
4. 帳號設置
用七牛作圖牀須要設置四個參數,分別是目標空間名,Accesskey, secrectkey以及域名。爲了方便存儲和讀取,用了C#裏的xml序列化和反序列化
1 if (File.Exists(Properties.Resources.ConfigFilePath)) 2 { 3 XmlSerializer xs = new XmlSerializer(typeof(AccountInfo)); 4 using (Stream s = File.OpenRead(Properties.Resources.ConfigFilePath)) 5 { 6 UserAccount = (AccountInfo)(xs.Deserialize(s)); 7 } 8 }
1 using (Stream s = File.OpenWrite(Properties.Resources.ConfigFilePath)) 2 { 3 XmlSerializer xs = new XmlSerializer(typeof(AccountInfo)); 4 xs.Serialize(s, MainWindow.UserAccount); 5 }
5. 未完成功能:歷史記錄查看等
完整代碼:
https://github.com/HaoLiuHust/QiniuUpload
PS: 代碼很爛,還須要多練