#!/usr/bin/env bash # # md-to-longimg.sh — Markdown → HTML → 长图 一键导出脚本 # # 使用方法: # bash md-to-longimg.sh input.md -o output.png # bash md-to-longimg.sh input.md # 默认输出到 input.png # bash md-to-longimg.sh input.md --width 750 # bash md-to-longimg.sh input.md --html-only # 仅生成 HTML,不截图 # bash md-to-longimg.sh input.md --serve # 启动 HTTP 服务预览 HTML # # 依赖: # - Node.js >= 18 # - Playwright 或 Puppeteer (自动检测 OpenClaw 集成的版本) # - chromium 浏览器 (截图需要,否则仅生成 HTML) # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONVERTER_DIR="$SCRIPT_DIR/md-to-longimg" CONVERTER_JS="$CONVERTER_DIR/converter.js" MARKDOWN2HTML="/root/.openclaw/agents/发布大师/workspace/scripts/md2html.py" # ====== 颜色 ====== RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } highlight() { echo -e "${CYAN}$*${NC}"; } # ====== 检查 Node.js ====== if ! command -v node &>/dev/null; then error "需要 Node.js,但未安装。请先安装 Node.js。" exit 1 fi NODE_VER=$(node -v | sed 's/v//' | cut -d. -f1) if [ "$NODE_VER" -lt 18 ]; then warn "Node.js 版本过低 ($(node -v)),建议 >= 18" fi # ====== 解析参数 ====== INPUT_FILE="" OUTPUT_FILE="" WIDTH=640 HTML_ONLY=false SERVE_MODE=false while [[ $# -gt 0 ]]; do case "$1" in -o) shift; OUTPUT_FILE="$1" ;; --width) shift; WIDTH="$1" ;; --html-only) HTML_ONLY=true ;; --serve) SERVE_MODE=true ;; -h|--help) echo "用法: $0 [-o output.png] [--width 640] [--html-only] [--serve]" echo "" echo "选项:" echo " -o 输出文件路径 (默认: input.png)" echo " --width 图片宽度 (默认: 640)" echo " --html-only 仅生成 HTML,不截图" echo " --serve 启动 HTTP 服务预览生成的 HTML" exit 0 ;; -*) error "未知参数: $1" echo "用法: $0 [-o output.png] [--width 640] [--html-only] [--serve]" exit 1 ;; *) [ -z "$INPUT_FILE" ] && INPUT_FILE="$1" || { error "只能指定一个输入文件"; exit 1; } ;; esac shift done [ -z "$INPUT_FILE" ] && { error "请指定输入 Markdown 文件"; exit 1; } [ ! -f "$INPUT_FILE" ] && { error "文件不存在: $INPUT_FILE"; exit 1; } INPUT_FILE="$(realpath "$INPUT_FILE")" INPUT_DIR="$(dirname "$INPUT_FILE")" INPUT_BASENAME="$(basename "$INPUT_FILE")" INPUT_NAME="${INPUT_BASENAME%.*}" if [ -z "$OUTPUT_FILE" ]; then OUTPUT_FILE="${INPUT_DIR}/${INPUT_NAME}.png" fi # ====== 确保输出目录 ====== mkdir -p "$(dirname "$OUTPUT_FILE")" # ====== 安装 Node 依赖 ====== info "检查依赖..." mkdir -p "$CONVERTER_DIR" cd "$CONVERTER_DIR" # package.json if [ ! -f package.json ]; then echo '{"name":"md-to-longimg","private":true}' > package.json fi # 安装 markdown-it (用于 MD→HTML) if [ ! -d "node_modules/markdown-it" ]; then info "安装 markdown-it..." npm install --no-save --no-package-lock markdown-it 2>&1 | tail -2 || true fi # 复制关键依赖 if [ -d node_modules/markdown-it ]; then info "markdown-it 就绪" else warn "markdown-it 安装失败,尝试用 Python md2html.py 替代" fi # ====== 第1步:MD → HTML ====== info "第1步: 转换 Markdown → HTML..." REDIRECT_NOJS="" # 生成 HTML 到 tmp 文件 TEMP_HTML=$(mktemp /tmp/md-longimg-XXXXXX.html) # 优先用 converter.js 生成 HTML(含样式),否则用 md2html.py if node "$CONVERTER_JS" --generate-html-only "$INPUT_FILE" -o "$TEMP_HTML" --width "$WIDTH" 2>/dev/null; then info "✓ 使用 converter.js 生成 HTML 成功" elif [ -f "$MARKDOWN2HTML" ]; then info "使用 md2html.py 生成 HTML..." python3 "$MARKDOWN2HTML" "$INPUT_FILE" -o "$TEMP_HTML" info "✓ 使用 md2html.py 生成 HTML 成功" else # 最简 fallback info "使用内置 fallback 生成 HTML..." cat "$INPUT_FILE" | node -e " const fs = require('fs'); let md = fs.readFileSync('/dev/stdin','utf-8'); // 简单的 markdown 转 HTML let html = md .replace(/&/g,'&').replace(//g,'>') .replace(/^### (.+)$/gm,'

\$1

') .replace(/^## (.+)$/gm,'

\$1

') .replace(/^# (.+)$/gm,'

\$1

') .replace(/\*\*(.+?)\*\*/g,'\$1') .replace(/\n\n/g,'

'); html = '

' + html + '

'; console.log(html); " > "$TEMP_HTML" info "✓ 内置 fallback 生成 HTML 完成" fi HTML_SIZE=$(stat -c%s "$TEMP_HTML" 2>/dev/null || echo 0) info " HTML 文件: $TEMP_HTML ($HTML_SIZE bytes)" # ====== 如果只是生成 HTML ====== if [ "$HTML_ONLY" = true ]; then HTML_OUT="${OUTPUT_FILE%.*}.html" cp "$TEMP_HTML" "$HTML_OUT" info "✅ 仅生成 HTML 模式" info " 输出: $HTML_OUT" rm -f "$TEMP_HTML" exit 0 fi # ====== Serve 模式 ====== if [ "$SERVE_MODE" = true ]; then info "📡 启动 HTTP 服务 → 浏览器打开查看" info " 文件: $TEMP_HTML" PORT=${PORT:-8765} node -e " const http = require('http'), fs = require('fs'); const html = fs.readFileSync('$TEMP_HTML','utf-8'); http.createServer((req,res) => { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.end(html); }).listen($PORT, () => console.log('http://localhost:$PORT')); " exit 0 fi # ====== 第2步:HTML → 截图 ====== info "第2步: HTML → 长图截图..." # 尝试使用 OpenClaw 集成的 playwright SCREENSHOT_OK=false # 方法1: 尝试用 converter.js 截图 (用 playwright) if [ "$SCREENSHOT_OK" = false ]; then if node "$CONVERTER_JS" "$INPUT_FILE" -o "$OUTPUT_FILE" --width "$WIDTH" 2>&1; then SCREENSHOT_OK=true fi fi # 方法2: 尝试用 Python + selenium (如果有) if [ "$SCREENSHOT_OK" = false ]; then if python3 -c "from selenium import webdriver" 2>/dev/null; then info "使用 Python Selenium 截图..." python3 -c " import sys sys.path.insert(0, '$CONVERTER_DIR') from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() options.add_argument('--headless') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') try: driver = webdriver.Chrome(options=options) driver.get('file://$TEMP_HTML') width = $WIDTH height = driver.execute_script('return document.body.scrollHeight') driver.set_window_size(width, height) driver.save_screenshot('$OUTPUT_FILE') driver.quit() print('Screenshot saved') except Exception as e: print(f'Selenium failed: {e}') sys.exit(1) " 2>&1 && SCREENSHOT_OK=true fi fi # ====== 结果 ====== if [ "$SCREENSHOT_OK" = true ]; then FILE_SIZE=$(stat -c%s "$OUTPUT_FILE" 2>/dev/null || echo 0) SIZE_KB=$((FILE_SIZE / 1024)) info "✅ 转换完成!" info " 图片: $OUTPUT_FILE" info " 大小: ${SIZE_KB}KB" info " 宽度: ${WIDTH}px" info " HTML 文件: $TEMP_HTML (可保留用于调试)" else HTML_OUT="${OUTPUT_FILE%.*}.html" cp "$TEMP_HTML" "$HTML_OUT" warn "⚠️ 无法截图(当前环境缺少浏览器)" warn " 已生成 HTML 文件: $HTML_OUT" warn "" highlight " 💡 下一步操作:" highlight " 1. 用浏览器打开上面的 HTML 文件" highlight " 2. 按 Ctrl+P (或 Cmd+P) 打印" highlight " 3. 选择「另存为 PDF」或使用截图工具" highlight " 4. 或用截屏工具截取全页长图" echo "" info " 或者在本机浏览器上打开链接查看效果" fi