動手寫Python程式将圖檔嵌入Markdown
理想很豐滿,現實很骨感,根據CSDN部落格測試,他的編輯器無法接受太大的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
擷取圖檔的Base64編碼BytesIO
- 使用連結名替換圖檔路徑,并在檔案末尾添加資料連結。
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 總結
理想很豐滿,現實很骨感,根據CSDN部落格測試,他的編輯器無法接受太大的Markdown文本,測試500KB的文本已經有了圖檔顯示不全的問題,這裡提到的方法大家看看就好o(╥﹏╥)o