最近一段时间有用markdown做笔记,其他都好,但是markdown插入图片挺麻烦的,特别是想截图之后直接插入的时候。需要首先把图片保存了,然后还要上传到一个地方生成链接才能插入。如果有个工具可以直接上传图片或者截图生成markdown可以用的链接就好了。所以决定自己下班后写一个,不过自己挺菜的,也就能用,代码完全是渣不能看。。。在这里把自己的思路还有其中遇到的问题记录一下。

  首先需要选一个图床,我选了七牛,主要是一个是有免费的空间,加上提供了SDK,这样就能写程序上传了。语言挑了C#,因为感觉WPF写界面还算方便吧。根据七牛文档写得,首先要用nuget下载官方的SDK,这个可以参考http://developer.qiniu.com/code/v6/sdk/csharp.html

  所要完成的功能:能够选择图片上传,能够自动上传截图,生成markdown可用的链接

1、界面

主界面:

  

设置账号界面:

2. 选择图片上传功能

点击中间区域弹出文件浏览框,选择图片后上传。这个通过绑定控件的鼠标事件来完成,上传图片用到了七牛提供的API。主体函数如下,首先是通过比对文件的hash值来判断是否本地以及远程已经有过上传,如果没有上传过,就通过七牛提供的上传API进行上传,并在预览区显示图片。

 private bool UpLoadFile(string filepath)
{
string filename = System.IO.Path.GetFileName(filepath);
Qiniu.Util.Mac lMac = new Qiniu.Util.Mac(UserAccount.AccessKey, UserAccount.SecretKey);
string lRemoteHash = RemoteFileInfo.RemoteFileStat(lMac, UserAccount.SpaceName, filename);
bool lSkip = false;
bool lUpLoadSuccess = false;
//check local
string lLocalHash = String.Empty;
if (!string.IsNullOrEmpty(lRemoteHash))
{
lLocalHash = QETag.hash(filepath); if (historyLog.ContainsKey(lLocalHash))
{
if(historyLog[lLocalHash].Contains(filename))
{
lSkip = true;
URL = CreateURL(filename);
lUpLoadSuccess = true;
}
}
else if (string.Equals(lLocalHash, lRemoteHash))
{
lSkip = true;
URL = CreateURL(filename);
lUpLoadSuccess = true;
}
}
if (!lSkip)
{
putPolicy.Scope = UserAccount.SpaceName;
putPolicy.SetExpires( * * );
string lUploadToken = Auth.createUploadToken(putPolicy, lMac);
UploadManager lUploadMgr = new UploadManager();
lUploadMgr.uploadFile(filepath, filename, lUploadToken, null, new UpCompletionHandler(delegate (string key, ResponseInfo responseinfo, string response)
{
if (responseinfo.StatusCode != )
{
MessageStr = Properties.Resources.ErrorMessage;
}
else
{
MessageStr = Properties.Resources.SuccessMessage;
if (historyLog.ContainsKey(lLocalHash))
{
historyLog[lLocalHash].Add(filename);
}
URL = CreateURL(filename);
lUpLoadSuccess = true;
}
}));
} if (lUpLoadSuccess)
{
DisplayImage(filepath);
MessageStr = URL;
} return lUpLoadSuccess;
}

3. 截图上传

为了完成这个,搜了下资料,需要用到win32的两个函数,分别是AddClipboardFormatListener以及RemoveClipboardFormatListener,然后检查系统消息是否是WM_CLIPBOARDUPDATE。为了给用户提供选择是否开启这个,在主界面上添加了一个button来控制是否开启。因为七牛SDK的上传api的参数是一个文件路径,所以这里我首先会将截图存储到本地再上传。

     private void CBViewerButton_Click(object sender, RoutedEventArgs e)
{
if(!IsViewing)
{
InitCBViewer();
this.CBViewerButton.Content = "停止监控";
}
else
{
StopCBViewer();
this.CBViewerButton.Content = "监控剪切板";
}
}
private void InitCBViewer()
{
WindowInteropHelper lwindowih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(lwindowih.Handle); hWndSource.AddHook(this.WndProc);
Win32.AddClipboardFormatListener(hWndSource.Handle);
IsViewing = true;
} private void StopCBViewer()
{
Win32.RemoveClipboardFormatListener(hWndSource.Handle);
hWndSource.RemoveHook(this.WndProc);
IsViewing = false;
} private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParm, ref bool handled)
{
if(msg == Win32.WM_CLIPBOARDUPDATE)
{
ProcessClipBoard();
}
return IntPtr.Zero;
} private void ProcessClipBoard()
{
if(System.Windows.Clipboard.ContainsImage())
{
MessageStr = Properties.Resources.UpLoading; BmpBitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(System.Windows.Clipboard.GetImage())); string lFileName = CreateFileName();
string lSaveFilePath = System.IO.Path.Combine(Properties.Resources.ImageSavePathDir, lFileName);
using (FileStream fs = new FileStream(lSaveFilePath, FileMode.OpenOrCreate, FileAccess.Write))
{
enc.Save(fs);
fs.Close();
} //because unkown reason, when use wechat snapshot hotkey, the message will process twice, to avoid this, check whether we save the same file
string lLocalHash = QETag.hash(lSaveFilePath);
if(historyLog.ContainsKey(lLocalHash))
{
File.Delete(lSaveFilePath);
URL = CreateURL(historyLog[lLocalHash][]);
lSaveFilePath = System.IO.Path.Combine(Properties.Resources.ImageSavePathDir, historyLog[lLocalHash][]);
}
else
{
if(!UpLoadFile(lSaveFilePath))
{
File.Delete(lSaveFilePath);
}
}
}
}

PS:在做这个的时候我碰到一个问题就是当我用微信的截图快捷键的时候,这个Clipboard事件会被触发两次,为了解决这个,我的做法是判断本地的上传记录,比对文件的hash值。如果已经上传过,就把后来又存储的文件给删除掉。目前我也想不到其他方式,暂且这样处理吧。

4. 账号设置

用七牛做图床需要设置四个参数,分别是目标空间名,Accesskey, secrectkey以及域名。为了方便存储和读取,用了C#里的xml序列化和反序列化

  if (File.Exists(Properties.Resources.ConfigFilePath))
{
XmlSerializer xs = new XmlSerializer(typeof(AccountInfo));
using (Stream s = File.OpenRead(Properties.Resources.ConfigFilePath))
{
UserAccount = (AccountInfo)(xs.Deserialize(s));
}
}
  using (Stream s = File.OpenWrite(Properties.Resources.ConfigFilePath))
{
XmlSerializer xs = new XmlSerializer(typeof(AccountInfo));
xs.Serialize(s, MainWindow.UserAccount);
}

5. 未完成功能:历史记录查看等

完整代码:

https://github.com/HaoLiuHust/QiniuUpload

PS: 代码很烂,还需要多练

QiniuUpload- 一个方便用七牛做图床然后插入markdown的小工具的更多相关文章

  1. win10 uwp 使用 asp dotnet core 做图床服务器客户端

    原文 win10 uwp 使用 asp dotnet core 做图床服务器客户端 本文告诉大家如何在 UWP 做客户端和 asp dotnet core 做服务器端来做一个图床工具   服务器端 从 ...

  2. 分享一个超级好用的SM图床

    分享一个超级好用的SM图床 ​ 大家都知道我是一个喜欢sm Markdown的人,但是Markdown有个很不方便的地方,就是图片的插入,一般用Markdown编辑器(我用的是Typora)直接插入图 ...

  3. 图床plus演示 | 图床及在线分享演示文稿工具

    文章目录 关于图床 什么是图床? 墙内 墙外 关于在线分享演示文稿 在线分享演示文稿 工具分享 待补充 关于图床 什么是图床? 这并不是一个多么高大上的名词概念!用比较通俗的话来说,当你在撰写新文章时 ...

  4. u-tools图床便捷生成markdown图片

    u-tools 图床 上传图片生成markdown图片非常便捷. 支持的图片服务器有几种,其中搜狗.网易和掘金的加载速度更快些: 也可以用阿里与和腾讯云的OSS; 其中网易生成图片不是原图尺寸好像被改 ...

  5. 使用GitHub API上传文件及GitHub做图床

    本文介绍GitHub API基础及上传文件到仓库API,并应用API将GitHub作为图床 GitHub API官方页面 GitHub API版本 当前版本为v3,官方推荐在请求头中显示添加版本标识. ...

  6. Typora使用教程 之 PicGo集成做图床

    目录 一.Typora是什么 二.研究它的原因 三.需要解决的问题 四.解决图床问题 1.下载PicGo 2.安装下载的PicGo,并根据下图所示配置(必须安装nodejs,否则插件一直是" ...

  7. 自己做的加速app测试流程的小工具,目前打算开放使用,想注册的朋友抓紧了,嘻嘻

    为了加速小团队app的测试流程做了这个东西,www.xunce.net 主要特性: web: 一键上传app,方便随时下载 备注测试要点 添加附件,如checklist等文档  自动识别app版本,名 ...

  8. 在这个插件帮助下,终于用上免费的Https协议外链的图床了

    前天,强哥发了一篇推文,讲述了应该如何免费且快速的生成自己的博客网站: 期间也有提到一点就是我们在写博客的时候,因为使用的是Markdown格式的文件,而如果想要​Markdown格式的文件在图片上传 ...

  9. Markdown编辑器及图床推荐

    Typora和自动图床工具 Typora 地址 ,极致简洁,界面很漂亮,最重要的是所见即所得 百度云搬运 密码:xi01 自动图床工具 需要七牛云做图床,感谢作者,详见博客 使用方法,只需两步即可完成 ...

随机推荐

  1. 常用分组函数count-avg-sum-max-min

    分组函数也称多行函数,用于对一组数据进行运算,针对一组数据(取自于多行记录的相同字段)只返回一个结果,例如计算公司全体员工的工资总和.最高工资.最低工资.各部门的员工平均工资(按部门分组)等.由于分组 ...

  2. VS2012发布网站IIS配置

    首先要配置好下面步骤 然后 把图上勾选的都勾选 最后一步 那IIS就配置好了,怎么添加发布呢打开IIS管理器 然后带点击网站添加网站 ,在这之前首先要在磁盘里新建一个文件夹,把项目复制过去,网站随便命 ...

  3. [c#]asp.net开发微信公众平台(5)微信图文消息

    上篇已经成功响应了关注事件,也实现了文本消息的发送,这篇开始图文消息处理, 微信中最常用的消息类型就是图文消息了,因为它图文并茂,最能表达信息. 图文消息在微信中的接口定义如下: <xml> ...

  4. Zookeeper+Kafka+Storm+HDFS实践

    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据. Hadoop一般用在离线的分析计算中,而storm区别于hadoop,用在实时的流式计算中,被广泛用来 ...

  5. JavaWeb学习笔记之Servlet(一)

    1. 引子: 当我们开始进入JavaWeb开发的学习时,我们就必须要和Servlet和HTTP这两个词进行打交道了,尤其是Servlet.即使到了后面使用JSP (我们知道JSP其本身就是一个Serv ...

  6. uva 10370 - Above Average

    #include <iostream> #include <cstdio> using namespace std; int main() { unsigned C, N, t ...

  7. PHP数组的排序函数

    对保存在数组中的相关数据进行排序是一件非常有意义的事情.在PHP中提供了很多函数可以对数组进行排序,这些函数提供了多种排序的方法.例如,可以通过元素的值或键及自定义排序等. ①简单的数组排序函数简单的 ...

  8. python学习第十五天 -面向对象之继承和多态

    大家都知道面向对象的三大特性:封装,继承,多态.封装特性在上一章节已经讲解过.这一章节主要讲解继承和多态. 继承: 当定义一个类的时候,可以从现有的类进行继承.那么新定义的类可以称为子类,被继承的现有 ...

  9. C语言初学 计算表达式的值 switch的意义

    #include<stdio.h> main() { int a; printf("请输入一个数字\n"); scanf("%d",&a); ...

  10. 1234: ZJTZYRC筛offer(并查集 )

    链接:http://xcacm.hfut.edu.cn/problem.php?id=1234 以后关于字符的输入都用cin吧,换成scanf居然wa了 #include <iostream&g ...