0%

hexo兼容md图片的一种方式

标准md的图片格式

  • 但是,md时纯文本, 图片必须存储在正确的相对位置上
  • 可以使用图床, 把相对路径图片改为网络资源, 但是图床稳定性较差, 我更希望所有的图片都保存在post中, 离线也可以查看/编辑
  • 所有的md应该是标准的md格式

hexo 使用标准md图片的方式

  • _config.yml添加:
    • post_asset_folder: true
    • hexo new 会在source/_posts中生成同名文件夹, 将图片资源放在post_name中, 就可以用相对路径使用了.
  • md预览也没问题

无法在首页预览的问题

标签插件语法引用

  • {% asset_img image.png %}
    • 使用这种方式替代md的图片显示方式, 可以做到在首页显示
    • 但是md又无法预览了

最终解决方案

  • 我们还是使用标准md语法
  • hexo generate用正则表达式实现替换
  • generate 结束后 时还原文件(git)
  • 当然需要检查当前work dir git clean, 不然还原会导致丢文件

实现

  • 由于我不熟悉js, 就用python+shell写了
  • 在 根目录下添加
  • post_fix_tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import enum
import sys
from pathlib import Path
import os
import re

posts = "source/_posts"

valid_pic_suffix = ["png", "jpg", "jpeg", "gif", "svg"]


def check_is_pic(pic_file_name):
suffix = Path(pic_file_name).suffix.lower()
if suffix is None or suffix == "":
return False
return suffix[1:] in valid_pic_suffix


class OperateType(enum.Enum):
# 在所有图片后面, 插入一行 asset 标记
ADD_ASSET = 1
# 删除 所有 asset 标记
REM_ASSET = 2
# 用 asset 标记, 替代 md 图片, 只用于打包, 目前还没做还原, 得用Git 还原
REPLACE_BY_ASSERT = 3


def fix_one_post(file, operate_type):
new_lines = []
with open(file, encoding="utf-8") as f:
old_lines = f.readlines()
for i in range(len(old_lines)):
l = old_lines[i]
# 忽略资源行, 直接添加
if l.startswith("["):
new_lines.append(l)
continue
# 忽略 asset 行, 按需添加
if l.strip().startswith("{%"):
continue
if operate_type == OperateType.REM_ASSET:
new_lines.append(l)
else:
# {% asset_img pic.png%}
re_obj = re.search(r"(.*)!\[(.*)](.*)\((.*)\)(.*)", l)
if re_obj is not None:
groups = re_obj.groups()
# print(f"{re_obj} --- {re_obj.groups()}")
assert len(groups) == 5
pic_file_path = groups[3]
assert check_is_pic(pic_file_path)
# {% asset_img pic.png This is an example image %}
pic_file_name = str(Path(pic_file_path).name)
# 添加 asset 行时, 保留原有行
if operate_type == OperateType.ADD_ASSET:
new_lines.append(l)
asset_line = f"{{% asset_img {pic_file_name}%}}\n"
new_lines.append(asset_line)
else:
# 否则, 忽略原有行, 用asset 替代
asset_line = f"{groups[0]}{{% asset_img {pic_file_name}%}}{groups[4]}\n"
new_lines.append(asset_line)
else:
# 正则匹配失败的行直接添加
new_lines.append(l)
with open(file, "w", encoding="utf-8") as f:
f.writelines(new_lines)


def main():
argv = sys.argv
operate_type = OperateType.ADD_ASSET
if argv[1] == "add":
operate_type = OperateType.ADD_ASSET
elif argv[1] == "rem":
operate_type = OperateType.REM_ASSET
elif argv[1] == "replace":
operate_type = OperateType.REPLACE_BY_ASSERT
else:
raise RuntimeError(f"wrong arguments {argv}")
for path, dir_list, file_list in os.walk(posts):
for file_name in file_list:
if file_name.lower().endswith(".md"):
real_name = os.path.join(path, file_name)
fix_one_post(real_name, operate_type)
pass


if __name__ == '__main__':
main()

  • for *nix:
  • build.sh
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
if [[ -z $(git status -s) ]]; then
echo 'clean work space, will build'
python3 post_fix_tools.py replace
hexo g
git reset --hard HEAD
else
echo 'dirty , not work'
fi

  • for win:
  • build.bat
1
2
3
4
5
6
7
8
@echo  off
for /f "delims=*" %%i in ('git status -s') do (
echo dirty , not work :
echo %%i
goto :EOF
)
echo clean work space, will build
cmd /k "python3 post_fix_tools.py replace && hexo g && git reset --hard HEAD"

使用

  • 在我们用标准的md写完后, 首先提交git, 保持仓库clean
  • 使用 build.sh/build.bat 替代 hexo g
    • 会临时把所有post的图片修改为 asset 格式, 再掉哟给你hexo g, 最后用 git reset 还原
  • 剩下的没啥区别