From a10969b562972dcb99c7be8fbb45675804e33ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=BF=9B?= Date: Mon, 27 Jul 2026 12:20:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20jszip=20=E5=90=8E=E5=A4=84=E7=90=86?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=20type=3Dcustom=20+=20=E7=94=BB=E5=B8=83?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=E9=99=90=E5=88=B6140cm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 用 jszip 原地修改 PPTX 的 sldSz,加 type=custom(WPS 识别自定义尺寸) - 画布最大高度限制 140cm(WPS 上限) - zip 命令行打包会破坏 PPTX 结构,改用 jszip 保证完整性 --- convert-w2p.js | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/convert-w2p.js b/convert-w2p.js index daa4bb8..57a998c 100644 --- a/convert-w2p.js +++ b/convert-w2p.js @@ -932,16 +932,18 @@ async function convert(input) { // 第三步:组装最终 Schema // ---------------------------------------------------------- // 画布尺寸:多 slide(PPT设计稿)用容器尺寸,单 slide(网页)用 canvas + // 限制最大高度 140cm(WPS 上限约140cm) + const MAX_H_IN = 55.12; // 140cm let layout = 'LAYOUT_16x9'; var sizeSource; if (slideGroups.length > 1) { sizeSource = slideGroups[0].slideRect; } else { - sizeSource = { w: canvas.width || 1920, h: canvas.height || 1080 }; + sizeSource = { w: canvas.width || 1920, h: Math.min(canvas.height || 1080, MAX_H_IN * 72) }; } if (sizeSource.w && sizeSource.h) { const sw = sizeSource.w / 72; - const sh = sizeSource.h / 72; + const sh = Math.min(sizeSource.h / 72, MAX_H_IN); layout = 'CUSTOM'; return { presentation: { layout: 'CUSTOM', slideWidth: sw, slideHeight: sh }, @@ -1046,7 +1048,30 @@ if (require.main === module) { const pptxPath = inputPath.replace(/\.json$/, '.pptx'); pres.writeFile({ fileName: pptxPath }).then(() => { - console.log('✅ PPTX: ' + pptxPath); + // 后处理:给 sldSz 加 type="custom",确保 WPS 等应用识别自定义尺寸 + try { + const JSZip = require('jszip'); + const zipData = fs.readFileSync(pptxPath); + JSZip.loadAsync(zipData).then(function(zip) { + return zip.file('ppt/presentation.xml').async('string'); + }).then(function(presXml) { + if (presXml.includes('sldSz') && !presXml.includes('type="custom"')) { + var fixed = presXml.replace(/sldSz cx="([^"]*)" cy="([^"]*)"/, 'sldSz cx="$1" cy="$2" type="custom"'); + return JSZip.loadAsync(zipData).then(function(zip) { + zip.file('ppt/presentation.xml', fixed); + return zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' }); + }).then(function(buf) { + fs.writeFileSync(pptxPath, buf); + }); + } + }).then(function() { + console.log('✅ PPTX: ' + pptxPath); + }).catch(function(e) { + console.log('✅ PPTX: ' + pptxPath + ' (后处理跳过)'); + }); + } catch (e) { + console.log('✅ PPTX: ' + pptxPath + ' (后处理跳过)'); + } }).catch(e => console.error('❌ PPTX 渲染失败:', e.message)); fs.writeFileSync(outputPath, JSON.stringify(result, null, 2), 'utf8');