最近一段时间有用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. HTML 5 与HTML 4 的区别

    (1)HTML 5 与HTML 4 的相比,语法的改变,以下四个方面: 字符编码改变举例: 省略标记值: (2)新增和废弃的元素 (3)新增html全局属性 (1)指定元素是否可编辑 (2)指定页面是 ...

  2. 使用VS Code开发TypeScript--定义变量推荐使用let

    使用VS Code开发TypeScript--定义变量推荐使用let 目录 作用域规则 JavaScript的严格模式 let与var的区别 作用域规则 一直以来我们都是通过var关键字定义JavaS ...

  3. BubbleSort - 实用委托

    概述: 排序类,可以对任意类型的对象进行排序,包括基本数据类型; 对象类,不仅定义本身数据,同时包含了排序的细节. 排序类(BubbleSorter): using System; using Sys ...

  4. iOS开发之17个常用代码整理

    http://www.cnblogs.com/ios8/p/ios-17-code.html

  5. 修改Servlet模板

    1.找到jar文件 查看MyEclipse根目录下的myeclipse.ini,找到Common文件夹的位置,打开文件夹..\Common\plugins 找到文件 com.genuitec.ecli ...

  6. Sql Server批量停止作业

    CREATE Proc [dbo].[Proc_StopJob] as begin declare @I int declare @JobID uniqueidentifier -- 1. creat ...

  7. zendguard安装破解

    http://www.thefox.cn/zend-guard.shtml 到官网下载6.0版本安装后 URL: http://www.zend.com/en/products/guard/downl ...

  8. PHP学习系列(1)——字符串处理函数(5)

    31.ord() 函数返回字符串第一个字符的 ASCII 值. 语法:ord(string) 例子 <?php echo ord("h"); echo ord("h ...

  9. Android再学习-便签开发小结-20141119

    这几天的便签开发,首先遇到的问题就是数据库操作问题.现在已经可以读写数据库了,并能将数据放在正确的位置显示. 专门建立了一个数据库操作的包,命名为"...database".新建一 ...

  10. jave script 经典排序 - -冒泡排序

    有 5个数字,2:3:1:0:4,按大小顺序排列 <script type="text/javascript"> var arr =new Array(); arr . ...