diff --git a/convert-w2p.js b/convert-w2p.js index bf3261f..09b1354 100644 --- a/convert-w2p.js +++ b/convert-w2p.js @@ -524,6 +524,9 @@ function convert(input) { // text 节点 if (n.type === 'TEXT' && n.src) { + // 跳过不可见节点 + if (n.styles.display === 'none' || n.styles.visibility === 'hidden') { continue; } + const st = n.styles; const fs = parseFloat(st.fontSize) || 14; var pt = Math.round(fs); @@ -533,6 +536,28 @@ function convert(input) { if (parseInt(st.fontWeight) >= 700) opts.bold = true; if (st.fontStyle === 'italic') opts.italic = true; if (st.textAlign && st.textAlign !== 'start') opts.align = st.textAlign; + // 文字装饰 + if (st.textDecorationLine) { + if (st.textDecorationLine.includes('underline')) opts.underline = true; + if (st.textDecorationLine.includes('line-through')) opts.strike = 'sngStrike'; + } + // 字符间距 + if (st.letterSpacing && st.letterSpacing !== 'normal') { + var ls = parseFloat(st.letterSpacing); + if (!isNaN(ls) && ls !== 0) opts.charSpacing = Math.round(ls * 100 / fs); // 转为百分比 + } + // 透明度 + if (st.opacity !== undefined && st.opacity !== '' && parseFloat(st.opacity) < 1) { + opts.transparency = Math.round((1 - parseFloat(st.opacity)) * 100); + } + // 行高 + if (st.lineHeight && st.lineHeight !== 'normal') { + var lh = parseFloat(st.lineHeight); + if (!isNaN(lh) && lh > 0) { + var lhRatio = lh / fs; + if (lhRatio > 0.5 && lhRatio < 5) opts.lineSpacingMultiple = Math.round(lhRatio * 100) / 100; + } + } // 宽度:顶层元素用 contentW,嵌套元素用 parentW,加最小宽度保障 var textW = n.parentW || r.w; @@ -571,6 +596,9 @@ function convert(input) { } // ===== 提取填充色 ===== + // 跳过不可见节点 + if (n.styles.display === 'none' || n.styles.visibility === 'hidden') { continue; } + let fillColor = null; const bg = n.styles.backgroundColor; if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') { @@ -585,6 +613,10 @@ function convert(input) { } if (fillColor) { var shapeOpts = { x: opts.x, y: opts.y, w: opts.w, h: opts.h, fill: { color: fillColor } }; + // 透明度 + if (n.styles.opacity !== undefined && n.styles.opacity !== '' && parseFloat(n.styles.opacity) < 1) { + shapeOpts.transparency = Math.round((1 - parseFloat(n.styles.opacity)) * 100); + } // 圆角 var brVal = n.styles.borderTopLeftRadius; @@ -764,14 +796,20 @@ if (require.main === module) { for (const obj of (slideData.objects || [])) { const o = obj.options || {}; if (obj.type === 'text') { - slide.addText(obj.text || '', { + const textOpts = { x: o.x, y: o.y, w: o.w, h: o.h, fontSize: o.fontSize || 12, fontFace: o.fontFace || 'Arial', color: o.color || '000000', bold: o.bold || false, align: o.align || 'left' - }); + }; + if (o.underline) textOpts.underline = o.underline; + if (o.strike) textOpts.strike = o.strike; + if (o.charSpacing) textOpts.charSpacing = o.charSpacing; + if (o.transparency !== undefined) textOpts.transparency = o.transparency; + if (o.lineSpacingMultiple) textOpts.lineSpacingMultiple = o.lineSpacingMultiple; + slide.addText(obj.text || '', textOpts); } else if (obj.type === 'shape') { const st = { rect: 'rect', roundRect: 'roundRect', ellipse: 'ellipse' }[obj.shapeName] || 'rect'; const shapeOpts = { @@ -782,6 +820,7 @@ if (require.main === module) { else shapeOpts.line = { type: 'none' }; // 去掉 pptxgenjs 默认边框 if (o.shadow) shapeOpts.shadow = o.shadow; if (o.rectRadius) shapeOpts.rectRadius = o.rectRadius; + if (o.transparency !== undefined) shapeOpts.transparency = o.transparency; slide.addShape(pres.ShapeType[st] || pres.ShapeType.rect, shapeOpts); } else if (obj.type === 'image') { slide.addImage({