md-img-base64 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/$null +2 -0
- package/EXAMPLES.md +177 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/RELEASE_CHECKLIST.md +152 -0
- package/package.json +35 -0
- package/src/cli.js +43 -0
- package/src/index.js +36 -0
- package/src/lib.js +106 -0
- package/src/test.js +105 -0
package/$null
ADDED
package/EXAMPLES.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 使用示例
|
|
2
|
+
|
|
3
|
+
## 示例 1: 命令行使用
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# 基本用法
|
|
7
|
+
md-img-base64 README.md
|
|
8
|
+
|
|
9
|
+
# 指定输出文件
|
|
10
|
+
md-img-base64 README.md -o README-with-images.md
|
|
11
|
+
|
|
12
|
+
# 不创建备份
|
|
13
|
+
md-img-base64 README.md --no-backup
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 示例 2: 作为 Node.js 模块使用
|
|
17
|
+
|
|
18
|
+
### 转换文件
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const { convertMarkdownImages } = require('md-img-base64');
|
|
22
|
+
|
|
23
|
+
// 转换文件(覆盖原文件)
|
|
24
|
+
convertMarkdownImages('README.md');
|
|
25
|
+
|
|
26
|
+
// 转换并保存到新文件
|
|
27
|
+
convertMarkdownImages('README.md', 'README-converted.md');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 转换字符串
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const { convertMarkdownString } = require('md-img-base64');
|
|
34
|
+
|
|
35
|
+
const markdown = `
|
|
36
|
+
# 我的文档
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const converted = convertMarkdownString(markdown, '/path/to/project');
|
|
42
|
+
console.log(converted);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 转换单张图片
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const { imageToBase64 } = require('md-img-base64');
|
|
49
|
+
|
|
50
|
+
const base64 = imageToBase64('./images/logo.png');
|
|
51
|
+
console.log(base64);
|
|
52
|
+
// 输出: data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 示例 3: 在 Web 项目中使用
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const fs = require('fs');
|
|
59
|
+
const { convertMarkdownImages } = require('md-img-base64');
|
|
60
|
+
|
|
61
|
+
// 读取并转换 markdown
|
|
62
|
+
const content = fs.readFileSync('docs/README.md', 'utf-8');
|
|
63
|
+
const converted = convertMarkdownImages('docs/README.md');
|
|
64
|
+
|
|
65
|
+
// 在网页中使用转换后的内容
|
|
66
|
+
const html = marked(converted); // 使用 marked 等 markdown 解析器
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 示例 4: 批量处理多个文件
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const fs = require('fs');
|
|
73
|
+
const path = require('path');
|
|
74
|
+
const { convertMarkdownImages } = require('md-img-base64');
|
|
75
|
+
|
|
76
|
+
// 遍历目录中的所有 .md 文件
|
|
77
|
+
function processDirectory(dir) {
|
|
78
|
+
const files = fs.readdirSync(dir);
|
|
79
|
+
|
|
80
|
+
files.forEach(file => {
|
|
81
|
+
const filePath = path.join(dir, file);
|
|
82
|
+
const stat = fs.statSync(filePath);
|
|
83
|
+
|
|
84
|
+
if (stat.isDirectory()) {
|
|
85
|
+
processDirectory(filePath);
|
|
86
|
+
} else if (path.extname(file) === '.md') {
|
|
87
|
+
console.log(`处理: ${filePath}`);
|
|
88
|
+
try {
|
|
89
|
+
convertMarkdownImages(filePath);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(`错误: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 处理当前目录
|
|
98
|
+
processDirectory('.');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 示例 5: 与构建工具集成
|
|
102
|
+
|
|
103
|
+
### 在 package.json 中添加脚本
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"scripts": {
|
|
108
|
+
"prepare-docs": "node scripts/prepare-docs.js"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 创建准备脚本 (scripts/prepare-docs.js)
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
const { convertMarkdownImages } = require('md-img-base64');
|
|
117
|
+
const glob = require('glob');
|
|
118
|
+
|
|
119
|
+
// 批量转换所有 markdown 文件
|
|
120
|
+
glob('docs/**/*.md', (err, files) => {
|
|
121
|
+
if (err) {
|
|
122
|
+
console.error(err);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
files.forEach(file => {
|
|
127
|
+
console.log(`转换: ${file}`);
|
|
128
|
+
convertMarkdownImages(file);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
console.log('✓ 所有文档转换完成');
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 示例 6: 在 CI/CD 中使用
|
|
136
|
+
|
|
137
|
+
### GitHub Actions 示例
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
name: Build Docs
|
|
141
|
+
|
|
142
|
+
on:
|
|
143
|
+
push:
|
|
144
|
+
branches: [ main ]
|
|
145
|
+
|
|
146
|
+
jobs:
|
|
147
|
+
build:
|
|
148
|
+
runs-on: ubuntu-latest
|
|
149
|
+
steps:
|
|
150
|
+
- uses: actions/checkout@v2
|
|
151
|
+
|
|
152
|
+
- name: Setup Node.js
|
|
153
|
+
uses: actions/setup-node@v2
|
|
154
|
+
with:
|
|
155
|
+
node-version: '18'
|
|
156
|
+
|
|
157
|
+
- name: Install dependencies
|
|
158
|
+
run: npm install
|
|
159
|
+
|
|
160
|
+
- name: Prepare docs
|
|
161
|
+
run: npm run prepare-docs
|
|
162
|
+
|
|
163
|
+
- name: Upload docs
|
|
164
|
+
uses: actions/upload-artifact@v2
|
|
165
|
+
with:
|
|
166
|
+
name: docs
|
|
167
|
+
path: docs/
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 注意事项
|
|
171
|
+
|
|
172
|
+
1. **文件大小**: base64 编码会使文件体积增加约 33%
|
|
173
|
+
2. **大图片**: 不建议处理大量大图片(> 1MB)
|
|
174
|
+
3. **性能**: 转换后的 markdown 文件可能变得很大,某些编辑器可能性能不佳
|
|
175
|
+
4. **备份**: 默认会创建 `.bak` 备份文件,确保数据安全
|
|
176
|
+
5. **网络图片**: 以 `http://` 或 `https://` 开头的图片不会被转换
|
|
177
|
+
6. **已嵌入图片**: 已经是 `data:` URI 的图片不会被重复转换
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Your Name
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# md-img-base64
|
|
2
|
+
|
|
3
|
+
将 markdown 文件中的本地图片转换为 base64 编码嵌入,实现单文件分发。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 自动将 markdown 文件中的本地图片转换为 base64 编码
|
|
8
|
+
- ✅ 支持多种图片格式(PNG, JPG, GIF, SVG, WebP, BMP)
|
|
9
|
+
- ✅ 自动识别相对路径和绝对路径
|
|
10
|
+
- ✅ 命令行工具,支持直接运行
|
|
11
|
+
- ✅ 可选自动备份原文件
|
|
12
|
+
- ✅ 可作为 Node.js 模块集成到项目中
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
### 全局安装(推荐用于命令行使用)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g md-img-base64
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 局部安装(用于项目中使用)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install md-img-base64
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 使用方法
|
|
29
|
+
|
|
30
|
+
### 命令行使用
|
|
31
|
+
|
|
32
|
+
安装后,可以直接使用 `md-img-base64` 命令:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 转换文件(默认创建 .bak 备份)
|
|
36
|
+
md-img-base64 your-file.md
|
|
37
|
+
|
|
38
|
+
# 指定输出文件
|
|
39
|
+
md-img-base64 your-file.md -o output.md
|
|
40
|
+
|
|
41
|
+
# 不创建备份
|
|
42
|
+
md-img-base64 your-file.md --no-backup
|
|
43
|
+
|
|
44
|
+
# 查看帮助
|
|
45
|
+
md-img-base64 --help
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 作为 Node.js 模块使用
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const { convertMarkdownImages } = require('md-img-base64');
|
|
52
|
+
|
|
53
|
+
// 转换 markdown 文件(会覆盖原文件)
|
|
54
|
+
convertMarkdownImages('path/to/your/file.md');
|
|
55
|
+
|
|
56
|
+
// 或指定输出文件
|
|
57
|
+
convertMarkdownImages('input.md', 'output.md');
|
|
58
|
+
|
|
59
|
+
// 转换 markdown 字符串
|
|
60
|
+
const { convertMarkdownString } = require('md-img-base64');
|
|
61
|
+
const content = '';
|
|
62
|
+
const converted = convertMarkdownString(content, '/path/to/base/dir');
|
|
63
|
+
|
|
64
|
+
// 单独转换图片为 base64
|
|
65
|
+
const { imageToBase64 } = require('md-img-base64');
|
|
66
|
+
const base64 = imageToBase64('./images/pic.png');
|
|
67
|
+
console.log(base64);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 示例
|
|
71
|
+
|
|
72
|
+
假设你有以下 markdown 文件:
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
# 我的文档
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+

|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
运行命令:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
md-img-base64 doc.md
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
转换后的文件:
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
# 我的文档
|
|
92
|
+
|
|
93
|
+

|
|
94
|
+
|
|
95
|
+

|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API 文档
|
|
99
|
+
|
|
100
|
+
### `convertMarkdownImages(filePath, outputPath)`
|
|
101
|
+
|
|
102
|
+
将 markdown 文件中的图片转换为 base64。
|
|
103
|
+
|
|
104
|
+
- **参数**:
|
|
105
|
+
- `filePath` (string): 输入的 markdown 文件路径
|
|
106
|
+
- `outputPath` (string, 可选): 输出文件路径,默认覆盖原文件
|
|
107
|
+
- **返回值**: 处理后的 markdown 内容字符串
|
|
108
|
+
|
|
109
|
+
### `convertMarkdownString(markdownContent, baseDir)`
|
|
110
|
+
|
|
111
|
+
将 markdown 字符串中的图片转换为 base64。
|
|
112
|
+
|
|
113
|
+
- **参数**:
|
|
114
|
+
- `markdownContent` (string): markdown 内容字符串
|
|
115
|
+
- `baseDir` (string): 基准目录(用于解析相对路径)
|
|
116
|
+
- **返回值**: 处理后的 markdown 内容字符串
|
|
117
|
+
|
|
118
|
+
### `imageToBase64(imagePath)`
|
|
119
|
+
|
|
120
|
+
将图片文件转换为 base64 编码。
|
|
121
|
+
|
|
122
|
+
- **参数**:
|
|
123
|
+
- `imagePath` (string): 图片文件路径
|
|
124
|
+
- **返回值**: base64 编码的 data URI 字符串
|
|
125
|
+
|
|
126
|
+
## 注意事项
|
|
127
|
+
|
|
128
|
+
- ⚠️ 图片转换为 base64 后文件体积会增大约 33%,不建议处理大量大图片
|
|
129
|
+
- ⚠️ 转换后的文件可能变得很大,某些 markdown 编辑器可能性能不佳
|
|
130
|
+
- 💡 建议在发布文档前进行转换,以方便单文件分发
|
|
131
|
+
- 💡 默认会创建 `.bak` 备份文件,可用 `--no-backup` 选项禁用
|
|
132
|
+
|
|
133
|
+
## 支持的图片格式
|
|
134
|
+
|
|
135
|
+
- PNG (`.png`)
|
|
136
|
+
- JPEG (`.jpg`, `.jpeg`)
|
|
137
|
+
- GIF (`.gif`)
|
|
138
|
+
- SVG (`.svg`)
|
|
139
|
+
- WebP (`.webp`)
|
|
140
|
+
- BMP (`.bmp`)
|
|
141
|
+
|
|
142
|
+
## 开发
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# 克隆仓库
|
|
146
|
+
git clone https://github.com/yourusername/md-img-base64.git
|
|
147
|
+
|
|
148
|
+
# 安装依赖
|
|
149
|
+
npm install
|
|
150
|
+
|
|
151
|
+
# 运行测试
|
|
152
|
+
npm test
|
|
153
|
+
|
|
154
|
+
# 本地测试命令行工具
|
|
155
|
+
node src/cli.js your-file.md
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|
|
161
|
+
|
|
162
|
+
## 作者
|
|
163
|
+
|
|
164
|
+
Your Name
|
|
165
|
+
|
|
166
|
+
## 贡献
|
|
167
|
+
|
|
168
|
+
欢迎提交 Issue 和 Pull Request!
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# 发布前检查清单
|
|
2
|
+
|
|
3
|
+
## ✅ 代码检查
|
|
4
|
+
|
|
5
|
+
- [x] 所有代码文件已检查,无第三方版权内容
|
|
6
|
+
- [x] 测试文件已更新,使用自包含的测试数据
|
|
7
|
+
- [x] 所有功能测试通过(3/3)
|
|
8
|
+
- [x] 代码无语法错误
|
|
9
|
+
- [x] CLI 工具可正常运行
|
|
10
|
+
|
|
11
|
+
## ✅ 文档检查
|
|
12
|
+
|
|
13
|
+
- [x] README.md 完整清晰
|
|
14
|
+
- [x] LICENSE 文件存在(MIT)
|
|
15
|
+
- [x] EXAMPLES.md 提供详细示例
|
|
16
|
+
- [x] package.json 元数据完整
|
|
17
|
+
|
|
18
|
+
## ✅ 配置检查
|
|
19
|
+
|
|
20
|
+
### package.json 检查
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"name": "md-img-base64", // ✅ 包名
|
|
25
|
+
"version": "1.0.0", // ✅ 版本号
|
|
26
|
+
"description": "...", // ✅ 描述
|
|
27
|
+
"main": "src/index.js", // ✅ 入口文件
|
|
28
|
+
"bin": { // ✅ 命令行工具
|
|
29
|
+
"md-img-base64": "./src/cli.js"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [...], // ✅ 关键词
|
|
32
|
+
"license": "MIT", // ✅ 许可证
|
|
33
|
+
"engines": { // ✅ Node 版本要求
|
|
34
|
+
"node": ">=14.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## ✅ 发布步骤
|
|
40
|
+
|
|
41
|
+
### 1. 检查包名是否可用
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm view md-img-base64
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
如果返回 `404 Not Found`,则包名可用。
|
|
48
|
+
|
|
49
|
+
### 2. 登录 npm
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm login
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. 测试本地包
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm test
|
|
59
|
+
|
|
60
|
+
# 测试 CLI
|
|
61
|
+
node src/cli.js your-test-file.md
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 4. 推送到 GitHub(可选但推荐)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git init
|
|
68
|
+
git add .
|
|
69
|
+
git commit -m "Initial release: md-img-base64 v1.0.0"
|
|
70
|
+
git remote add origin https://github.com/yourusername/md-img-base64.git
|
|
71
|
+
git push -u origin main
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 5. 发布到 npm
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm publish
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 6. 验证发布
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# 查看包信息
|
|
84
|
+
npm view md-img-base64
|
|
85
|
+
|
|
86
|
+
# 全局安装测试
|
|
87
|
+
npm install -g md-img-base64
|
|
88
|
+
md-img-base64 --help
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 📦 发布后的后续工作
|
|
92
|
+
|
|
93
|
+
- [ ] 在 GitHub README 中添加 npm 徽章
|
|
94
|
+
- [ ] 标记 GitHub Release
|
|
95
|
+
- [ ] 分享到社交媒体
|
|
96
|
+
- [ ] 收集用户反馈
|
|
97
|
+
|
|
98
|
+
## 🔧 故障排除
|
|
99
|
+
|
|
100
|
+
### 包名已被占用
|
|
101
|
+
|
|
102
|
+
修改 `package.json` 中的 `name` 字段,使用其他名称:
|
|
103
|
+
- `@username/md-img-base64` (作用域包)
|
|
104
|
+
- `md-img-to-base64`
|
|
105
|
+
- `markdown-image-embed`
|
|
106
|
+
- `md-base64-embed`
|
|
107
|
+
|
|
108
|
+
### 登录失败
|
|
109
|
+
|
|
110
|
+
确保使用正确的 npm 用户名和密码,或尝试:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm logout
|
|
114
|
+
npm login
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 发布失败 - 403 Forbidden
|
|
118
|
+
|
|
119
|
+
检查:
|
|
120
|
+
1. 是否有发布权限
|
|
121
|
+
2. 包名是否已被占用
|
|
122
|
+
3. `.npmrc` 配置是否正确
|
|
123
|
+
|
|
124
|
+
### 2FA 问题
|
|
125
|
+
|
|
126
|
+
如果启用了两步验证,需要使用 OTP 令牌:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm publish --otp=123456
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 📝 更新版本号
|
|
133
|
+
|
|
134
|
+
发布更新时,遵循语义化版本:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# 补丁版本(bug 修复)
|
|
138
|
+
npm version patch # 1.0.0 -> 1.0.1
|
|
139
|
+
|
|
140
|
+
# 次版本(新功能,向后兼容)
|
|
141
|
+
npm version minor # 1.0.0 -> 1.1.0
|
|
142
|
+
|
|
143
|
+
# 主版本(破坏性变更)
|
|
144
|
+
npm version major # 1.0.0 -> 2.0.0
|
|
145
|
+
|
|
146
|
+
# 发布新版本
|
|
147
|
+
npm publish
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 🎉 完成!
|
|
151
|
+
|
|
152
|
+
现在你的 npm 包已经准备好发布了!
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "md-img-base64",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "将 markdown 文件中的本地图片转换为 base64 编码嵌入,实现单文件分发",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"md-img-base64": "src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node src/test.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"markdown",
|
|
14
|
+
"base64",
|
|
15
|
+
"image",
|
|
16
|
+
"embed",
|
|
17
|
+
"convert"
|
|
18
|
+
],
|
|
19
|
+
"author": "wyc2025 <1429978418@qq.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"homepage": "https://github.com/wyc2025/md-img-base64#readme",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/wyc2025/md-img-base64.git"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/wyc2025/md-img-base64/issues"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^11.0.0"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=14.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const { convertMarkdownImages } = require('./index');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('md-img-base64')
|
|
12
|
+
.description('将 markdown 文件中的本地图片转换为 base64 编码嵌入')
|
|
13
|
+
.version('1.0.0')
|
|
14
|
+
.argument('<input>', '输入的 markdown 文件路径')
|
|
15
|
+
.option('-o, --output <path>', '输出文件路径(默认覆盖原文件)')
|
|
16
|
+
.option('--no-backup', '不创建备份文件')
|
|
17
|
+
.action((input, options) => {
|
|
18
|
+
try {
|
|
19
|
+
const inputPath = path.resolve(input);
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(inputPath)) {
|
|
22
|
+
console.error(`错误: 文件不存在: ${inputPath}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 创建备份
|
|
27
|
+
if (options.backup !== false) {
|
|
28
|
+
const backupPath = inputPath + '.bak';
|
|
29
|
+
fs.copyFileSync(inputPath, backupPath);
|
|
30
|
+
console.log(`✓ 已创建备份: ${backupPath}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 处理文件
|
|
34
|
+
const outputPath = options.output ? path.resolve(options.output) : inputPath;
|
|
35
|
+
convertMarkdownImages(inputPath, outputPath);
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`错误: ${error.message}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
program.parse();
|
package/src/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { processMarkdownFile, processMarkdown, fileToBase64 } = require('./lib');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 将 markdown 文件中的本地图片转换为 base64 编码
|
|
5
|
+
* @param {string} markdownFilePath - markdown 文件路径
|
|
6
|
+
* @param {string} outputPath - 输出文件路径(可选,默认覆盖原文件)
|
|
7
|
+
* @returns {string} 处理后的内容
|
|
8
|
+
*/
|
|
9
|
+
function convertMarkdownImages(markdownFilePath, outputPath = null) {
|
|
10
|
+
return processMarkdownFile(markdownFilePath, outputPath);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 将 markdown 字符串中的本地图片转换为 base64 编码
|
|
15
|
+
* @param {string} markdownContent - markdown 内容字符串
|
|
16
|
+
* @param {string} baseDir - 基准目录(用于解析相对路径)
|
|
17
|
+
* @returns {string} 处理后的 markdown 内容
|
|
18
|
+
*/
|
|
19
|
+
function convertMarkdownString(markdownContent, baseDir) {
|
|
20
|
+
return processMarkdown(markdownContent, baseDir);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 将图片文件转换为 base64 编码
|
|
25
|
+
* @param {string} imagePath - 图片文件路径
|
|
26
|
+
* @returns {string} base64 编码的 data URI
|
|
27
|
+
*/
|
|
28
|
+
function imageToBase64(imagePath) {
|
|
29
|
+
return fileToBase64(imagePath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
convertMarkdownImages,
|
|
34
|
+
convertMarkdownString,
|
|
35
|
+
imageToBase64
|
|
36
|
+
};
|
package/src/lib.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 将文件转换为 base64 编码
|
|
6
|
+
* @param {string} filePath - 图片文件路径
|
|
7
|
+
* @returns {string} base64 编码的字符串
|
|
8
|
+
*/
|
|
9
|
+
function fileToBase64(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const buffer = fs.readFileSync(filePath);
|
|
12
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
13
|
+
const mimeTypes = {
|
|
14
|
+
'.png': 'image/png',
|
|
15
|
+
'.jpg': 'image/jpeg',
|
|
16
|
+
'.jpeg': 'image/jpeg',
|
|
17
|
+
'.gif': 'image/gif',
|
|
18
|
+
'.svg': 'image/svg+xml',
|
|
19
|
+
'.webp': 'image/webp',
|
|
20
|
+
'.bmp': 'image/bmp'
|
|
21
|
+
};
|
|
22
|
+
const mimeType = mimeTypes[ext] || 'application/octet-stream';
|
|
23
|
+
return `data:${mimeType};base64,${buffer.toString('base64')}`;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.warn(`警告: 无法读取图片文件 ${filePath}: ${error.message}`);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 处理 markdown 文本,将图片引用转换为 base64
|
|
32
|
+
* @param {string} content - markdown 内容
|
|
33
|
+
* @param {string} markdownDir - markdown 文件所在目录
|
|
34
|
+
* @returns {string} 处理后的 markdown 内容
|
|
35
|
+
*/
|
|
36
|
+
function processMarkdown(content, markdownDir) {
|
|
37
|
+
// 匹配 markdown 图片语法: 
|
|
38
|
+
const imgRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
39
|
+
|
|
40
|
+
return content.replace(imgRegex, (match, alt, imagePath) => {
|
|
41
|
+
// 如果已经是 data URI 或 URL,则跳过
|
|
42
|
+
if (imagePath.startsWith('data:') || imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
|
|
43
|
+
return match;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 解析相对路径
|
|
47
|
+
let absolutePath;
|
|
48
|
+
if (path.isAbsolute(imagePath)) {
|
|
49
|
+
absolutePath = imagePath;
|
|
50
|
+
} else {
|
|
51
|
+
// 处理 ./assets/xxx.png 或 assets/xxx.png 的情况
|
|
52
|
+
absolutePath = path.resolve(markdownDir, imagePath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 检查文件是否存在
|
|
56
|
+
if (!fs.existsSync(absolutePath)) {
|
|
57
|
+
console.warn(`警告: 图片文件不存在: ${absolutePath}`);
|
|
58
|
+
return match;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 转换为 base64
|
|
62
|
+
const base64 = fileToBase64(absolutePath);
|
|
63
|
+
if (base64) {
|
|
64
|
+
console.log(`✓ 已转换: ${imagePath}`);
|
|
65
|
+
return ``;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return match;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 处理 markdown 文件
|
|
74
|
+
* @param {string} markdownFilePath - markdown 文件路径
|
|
75
|
+
* @param {string} outputPath - 输出文件路径(可选)
|
|
76
|
+
* @returns {string} 处理后的内容
|
|
77
|
+
*/
|
|
78
|
+
function processMarkdownFile(markdownFilePath, outputPath = null) {
|
|
79
|
+
if (!fs.existsSync(markdownFilePath)) {
|
|
80
|
+
throw new Error(`文件不存在: ${markdownFilePath}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(`正在处理: ${markdownFilePath}`);
|
|
84
|
+
|
|
85
|
+
// 读取 markdown 文件
|
|
86
|
+
const content = fs.readFileSync(markdownFilePath, 'utf-8');
|
|
87
|
+
const markdownDir = path.dirname(markdownFilePath);
|
|
88
|
+
|
|
89
|
+
// 处理图片
|
|
90
|
+
const processedContent = processMarkdown(content, markdownDir);
|
|
91
|
+
|
|
92
|
+
// 确定输出路径
|
|
93
|
+
const finalOutputPath = outputPath || markdownFilePath;
|
|
94
|
+
|
|
95
|
+
// 写入文件
|
|
96
|
+
fs.writeFileSync(finalOutputPath, processedContent, 'utf-8');
|
|
97
|
+
console.log(`✓ 处理完成,已保存到: ${finalOutputPath}`);
|
|
98
|
+
|
|
99
|
+
return processedContent;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
fileToBase64,
|
|
104
|
+
processMarkdown,
|
|
105
|
+
processMarkdownFile
|
|
106
|
+
};
|
package/src/test.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// 测试文件
|
|
2
|
+
const { convertMarkdownImages, convertMarkdownString, imageToBase64 } = require('./index');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
console.log('=== 测试 md-img-base64 ===\n');
|
|
7
|
+
|
|
8
|
+
// 创建测试用的 markdown 文件和图片
|
|
9
|
+
const testDir = path.join(__dirname, '../test-temp');
|
|
10
|
+
const testFile = path.join(testDir, 'test.md');
|
|
11
|
+
const testImage = path.join(testDir, 'test-image.png');
|
|
12
|
+
|
|
13
|
+
// 清理旧的测试目录
|
|
14
|
+
if (fs.existsSync(testDir)) {
|
|
15
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 创建测试目录
|
|
19
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
20
|
+
|
|
21
|
+
// 创建一个简单的 PNG 图片(1x1 像素透明图片)
|
|
22
|
+
const pngData = Buffer.from([
|
|
23
|
+
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG signature
|
|
24
|
+
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR
|
|
25
|
+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1
|
|
26
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
|
|
27
|
+
0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, // IDAT
|
|
28
|
+
0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00,
|
|
29
|
+
0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4,
|
|
30
|
+
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, // IEND
|
|
31
|
+
0xAE, 0x42, 0x60, 0x82
|
|
32
|
+
]);
|
|
33
|
+
fs.writeFileSync(testImage, pngData);
|
|
34
|
+
|
|
35
|
+
// 创建测试 markdown 文件
|
|
36
|
+
const testMarkdownContent = `# 测试文档
|
|
37
|
+
|
|
38
|
+
这是一张本地图片:
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
`;
|
|
46
|
+
fs.writeFileSync(testFile, testMarkdownContent, 'utf-8');
|
|
47
|
+
|
|
48
|
+
// 测试 1: 转换单个 markdown 文件
|
|
49
|
+
console.log('测试 1: 转换 markdown 文件');
|
|
50
|
+
const outputFile = path.join(testDir, 'test-output.md');
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
convertMarkdownImages(testFile, outputFile);
|
|
54
|
+
|
|
55
|
+
// 验证输出文件
|
|
56
|
+
const outputContent = fs.readFileSync(outputFile, 'utf-8');
|
|
57
|
+
const hasBase64 = outputContent.includes('data:image/png;base64');
|
|
58
|
+
const hasNetworkImage = outputContent.includes('https://example.com/image.png');
|
|
59
|
+
|
|
60
|
+
if (hasBase64 && hasNetworkImage) {
|
|
61
|
+
console.log('✓ 测试 1 通过: 本地图片已转换,网络图片保持不变\n');
|
|
62
|
+
} else {
|
|
63
|
+
console.log('✗ 测试 1 失败: 转换结果不符合预期\n');
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('✗ 测试 1 失败:', error.message, '\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 测试 2: 转换单个图片为 base64
|
|
70
|
+
console.log('测试 2: 转换单个图片为 base64');
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const base64 = imageToBase64(testImage);
|
|
74
|
+
if (base64 && base64.startsWith('data:image/png;base64,')) {
|
|
75
|
+
console.log('✓ 测试 2 通过');
|
|
76
|
+
console.log(` Base64 长度: ${base64.length} 字符\n`);
|
|
77
|
+
} else {
|
|
78
|
+
console.log('✗ 测试 2 失败: base64 格式不正确\n');
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('✗ 测试 2 失败:', error.message, '\n');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 测试 3: 转换 markdown 字符串
|
|
85
|
+
console.log('测试 3: 转换 markdown 字符串');
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const markdownStr = ``;
|
|
89
|
+
const converted = convertMarkdownString(markdownStr, testDir);
|
|
90
|
+
|
|
91
|
+
if (converted.includes('data:image/png;base64,')) {
|
|
92
|
+
console.log('✓ 测试 3 通过: markdown 字符串转换成功\n');
|
|
93
|
+
} else {
|
|
94
|
+
console.log('✗ 测试 3 失败: markdown 字符串转换失败\n');
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error('✗ 测试 3 失败:', error.message, '\n');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 清理测试文件
|
|
101
|
+
console.log('清理测试文件...');
|
|
102
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
103
|
+
console.log('✓ 测试完成\n');
|
|
104
|
+
|
|
105
|
+
console.log('=== 所有测试完成 ===');
|