426 lines
10 KiB
Markdown
426 lines
10 KiB
Markdown
|
|
# Word/Markdown 转 PDF API 使用指南
|
|||
|
|
|
|||
|
|
## API 端点
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
POST /api/pdf/convert
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 支持的输入方式
|
|||
|
|
|
|||
|
|
### 1. 上传文件
|
|||
|
|
|
|||
|
|
支持上传 `.doc`, `.docx`, `.md` 文件:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// 上传 Word 文件
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('file', fileInput.files[0]); // .doc 或 .docx
|
|||
|
|
|
|||
|
|
// 可选参数
|
|||
|
|
formData.append('toc', 'true'); // 生成目录
|
|||
|
|
formData.append('header_text', '文档标题|页码'); // 页眉
|
|||
|
|
formData.append('footer_text', '版权信息'); // 页脚
|
|||
|
|
formData.append('filename_text', '我的文档'); // 文件名
|
|||
|
|
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const blob = await response.blob();
|
|||
|
|
const url = URL.createObjectURL(blob);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 指定本地文件路径
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('file_path', '/path/to/document.docx');
|
|||
|
|
formData.append('toc', 'true');
|
|||
|
|
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 直接提交 Markdown 内容
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('markdown_content', '# 标题\n\n这是内容');
|
|||
|
|
formData.append('filename_text', '我的文档');
|
|||
|
|
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 完整参数列表
|
|||
|
|
|
|||
|
|
| 参数 | 类型 | 必填 | 说明 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| file | File | 否* | 上传的文件 |
|
|||
|
|
| file_path | string | 否* | 本地文件路径 |
|
|||
|
|
| markdown_content | string | 否* | Markdown 内容 |
|
|||
|
|
| toc | boolean | 否 | 是否生成目录,默认 false |
|
|||
|
|
| header_text | string | 否 | 页眉文本,可用 `\|` 分隔左右 |
|
|||
|
|
| footer_text | string | 否 | 页脚文本 |
|
|||
|
|
| logo_url | string | 否 | Logo 图片 URL |
|
|||
|
|
| copyright_text | string | 否 | 版权声明 |
|
|||
|
|
| filename_text | string | 否 | 显示的文件名 |
|
|||
|
|
| cover_src | string | 否 | 封面图片 URL |
|
|||
|
|
| product_name | string | 否 | 产品名称(封面) |
|
|||
|
|
| document_name | string | 否 | 文档名称(封面) |
|
|||
|
|
| product_version | string | 否 | 产品版本 |
|
|||
|
|
| document_version | string | 否 | 文档版本 |
|
|||
|
|
| css_name | string | 否 | CSS 样式名称 |
|
|||
|
|
| css_text | string | 否 | 自定义 CSS |
|
|||
|
|
| download | boolean | 否 | 是否直接下载,默认 true |
|
|||
|
|
|
|||
|
|
*注:file、file_path、markdown_content 三者必选其一
|
|||
|
|
|
|||
|
|
## 完整示例代码
|
|||
|
|
|
|||
|
|
### React 示例
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
import { useState, useRef } from 'react';
|
|||
|
|
|
|||
|
|
function PdfConverter() {
|
|||
|
|
const [loading, setLoading] = useState(false);
|
|||
|
|
const fileInput = useRef(null);
|
|||
|
|
|
|||
|
|
const convertToPdf = async () => {
|
|||
|
|
const file = fileInput.current.files[0];
|
|||
|
|
if (!file) return;
|
|||
|
|
|
|||
|
|
setLoading(true);
|
|||
|
|
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('file', file);
|
|||
|
|
formData.append('toc', 'true');
|
|||
|
|
formData.append('header_text', '我的文档|第 {page} 页');
|
|||
|
|
formData.append('footer_text', '© 2024 公司名称');
|
|||
|
|
formData.append('filename_text', file.name.replace(/\.[^/.]+$/, ''));
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
const error = await response.json();
|
|||
|
|
throw new Error(error.detail || '转换失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const blob = await response.blob();
|
|||
|
|
const url = URL.createObjectURL(blob);
|
|||
|
|
|
|||
|
|
// 下载 PDF
|
|||
|
|
const a = document.createElement('a');
|
|||
|
|
a.href = url;
|
|||
|
|
a.download = file.name.replace(/\.[^/.]+$/, '') + '.pdf';
|
|||
|
|
document.body.appendChild(a);
|
|||
|
|
a.click();
|
|||
|
|
document.body.removeChild(a);
|
|||
|
|
URL.revokeObjectURL(url);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('转换失败:', error);
|
|||
|
|
alert('转换失败: ' + error.message);
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<input
|
|||
|
|
type="file"
|
|||
|
|
ref={fileInput}
|
|||
|
|
accept=".doc,.docx,.md"
|
|||
|
|
/>
|
|||
|
|
<button
|
|||
|
|
onClick={convertToPdf}
|
|||
|
|
disabled={loading}
|
|||
|
|
>
|
|||
|
|
{loading ? '转换中...' : '转换为 PDF'}
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Vue 3 示例
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<template>
|
|||
|
|
<div>
|
|||
|
|
<input
|
|||
|
|
ref="fileInput"
|
|||
|
|
type="file"
|
|||
|
|
accept=".doc,.docx,.md"
|
|||
|
|
/>
|
|||
|
|
<button
|
|||
|
|
@click="convertToPdf"
|
|||
|
|
:disabled="loading"
|
|||
|
|
>
|
|||
|
|
{{ loading ? '转换中...' : '转换为 PDF' }}
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref } from 'vue';
|
|||
|
|
|
|||
|
|
const fileInput = ref(null);
|
|||
|
|
const loading = ref(false);
|
|||
|
|
|
|||
|
|
const convertToPdf = async () => {
|
|||
|
|
const file = fileInput.value.files[0];
|
|||
|
|
if (!file) return;
|
|||
|
|
|
|||
|
|
loading.value = true;
|
|||
|
|
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('file', file);
|
|||
|
|
formData.append('toc', 'true');
|
|||
|
|
formData.append('header_text', '我的文档');
|
|||
|
|
formData.append('filename_text', file.name.replace(/\.[^/.]+$/, ''));
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
const error = await response.json();
|
|||
|
|
throw new Error(error.detail || '转换失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const blob = await response.blob();
|
|||
|
|
const url = URL.createObjectURL(blob);
|
|||
|
|
|
|||
|
|
const a = document.createElement('a');
|
|||
|
|
a.href = url;
|
|||
|
|
a.download = file.name.replace(/\.[^/.]+$/, '') + '.pdf';
|
|||
|
|
document.body.appendChild(a);
|
|||
|
|
a.click();
|
|||
|
|
document.body.removeChild(a);
|
|||
|
|
URL.revokeObjectURL(url);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('转换失败:', error);
|
|||
|
|
alert('转换失败: ' + error.message);
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原生 JavaScript 示例
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html>
|
|||
|
|
<head>
|
|||
|
|
<title>Word/Markdown 转 PDF</title>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<h1>文档转 PDF</h1>
|
|||
|
|
|
|||
|
|
<input type="file" id="fileInput" accept=".doc,.docx,.md">
|
|||
|
|
<button id="convertBtn">转换为 PDF</button>
|
|||
|
|
|
|||
|
|
<div id="status" style="margin-top: 10px;"></div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
document.getElementById('convertBtn').addEventListener('click', async () => {
|
|||
|
|
const fileInput = document.getElementById('fileInput');
|
|||
|
|
const status = document.getElementById('status');
|
|||
|
|
const file = fileInput.files[0];
|
|||
|
|
|
|||
|
|
if (!file) {
|
|||
|
|
status.textContent = '请选择文件';
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
status.textContent = '转换中...';
|
|||
|
|
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('file', file);
|
|||
|
|
formData.append('toc', 'true');
|
|||
|
|
formData.append('header_text', '我的文档|{page}');
|
|||
|
|
formData.append('footer_text', '© 2024');
|
|||
|
|
formData.append('filename_text', file.name.replace(/\.[^/.]+$/, ''));
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
const error = await response.json();
|
|||
|
|
throw new Error(error.detail || '转换失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const blob = await response.blob();
|
|||
|
|
const url = URL.createObjectURL(blob);
|
|||
|
|
|
|||
|
|
const a = document.createElement('a');
|
|||
|
|
a.href = url;
|
|||
|
|
a.download = file.name.replace(/\.[^/.]+$/, '') + '.pdf';
|
|||
|
|
document.body.appendChild(a);
|
|||
|
|
a.click();
|
|||
|
|
document.body.removeChild(a);
|
|||
|
|
URL.revokeObjectURL(url);
|
|||
|
|
|
|||
|
|
status.textContent = '转换成功!';
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(error);
|
|||
|
|
status.textContent = '转换失败: ' + error.message;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Markdown 内容转 PDF 示例
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
async function markdownToPdf() {
|
|||
|
|
const markdownContent = `
|
|||
|
|
# 我的文档
|
|||
|
|
|
|||
|
|
## 第一章
|
|||
|
|
|
|||
|
|
这是第一章的内容。
|
|||
|
|
|
|||
|
|
### 小节
|
|||
|
|
|
|||
|
|
- 列表项 1
|
|||
|
|
- 列表项 2
|
|||
|
|
|
|||
|
|
| 列1 | 列2 |
|
|||
|
|
|-----|-----|
|
|||
|
|
| A | B |
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const formData = new FormData();
|
|||
|
|
formData.append('markdown_content', markdownContent);
|
|||
|
|
formData.append('filename_text', '我的Markdown文档');
|
|||
|
|
formData.append('toc', 'true');
|
|||
|
|
formData.append('header_text', 'Markdown文档');
|
|||
|
|
formData.append('footer_text', '© 2024');
|
|||
|
|
|
|||
|
|
const response = await fetch('/api/pdf/convert', {
|
|||
|
|
method: 'POST',
|
|||
|
|
body: formData
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const blob = await response.blob();
|
|||
|
|
// 保存 PDF
|
|||
|
|
saveAs(blob, 'document.pdf');
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Python 调用示例
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import requests
|
|||
|
|
|
|||
|
|
def convert_word_to_pdf(file_path, output_path):
|
|||
|
|
"""将 Word 文件转换为 PDF"""
|
|||
|
|
with open(file_path, 'rb') as f:
|
|||
|
|
files = {'file': f}
|
|||
|
|
data = {
|
|||
|
|
'toc': 'true',
|
|||
|
|
'header_text': '我的文档',
|
|||
|
|
'footer_text': '© 2024',
|
|||
|
|
'filename_text': '文档名称'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response = requests.post(
|
|||
|
|
'http://localhost:8000/api/pdf/convert',
|
|||
|
|
files=files,
|
|||
|
|
data=data
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
with open(output_path, 'wb') as out:
|
|||
|
|
out.write(response.content)
|
|||
|
|
print(f"PDF 已保存到: {output_path}")
|
|||
|
|
else:
|
|||
|
|
print(f"转换失败: {response.text}")
|
|||
|
|
|
|||
|
|
# 使用示例
|
|||
|
|
convert_word_to_pdf('document.docx', 'output.pdf')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## cURL 示例
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 上传 Word 文件转 PDF
|
|||
|
|
curl -X POST http://localhost:8000/api/pdf/convert \
|
|||
|
|
-F "file=@document.docx" \
|
|||
|
|
-F "toc=true" \
|
|||
|
|
-F "header_text=我的文档" \
|
|||
|
|
-F "footer_text=© 2024" \
|
|||
|
|
-o output.pdf
|
|||
|
|
|
|||
|
|
# Markdown 内容转 PDF
|
|||
|
|
curl -X POST http://localhost:8000/api/pdf/convert \
|
|||
|
|
-F "markdown_content=# 标题\n\n这是内容" \
|
|||
|
|
-F "filename_text=文档" \
|
|||
|
|
-o output.pdf
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 错误处理
|
|||
|
|
|
|||
|
|
API 返回的错误格式:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"detail": "错误信息"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
常见错误:
|
|||
|
|
|
|||
|
|
| 错误信息 | 原因 | 解决方法 |
|
|||
|
|
|---------|------|----------|
|
|||
|
|
| 必须提供 file、file_path 或 markdown_content 中的一个 | 未提供输入 | 检查请求参数 |
|
|||
|
|
| 不支持的文件格式 | 文件格式错误 | 确保是 .doc/.docx/.md |
|
|||
|
|
| 文件不存在 | 本地文件路径无效 | 检查 file_path 参数 |
|
|||
|
|
| PDF 转换失败 | 转换过程出错 | 查看服务器日志 |
|
|||
|
|
|
|||
|
|
## 返回格式
|
|||
|
|
|
|||
|
|
### download=true (默认)
|
|||
|
|
|
|||
|
|
直接返回 PDF 文件流:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Content-Type: application/pdf
|
|||
|
|
Content-Disposition: attachment; filename="document.pdf"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### download=false
|
|||
|
|
|
|||
|
|
返回 JSON,包含 base64 编码的 PDF:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"ok": true,
|
|||
|
|
"pdf_base64": "JVBERi0xLjQK...",
|
|||
|
|
"filename": "document.pdf",
|
|||
|
|
"size": 12345
|
|||
|
|
}
|
|||
|
|
```
|