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

代码下载地址

https://github.com/Twzy/MarkWord

展示与说明

代码同步编辑

博客发布

代码说明

博客发布

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

 /// <summary>
/// 文档上传,包括新增与更新
/// </summary>
public static string UploadBlogs(string apiUrl, string BlogId, string userId, string password, string
BlogsModel, string postId, string title, string Markdown, bool publish)
{ int procIndex = ; SendMsg(, procIndex, "准备数据中……");
//转换为html
string Blogs = string.Format("<!-- edit by MarkWord 墨云软件 -->\r\n{0}",
CommonMark.CommonMarkConverter.Convert(Markdown));
metaTools.Url = apiUrl; Post blogsPost = new Post(); //分类
List<string> tmpCategories = new List<string>();
tmpCategories.Add("");//添加空分类,是因为部分博客(如csdn)字段这部分为必填字段不添加会产生异常
blogsPost.categories = tmpCategories.ToArray(); //添加时间
blogsPost.dateCreated = DateTime.Now.ToLocalTime(); //添加标题
blogsPost.title = title; //指定文章编号
blogsPost.postid = postId; //内容
blogsPost.description = BlogsModel.Contains("{0}") ?//必须使用{0}占位符
string.Format(BlogsModel, Blogs) : //根据模板生成数据 主要是为了制定Markdown模板
BlogsModel + Blogs; //通过前缀方式添加 //开始查找图片并更新到服务器
HtmlDocument htmlDoc = new HtmlDocument();
WebClient webClient = new WebClient();
htmlDoc.LoadHtml(blogsPost.description);
var ImgList = htmlDoc.DocumentNode.Descendants("img"); int procCount = + ImgList.Count(); SendMsg(procCount, procIndex++, string.Format("数据分析完成,总共需要上传{0}张图片", ImgList.Count()));
int imgErr = ;//图片上传错误数量
foreach (var i in ImgList)
{
SendMsg(procCount, procIndex++, "正在上传图片数据……");
//获取图片文件字符串
string ImgUrl = i.GetAttributeValue("src", "");
if (string.IsNullOrEmpty(ImgUrl))
{
imgErr++;
continue;
}
try
{
var imgeData = webClient.DownloadData(ImgUrl);//下载文件 FileData fd = default(FileData);
fd.bits = imgeData;//图片数据
fd.name = Path.GetExtension(ImgUrl);//文件名
fd.type = string.Format("image/{0}", fd.name.Substring()); UrlData obj = metaTools.newMediaObject(BlogId, userId, password, fd);
blogsPost.description = blogsPost.description.Replace(ImgUrl, obj.url);
}
catch
{
imgErr++;
continue;
}
}
try
{
if (string.IsNullOrWhiteSpace(postId))
{
SendMsg(procCount, procIndex++, "开始发布文章……");
postId = metaTools.newPost(BlogId, userId, password, blogsPost, publish);
}
else
{
SendMsg(procCount, procIndex++, "正在更新文章……");
metaTools.editPost(postId, userId, password, blogsPost, publish);
}
}
catch (Exception ex)
{
Common.ShowMessage("博客发送失败");
return postId;
} if (imgErr == )
{
Common.ShowMessage("博客发送成功");
}
else
{
Common.ShowMessage(string.Format("博客发送成功了,但是有{0}张图片发送失败", imgErr));
}
SendMsg(procCount, procCount, "完成");
return postId; }

具体API实现方法见代码中的BlogsAPI项目

PDF导出

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

 //html to Pdf
public static void HtmlToPdf(string filePath, string html, bool isOrientation = false)
{
if (string.IsNullOrEmpty(html))
html = "Null";
// 创建全局信息
GlobalConfig gc = new GlobalConfig();
gc.SetMargins(new Margins(, , , ))
.SetDocumentTitle("MarkWord")
.SetPaperSize(PaperKind.A4)
.SetPaperOrientation(isOrientation)
.SetOutlineGeneration(true); //页面信息
ObjectConfig oc = new ObjectConfig();
oc.SetCreateExternalLinks(false)
.SetFallbackEncoding(Encoding.UTF8)
.SetLoadImages(true)
.SetScreenMediaType(true)
.SetPrintBackground(true);
//.SetZoomFactor(1.5); var pechkin = new SimplePechkin(gc);
pechkin.Finished += Pechkin_Finished;
pechkin.Error += Pechkin_Error;
pechkin.ProgressChanged += Pechkin_ProgressChanged;
var buf = pechkin.Convert(oc, html); if (buf == null)
{
Common.ShowMessage("导出异常");
return;
} try
{
string fn = filePath; //Path.GetTempFileName() + ".pdf";
FileStream fs = new FileStream(fn, FileMode.Create);
fs.Write(buf, , buf.Length);
fs.Close(); //Process myProcess = new Process();
//myProcess.StartInfo.FileName = fn;
//myProcess.Start();
}
catch { }
}

 

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端的代码为

         /// <summary>
/// 同步呈现
/// </summary>
/// <param name="value"></param>
public void LoadBody(string MarkValue)
{ if (winWebDoc.Document == null)
return;
winWebDoc.Document.InvokeScript("updatePageContent", new object[] { CommonMark.CommonMarkConverter.Convert(MarkValue) });
} /// <summary>
/// 文本更变
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textEditor_TextChanged(object sender, EventArgs e)
{
if (!isLoadFlag)
{
if (this.textEditor.Text != "" && scrViewer != null)
if (scrViewer.ScrollableHeight == scrViewer.VerticalOffset)
scrViewer.ScrollToBottom(); BLL.FileManager.isChangeFlag = true;
}
//加载文档
if (MarkDoc == null)
return;
if (Config.Common.WorkType == WorkType.Both)
{
MarkDoc.LoadBody(this.textEditor.Text);
}
}
//////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 同步滚动
/// </summary>
/// <param name="value"></param>
public void ScrollAuto(double value)
{
if (winWebDoc.Document == null)
return;
winWebDoc.Document.InvokeScript("scrollToPageContent", new object[] { value.ToString(System.Globalization.CultureInfo.InvariantCulture) }); }
//计算比例
public double ScrollViewerPositionPercentage
{
get
{
double num = this.scrViewer.ExtentHeight - this.scrViewer.ViewportHeight;
double result;
if (num != 0.0)
{
result = this.scrViewer.VerticalOffset / num;
}
else
{
result = 0.0;
}
return result;
}
} //触发同步
private void scrViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (MarkDoc == null) return;
if (Config.Common.WorkType == WorkType.Both)
{
MarkDoc.ScrollAuto(this.ScrollViewerPositionPercentage);
}
}

至此,Markword 中设计到的内容点已经基本覆盖到了,如有疑问欢迎交流!!!


最后来一发小广告

NetAnalyzer2016网络协议分析软件源码开放购买,可以分析80多种协议,支持http数据还原(包含chunked和gzip数据) ,欢迎大家可以支持一下!!

墨云NetAnalyzer官网
代码购买链接
如有疑问欢迎QQ联系:470200051

祝大家周末愉快

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

  1. 博客用Markdown编辑器插入视频

    要展示一些App的效果用或者更方便地展示工具的操作,可以使用视频. 以下有两种方式可以在博客中插入视频 第一种 此方法适用于插入来源优酷的视频或者你自己录制了视频上传到优酷,这种方法的好处是可以插入时 ...

  2. Orchard运用 - 为博客启用Markdown编辑器

    有时决定你是否使用某一个博客系统,最看重就是如何更简便的写博客,不能让其成为一个负担或别扭费力不讨好的工作. 对此一个好的编辑器就是一个最靓丽的卖点.比如最新的博客系统ghost.org就只定位一个最 ...

  3. 201771010117—马兴德—实验一 软件工程准备—掌握博客中MarkDown的使用以及通读《现代软件工程—构建之法》的总结

    实验一 软件工程的前期准备工作 在前期的准备工作以及老师上课的讲解中,我懂得了"软件=程序+软件工程"这句话的基本含义,以前只是对软件工程有一个很浅显的概念,现在在读了<现代 ...

  4. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)下,前后台布局实现、发布博客以及展示。

    一.博客系统进度回顾 目前已经完成了,前台展示,以及后台发布的功能,最近都在做这个,其实我在国庆的时候就可以弄完的,但是每天自己弄,突然最后国庆2天,连电脑都不想碰,所以就一直拖着,上一篇写了前端实现 ...

  5. Flask博客开发——Tinymce编辑器

    之前Flask博客的文本编辑器比较简陋,这里为博客添加个优雅易用的Tinymce文本编辑器. 1.项目中添加Tinymce 下载好Tinymce包以及语言包,并添加到项目中.添加到项目的方法,参考了这 ...

  6. 【干货】利用MVC5+EF6搭建博客系统(四)(下)前后台布局实现、发布博客以及展示

    二.博客系统后台布局实现 2.1.这里所用的是MVC的布局页来实现的,后台主要分为三部分:导航.菜单.主要内容 代码实现: 这里把后台单独放在一个区域里面,所以我这里建立一个admin的区域 在布局页 ...

  7. 测试用Word2007发布博客文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  8. 用WORD2007发布博客文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  9. Word2007发布博客

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

随机推荐

  1. Linux磁盘分区实战案例

    一.查看新添加磁盘   [root@localhost /]# fdisk -l   磁盘 /dev/sda:53.7 GB, 53687091200 字节,104857600 个扇区 Units = ...

  2. C# SqlHelper

    操作数据库时,经常会把常用的方法封装到一个类中,这里简单写了一个SQLHelper类,供我平时调用. public static class SqlHelper { private static re ...

  3. ListIterator add remove 使用注意

    add方法示例 //在最前面添加 List<String> list1 = new LinkedList<String>(Arrays.asList(new String[]  ...

  4. crontab 配置

    * * * * * (cd /opt/bd/www/crm/scripts/zb_insure; /opt/tuniu/php/bin/php /opt/bd/www/crm/scripts/zb_i ...

  5. 开发中遇到的java小知识

    今天在优化一个功能的时候遇到了instr与substr函数,之前没有接触过这两个函数,但是今天无意中用到,一查才发现,真是实用的一对兄弟啊. 先来说说substr函数,这个函数返回的是字符串的一部分. ...

  6. 用POP动画引擎实现衰减动画(POPDecayAnimation)

    效果图: #import "ViewController.h" #import <POP.h> @interface ViewController () @end @i ...

  7. MySQL查询优化处理

    查询的生命周期的下一步是将一个sql转化成一个执行计划,MySQL再依照这个执行计划和存储引擎进行交互.这包括多个子阶段:解析sql,预处理,优化sql执行计划.这个过程中任何错误(例如语法错误)都可 ...

  8. 外国高手画神级的linux 内核图,够详细!

  9. SelectObject

    CPen* SelectObject( CPen* pPen ); CBrush* SelectObject( CBrush* pBrush ); virtual CFont* SelectObjec ...

  10. discuz php判断是手机访问还是电脑访问网站

    首先在模块处填入代码: //手机网页跳转 //如果检测到访问的浏览器为下列一个指定的移动浏览器 则返回true function is_mobile(){ $regex_match="/(n ...