由於前一段時間看到 NetAnalyzer 在Windows10系統下UI表現慘不忍睹,因此利用一段時間爲了學習一下WPF相關的內容,因而停停寫寫,用了WPF相關的技術,兩個星期作了一個Markdown編輯器,而且集成了:編輯時與網頁同步,博客發佈,PDF導出等功能。也主要是不忿某款外國軟件收費,故有此做。html
https://github.com/Twzy/MarkWordgit
代碼同步編輯github
博客發佈web
MarkWord支持博客園和CSDN博客發佈,而且能夠進行圖片同步(不管是本地圖片仍是網上的圖片,均可以同步到博客服務器)。 該功能使用了MetaWeblog技術。使用方法以下,其中圖片上傳爲newMediaObject 接口api
1 /// <summary> 2 /// 文檔上傳,包括新增與更新 3 /// </summary> 4 public static string UploadBlogs(string apiUrl, string BlogId, string userId, string password, string 5 BlogsModel, string postId, string title, string Markdown, bool publish) 6 { 7 8 int procIndex = 1; 9 10 SendMsg(5, procIndex, "準備數據中……"); 11 //轉換爲html 12 string Blogs = string.Format("<!-- edit by MarkWord 墨雲軟件 -->\r\n{0}", 13 CommonMark.CommonMarkConverter.Convert(Markdown)); 14 metaTools.Url = apiUrl; 15 16 17 Post blogsPost = new Post(); 18 19 //分類 20 List<string> tmpCategories = new List<string>(); 21 tmpCategories.Add("");//添加空分類,是由於部分博客(如csdn)字段這部分爲必填字段不添加會產生異常 22 blogsPost.categories = tmpCategories.ToArray(); 23 24 //添加時間 25 blogsPost.dateCreated = DateTime.Now.ToLocalTime(); 26 27 //添加標題 28 blogsPost.title = title; 29 30 31 //指定文章編號 32 blogsPost.postid = postId; 33 34 //內容 35 blogsPost.description = BlogsModel.Contains("{0}") ?//必須使用{0}佔位符 36 string.Format(BlogsModel, Blogs) : //根據模板生成數據 主要是爲了制定Markdown模板 37 BlogsModel + Blogs; //經過前綴方式添加 38 39 //開始查找圖片並更新到服務器 40 HtmlDocument htmlDoc = new HtmlDocument(); 41 WebClient webClient = new WebClient(); 42 htmlDoc.LoadHtml(blogsPost.description); 43 var ImgList = htmlDoc.DocumentNode.Descendants("img"); 44 45 int procCount = 3 + ImgList.Count(); 46 47 SendMsg(procCount, procIndex++, string.Format("數據分析完成,總共須要上傳{0}張圖片", ImgList.Count())); 48 int imgErr = 0;//圖片上傳錯誤數量 49 foreach (var i in ImgList) 50 { 51 SendMsg(procCount, procIndex++, "正在上傳圖片數據……"); 52 //獲取圖片文件字符串 53 string ImgUrl = i.GetAttributeValue("src", ""); 54 if (string.IsNullOrEmpty(ImgUrl)) 55 { 56 imgErr++; 57 continue; 58 } 59 try 60 { 61 var imgeData = webClient.DownloadData(ImgUrl);//下載文件 62 63 FileData fd = default(FileData); 64 fd.bits = imgeData;//圖片數據 65 fd.name = Path.GetExtension(ImgUrl);//文件名 66 fd.type = string.Format("image/{0}", fd.name.Substring(1)); 67 68 UrlData obj = metaTools.newMediaObject(BlogId, userId, password, fd); 69 blogsPost.description = blogsPost.description.Replace(ImgUrl, obj.url); 70 } 71 catch 72 { 73 imgErr++; 74 continue; 75 } 76 } 77 try 78 { 79 if (string.IsNullOrWhiteSpace(postId)) 80 { 81 SendMsg(procCount, procIndex++, "開始發佈文章……"); 82 postId = metaTools.newPost(BlogId, userId, password, blogsPost, publish); 83 } 84 else 85 { 86 SendMsg(procCount, procIndex++, "正在更新文章……"); 87 metaTools.editPost(postId, userId, password, blogsPost, publish); 88 } 89 } 90 catch (Exception ex) 91 { 92 Common.ShowMessage("博客發送失敗"); 93 return postId; 94 } 95 96 if (imgErr == 0) 97 { 98 Common.ShowMessage("博客發送成功"); 99 } 100 else 101 { 102 Common.ShowMessage(string.Format("博客發送成功了,可是有{0}張圖片發送失敗", imgErr)); 103 } 104 SendMsg(procCount, procCount, "完成"); 105 return postId; 106 107 }
具體API實現方法見代碼中的BlogsAPI項目服務器
PDF導出功能,使用了HTML轉PDF方法 相關DLL已經包含在項目當中了markdown
1 //html to Pdf 2 public static void HtmlToPdf(string filePath, string html, bool isOrientation = false) 3 { 4 if (string.IsNullOrEmpty(html)) 5 html = "Null"; 6 // 建立全局信息 7 GlobalConfig gc = new GlobalConfig(); 8 gc.SetMargins(new Margins(50, 50, 60, 60)) 9 .SetDocumentTitle("MarkWord") 10 .SetPaperSize(PaperKind.A4) 11 .SetPaperOrientation(isOrientation) 12 .SetOutlineGeneration(true); 13 14 15 //頁面信息 16 ObjectConfig oc = new ObjectConfig(); 17 oc.SetCreateExternalLinks(false) 18 .SetFallbackEncoding(Encoding.UTF8) 19 .SetLoadImages(true) 20 .SetScreenMediaType(true) 21 .SetPrintBackground(true); 22 //.SetZoomFactor(1.5); 23 24 var pechkin = new SimplePechkin(gc); 25 pechkin.Finished += Pechkin_Finished; 26 pechkin.Error += Pechkin_Error; 27 pechkin.ProgressChanged += Pechkin_ProgressChanged; 28 var buf = pechkin.Convert(oc, html); 29 30 if (buf == null) 31 { 32 Common.ShowMessage("導出異常"); 33 return; 34 } 35 36 try 37 { 38 string fn = filePath; //Path.GetTempFileName() + ".pdf"; 39 FileStream fs = new FileStream(fn, FileMode.Create); 40 fs.Write(buf, 0, buf.Length); 41 fs.Close(); 42 43 //Process myProcess = new Process(); 44 //myProcess.StartInfo.FileName = fn; 45 //myProcess.Start(); 46 } 47 catch { } 48 }
CommonMark使用網絡
最後就Markdown的轉換,在這裏我使用了CommonMark,使用方法比較簡單app
CommonMark.CommonMarkConverter.Convert("### test")
編輯與html頁面同步原理 編輯器
在改工具中比較有意思的就是編輯器與Webbrower的頁面同步功能,包括頁面"無刷新"同步呈現,已經頁面同步滾動,在這裏使用的是編輯器觸發 textEditor_TextChanged 事件和 ScrollViewer 觸發的scrViewer_ScrollChanged 分別經過webbrowser 的 InvokeScript 動態調用Js實現的,咱們先來看看兩個js的內容
同步呈現
function updatePageContent(msg){ document.body.innerHTML= msg; }
很是簡單,只是將轉換出來的html直接經過document.body.innerHTML 賦給當前頁面既能夠了。
同步滾動
function scrollToPageContent(value){ window.scrollTo(0, value * (document.body.scrollHeight - document.body.clientHeight)); }
這部分,是須要經過WPF頁面轉過來一個對應的頁面位移高度與窗口顯示高度的一個頁面比例,而後在webbrowser中根據該比例計算頁面須要偏移量來實現同步移動
而對應的WPF端的代碼爲
1 /// <summary> 2 /// 同步呈現 3 /// </summary> 4 /// <param name="value"></param> 5 public void LoadBody(string MarkValue) 6 { 7 8 if (winWebDoc.Document == null) 9 return; 10 winWebDoc.Document.InvokeScript("updatePageContent", new object[] { CommonMark.CommonMarkConverter.Convert(MarkValue) }); 11 } 12 13 /// <summary> 14 /// 文本更變 15 /// </summary> 16 /// <param name="sender"></param> 17 /// <param name="e"></param> 18 private void textEditor_TextChanged(object sender, EventArgs e) 19 { 20 if (!isLoadFlag) 21 { 22 if (this.textEditor.Text != "" && scrViewer != null) 23 if (scrViewer.ScrollableHeight == scrViewer.VerticalOffset) 24 scrViewer.ScrollToBottom(); 25 26 BLL.FileManager.isChangeFlag = true; 27 } 28 //加載文檔 29 if (MarkDoc == null) 30 return; 31 if (Config.Common.WorkType == WorkType.Both) 32 { 33 MarkDoc.LoadBody(this.textEditor.Text); 34 } 35 } 36 ////////////////////////////////////////////////////////////////////////////////// 37 /// <summary> 38 /// 同步滾動 39 /// </summary> 40 /// <param name="value"></param> 41 public void ScrollAuto(double value) 42 { 43 if (winWebDoc.Document == null) 44 return; 45 winWebDoc.Document.InvokeScript("scrollToPageContent", new object[] { value.ToString(System.Globalization.CultureInfo.InvariantCulture) }); 46 47 } 48 //計算比例 49 public double ScrollViewerPositionPercentage 50 { 51 get 52 { 53 double num = this.scrViewer.ExtentHeight - this.scrViewer.ViewportHeight; 54 double result; 55 if (num != 0.0) 56 { 57 result = this.scrViewer.VerticalOffset / num; 58 } 59 else 60 { 61 result = 0.0; 62 } 63 return result; 64 } 65 } 66 67 //觸發同步 68 private void scrViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 69 { 70 if (MarkDoc == null) return; 71 if (Config.Common.WorkType == WorkType.Both) 72 { 73 MarkDoc.ScrollAuto(this.ScrollViewerPositionPercentage); 74 } 75 }
至此,Markword 中設計到的內容點已經基本覆蓋到了,若有疑問歡迎交流!!!
NetAnalyzer2016網絡協議分析軟件源碼開放購買,能夠分析80多種協議,支持http數據還原(包含chunked和gzip數據) ,歡迎你們能夠支持一下!!
墨雲NetAnalyzer官網
代碼購買連接
若有疑問歡迎QQ聯繫:470200051
祝你們週末愉快