diff --git a/convert-w2p.js b/convert-w2p.js index 233b55f..d2ce2f6 100644 --- a/convert-w2p.js +++ b/convert-w2p.js @@ -571,13 +571,62 @@ function convert(input) { // 移除已合并的原始节点 sg.children = sg.children.filter(n => !merged.has(n.id)); + // ===== z-index 排序:同父容器的兄弟节点按 zIndex 排序 ===== + sg.children.sort(function(a, b) { + const za = parseInt(a.styles?.zIndex) || 0; + const zb = parseInt(b.styles?.zIndex) || 0; + return za - zb; + }); + + // ===== 同坐标完全重叠去重:保留后者(高层) ===== + var seen = {}; + var overlapRemove = new Set(); + for (var i = sg.children.length - 1; i >= 0; i--) { + var ci = sg.children[i]; + if (!ci.rect) continue; + var key = Math.round(ci.rect.x) + ',' + Math.round(ci.rect.y) + ',' + Math.round(ci.rect.w) + ',' + Math.round(ci.rect.h); + if (seen[key]) { + overlapRemove.add(ci.id); // 后出现的(更高层)保留,前面的移除 + } else { + seen[key] = true; + } + } + if (overlapRemove.size > 0) { + sg.children = sg.children.filter(n => !overlapRemove.has(n.id)); + } + + // ===== overflow:hidden 裁剪:子元素超出父容器 clipped 区域的跳过 ===== + // 建立父容器 clip 区域映射 + var clipMap = {}; // id → {x, y, w, h} + function buildClipMap(node, parentClip) { + if (!node) return; + var myClip = parentClip; + if (node.clipped && node.clipRect) { + myClip = { x: node.clipRect.x, y: node.clipRect.y, w: node.clipRect.width, h: node.clipRect.height }; + } + clipMap[node.id] = myClip; + if (node.children) for (var c of node.children) buildClipMap(c, myClip); + } + // 只对 slide 容器的子树建 clip 映射 + var slideNode = slideContainers.find(s => s.name === sg.name); + if (slideNode) buildClipMap(slideNode, null); + for (const n of sg.children) { - // 跳过 raster 底图(保留 IMAGE 类型) - if (n.type === 'RECTANGLE') { continue; } + // 跳过 raster 底图(保留 IMAGE 类型和有背景图的 RECTANGLE) + if (n.type === 'RECTANGLE' && !n.backgroundImages?.length) { continue; } if (n.tag === 'BODY' || n.tag === 'HTML') { continue; } const r = n.rect; if (r == null || r.w == null || r.h == null) { continue; } + + // overflow:hidden 裁剪:节点完全在 clip 区域外时跳过 + var clip = clipMap[n.id]; + if (clip) { + var nx = r.x, ny = r.y, nr2 = r.x + r.w, nb = r.y + r.h; + if (nx > clip.x + clip.w || nr2 < clip.x || ny > clip.y + clip.h || nb < clip.y) { + continue; // 完全在 clip 区域外 + } + } const S = 1/72; const opts = { x: Math.round(r.x * S * 1000) / 1000, @@ -647,8 +696,8 @@ function convert(input) { continue; // TEXT 节点不参与后续的填充色/边框逻辑 } - // ===== 图片节点 ===== - if (n.type === 'IMAGE' && n.backgroundImages && n.backgroundImages.length > 0) { + // ===== 图片节点(IMAGE 类型或有背景图的 RECTANGLE) ===== + if ((n.type === 'IMAGE' || n.type === 'RECTANGLE') && n.backgroundImages && n.backgroundImages.length > 0) { var imgKey = n.backgroundImages[0]; var asset = ctx.assets[imgKey]; if (asset && asset.data) {