Skip to content

Commit ab0cdac

Browse files
committed
feat(水印): 优化水印和二维码处理逻辑,仅在用户明确要求时添加
- 修改水印处理优先级:用户文字 > 用户图片 > 环境变量图片 > 默认文字 - 仅在用户明确设置 addWatermark=true 时添加水印 - 更新相关工具描述以反映新的处理逻辑 - 提升版本号至 0.2.1
1 parent 6a19cbb commit ab0cdac

File tree

2 files changed

+77
-26
lines changed

2 files changed

+77
-26
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "doc-ops-mcp",
33
"author": "Tele-AI",
4-
"version": "0.1.9",
4+
"version": "0.2.1",
55
"description": "MCP Document Converter Server — A Model Context Protocol server for seamless document format conversion and processing",
66
"main": "dist/index.cjs",
77
"license": "MIT",

src/index.ts

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -962,8 +962,8 @@ async function handleDirectConversionSuccess(result: any, hasWatermark: boolean,
962962
},
963963
};
964964

965-
// 自动添加水印
966-
if (hasWatermark && defaultResourcePaths.defaultWatermarkPath) {
965+
// 只有在用户明确要求时才添加水印
966+
if (hasWatermark) {
967967
const watermarkResult = await addWatermarkToPdf(result.outputPath);
968968
if (watermarkResult.success) {
969969
(finalResult as any).watermarkAdded = true;
@@ -972,9 +972,8 @@ async function handleDirectConversionSuccess(result: any, hasWatermark: boolean,
972972
}
973973
}
974974

975-
// 添加二维码(仅在用户明确要求时)
976-
//@ts-ignore
977-
if (hasQRCode && defaultQrCodePath) {
975+
// 只有在用户明确要求时才添加二维码
976+
if (hasQRCode) {
978977
const qrResult = await addQRCodeToPdf(result.outputPath);
979978
if (qrResult.success) {
980979
(finalResult as any).qrCodeAdded = true;
@@ -1954,7 +1953,24 @@ async function addWatermark(pdfPath: string, options: WatermarkOptions = {}) {
19541953
for (const page of pages) {
19551954
const { width, height } = page.getSize();
19561955

1957-
if (options.watermarkImage) {
1956+
// 优先级:用户文字 > 用户图片 > 环境变量图片 > 默认文字
1957+
// 如果用户明确提供了文字水印,优先使用文字水印
1958+
if (options.watermarkText) {
1959+
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
1960+
const fontSize = options.watermarkFontSize ?? 48;
1961+
const opacity = options.watermarkTextOpacity ?? 0.3;
1962+
const watermarkText = options.watermarkText;
1963+
1964+
page.drawText(watermarkText, {
1965+
x: width / 2 - (watermarkText.length * fontSize) / 4,
1966+
y: height / 2,
1967+
size: fontSize,
1968+
font,
1969+
color: rgb(0.5, 0.5, 0.5),
1970+
opacity,
1971+
rotate: { angle: Math.PI / 4, origin: { x: width / 2, y: height / 2 } },
1972+
});
1973+
} else if (options.watermarkImage && fsSync.existsSync(options.watermarkImage)) {
19581974
const imageBytes = await fs.readFile(options.watermarkImage);
19591975
const image = await pdfDoc.embedPng(imageBytes);
19601976
const scale = options.watermarkImageScale ?? 0.25;
@@ -2022,15 +2038,15 @@ async function addWatermark(pdfPath: string, options: WatermarkOptions = {}) {
20222038
height: image.height * scale,
20232039
opacity,
20242040
});
2025-
}
2026-
2027-
if (options.watermarkText) {
2041+
} else {
2042+
// 如果没有用户文字和用户图片,使用默认文字水印 'doc-ops-mcp'
20282043
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
20292044
const fontSize = options.watermarkFontSize ?? 48;
20302045
const opacity = options.watermarkTextOpacity ?? 0.3;
2046+
const watermarkText = 'doc-ops-mcp';
20312047

2032-
page.drawText(options.watermarkText, {
2033-
x: width / 2 - (options.watermarkText.length * fontSize) / 4,
2048+
page.drawText(watermarkText, {
2049+
x: width / 2 - (watermarkText.length * fontSize) / 4,
20342050
y: height / 2,
20352051
size: fontSize,
20362052
font,
@@ -2183,12 +2199,16 @@ function resolvePostProcessingPath(playwrightPdfPath: string, targetPath?: strin
21832199
}
21842200

21852201
async function processWatermarkAddition(finalPath: string, options: any): Promise<any> {
2186-
if (!(options.addWatermark || process.env.WATERMARK_IMAGE)) {
2202+
// 只有在用户明确要求添加水印时才处理
2203+
if (!options.addWatermark) {
21872204
return null;
21882205
}
21892206

2207+
// 优先级:用户明确提供的参数 > 环境变量 > 默认值
21902208
const watermarkOptions = {
2191-
watermarkImage: options.watermarkImage ?? process.env.WATERMARK_IMAGE,
2209+
// 用户明确提供的图片地址具有最高优先级
2210+
watermarkImage: options.watermarkImage || process.env.WATERMARK_IMAGE,
2211+
// 用户明确提供的文字具有最高优先级
21922212
watermarkText: options.watermarkText,
21932213
watermarkImageScale: options.watermarkImageScale ?? 0.25,
21942214
watermarkImageOpacity: options.watermarkImageOpacity ?? 0.6,
@@ -2205,7 +2225,8 @@ async function processWatermarkAddition(finalPath: string, options: any): Promis
22052225
}
22062226

22072227
async function processQRCodeAddition(finalPath: string, options: any): Promise<any> {
2208-
if (!(options.addQrCode || (options.addQrCode !== false && process.env.QR_CODE_IMAGE))) {
2228+
// 只有在用户明确要求添加二维码时才处理
2229+
if (!options.addQrCode) {
22092230
return null;
22102231
}
22112232

@@ -2220,11 +2241,13 @@ async function processQRCodeAddition(finalPath: string, options: any): Promise<a
22202241
};
22212242

22222243
try {
2244+
// 优先级:用户明确提供的二维码图片地址 > 环境变量
2245+
// 二维码只能是图片地址,不支持文字
22232246
const qrCodePath = options.qrCodePath || process.env.QR_CODE_IMAGE;
22242247
if (qrCodePath) {
22252248
return await addQRCode(finalPath, qrCodePath, qrOptions);
22262249
} else {
2227-
return { success: false, error: 'QR code path not provided' };
2250+
return { success: false, error: 'QR code image path not provided. QR code requires an image file.' };
22282251
}
22292252
} catch (error: any) {
22302253
return { success: false, error: error.message };
@@ -2306,11 +2329,19 @@ function createMarkdownPostProcessingSteps(options: any): string[] {
23062329
const postProcessingSteps: string[] = [];
23072330
const defaultWatermarkPath = process.env.WATERMARK_IMAGE ?? null;
23082331
const defaultQrCodePath = process.env.QR_CODE_IMAGE ?? null;
2332+
const addWatermark = options.addWatermark ?? false;
23092333
const addQrCode = options.addQrCode ?? false;
23102334

2311-
if (defaultWatermarkPath) {
2312-
postProcessingSteps.push(`添加水印: ${defaultWatermarkPath}`);
2335+
// 只有在用户明确要求时才添加水印
2336+
if (addWatermark) {
2337+
const watermarkPath = options.watermarkImage || defaultWatermarkPath;
2338+
if (watermarkPath) {
2339+
postProcessingSteps.push(`添加水印: ${watermarkPath}`);
2340+
} else {
2341+
postProcessingSteps.push(`添加水印: 默认文字 'doc-ops-mcp'`);
2342+
}
23132343
}
2344+
// 只有在用户明确要求时才添加二维码
23142345
if (addQrCode && defaultQrCodePath) {
23152346
postProcessingSteps.push(`添加二维码: ${defaultQrCodePath}`);
23162347
}
@@ -2342,6 +2373,7 @@ async function convertMarkdownToPdf(inputPath: string, outputPath?: string, opti
23422373
// 获取水印和二维码配置
23432374
const defaultWatermarkPath = process.env.WATERMARK_IMAGE ?? null;
23442375
const defaultQrCodePath = process.env.QR_CODE_IMAGE ?? null;
2376+
const addWatermark = options.addWatermark ?? false;
23452377
const addQrCode = options.addQrCode ?? false;
23462378

23472379
// 构建 playwright 命令,包含水印和二维码处理
@@ -2356,7 +2388,7 @@ async function convertMarkdownToPdf(inputPath: string, outputPath?: string, opti
23562388
finalPdfPath: finalOutputPath,
23572389
requiresPlaywrightMcp: true,
23582390
message: 'Markdown 已转换为 HTML,需要使用 playwright-mcp 完成 PDF 转换',
2359-
watermarkPath: defaultWatermarkPath,
2391+
watermarkPath: addWatermark ? (options.watermarkImage || defaultWatermarkPath) : null,
23602392
qrCodePath: addQrCode ? defaultQrCodePath : null,
23612393
instructions: {
23622394
step1: '已完成:Markdown → HTML',
@@ -2681,13 +2713,13 @@ const TOOL_DEFINITIONS = {
26812713

26822714
add_watermark: {
26832715
name: 'add_watermark',
2684-
description: 'Add watermarks (image or text) to PDF documents',
2716+
description: 'Add watermarks to PDF documents. Supports both text and image watermarks. Priority: user text > user image > environment variable image > default text "doc-ops-mcp"',
26852717
inputSchema: {
26862718
type: 'object',
26872719
properties: {
26882720
pdfPath: { type: 'string', description: 'PDF file path' },
2689-
watermarkImage: { type: 'string', description: 'Watermark image path (PNG/JPG)' },
2690-
watermarkText: { type: 'string', description: 'Watermark text (ASCII only)' },
2721+
watermarkImage: { type: 'string', description: 'Watermark image path (PNG/JPG). Has higher priority than environment variable but lower than watermarkText.' },
2722+
watermarkText: { type: 'string', description: 'Watermark text content. Has highest priority. If not provided, will use image or default text "doc-ops-mcp".' },
26912723
watermarkImageScale: { type: 'number', description: 'Image scale ratio', default: 0.25 },
26922724
watermarkImageOpacity: { type: 'number', description: 'Image opacity', default: 0.6 },
26932725
watermarkImagePosition: {
@@ -2702,12 +2734,12 @@ const TOOL_DEFINITIONS = {
27022734

27032735
add_qrcode: {
27042736
name: 'add_qrcode',
2705-
description: 'Add QR code to PDF documents with friendly text below',
2737+
description: 'Add QR code to PDF documents with friendly text below. QR code must be an image file (PNG/JPG). Priority: user provided path > environment variable QR_CODE_IMAGE',
27062738
inputSchema: {
27072739
type: 'object',
27082740
properties: {
27092741
pdfPath: { type: 'string', description: 'PDF file path' },
2710-
qrCodePath: { type: 'string', description: 'QR code image path (optional, uses default)' },
2742+
qrCodePath: { type: 'string', description: 'QR code image path (PNG/JPG). Has highest priority. If not provided, uses QR_CODE_IMAGE environment variable.' },
27112743
qrScale: { type: 'number', description: 'QR code scale ratio', default: 0.15 },
27122744
qrOpacity: { type: 'number', description: 'QR code opacity', default: 1.0 },
27132745
qrPosition: {
@@ -2736,7 +2768,7 @@ const TOOL_DEFINITIONS = {
27362768
convert_docx_to_pdf: {
27372769
name: 'convert_docx_to_pdf',
27382770
description:
2739-
'Enhanced DOCX to PDF conversion with perfect Word style replication and Playwright integration. Automatically adds watermark if WATERMARK_IMAGE environment variable is set. QR code can be added by setting addQrCode=true (requires QR_CODE_IMAGE environment variable). Output directory is controlled by OUTPUT_DIR environment variable. Files will be automatically saved to OUTPUT_DIR with auto-generated names.',
2771+
'Enhanced DOCX to PDF conversion with perfect Word style replication and Playwright integration. Watermark can be added by setting addWatermark=true (uses WATERMARK_IMAGE environment variable or default text "doc-ops-mcp"). QR code can be added by setting addQrCode=true (requires QR_CODE_IMAGE environment variable). Output directory is controlled by OUTPUT_DIR environment variable. Files will be automatically saved to OUTPUT_DIR with auto-generated names.',
27402772
inputSchema: {
27412773
type: 'object',
27422774
properties: {
@@ -2751,6 +2783,11 @@ const TOOL_DEFINITIONS = {
27512783
description: 'Chinese font family to use',
27522784
default: 'Microsoft YaHei',
27532785
},
2786+
addWatermark: {
2787+
type: 'boolean',
2788+
description: 'Add watermark to PDF (uses WATERMARK_IMAGE environment variable or default text "doc-ops-mcp")',
2789+
default: false,
2790+
},
27542791
addQrCode: {
27552792
type: 'boolean',
27562793
description: 'Add QR code to PDF (requires QR_CODE_IMAGE environment variable)',
@@ -2818,7 +2855,7 @@ const TOOL_DEFINITIONS = {
28182855
convert_markdown_to_pdf: {
28192856
name: 'convert_markdown_to_pdf',
28202857
description:
2821-
'Enhanced Markdown to PDF conversion with beautiful styling and theme support. Automatically adds watermark if WATERMARK_IMAGE environment variable is set. QR code can be added by setting addQrCode=true (requires QR_CODE_IMAGE environment variable). Requires playwright-mcp for final PDF generation. Output directory is controlled by OUTPUT_DIR environment variable. Files will be automatically saved to OUTPUT_DIR with auto-generated names.',
2858+
'Enhanced Markdown to PDF conversion with beautiful styling and theme support. Watermark can be added by setting addWatermark=true (uses WATERMARK_IMAGE environment variable or default text "doc-ops-mcp"). QR code can be added by setting addQrCode=true (requires QR_CODE_IMAGE environment variable). Requires playwright-mcp for final PDF generation. Output directory is controlled by OUTPUT_DIR environment variable. Files will be automatically saved to OUTPUT_DIR with auto-generated names.',
28222859
inputSchema: {
28232860
type: 'object',
28242861
properties: {
@@ -2834,6 +2871,11 @@ const TOOL_DEFINITIONS = {
28342871
description: 'Generate table of contents',
28352872
default: false,
28362873
},
2874+
addWatermark: {
2875+
type: 'boolean',
2876+
description: 'Add watermark to PDF (uses WATERMARK_IMAGE environment variable or default text "doc-ops-mcp")',
2877+
default: false,
2878+
},
28372879
addQrCode: {
28382880
type: 'boolean',
28392881
description: 'Add QR code to PDF (requires QR_CODE_IMAGE environment variable)',
@@ -3059,6 +3101,15 @@ async function handleToolCall(name: string, args: any) {
30593101

30603102

30613103

3104+
// 水印和二维码操作
3105+
if (name === 'add_watermark') {
3106+
return await addWatermark(args.pdfPath, args);
3107+
}
3108+
3109+
if (name === 'add_qrcode') {
3110+
return await addQRCode(args.pdfPath, args.qrCodePath, args);
3111+
}
3112+
30623113
// 转换规划操作
30633114
if (name === 'plan_conversion') {
30643115
return await handleConversionPlanning(args);

0 commit comments

Comments
 (0)