MarkWord - 可发布博客的 Markdown编辑器 代码开源

因为前一段时间看到 NetAnalyzer 在Windows10系统下UI表现惨不忍睹,所以利用一段时间为了学习一下WPF相关的内容,于是停停写写,用了WPF相关的技术,两个星期做了一个Markdown编辑器,并且集成了:编辑时与网页同步,博客发布,PDF导出等功能。也主要是不忿某款外国软件收费,故有此作。

代码下载地址

https://github.com/Twzy/MarkWord

展示与说明

代码同步编辑

博客发布

代码说明

博客发布

MarkWord支持博客园和CSDN博客发布,并且可以进行图片同步(无论是本地图片还是网上的图片,都可以同步到博客服务器)。 该功能使用了MetaWeblog技术。使用方法如下,其中图片上传为newMediaObject 接口

  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导出

PDF导出功能,使用了HTML转PDF方法 相关DLL已经包含在项目当中了

 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,使用方法比较简单

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

祝大家周末愉快

时间: 2024-12-20 06:02:58

MarkWord - 可发布博客的 Markdown编辑器 代码开源的相关文章

修改博客园markdown编辑器代码高亮风格的方法

???????作为一个工程师,追求极致与艺术也应当成为我们生活中的一部分,作为自己的心爱之物--博客,当然也得装扮一下,我对代码高亮有自己所喜欢的风格~还好程序员的世界总是共通的,已经有前辈开发了一些代码高亮的样式可供我们开箱即用.Highlightjs就是这样一款产品. ???????下面介绍一下我是如何将这款产品应用于博客园markdown编辑器中的. 第一步,找到你所喜欢的高亮主题 ???????打开Hightlightjs的demo页面 选择你所喜欢的高亮主题.我选择的是Atom One

博客园 Markdown编辑器简要教程

简介 ?? 在刚才的导语里提到,Markdown 是一种用来写作的轻量级「标记语言」,它用简洁的语法代替排版,而不像一般我们用的字处理软件 Word 或 Pages 有大量的排版.字体设置.它使我们专心于码字,用「标记」语法,来代替常见的排版格式.例如此文从内容到格式,甚至插图,键盘就可以通通搞定了.?? 目前来看,支持 Markdown 语法的编辑器有很多,包括很多网站(例如简书)也支持了 Markdown 的文字录入.Markdown 从写作到完成,导出格式随心所欲,你可以导出 HTML 格

博客园 Markdown 编辑器指南

标题 只要前面加 # 号即可,一共六级标题 列表 无序列表 无序列表前面加* 无序列表前面加* 无序列表前面加* 有序列表 前面加列号序号1 前面加列号序号2 前面加列号序号3 引用 只需要在前面加>符号 粗体于斜体 打两个**就是粗体 打一个*就是斜体 代码框 这是代码框,有包起来的 使用\`\`\`py更加好一点, 可以包含多行代码 分割线 分割线的语法只需要三个 * 号 在此处分割 在此处分割 博客园 Markdown 编辑器指南 原文地址:https://www.cnblogs.com/

公开求助:博客园Markdown编辑器的改进(太简陋)

本人学生党,学业繁重,对JavaScript等一无所知,同时无法忍受博客园默认的markdown编辑器--它太丑.太简陋了. 然后,我看到一个网站:这大概是"所见即所得"Markdown吧_V2EX 上也能用 发现这个项目 HyperMD HyperMD是一个在线的能够"实时预览"的markdown编辑器. HyperMD 是一组 [CodeMirror][] 插件.模式.主题.编辑器命令(Commands)和按键绑定(KeyMap)等. 你可以在一个页面上同时使用

CSDN博客支持MarkDown编辑器了

真是良心做法啊....

博客园markdown编辑器下上传图片

先对图片进行base64转码 再写语法,eg: ![picture](base64密钥) 为不影响编辑,可将密钥内容放到文章最后,eg: ![picture][img] [img]:base64密钥 转码链接:link 原文地址:https://www.cnblogs.com/junecode/p/11829717.html

使用Live Writer发布博客到博客园

使用Live Writer发布博客到博客园 配置参见 Windows Live Writer配置步骤 Markdown支持参见MarkdownInLiveWriter

51CTO博客2.0-Markdown编辑器:脉络清晰的排版速成班

基础: 1.[语法]请参看<51CTO博客2.0-Markdown编辑器使用技巧>2.[内容] 文章总标题&作者个人姓名介绍,不要放在正文3.[空行]使用markdown语法的段落,上下段之间空一行,避免与上下段落的语法重合. 正文组成10要素: 1.首段引言2.正文内标题3.图片4.代码段(长代码)5.代码块(短代码)6.文字型链接7.图片型链接8.重点词9.重点语句10.表格 1.首段引言: 位置:正文前1-3段.速成:①每段第一个字前加符号">".(或者

Word 2010发布博客文章

目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写博客需要在第三方博客平台注册帐号,且需要第三方博客平台提供API接口.目前的有的博客平台均已关闭博客接口,所以无法使用Word来发布博客. 2.发布到博客或公众号平台的图片无法转载.由于所有博客平台,公众号平台(如微信)开启了图片防盗链功能,作者发布到这些平台上的图片则无法转载到其它的网站中,这限制