markdown将图片转换为base64格式
1 背景
Markdown 是一种轻量级标记语言,使人可以将时间都花在撰写内容而不是调整格式上,用来写技术文档再合适不过了。但markdown有个痛点---添加图片不方便。
markdown添加图片的方法:
- 方法1:插入本地图片(支持绝对路径和相对路径)
![avatar](/home/picture/1.png)
- 方法2:插入网络图片
![avatar](https://baidu.com/pic/doge.png)
如果图片在本地,markdown中插入本地图片,这样做缺点很多:
1 本地图片路径更改或丢失导致markdown找不到图片;
2 分享不灵活,mk文档发给别人时,找不到图片路径。
插入网络图片,需要自己制造图床,写文档时并不方便,另外看文档时需要网络环境。
还有一种办法,用base64转码工具,把图片转成一段字符串,然后引用这段base64编码即可,这样添加图片比较方便,但是需要一些多的动作。
- 方法3:图片转为base64
![avatar][doge]
# 放在文章末尾
[doge]:data:image/png;base64,iVBORw0......
2 图片转为base64
2.1 剪切板图片转为base64
在添加图片时,大多数情况可以使用截图工具(常用snipaste),将截图复制到剪切板,然后运行python脚本,将剪切板的截图转为base64格式字符串,然后将此字符串贴回到剪切板,供我们粘贴使用。
img2base64.py内容如下:
(python3脚本,脚本来源于网络)
import base64
from PIL import Image
from PIL import ImageGrab
import pyperclip
from io import BytesIO
im = ImageGrab.grabclipboard()
def pil_base64(image):
img_buffer = BytesIO()
w, h = image.size
# image.thumbnail((480, 480))
image.save(img_buffer, format='JPEG', quality=95)
byte_data = img_buffer.getvalue()
base64_str = base64.b64encode(byte_data)
return base64_str
if isinstance(im, Image.Image):
print(im.format, im.size, im.mode)
px = im.load()
msg = str(pil_base64(im))
msg = 'data:image/png;base64,' + msg[2:-2]
#print(msg)
pyperclip.copy(msg)
else:
pass
为了方便使用,可以将这个脚本制作成exe可执行程序。
# 生成可执行文件
pip install pyinstaller
pyinstaller -F -w img2base64.py #打包成exe, 在且不包含控制台,exe默认在dist目录下
2.2 将markdown本地图片转为base64格式
写markdown文档时,如果像2.1节一样,一张图一张图转base64,但效率比较低,我们也可以写文档时先临时插入本地图片,写完之后通过脚本一次性生成base64的形式。
脚本有如下要求:
- 1 读取markdown文件,并用正则查找出所有的本地引用标签
- 2 替换图片标签
![image-name](url)
为![image-name][image-name]
- 3 在md文件后面追加上base64编码
[image-name]:图片base64编码
mark2base64.py脚本如下:
import sys
import re
import base64
import chardet
images_suffix = ["gif", "png", "jpg", "jpeg"]
appendix = []
def transform(lines):
newlines = []
pattern = re.compile(r'!\[(.*)\]\((.*)\)', re.I) # 正则匹配
for line in lines:
li = pattern.findall(line)
if not li:
newlines.append(line)
continue
for match in li:
img_name = match[0]
img_path = match[1]
if not img_name or not img_path:
newlines.append(line)
continue
if 'http' in img_path: # skip http img
newlines.append(line)
continue
suffix = img_path.rsplit(".")[1]
if suffix in images_suffix:
try:
with open(img_path, 'rb') as f:
image_bytes = base64.b64encode(f.read())
except:
newlines.append(line)
continue
image_str = str(image_bytes)
#print(image_str)
base64_pre = 'data:image/' + suffix + ';base64,'
real_image_str = base64_pre + image_str[2:len(image_str) - 1]
appendix.append('[' + img_name + ']' + ':' + real_image_str + '\n\n\n')
line = line.replace('(' + img_path + ')', '[' + img_name + ']')
newlines.append(line)
return newlines
def md_2_img(markdown_file):
if not markdown_file.endswith('.md'):
return
code = chardet.detect(open(markdown_file, 'rb').read())['encoding']
with open(markdown_file, 'r', encoding=code) as mk:
lines = mk.readlines()
newlines = transform(lines)
with open(markdown_file, 'w', encoding=code) as mk:
mk.writelines(newlines)
with open(markdown_file, 'a+', encoding=code) as mk:
mk.write("\n\n")
mk.write("".join(appendix))
if __name__ == '__main__':
markdown_file = sys.argv[1]
print(markdown_file)
md_2_img(markdown_file)
参考: