添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Markdown 已然成为事实上的技术文档编写标准,作为 markdown 编辑器,typora 也收到越来越多人的推荐和喜爱。在 markdown 中我们经常需要插入图片,而 markdown 只是普通文本文件,因此图片只能作为外部链接而存在。这里的链接可以使用本地的相对路径,也可以使用网络 url。当使用网络 url 的时候,我们需要一个地方去维护和存储图片,这就是我们所谓的“图床”。

而我之前一直没有考虑使用图床,图片都是和 markdown 文件一起在 git 里面维护,主要的考虑点有:

  • markdown 文件以及图片是作为一个整体,可以理解成是一个项目,那么项目内容本身就是密不可分的;
  • 图片的访问权限可以跟随 markdown 文件,需要时可以有统一的访问鉴权策略;
  • 方便管理一篇文章的所有图片,对于无用的图片可以直接删除;
  • 在使用过程中遇到了越来越多的不便之处:

  • github 网站在国内访问速度较慢,文字影响不大,大量的图片下载耗时很影响体验;
  • 不方便直接分享给他人 markdown 文件,需要导出 pdf 或者打包进行分享;
  • 在 github 仓库中,大量的图片也影响了 git 仓库的导出速度;
  • 本地存储图片时,图片存储路径在不同场景有差异,不方便统一管理;
  • 不能方便地进行图片的动态缩放;
  • 权衡之后决定还是决定拥抱“图床”。typora 自带支持 iPic、uPic、PicGo 等图片上传工具,我选择国人开发的 PicGo。另外因为一直在用腾讯云服务器,自然选择了腾讯云 cos 作为图床的云存储。

    对象存储控制台 创建一个存储桶,选择所属地域,填写桶名称,访问权限选择“公有读私有写”

    Picgo

    PicGo 是一款开源跨平台的图片上传工具,能方便地上传至各种图床和云存储服务器上。可以使用带图片 GUI 的应用,也可以直接使用其核心部分基于命令行的 PicGo-Core 。我推荐直接使用 PicGo-Core,再加上 插件能力 足够满足我们的需求了。

    # 如果没有npm的话需要先安装
    # brew install npm
    # 安装picgo
    npm install picgo -g
    # 安装picgo插件
    picgo install autocopy
    picgo install rename-file
    

    安装完 picgo 和插件之后需要进行相关配置,同样有两种方式,一种是基于命令行的交互输入,而另一种是推荐的直接修改配置文件。配置文件在 Windows 下路径为 %HOMEPATH%\.picgo\config.json,Mac 下路径为~/.picgo/config.json

    "picBed": { "current": "tcyun", "tcyun": { "secretId": "子账号的SecretId", "secretKey": "子账号的SecretKey", "bucket": "Bucket名称", "appId": "", "area": "COS区域,类似ap-shanghai", "path": "", "customUrl": "数据万象url", "version": "v5" "uploader": "tcyun", "transformer": "path" "picgoPlugins": { "picgo-plugin-rename-file": true, "picgo-plugin-autocopy": true "picgo-plugin-rename-file": { "format": "pic/{y}/{m}/{d}/{rand:6}"

    根据上面的注释进行字段的编辑,重命名插件的具体参数可以参考这里。配置完成之后可以通过执行picgo upload xxx.png来验证图片上传及插件配置是否生效。这里 xxx.png 可以支持本地也可以支持网络的 url。如果上传成功之后能看到完整的 url,同时也会将 url 写入剪切板,可以直接在浏览器中进行访问验证。

    比如这个地址https://pic-1251468582.picsh.myqcloud.com/pic/2021/11/03/80da56.png,,可以查看其链接规则是符合 rename-file 插件的配置的。

    Typora

    打开偏好设置,按需要勾选之后点击“验证图片上传选项”确认上传是否正常。

    这里要注意下 mac 系统的PicGo-Core选项并不可用,需要选择Custom Commeand,手动输入命令。另外命令还需要输入完整地址(我尝试了三遍才知道)。我配置的命令内容如下:

    /opt/homebrew/bin/node /opt/homebrew/bin/picgo upload
    

    好了,到这里就可以在文章中很方便的插入图片了。使用过程中,可以发现本地图片转化为网络图片是需要一些时间,在上传成功之后才会替换掉本地 url。如果在中途不小心修改或者删除了相关内容,会导致后续替换 url 失败。好在我们是用了 autocopy 的插件,正确地址已经写入剪切板了,只要 ctrl+v 就可以了啦。

    将历史文章中的本地图片批量上传

    不想旧文章使用本地图片,而新文章才使用网络图片,这些批量化的工作当然得交给程序。用 node 或许是比较理想的方式,可以直接以 API 形式调用 picgo。但这是在我用 python 写到最后才想起的点。不多说,直接给代码,直接保存运行就好了:

    import os
    import re
    import pyperclip
    def Upload(img):
        # 使用picgo上传,需要安装插件autocopy
        pyperclip.copy("")
        ret = os.system('picgo upload ./{}'.format(img))
        if ret != 0:
            print('图片[{}]上传失败'.format(img))
            return img
        new_img = pyperclip.paste().rstrip('\n')
        if not new_img:
            print('图片[{}]似乎上传失败'.format(img))
            return img
        print('图片[{}]上传成功 ->[{}]'.format(img, new_img))
        return new_img
    def Process(root, file):
        content = ''
        print('process file:{}/{}'.format(root, file))
        inf = open('{}/{}'.format(root, file), 'r')
        for line in inf.readlines():
            result = re.finditer('!\[([^]]*)\]\(([^)]*)\)', line)
            update = False
            new_line = ''
            last_pos = 0
            for r in result:
                img = r.group(2)
                if not (img.startswith('http://') or img.startswith('https://')):
                    update = True
                    new_line += line[last_pos : r.start(2)]
                    last_pos = r.end(2)
                    new_line += Upload(img)
            new_line += line[last_pos:]
            if update:
                content += new_line
            else:
                content += line
        inf.close()
        outf = open('{}/{}'.format(root, file), 'w')
        outf.write(content)
        outf.close()
    if __name__ == '__main__':
        for root, dirs, files in os.walk('./_posts/'):
            for file in files:
                if file.endswith(".md") or file.endswith(".markdown"):
                    Process(root, file)