"Generates a professional resume HTML, exports to PDF, and renders page-by-page PNG images. Invoke when user asks to create/make a resume, or wants HTML-to-PDF-to-image pipeline."
Resources
3Install
npx skillscat add meetmx-ai/resume-maker Install via the SkillsCat registry.
Resume Maker
This skill automates the full pipeline: content structuring → HTML generation → PDF export → page-by-page image rendering. It produces a single-page A4 resume in Chinese, optimized for print and screen.
Works with any AI coding assistant or IDE — no tool-specific dependencies.
Pipeline Overview
用户素材 → Step 1: 内容结构化 → Step 2: 生成 HTML → Step 3: 导出 PDF → Step 4: 逐页截图Step 1: 收集素材 & 内容结构化
Ask the user for the following information. If they don't provide everything, generate realistic placeholder data and mark it clearly.
| 类别 | 必需字段 |
|---|---|
| 基本信息 | 姓名、电话、邮箱、求职意向、城市 |
| 教育背景 | 学校、专业、学历、时间 |
| 工作经历 | 公司、岗位、时间、3-4 条工作内容(量化成果优先) |
| 项目经验 | 2-3 个:项目名、角色、技术栈、成果数据 |
| 技能清单 | 分类列出:编程语言、框架工具、工程化、语言能力 |
内容优化规则
Apply these transformations to every bullet point:
- 动词升级:把"负责"、"参与"、"协助"替换为"主导"、"独立完成"、"推动落地"
- 数据量化:每条工作内容必须有数字(百分比、用户量、时间缩短等)
- 核心成果标签:每段经历末尾加一个
result标签,用一句话浓缩最大成果 - 一页原则:内容必须压缩到 A4 单页,必要时精简措辞而非删减经历
Step 2: 生成 HTML
Generate a complete, self-contained HTML file with the following design system.
Design Tokens
:root {
--ink: #1a1a1a;
--ink-soft: #4a4a4a;
--ink-muted: #8a8a8a;
--accent: #c45c3c;
--accent-light: rgba(196, 92, 60, 0.08);
--line: #e0dcd7;
--bg: #faf9f7;
--paper: #ffffff;
}Layout Rules
- Page:
width: 210mm; height: 297mm;withoverflow: hiddento enforce single page - Top accent bar: 3px gradient
linear-gradient(90deg, var(--accent), #d4845a, var(--accent)) - Header: flex row — name left (Noto Serif SC, 28px, letter-spacing 4px), contact info right (11.5px, muted)
- Sections: each has
.section-headwith dot + title + horizontal rule - Entries: left-border highlight on hover (2px, accent color), hidden in print
- Bullet points: use
›character in accent color, NOT standard disc/circle - Result tags: inline pill with
var(--accent-light)background,var(--accent)text - Skills: 2-column grid, tags use
#f5f3f0background - Footer: absolute positioned at bottom, centered, muted
Typography
- Name:
"Noto Serif SC", serif— 28px, weight 700 - Body:
"DM Sans", "Noto Sans SC", -apple-system, sans-serif - Section titles: 12px, letter-spacing 3px
- Entry titles: 13px, weight 600
- Body text: 11.5px, line-height 1.6
- Result tags: 10.5px, weight 600
Print Styles
@media print {
body { background: white; }
.page { width: 100%; height: auto; margin: 0; padding: 28px 36px 24px; box-shadow: none; }
.entry:hover { border-left-color: transparent; }
.footer-line { position: static; }
}Fonts Import
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&family=Noto+Serif+SC:wght@600;700&family=DM+Sans:wght@400;500;600;700&display=swap');HTML Structure Template
<div class="page">
<header class="header">
<div class="header-left">
<h1>{姓名}</h1>
<div class="title">{求职意向}</div>
</div>
<div class="header-right">
{电话} · {邮箱}<br>
{城市} · {GitHub/网站}<br>
求职意向:{岗位}
</div>
</header>
<section class="section">
<div class="section-head">
<span class="dot"></span>
<h2>教育背景</h2>
<span class="rule"></span>
</div>
<div class="entry">
<div class="entry-top">
<h3>{学校} · {专业}</h3>
<span class="meta">{时间}</span>
</div>
<div class="subtitle">{学历} · GPA · 奖学金等</div>
</div>
</section>
<section class="section">
<div class="section-head">
<span class="dot"></span>
<h2>工作经历</h2>
<span class="rule"></span>
</div>
<!-- 每段经历一个 .entry -->
<div class="entry">
<div class="entry-top">
<h3>{公司} · {岗位}</h3>
<span class="meta">{时间}</span>
</div>
<div class="subtitle">{部门} · {团队}</div>
<ul>
<li>{量化成果描述}</li>
</ul>
<span class="result">核心成果:{一句话浓缩}</span>
</div>
</section>
<section class="section">
<div class="section-head">
<span class="dot"></span>
<h2>项目经验</h2>
<span class="rule"></span>
</div>
<!-- 同工作经历结构 -->
</section>
<section class="section">
<div class="section-head">
<span class="dot"></span>
<h2>技能清单</h2>
<span class="rule"></span>
</div>
<div class="skills-grid">
<div class="skill-group">
<h4>{分类名}</h4>
<p>{技能内容或 tag 列表}</p>
</div>
</div>
</section>
<div class="footer-line">{姓名} · {岗位} · {年份}</div>
</div>Save the HTML file as {姓名}_简历.html in the user's working directory.
Step 3: 导出 PDF
Use a headless Chromium-based browser to convert HTML to PDF. Detect the available browser on the current system:
Browser Detection (priority order)
- Google Chrome:
C:\Program Files\Google\Chrome\Application\chrome.exe(Windows) //Applications/Google Chrome.app/...(macOS) /google-chrome(Linux) - Microsoft Edge:
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe(Windows) /microsoft-edge(Linux) - Chromium:
chromiumorchromium-browser(Linux)
Command
import subprocess, platform
def get_browser_cmd():
"""Detect available Chromium-based browser."""
if platform.system() == "Windows":
candidates = [
r"C:\Program Files\Google\Chrome\Application\chrome.exe",
r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
]
elif platform.system() == "Darwin":
candidates = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
]
else: # Linux
candidates = ["google-chrome", "microsoft-edge", "chromium-browser", "chromium"]
for cmd in candidates:
try:
subprocess.run([cmd, "--version"], capture_output=True, timeout=5)
return cmd
except (FileNotFoundError, subprocess.TimeoutExpired):
continue
raise RuntimeError("No Chromium-based browser found. Install Chrome or Edge.")
browser = get_browser_cmd()
subprocess.run([
browser,
"--headless", "--disable-gpu", "--no-pdf-header-footer",
f"--print-to-pdf={pdf_path}",
f"file:///{html_path.replace(os.sep, '/')}"
], capture_output=True)Save as {姓名}_简历.pdf in the same directory.
Step 4: 逐页截图
Use PyMuPDF (fitz) + Pillow to render each page as a high-res PNG with a page-number pill overlay.
Dependencies
pip install PyMuPDF PillowFont Detection
import platform
def get_font_path():
"""Detect a suitable CJK font for the page-number pill."""
system = platform.system()
if system == "Windows":
return r"C:\Windows\Fonts\msyh.ttc" # Microsoft YaHei
elif system == "Darwin":
return "/System/Library/Fonts/PingFang.ttc" # PingFang SC
else: # Linux
candidates = [
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
]
for p in candidates:
if os.path.exists(p):
return p
return None # Will fall back to default fontScript Template
import fitz
import os
import shutil
import subprocess
import platform
from PIL import Image, ImageDraw, ImageFont
def get_browser_cmd():
if platform.system() == "Windows":
candidates = [
r"C:\Program Files\Google\Chrome\Application\chrome.exe",
r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
]
elif platform.system() == "Darwin":
candidates = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
]
else:
candidates = ["google-chrome", "microsoft-edge", "chromium-browser", "chromium"]
for cmd in candidates:
try:
subprocess.run([cmd, "--version"], capture_output=True, timeout=5)
return cmd
except (FileNotFoundError, subprocess.TimeoutExpired):
continue
raise RuntimeError("No Chromium-based browser found.")
def get_font_path():
system = platform.system()
if system == "Windows":
return r"C:\Windows\Fonts\msyh.ttc"
elif system == "Darwin":
return "/System/Library/Fonts/PingFang.ttc"
else:
for p in ["/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"]:
if os.path.exists(p):
return p
return None
label = "{姓名}"
html_path = r"{html_path}"
pdf_path = r"{pdf_path}"
output_dir = r"{output_dir}"
if os.path.exists(pdf_path):
os.remove(pdf_path)
if os.path.exists(output_dir):
shutil.rmtree(output_dir)
os.makedirs(output_dir, exist_ok=True)
# Step 3: HTML → PDF
browser = get_browser_cmd()
file_url = "file:///" + html_path.replace(os.sep, "/") if platform.system() == "Windows" else "file://" + html_path
subprocess.run([
browser,
"--headless", "--disable-gpu", "--no-pdf-header-footer",
f"--print-to-pdf={pdf_path}",
file_url
], capture_output=True)
# Step 4: PDF → 逐页 PNG
doc = fitz.open(pdf_path)
total = len(doc)
digits = len(str(total))
print(f"共 {total} 页")
font_path = get_font_path()
for i, page in enumerate(doc):
img = page.get_pixmap(matrix=fitz.Matrix(4, 4))
filename = f"page_{str(i+1).zfill(digits)}.png"
filepath = os.path.join(output_dir, filename)
img.save(filepath)
# 添加页码胶囊标签
pil_img = Image.open(filepath)
w, h = pil_img.size
draw = ImageDraw.Draw(pil_img)
font_size = max(18, h // 50)
if font_path:
try:
font = ImageFont.truetype(font_path, font_size)
except:
font = ImageFont.load_default()
else:
font = ImageFont.load_default()
text = f"{label} · {i + 1}/{total}"
bbox = draw.textbbox((0, 0), text, font=font)
tw = bbox[2] - bbox[0]
th = bbox[3] - bbox[1]
pad_x = int(h * 0.02)
pad_y = int(h * 0.008)
pill_w = tw + pad_x * 2
pill_h = th + pad_y * 2
pill_x = (w - pill_w) // 2
pill_y = h - pill_h - int(h * 0.03)
draw.rounded_rectangle(
[pill_x, pill_y, pill_x + pill_w, pill_y + pill_h],
radius=pill_h // 2,
fill=(250, 248, 245),
outline=(235, 230, 222),
width=1
)
text_x = (w - tw) // 2
text_y = pill_y + pad_y
draw.text((text_x, text_y), text, fill=(180, 175, 165), font=font)
pil_img.save(filepath)
print(f" [{i+1}/{total}] {filename}")
doc.close()
print(f"完成!图片已保存到:{output_dir}")Save this script as {姓名}_简历_to_img.py and execute it.
Output Checklist
After completing all steps, verify:
-
{姓名}_简历.html— 可在浏览器中打开,单页 A4 -
{姓名}_简历.pdf— PDF 导出成功 -
{姓名}_简历_pages/page_1.png— 逐页截图,底部有页码胶囊 - 内容无 AI 编造的经历(所有数据来自用户或明确标注为模拟)
- 每段经历有"核心成果"标签
- 动词已升级(无"负责"、"参与"、"协助")
- 打印样式正常(Ctrl+P / Cmd+P 无溢出)
Style Variants
If the user specifies a different style, adjust these tokens:
| 风格 | accent | 背景色 | 适用场景 |
|---|---|---|---|
| 简洁现代(默认) | #c45c3c |
#faf9f7 |
互联网公司 |
| 经典专业 | #2c3e50 |
#f8f9fa |
外企、金融、咨询 |
| 个性创意 | #6c5ce7 |
#fefefe |
创业公司 |
| 视觉化 | #e17055 |
#fff5f0 |
设计师、产品、运营 |