@ww_nero/skills 2.2.3 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/ppt_slide.html +6 -0
- package/assets/svg_to_pptx.py +63 -0
- package/index.js +3 -7
- package/package.json +1 -1
package/assets/ppt_slide.html
CHANGED
|
@@ -52,6 +52,12 @@
|
|
|
52
52
|
<!-- Image Placeholder - circle (圆形头像占位) -->
|
|
53
53
|
<circle id="image-placeholder-circle" cx="1150" cy="120" r="50" fill="rgba(255,255,255,0.1)" stroke="#00e5ff" stroke-width="2" stroke-dasharray="8 4"/>
|
|
54
54
|
|
|
55
|
+
<!-- Icon Placeholder (图标占位符,转换时会先保存为小PNG再插入) -->
|
|
56
|
+
<g id="icon-placeholder" transform="translate(1100, 650)">
|
|
57
|
+
<rect x="0" y="0" width="24" height="24" fill="none"/>
|
|
58
|
+
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke="#00e5ff" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
59
|
+
</g>
|
|
60
|
+
|
|
55
61
|
<!-- Header Section -->
|
|
56
62
|
<g transform="translate(60, 80)">
|
|
57
63
|
<text x="0" y="0" font-family="'Segoe UI', Roboto, Helvetica, Arial, sans-serif" font-size="48" font-weight="bold" fill="#ffffff" letter-spacing="1">深度学习的崛起(1990-2017)</text>
|
package/assets/svg_to_pptx.py
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
"""
|
|
4
4
|
将HTML文件中的SVG转换为PPTX
|
|
5
|
+
|
|
6
|
+
注意事项:
|
|
7
|
+
- 对于 icon 元素(如带有 id="icon-*" 的 <g> 元素),
|
|
8
|
+
会先将其独立保存为小的 PNG 图片,然后再插入到 PPTX 中。
|
|
9
|
+
这样可以保证矢量图标在 PowerPoint 中正确显示。
|
|
5
10
|
"""
|
|
6
11
|
import os
|
|
7
12
|
import re
|
|
13
|
+
import tempfile
|
|
8
14
|
from pptx import Presentation
|
|
9
15
|
from pptx.util import Pt, Emu
|
|
10
16
|
from pptx.dml.color import RGBColor
|
|
@@ -508,6 +514,58 @@ def add_image(slide, image_path, x, y, width, height):
|
|
|
508
514
|
shape = slide.shapes.add_picture(image_path, px(x), px(y), px(width), px(height))
|
|
509
515
|
return shape
|
|
510
516
|
|
|
517
|
+
def add_icon(slide, svg_content, x, y, width, height, scale=2):
|
|
518
|
+
"""
|
|
519
|
+
添加图标(先将SVG转为PNG再插入)
|
|
520
|
+
"""
|
|
521
|
+
try:
|
|
522
|
+
from playwright.sync_api import sync_playwright
|
|
523
|
+
from PIL import Image
|
|
524
|
+
import io
|
|
525
|
+
|
|
526
|
+
# 确保 svg_content 是完整的 SVG
|
|
527
|
+
if not svg_content.strip().startswith('<svg'):
|
|
528
|
+
svg_content = f'''<svg xmlns="http://www.w3.org/2000/svg"
|
|
529
|
+
width="{int(width * scale)}" height="{int(height * scale)}"
|
|
530
|
+
viewBox="0 0 {width} {height}">
|
|
531
|
+
{svg_content}
|
|
532
|
+
</svg>'''
|
|
533
|
+
|
|
534
|
+
# 使用 Playwright 渲染 SVG 为 PNG
|
|
535
|
+
with sync_playwright() as p:
|
|
536
|
+
browser = p.chromium.launch()
|
|
537
|
+
page = browser.new_page()
|
|
538
|
+
|
|
539
|
+
html_content = f'''<!DOCTYPE html>
|
|
540
|
+
<html>
|
|
541
|
+
<head>
|
|
542
|
+
<style>
|
|
543
|
+
body {{ margin: 0; padding: 0; background: transparent; }}
|
|
544
|
+
</style>
|
|
545
|
+
</head>
|
|
546
|
+
<body>{svg_content}</body>
|
|
547
|
+
</html>'''
|
|
548
|
+
|
|
549
|
+
page.set_content(html_content)
|
|
550
|
+
page.set_viewport_size({"width": int(width * scale), "height": int(height * scale)})
|
|
551
|
+
|
|
552
|
+
# 截图为 PNG
|
|
553
|
+
png_bytes = page.screenshot(type="png", omit_background=True)
|
|
554
|
+
browser.close()
|
|
555
|
+
|
|
556
|
+
# 插入图片到幻灯片
|
|
557
|
+
buffer = io.BytesIO(png_bytes)
|
|
558
|
+
shape = slide.shapes.add_picture(buffer, px(x), px(y), px(width), px(height))
|
|
559
|
+
return shape
|
|
560
|
+
|
|
561
|
+
except ImportError:
|
|
562
|
+
print("警告: 需要安装 playwright 和 PIL 来支持 icon 转换")
|
|
563
|
+
print("请运行: pip install playwright Pillow && playwright install chromium")
|
|
564
|
+
return None
|
|
565
|
+
except Exception as e:
|
|
566
|
+
print(f"警告: icon 转换失败: {e}")
|
|
567
|
+
return None
|
|
568
|
+
|
|
511
569
|
def add_circular_image(slide, image_path, cx, cy, r):
|
|
512
570
|
"""添加圆形裁剪图片"""
|
|
513
571
|
from PIL import Image, ImageDraw
|
|
@@ -634,6 +692,11 @@ def create_slide(prs):
|
|
|
634
692
|
add_circle(slide, 1216, 696, 2, "#00e5ff", opacity=0.5)
|
|
635
693
|
add_circle(slide, 1226, 696, 2, "#00e5ff", opacity=0.5)
|
|
636
694
|
|
|
695
|
+
# Icon 元素示例:复杂的 SVG 图标先转为小 PNG 再插入
|
|
696
|
+
icon_svg = '''<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"
|
|
697
|
+
stroke="#00e5ff" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>'''
|
|
698
|
+
add_icon(slide, icon_svg, 1100, 650, 24, 24)
|
|
699
|
+
|
|
637
700
|
def main():
|
|
638
701
|
prs = Presentation()
|
|
639
702
|
prs.slide_width = px(1280)
|
package/index.js
CHANGED
|
@@ -61,6 +61,7 @@ const SNIPPETS = {
|
|
|
61
61
|
{ label: '示例 HTML(ppt_slide.html)', file: 'ppt_slide.html', language: 'html' }
|
|
62
62
|
],
|
|
63
63
|
notes: [
|
|
64
|
+
'【Icon 元素处理】对于复杂的 SVG 图标(如 <g id="icon-*"> 元素或包含 path 的小图标),应先将其独立保存为小的 PNG 图片,再插入到 PPTX 中。**不能遗漏任何图标**。',
|
|
64
65
|
'【文本颜色丢失】python-pptx 设置字体名称时会添加 a:latin/a:ea 等元素,如果颜色填充放在 rPr 末尾会被 PowerPoint 忽略。解决:用 rPr.insert(0, solidFill/gradFill) 将颜色填充插入到 rPr 开头,确保优先级最高。',
|
|
65
66
|
'【渐变文本失效】设置渐变前必须先清理 a:solidFill、a:gradFill、a:noFill 三种标签,否则会冲突。同时添加 rotWithShape="1" 和 scaled="1" 属性确保渐变方向正确。',
|
|
66
67
|
'【背景渐变被覆盖】直接操作 slide._element 时,若 p:bg 已存在需先 clear() 再重建,否则新旧元素混杂导致渲染异常。用 cSld.insert(0, bg) 确保背景节点在正确位置。',
|
|
@@ -101,12 +102,7 @@ const GUIDES = {
|
|
|
101
102
|
- **不要使用\`BeautifulSoup\`这种通用的解析元素的方式,而是逐个元素从svg代码转化为python创建元素的代码**
|
|
102
103
|
- 转换过程中,需要把图片占位元素替换成前面准备好的图片素材
|
|
103
104
|
|
|
104
|
-
4.
|
|
105
|
-
- 转换完成后,需要把svg和pptx转化为图片,然后**逐页**对图片进行对比分析
|
|
106
|
-
- 判断两者**背景、容器、线条、文字、装饰的颜色、透明度和渐变效果**是否基本一致
|
|
107
|
-
- 如果差异较大,则需要进一步调整转化脚本
|
|
108
|
-
|
|
109
|
-
5. **保留工作文件**:
|
|
105
|
+
4. **保留工作文件**:
|
|
110
106
|
- 完成后**需要保留**规划文档、html页面文件和python转化脚本,方便进一步根据反馈进行修改`
|
|
111
107
|
}
|
|
112
108
|
};
|
|
@@ -196,7 +192,7 @@ const listTools = () => ({
|
|
|
196
192
|
]
|
|
197
193
|
});
|
|
198
194
|
|
|
199
|
-
const server = new Server({ name: 'skills', version: '2.2.
|
|
195
|
+
const server = new Server({ name: 'skills', version: '2.2.5' }, { capabilities: { tools: {} } });
|
|
200
196
|
|
|
201
197
|
server.setRequestHandler(ListToolsRequestSchema, async () => listTools());
|
|
202
198
|
|