动手写Python程序将图片嵌入Markdown
理想很丰满,现实很骨感,根据优快云博客测试,他的编辑器无法接受太大的Markdown文本,测试500KB的文本已经有了图片显示不全的问题,这里提到的方法大家看看就好o(╥﹏╥)o,或许可以考虑下图片压缩
1 前情提要
写技术文档或者做个简单的笔记用Markdown简直在舒服不过了,但是Markdown的图片插入缺非常让人难受。目前Markdown支持三种图片插入方式:
-
插入图片的网络URL

-
插入本地相对或绝对路径

-
插入图片数据Base64
 <!--由于这样做非常不利于观赏性,可以按照下面数据链接的方式改写,注意其中的小括号变为了中括号--> ![desc][link_name1] <!--文件末尾写下面--> [link_name1]:data:image/png;base64,iVBORw0KGgo...
第一种方式将图片存储在网络上,便于文档的分享,不论Markdown文档到了哪里,只要有网络都可以正常显示图片,但是存在一个巨大的问题,那就是存放图片的服务器的稳定性无法保证,低质量的图床可能没有多久就找不到你上传的图片了。
第二种方式不便于将文档进行网络共享(比如发博客),向他人共享文档需要将图片文件一同共享,有时还会有图片路径的问题。
第三种方式没有上面两种的缺点,但是其Markdown文本会显得很大(因为你在其中存储了能表示图片数据的字符串)
但是总的来说,对于发布博客等不是经常修改却要求图片长期稳定显示,第三种方式无疑非常Good。
2 动手
2.1 思路
- 从Markdown文件中通过正则找到插入图片的语法,并从中提取出图片路径(当前版本只支持本地图片,对我来说足够了,感兴趣的同学可以使用requests之类的方法从网络上获取图片)
- 使用
PIL
打开找到的图片文件,然后base64
与BytesIO
获取图片的Base64编码 - 使用链接名替换图片路径,并在文件末尾添加数据链接。
2.2 代码
requirements:
- python3.x
- PIL
from PIL import Image
import base64
from io import BytesIO
import re
import sys
def main(filename, encoding='utf-8'):
filenew = filename[0:-3]+'_new.md'
data_url = []
with open(filename,'r',encoding=encoding) as f:
with open(filenew,'w',encoding=encoding) as fn:
for line in f:
img_sents = re.findall(r'!\[[^[\]]*\]\(.+\)$',line.strip())
if not img_sents:
fn.write(line)
else:
for img_sent in img_sents:
start_index = img_sent.find('(')
end_index = img_sent.rfind(')')
img_path = img_sent[start_index+1:end_index]
try:
img = Image.open(img_path)
output_buffer = BytesIO()
if img_path.upper().endswith('JPG'):
file_format = 'JPEG'
elif img_path.upper().endswith('PNG'):
file_format = 'PNG'
img.save(output_buffer, format=file_format)
byte_data = output_buffer.getvalue()
base64_str = base64.b64encode(byte_data)
img_str = 'data:image/jpeg;base64,' + str(base64_str, encoding='utf-8')
data_url.append(img_str)
fn.write(line.replace('('+img_path+')','[link%d]'%len(data_url)))
except:
print("img error!!")
print(img_path)
fn.write('\n\n')
for i,data in enumerate(data_url):
fn.write('[link%d]:%s\n'%(i+1,data))
print('Done!')
print('Process %d imgs'%len(data_url))
return
if __name__ == '__main__':
if len(sys.argv) == 1 or not str(sys.argv[1]).endswith('md'):
print('wrong arg!!')
exit()
if len(sys.argv) == 3:
if str(sys.argv[2]).lower() not in ['utf-8','gbk']:
print('wrong arg!!')
else:
main(*sys.argv[1:])
else:
main(sys.argv[1])
2.3 测试
原始文档:
处理过程:
处理后文档:
3 总结
理想很丰满,现实很骨感,根据优快云博客测试,他的编辑器无法接受太大的Markdown文本,测试500KB的文本已经有了图片显示不全的问题,这里提到的方法大家看看就好o(╥﹏╥)o