天天看點

動手寫Python程式将圖檔嵌入Markdown動手寫Python程式将圖檔嵌入Markdown

動手寫Python程式将圖檔嵌入Markdown

理想很豐滿,現實很骨感,根據CSDN部落格測試,他的編輯器無法接受太大的Markdown文本,測試500KB的文本已經有了圖檔顯示不全的問題,這裡提到的方法大家看看就好o(╥﹏╥)o,或許可以考慮下圖檔壓縮

1 前情提要

寫技術文檔或者做個簡單的筆記用Markdown簡直在舒服不過了,但是Markdown的圖檔插入缺非常讓人難受。目前Markdown支援三種圖檔插入方式:

  1. 插入圖檔的網絡URL
    ![desc](http://example.png)
               
  2. 插入本地相對或絕對路徑
    ![desc](c:\example.png)
               
  3. 插入圖檔資料Base64
    ![desc](data:image/png;base64,iVBORw0KGgo...)
    <!--由于這樣做非常不利于觀賞性,可以按照下面資料連結的方式改寫,注意其中的小括号變為了中括号-->
    
    ![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 測試

原始文檔:

動手寫Python程式将圖檔嵌入Markdown動手寫Python程式将圖檔嵌入Markdown

處理過程:

動手寫Python程式将圖檔嵌入Markdown動手寫Python程式将圖檔嵌入Markdown

處理後文檔:

動手寫Python程式将圖檔嵌入Markdown動手寫Python程式将圖檔嵌入Markdown

3 總結

理想很豐滿,現實很骨感,根據CSDN部落格測試,他的編輯器無法接受太大的Markdown文本,測試500KB的文本已經有了圖檔顯示不全的問題,這裡提到的方法大家看看就好o(╥﹏╥)o