在Markdown中使用base64存图片

author="CKboss"

date="2022-4-19"

title="在Markdown中使用base64存图片"

+++

在Markdown中使用base64存图片

使用markdown最大的痛点之一就是上传图片时需要额外的图床, 而图床又很容意出问题导致图片丢失.

如果可以把图片以base64的方式存在markdown文件中, 就可以省去寻找可靠图床的麻烦.

本文会介绍一个可行的在markdown中使用base64存储图片的方案

什么是Data URL

简单来说, 就是先把图片或附件转成base64, 再利用类似 data:[<mediatype>][;base64],<datat> 的形式在html中展示.

DataURL可以方便的将附件以纯文本的形式在网页上保存, 这正是我们想要的.

但需注意, DataURL的缺点也很明显, base64编码后文件体积会大上30%, base64格式的图片在浏览器上加载缓慢, base64过长的编码会让html文件难以编辑等.

图片转base64

有很多在线的工具都可以进行图片到base64的转换.

为了离线方便, 还可以使用如下的python代码将图片转成data_url的形式:

import tkinter as tk
from tkinter import filedialog, messagebox
import pyperclip

import cv2
import os
import base64
import tempfile
from pathlib2 import Path

class ImageBase64Optim:

    # base64 前缀
    @classmethod
    def get_img_base64_prefix(cls, img_type):
        img_type_map = {
            'jpg': 'data:image/jpeg;base64,',
            'jpeg': 'data:image/jpeg;base64,',
            'png': 'data:image/png;base64,',
        }
        return img_type_map[img_type.lower()]

    # 短边1080
    @classmethod
    def shot_edge_resize(cls, img, short_edge=720):
        h,w,_ = img.shape
        if max(h,w) < short_edge:
            return img
        if w <= h :
            w2 = short_edge
            h2 = int( short_edge * h / w + 0.5)
        else:
            w2 = int( short_edge * w / h + 0.5 )
            h2 = short_edge
        img = cv2.resize(img,(w2,h2))
        return img

    # 低质量的jpg
    @classmethod
    def trans_to_low_quality_img(cls, img_path, tmpimg):
        img = cv2.imread(img_path)
        img = ImageBase64Optim.shot_edge_resize(img)
        cv2.imwrite(tmpimg,img,[cv2.IMWRITE_JPEG_QUALITY, 55])

    @classmethod
    def base64_img(cls, img_path):
        """
        拿到图片的base64编码结果
        :param img_path 图片路径
        :rtype: str
        """
        with tempfile.NamedTemporaryFile(mode='a+',suffix='.jpg',delete=False) as tmpimg:
            tname = tmpimg.name
            ImageBase64Optim.trans_to_low_quality_img(img_path,tname)
            with open(tname, 'rb') as f:
                compress_img_content = f.read()
            # 对图片内容编码
            ret_str = cls.get_img_base64_prefix(os.path.splitext(tname)[1][1:]) + str(base64.b64encode(compress_img_content), 'utf-8')
        os.remove(tmpimg.name)
        return ret_str

def process(img_path: str):
    # img_path = Path('./Microsoft_Nostalgic_Windows_Wallpaper_4k.jpg')
    img_path = Path(img_path)
    ret = ImageBase64Optim.base64_img(img_path.as_posix())
    return ret

def run_gui():
    window = tk.Tk()
    window.withdraw()
    img_file_path = filedialog.askopenfilename()
    ret = process(img_file_path)
    pyperclip.copy(ret)
    messagebox.showinfo(message="base64 already copy.")

def run_cli():
    img_file_path = filedialog.askopenfilename()
    ret = process(img_file_path)
    print(ret)

if  __name__=='__main__':
    run_gui()

为了让base64编码后的图片体积不过于庞大.

在此代码中, 对于过大的输入图片会将其缩放到短边1080像素, 同时还在进行jpeg编码的过程中降低了原有图像质量.

具体来说, 对于输入的4k大小的图片编码后的base64大小可以控制在300k左右, 图像质量会有些许损失, 不过对于个人blog来说, 还是足够使用的.

在Markdown中使用

可以在markdown文件的最后一部分, 以 [p1]: data ...... 的形式贴上转码后的图片base64

在markdown文件的正文中, 以 ![][p1] 的形式使用图片.

很多静态网站的主题, 是可以自动忽略掉data内容的, 所以不用担心文章最后有大量的base64编码看起来像乱码.

一个使用base64展示图片的例子

可以打开源码以供参考


posted @ 2022-04-19 14:30  酱_油  阅读(2973)  评论(0编辑  收藏  举报