<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Pages on ゲーム開発部</title>
		<link>/pages/</link>
		<description>Recent content in Pages on ゲーム開発部</description>
		<generator>Hugo</generator>
		<language>zh-CN</language>
		
		
		
		
			<lastBuildDate>Thu, 16 Jul 2026 08:29:17 +0800</lastBuildDate>
		
			<atom:link href="/pages/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Markdown 转 PNG</title>
				<link>/pages/md2png/</link>
				<pubDate>Thu, 16 Jul 2026 08:29:17 +0800</pubDate>
				<guid>/pages/md2png/</guid>
				<description>&lt;div class=&#34;md2png-tool page-surface page-surface--sky&#34;&gt;&lt;link rel=&#34;stylesheet&#34; href=&#34;https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css&#34;&gt;&#xA;    &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js&#34;&gt;&lt;/script&gt;&#xA;    &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/markdown/markdown.min.js&#34;&gt;&lt;/script&gt;&#xA;    &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js&#34;&gt;&lt;/script&gt;&#xA;    &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;    &lt;style&gt;@scope (.md2png-tool) {&#xA;        .md2png-tool {&#xA;            --border-color: #eeeeee;&#xA;            --bg-light: #ffffff;&#xA;            --accent-black: #000000;&#xA;        }&#xA;&#xA;        * {&#xA;            box-sizing: border-box;&#xA;            margin: 0;&#xA;            padding: 0;&#xA;        }&#xA;&#xA;        .md2png-tool {&#xA;            height: 100%;&#xA;            min-height: 100vh;&#xA;            min-height: 100svh;&#xA;            font-family: -apple-system, &#34;Noto Sans SC&#34;, &#34;PingFang SC&#34;, &#34;Microsoft YaHei&#34;, sans-serif;&#xA;            background: #fcfcfc;&#xA;        }&#xA;&#xA;        /* 响应式主容器 */&#xA;        .main-wrapper {&#xA;            display: flex;&#xA;            height: 100vh;&#xA;            height: 100svh;&#xA;            flex-direction: row;&#xA;            /* 默认电脑端左右 */&#xA;        }&#xA;&#xA;        /* 编辑器区域 */&#xA;        .editor-area {&#xA;            width: 40%;&#xA;            display: flex;&#xA;            flex-direction: column;&#xA;            border-right: 1px solid var(--border-color);&#xA;            background: var(--bg-light);&#xA;            z-index: 10;&#xA;        }&#xA;&#xA;        .CodeMirror {&#xA;            flex: 1;&#xA;            font-size: 14px;&#xA;            height: auto;&#xA;        }&#xA;&#xA;        /* 预览区域 */&#xA;        .preview-area {&#xA;            width: 60%;&#xA;            background: #f0f0f0;&#xA;            overflow-y: auto;&#xA;            overflow-x: hidden;&#xA;            padding: 20px 36px;&#xA;            position: relative;&#xA;        }&#xA;&#xA;        .preview-stage {&#xA;            width: 100%;&#xA;            min-height: 100%;&#xA;            display: flex;&#xA;            justify-content: center;&#xA;            align-items: flex-start;&#xA;            padding: 10px 0 24px;&#xA;        }&#xA;&#xA;        /* 控制面板优化 */&#xA;        .control-panel {&#xA;            padding: 16px;&#xA;            background: #fff;&#xA;            border-top: 1px solid var(--border-color);&#xA;        }&#xA;&#xA;        .control-row {&#xA;            display: flex;&#xA;            align-items: center;&#xA;            margin-bottom: 12px;&#xA;            gap: 10px;&#xA;            flex-wrap: wrap;&#xA;            /* 手机端自动换行 */&#xA;        }&#xA;&#xA;        .control-row label {&#xA;            font-size: 13px;&#xA;            min-width: 60px;&#xA;            color: #666;&#xA;        }&#xA;&#xA;        .control-row input[type=&#34;range&#34;] {&#xA;            flex: 1;&#xA;            min-width: 120px;&#xA;            /* 防止手机端缩得太小 */&#xA;        }&#xA;&#xA;        .val-indicator {&#xA;            font-size: 12px;&#xA;            min-width: 45px;&#xA;            text-align: right;&#xA;            font-variant-numeric: tabular-nums;&#xA;        }&#xA;&#xA;        .action-row {&#xA;            display: flex;&#xA;            gap: 10px;&#xA;            flex-wrap: wrap;&#xA;        }&#xA;&#xA;        .action-row .btn-action,&#xA;        .action-row .btn-save {&#xA;            flex: 1;&#xA;            min-width: 110px;&#xA;            width: auto;&#xA;        }&#xA;&#xA;        .btn-action {&#xA;            padding: 12px;&#xA;            border: 1px solid var(--border-color);&#xA;            background: #fff;&#xA;            color: #111;&#xA;            border-radius: 4px;&#xA;            cursor: pointer;&#xA;            font-weight: 600;&#xA;            transition: opacity 0.2s, background-color 0.2s, color 0.2s, border-color 0.2s;&#xA;        }&#xA;&#xA;        .btn-action:hover {&#xA;            background: #f7f7f7;&#xA;        }&#xA;&#xA;        .btn-danger {&#xA;            border-color: #f0c7c7;&#xA;            color: #b42318;&#xA;            background: #fffafa;&#xA;        }&#xA;&#xA;        .btn-danger:hover {&#xA;            background: #fff1f1;&#xA;        }&#xA;&#xA;        /* 导出容器样式 */&#xA;        #export-target {&#xA;            background: white;&#xA;            padding: 40px;&#xA;            flex-shrink: 0;&#xA;            /* 极其重要：禁止收缩宽度 */&#xA;            margin: 20px auto;&#xA;            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);&#xA;            transform-origin: top center;&#xA;            will-change: transform;&#xA;            align-self: center;&#xA;        }&#xA;&#xA;        /* =========  Markdown 渲染样式 (核心修复) ========= */&#xA;        .markdown-body {&#xA;            line-height: 1.7;&#xA;            color: #1a1a1a;&#xA;            word-wrap: break-word;&#xA;        }&#xA;&#xA;        /* 标题层级 */&#xA;        .markdown-body h1,&#xA;        .markdown-body h2,&#xA;        .markdown-body h3,&#xA;        .markdown-body h4,&#xA;        .markdown-body h5,&#xA;        .markdown-body h6 {&#xA;            margin-top: 1.2em;&#xA;            margin-bottom: 0.6em;&#xA;            font-weight: 700;&#xA;            line-height: 1.4;&#xA;            color: #111;&#xA;        }&#xA;&#xA;        .markdown-body h1 {&#xA;            font-size: 2em;&#xA;            border-bottom: 2px solid #eee;&#xA;            padding-bottom: 0.3em;&#xA;        }&#xA;&#xA;        .markdown-body h2 {&#xA;            font-size: 1.6em;&#xA;            border-bottom: 1px solid #eee;&#xA;            padding-bottom: 0.25em;&#xA;        }&#xA;&#xA;        .markdown-body h3 {&#xA;            font-size: 1.35em;&#xA;        }&#xA;&#xA;        .markdown-body h4 {&#xA;            font-size: 1.15em;&#xA;        }&#xA;&#xA;        .markdown-body h5 {&#xA;            font-size: 1em;&#xA;            color: #444;&#xA;        }&#xA;&#xA;        .markdown-body h6 {&#xA;            font-size: 0.9em;&#xA;            color: #666;&#xA;        }&#xA;&#xA;        /* 段落间距 */&#xA;        .markdown-body p {&#xA;            margin-bottom: 1em;&#xA;        }&#xA;&#xA;        /* 列表缩进 (关键修复) */&#xA;        .markdown-body ul,&#xA;        .markdown-body ol {&#xA;            padding-left: 2.2em;&#xA;            margin-bottom: 1em;&#xA;        }&#xA;&#xA;        .markdown-body li {&#xA;            margin-bottom: 0.3em;&#xA;        }&#xA;&#xA;        /* 嵌套列表也要保持缩进 */&#xA;        .markdown-body ul ul,&#xA;        .markdown-body ol ol,&#xA;        .markdown-body ul ol,&#xA;        .markdown-body ol ul {&#xA;            margin-top: 0.3em;&#xA;            margin-bottom: 0.3em;&#xA;        }&#xA;&#xA;        /* 引用块 */&#xA;        .markdown-body blockquote {&#xA;            margin: 1em 0;&#xA;            padding: 0.6em 1.2em;&#xA;            border-left: 4px solid #ccc;&#xA;            background: #f9f9f9;&#xA;            color: #555;&#xA;        }&#xA;&#xA;        /* 代码块与行内代码 */&#xA;        .markdown-body code {&#xA;            background: #f5f5f5;&#xA;            padding: 0.2em 0.4em;&#xA;            border-radius: 4px;&#xA;            font-family: &#34;SFMono-Regular&#34;, &#34;Menlo&#34;, &#34;Monaco&#34;, &#34;Consolas&#34;, monospace;&#xA;            font-size: 0.9em;&#xA;            color: #c7254e;&#xA;        }&#xA;&#xA;        .markdown-body pre {&#xA;            background: #f8f8f8;&#xA;            padding: 16px;&#xA;            border-radius: 6px;&#xA;            overflow-x: auto;&#xA;            margin: 1.2em 0;&#xA;            border: 1px solid #e1e1e1;&#xA;        }&#xA;&#xA;        .markdown-body pre code {&#xA;            background: none;&#xA;            padding: 0;&#xA;            font-size: 0.9em;&#xA;            color: #333;&#xA;        }&#xA;&#xA;        /* 表格 */&#xA;        .markdown-body table {&#xA;            width: 100% !important;&#xA;            border-collapse: collapse;&#xA;            margin: 1.5em 0;&#xA;            table-layout: auto;&#xA;        }&#xA;&#xA;        .markdown-body th,&#xA;        .markdown-body td {&#xA;            border: 1px solid #ddd;&#xA;            padding: 10px 12px;&#xA;            text-align: left;&#xA;        }&#xA;&#xA;        .markdown-body th {&#xA;            background: #f5f5f5;&#xA;            font-weight: 600;&#xA;        }&#xA;&#xA;        /* 图片自适应 */&#xA;        .markdown-body img {&#xA;            max-width: 100%;&#xA;            height: auto;&#xA;            border-radius: 4px;&#xA;        }&#xA;&#xA;        /* 分割线 */&#xA;        .markdown-body hr {&#xA;            border: none;&#xA;            border-top: 2px solid #eaeaea;&#xA;            margin: 2em 0;&#xA;        }&#xA;&#xA;        /* 按钮 */&#xA;        .btn-save {&#xA;            width: 100%;&#xA;            padding: 12px;&#xA;            background: var(--accent-black);&#xA;            color: white;&#xA;            border: none;&#xA;            border-radius: 4px;&#xA;            cursor: pointer;&#xA;            font-weight: 600;&#xA;            transition: opacity 0.2s;&#xA;        }&#xA;&#xA;        .btn-save:hover {&#xA;            opacity: 0.85;&#xA;        }&#xA;&#xA;        /* --- 手机端适配 (Max-width: 768px) --- */&#xA;        @media (max-width: 768px) {&#xA;            .main-wrapper {&#xA;                flex-direction: column;&#xA;                /* 改为上下排列 */&#xA;            }&#xA;&#xA;            .editor-area {&#xA;                width: 100%;&#xA;                height: 45vh;&#xA;                height: 45svh;&#xA;                /* 编辑器占上半部分 */&#xA;                border-right: none;&#xA;                border-bottom: 1px solid var(--border-color);&#xA;            }&#xA;&#xA;            .preview-area {&#xA;                width: 100%;&#xA;                height: 55vh;&#xA;                height: 55svh;&#xA;                padding: 10px 14px;&#xA;            }&#xA;&#xA;            .preview-stage {&#xA;                padding: 0 0 16px;&#xA;            }&#xA;&#xA;            #export-target {&#xA;                margin: 10px auto;&#xA;                padding: 25px;&#xA;                /* 手机端适当减小内边距 */&#xA;            }&#xA;&#xA;            .markdown-body {&#xA;                font-size: inherit;&#xA;                /* 继承动态字体大小 */&#xA;            }&#xA;        }&#xA;    }&lt;/style&gt;&#xA;&lt;style&gt;&#xA;.md2png-tool.page-surface { max-width: 100%; padding: 0; overflow: hidden; border-color: var(--page-line); box-shadow: 3px 3px 0 rgba(212,107,145,.35); }&#xA;.md2png-tool .main-wrapper { display: grid; grid-template-columns: minmax(280px, 38%) minmax(0, 1fr); height: clamp(560px, 72svh, 780px); min-height: 0; max-width: 100%; overflow: hidden; background: var(--page-paper); }&#xA;.md2png-tool .editor-area { width: auto; min-width: 0; border-right: 2px solid var(--page-line); background: #fffdf5; }&#xA;.md2png-tool .CodeMirror { min-width: 0; color: var(--page-ink); background: #fff; }&#xA;.md2png-tool .control-panel { padding: 12px; background: var(--page-accent-soft); border-top: 2px solid var(--page-line); }&#xA;.md2png-tool .control-row { display: grid; grid-template-columns: 64px minmax(0, 1fr) 52px; gap: 8px; margin-bottom: 8px; }&#xA;.md2png-tool .control-row label { min-width: 0; color: var(--page-accent); font-weight: 700; }&#xA;.md2png-tool .control-row input[type=&#34;range&#34;] { min-width: 0; width: 100%; accent-color: var(--page-pink); }&#xA;.md2png-tool .val-indicator { min-width: 0; color: var(--page-pink); font-weight: 700; }&#xA;.md2png-tool .action-row { gap: 6px; }&#xA;.md2png-tool .action-row .btn-action, .md2png-tool .action-row .btn-save { min-width: 0; padding: 9px 6px; font-size: 12px; border-radius: 2px; }&#xA;.md2png-tool .preview-area { width: auto; min-width: 0; padding: 14px; overflow: auto; background-color: var(--page-sky); background-image: radial-gradient(circle at 4px 4px, rgba(42,138,120,.16) 0 1px, transparent 1.5px), radial-gradient(circle at 12px 12px, rgba(212,107,145,.14) 0 1px, transparent 1.5px); background-size: 16px 16px; }&#xA;.md2png-tool .preview-stage { width: 100%; min-width: 0; min-height: 100%; overflow: hidden; padding: 4px 0 22px; }&#xA;.md2png-tool #export-target { max-width: none; margin: 12px auto; border: 1px solid var(--page-line); box-shadow: 3px 3px 0 rgba(31,106,90,.14); }&#xA;@media (max-width: 768px) { .md2png-tool .main-wrapper { grid-template-columns: 1fr; grid-template-rows: minmax(330px, 46%) minmax(0, 1fr); height: clamp(680px, 84svh, 900px); } .md2png-tool .editor-area { border-right: 0; border-bottom: 2px solid var(--page-line); } .md2png-tool .preview-area { padding: 10px; } }&#xA;&lt;/style&gt;&#xA;&#xA;    &lt;div class=&#34;main-wrapper&#34;&gt;&#xA;        &lt;div class=&#34;editor-area&#34;&gt;&#xA;            &lt;textarea id=&#34;md-editor&#34;&gt;&#xA;# 极简 Markdown 转图&#xA;&#xA;## 功能亮点&#xA;- ✅ 标题层级完整 **(H1-H6)**&#xA;- ✅ 列表缩进清晰** (有序/无序)**&#xA;- ✅ 表格自适应宽度**（不会超出图片的宽度）**&#xA;- ✅ 加粗块内可以紧跟符号**(“\*\*\(\)\*\*”可以被识别为加粗)**&#xA;### 使用步骤&#xA;1. 在左侧编辑 Markdown&#xA;2. 调整字体大小与图片宽度&#xA;3. 点击 **保存图片** 下载 PNG&#xA;&gt; 提示：导出的图片将包含所有样式，适合直接分享。&#xA;| 规格 | 适配情况 |&#xA;| :--- | :--- |&#xA;| PC端 | 左右分割布局 |&#xA;| 移动端 | 上下堆叠布局 |&#xA;| 表格 | 始终撑满且不溢出 |&#xA;&#xA;`行内代码` 与代码块示例：&#xA;```python&#xA;print(&#34;Kirari.fun&#34;)&#xA;```&#xA;&#xA;&lt;/textarea&gt;&#xA;&#xA;            &lt;div class=&#34;control-panel&#34;&gt;&#xA;                &lt;div class=&#34;control-row&#34;&gt;&#xA;                    &lt;label&gt;工作区高度&lt;/label&gt;&#xA;                    &lt;input type=&#34;range&#34; id=&#34;range-workspace-height&#34; min=&#34;440&#34; max=&#34;1100&#34; value=&#34;680&#34; step=&#34;10&#34;&gt;&#xA;                    &lt;span class=&#34;val-indicator&#34; id=&#34;val-workspace-height&#34;&gt;680px&lt;/span&gt;&#xA;                &lt;/div&gt;&#xA;                &lt;div class=&#34;control-row&#34;&gt;&#xA;                    &lt;label&gt;字体大小&lt;/label&gt;&#xA;                    &lt;input type=&#34;range&#34; id=&#34;range-fs&#34; min=&#34;13&#34; max=&#34;28&#34; value=&#34;17&#34;&gt;&#xA;                    &lt;span class=&#34;val-indicator&#34; id=&#34;val-fs&#34;&gt;17px&lt;/span&gt;&#xA;                &lt;/div&gt;&#xA;                &lt;div class=&#34;control-row&#34;&gt;&#xA;                    &lt;label&gt;图片宽度&lt;/label&gt;&#xA;                    &lt;input type=&#34;range&#34; id=&#34;range-width&#34; min=&#34;400&#34; max=&#34;1400&#34; value=&#34;900&#34; step=&#34;10&#34;&gt;&#xA;                    &lt;span class=&#34;val-indicator&#34; id=&#34;val-width&#34;&gt;900px&lt;/span&gt;&#xA;                &lt;/div&gt;&#xA;                &lt;div class=&#34;control-row&#34;&gt;&#xA;                    &lt;label&gt;阴影强度&lt;/label&gt;&#xA;                    &lt;input type=&#34;range&#34; id=&#34;range-shadow&#34; min=&#34;0&#34; max=&#34;4&#34; value=&#34;2&#34; step=&#34;1&#34;&gt;&#xA;                    &lt;span class=&#34;val-indicator&#34; id=&#34;val-shadow&#34;&gt;2档&lt;/span&gt;&#xA;                &lt;/div&gt;&#xA;                &lt;div class=&#34;action-row&#34;&gt;&#xA;                    &lt;button type=&#34;button&#34; class=&#34;btn-action btn-danger&#34; onclick=&#34;clearEditor()&#34;&gt;清空&lt;/button&gt;&#xA;                    &lt;button type=&#34;button&#34; class=&#34;btn-action&#34; onclick=&#34;pasteFromClipboard()&#34;&gt;一键粘贴&lt;/button&gt;&#xA;                    &lt;button type=&#34;button&#34; class=&#34;btn-save&#34; onclick=&#34;saveToImage()&#34;&gt;💾 保存图片 (PNG)&lt;/button&gt;&#xA;                &lt;/div&gt;&#xA;            &lt;/div&gt;&#xA;        &lt;/div&gt;&#xA;&#xA;        &lt;div class=&#34;preview-area&#34;&gt;&#xA;            &lt;div class=&#34;preview-stage&#34;&gt;&#xA;                &lt;div id=&#34;export-target&#34;&gt;&#xA;                    &lt;div id=&#34;html-render&#34; class=&#34;markdown-body&#34;&gt;&lt;/div&gt;&#xA;                &lt;/div&gt;&#xA;            &lt;/div&gt;&#xA;        &lt;/div&gt;&#xA;    &lt;/div&gt;&#xA;&#xA;    &lt;script&gt;&#xA;        (function() {&#xA;            // 获取DOM元素&#xA;            const editorTextarea = document.getElementById(&#39;md-editor&#39;);&#xA;            const renderEl = document.getElementById(&#39;html-render&#39;);&#xA;            const targetEl = document.getElementById(&#39;export-target&#39;);&#xA;            const previewArea = document.querySelector(&#39;.preview-area&#39;);&#xA;            const previewStage = document.querySelector(&#39;.preview-stage&#39;);&#xA;            const fsInput = document.getElementById(&#39;range-fs&#39;);&#xA;            const widthInput = document.getElementById(&#39;range-width&#39;);&#xA;            const shadowInput = document.getElementById(&#39;range-shadow&#39;);&#xA;            const workspaceHeightInput = document.getElementById(&#39;range-workspace-height&#39;);&#xA;            const valWorkspaceHeight = document.getElementById(&#39;val-workspace-height&#39;);&#xA;            const toolRoot = document.querySelector(&#39;.md2png-tool&#39;);&#xA;            const valFs = document.getElementById(&#39;val-fs&#39;);&#xA;            const valWidth = document.getElementById(&#39;val-width&#39;);&#xA;            const valShadow = document.getElementById(&#39;val-shadow&#39;);&#xA;            const saveBtn = document.querySelector(&#39;.btn-save&#39;);&#xA;&#xA;            /**&#xA;             * 兼容性增强：先把代码块和行内代码替换成占位符，&#xA;             * 再把 **...** 转成 &lt;strong&gt;... &lt;/strong&gt;，避免括号、符号等内容&#xA;             * 在某些 Markdown 解析场景下被漏掉。&#xA;             */&#xA;            function normalizeBoldSyntax(mdText) {&#xA;                const placeholders = [];&#xA;&#xA;                const protect = (pattern, text) =&gt; text.replace(pattern, (match) =&gt; {&#xA;                    const token = `__MD_PLACEHOLDER_${placeholders.length}__`;&#xA;                    placeholders.push(match);&#xA;                    return token;&#xA;                });&#xA;&#xA;                let text = mdText;&#xA;                text = protect(/```[\s\S]*?```/g, text);&#xA;                text = protect(/`[^`\n]+`/g, text);&#xA;                text = text.replace(/\*\*((?:\\.|[^*\n])+?)\*\*/g, &#39;&lt;strong&gt;$1&lt;/strong&gt;&#39;);&#xA;&#xA;                return text.replace(/__MD_PLACEHOLDER_(\d+)__/g, (_, index) =&gt; placeholders[Number(index)]);&#xA;            }&#xA;&#xA;            // 初始化 CodeMirror 编辑器&#xA;            const cm = CodeMirror.fromTextArea(editorTextarea, {&#xA;                mode: &#39;markdown&#39;,&#xA;                lineWrapping: true,&#xA;                theme: &#34;default&#34;,&#xA;                tabSize: 2,&#xA;            });&#xA;&#xA;            /**&#xA;             * 刷新预览：重新渲染 Markdown 并应用滑块参数&#xA;             */&#xA;            function refreshPreview() {&#xA;                // 获取当前 Markdown 文本&#xA;                const mdText = cm.getValue();&#xA;                // 先做加粗语法兼容处理，再交给 marked 解析为 HTML&#xA;                renderEl.innerHTML = marked.parse(normalizeBoldSyntax(mdText));&#xA;&#xA;                // 读取滑块值&#xA;                const fontSize = fsInput.value;&#xA;                const targetWidth = widthInput.value;&#xA;                const shadowLevel = Number(shadowInput.value);&#xA;                const workspaceHeight = workspaceHeightInput.value;&#xA;&#xA;                // 更新显示数值&#xA;                valFs.textContent = fontSize + &#39;px&#39;;&#xA;                valWidth.textContent = targetWidth + &#39;px&#39;;&#xA;                valShadow.textContent = shadowLevel === 0 ? &#39;关闭&#39; : `${shadowLevel}档`;&#xA;                valWorkspaceHeight.textContent = workspaceHeight + &#39;px&#39;;&#xA;&#xA;                // 动态设置样式 (字体大小应用到渲染容器，宽度应用到导出目标)&#xA;                renderEl.style.fontSize = fontSize + &#39;px&#39;;&#xA;                targetEl.style.width = targetWidth + &#39;px&#39;;&#xA;&#xA;                // 预览区超宽时自动缩小，避免横向滚动条&#xA;                updatePreviewScale();&#xA;            }&#xA;&#xA;            /**&#xA;             * 让预览卡片始终适配预览区域宽度&#xA;             */&#xA;            function updatePreviewScale() {&#xA;                const targetWidth = parseFloat(widthInput.value);&#xA;                const stageWidth = previewStage.clientWidth;&#xA;                const scale = targetWidth &gt; 0 ? Math.min(1, stageWidth / targetWidth) : 1;&#xA;&#xA;                if (scale &lt; 1) {&#xA;                    targetEl.style.transform = `scale(${scale})`;&#xA;                } else {&#xA;                    targetEl.style.transform = &#39;none&#39;;&#xA;                }&#xA;&#xA;                targetEl.style.marginLeft = &#39;auto&#39;;&#xA;                targetEl.style.marginRight = &#39;auto&#39;;&#xA;            }&#xA;&#xA;            /**&#xA;             * 清空编辑器内容&#xA;             */&#xA;            function clearEditor() {&#xA;                cm.setValue(&#39;&#39;);&#xA;                cm.focus();&#xA;            }&#xA;&#xA;            /**&#xA;             * 从剪贴板读取文本并替换编辑器内容&#xA;             */&#xA;            async function pasteFromClipboard() {&#xA;                try {&#xA;                    if (!navigator.clipboard || !navigator.clipboard.readText) {&#xA;                        throw new Error(&#39;Clipboard API unavailable&#39;);&#xA;                    }&#xA;&#xA;                    const text = await navigator.clipboard.readText();&#xA;                    cm.setValue(text || &#39;&#39;);&#xA;                    cm.focus();&#xA;                } catch (error) {&#xA;                    console.error(&#39;读取剪贴板失败:&#39;, error);&#xA;                    const pastedText = window.prompt(&#39;当前浏览器无法直接读取剪贴板，请手动粘贴内容：&#39;, &#39;&#39;);&#xA;                    if (pastedText !== null) {&#xA;                        cm.setValue(pastedText);&#xA;                        cm.focus();&#xA;                    }&#xA;                }&#xA;            }&#xA;&#xA;            // 监听编辑器内容变化&#xA;            cm.on(&#39;change&#39;, refreshPreview);&#xA;&#xA;            // 监听滑块变化&#xA;            fsInput.addEventListener(&#39;input&#39;, refreshPreview);&#xA;            widthInput.addEventListener(&#39;input&#39;, refreshPreview);&#xA;            shadowInput.addEventListener(&#39;input&#39;, refreshPreview);&#xA;            workspaceHeightInput.addEventListener(&#39;input&#39;, refreshPreview);&#xA;            window.addEventListener(&#39;resize&#39;, updatePreviewScale);&#xA;&#xA;            // 初次加载时立即渲染&#xA;            refreshPreview();&#xA;&#xA;            /**&#xA;             * 导出为 PNG 图片&#xA;             */&#xA;            async function saveToImage() {&#xA;                // 保存按钮原始文本&#xA;                const originalText = saveBtn.textContent;&#xA;                const shadowLevel = Number(shadowInput.value);&#xA;                saveBtn.textContent = &#39;⏳ 正在生成高清图片...&#39;;&#xA;                saveBtn.disabled = true;&#xA;&#xA;                try {&#xA;                    const baseCanvas = await html2canvas(targetEl, {&#xA;                        scale: 2, // 2倍分辨率，保证文字清晰&#xA;                        useCORS: true,&#xA;                        backgroundColor: null,&#xA;                        allowTaint: false,&#xA;                        onclone: (clonedDoc) =&gt; {&#xA;                            const clonedTarget = clonedDoc.getElementById(&#39;export-target&#39;);&#xA;                            const clonedBody = clonedDoc.getElementById(&#39;html-render&#39;);&#xA;&#xA;                            if (clonedTarget) {&#xA;                                clonedTarget.style.transform = &#39;none&#39;;&#xA;                                clonedTarget.style.margin = &#39;0&#39;;&#xA;                                clonedTarget.style.boxShadow = &#39;none&#39;;&#xA;                            }&#xA;&#xA;                            if (clonedBody) {&#xA;                                clonedBody.style.color = &#39;#1a1a1a&#39;;&#xA;                                clonedBody.style.background = &#39;transparent&#39;;&#xA;                            }&#xA;                        },&#xA;                    });&#xA;&#xA;                    let canvas = baseCanvas;&#xA;&#xA;                    if (shadowLevel &gt; 0) {&#xA;                        // Controls the transparent margin around the exported card shadow.&#xA;                        const shadowPadding = 110;&#xA;                        const shadowConfigs = {&#xA;                            1: { color: &#39;rgba(0, 0, 0, 0.24)&#39;, blur: 34, offsetY: 12 },&#xA;                            2: { color: &#39;rgba(0, 0, 0, 0.32)&#39;, blur: 50, offsetY: 18 },&#xA;                            3: { color: &#39;rgba(0, 0, 0, 0.40)&#39;, blur: 66, offsetY: 24 },&#xA;                            4: { color: &#39;rgba(0, 0, 0, 0.48)&#39;, blur: 86, offsetY: 32 },&#xA;                        };&#xA;                        const shadowConfig = shadowConfigs[shadowLevel] || shadowConfigs[2];&#xA;                        const shadowCanvas = document.createElement(&#39;canvas&#39;);&#xA;                        shadowCanvas.width = baseCanvas.width + shadowPadding * 2;&#xA;                        shadowCanvas.height = baseCanvas.height + shadowPadding * 2;&#xA;&#xA;                        const ctx = shadowCanvas.getContext(&#39;2d&#39;);&#xA;                        ctx.clearRect(0, 0, shadowCanvas.width, shadowCanvas.height);&#xA;                        ctx.shadowColor = shadowConfig.color;&#xA;                        ctx.shadowBlur = shadowConfig.blur;&#xA;                        ctx.shadowOffsetX = 0;&#xA;                        ctx.shadowOffsetY = shadowConfig.offsetY;&#xA;                        ctx.fillStyle = &#39;#ffffff&#39;;&#xA;                        ctx.fillRect(shadowPadding, shadowPadding, baseCanvas.width, baseCanvas.height);&#xA;                        ctx.shadowColor = &#39;transparent&#39;;&#xA;                        ctx.drawImage(baseCanvas, shadowPadding, shadowPadding);&#xA;&#xA;                        canvas = shadowCanvas;&#xA;                    }&#xA;&#xA;                    // 创建下载链接&#xA;                    const link = document.createElement(&#39;a&#39;);&#xA;                    const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, &#39;-&#39;);&#xA;                    link.download = `markdown-${timestamp}.png`;&#xA;                    link.href = canvas.toDataURL(&#39;image/png&#39;);&#xA;                    link.click();&#xA;&#xA;                } catch (error) {&#xA;                    console.error(&#39;导出图片失败:&#39;, error);&#xA;                    alert(&#39;❌ 保存失败，请刷新后重试。\n如果问题持续，请检查浏览器控制台。&#39;);&#xA;                } finally {&#xA;                    // 恢复按钮状态&#xA;                    saveBtn.textContent = originalText;&#xA;                    saveBtn.disabled = false;&#xA;                }&#xA;            }&#xA;&#xA;            // 将保存函数挂载到全局作用域，以便 onclick 调用&#xA;            window.saveToImage = saveToImage;&#xA;            window.clearEditor = clearEditor;&#xA;            window.pasteFromClipboard = pasteFromClipboard;&#xA;        })();&#xA;    &lt;/script&gt;&#xA;&#xA;&lt;/div&gt;&lt;style&gt;&#xA;.md2png-tool .main-wrapper { height: var(--md2png-workspace-height, 680px); max-height: calc(100svh - 110px); }&#xA;.md2png-tool .control-panel { order: -1; flex: 0 0 auto; }&#xA;.md2png-tool .CodeMirror { min-height: 0; }&#xA;@media (max-width: 768px) { .md2png-tool .main-wrapper { height: var(--md2png-workspace-height, 720px); max-height: none; } }&#xA;&lt;/style&gt;&lt;script&gt;&#xA;(() =&gt; {&#xA;  const root = document.querySelector(&#34;.md2png-tool&#34;);&#xA;  const workspace = root?.querySelector(&#34;.main-wrapper&#34;);&#xA;  const target = root?.querySelector(&#34;#export-target&#34;);&#xA;  const widthInput = root?.querySelector(&#34;#range-width&#34;);&#xA;  if (!root || !workspace || !target) return;&#xA;&#xA;  const updateWorkspaceHeight = () =&gt; {&#xA;    const minimum = Number.parseInt(getComputedStyle(root).getPropertyValue(&#34;--page-workspace-height&#34;), 10) || 680;&#xA;    const previewHeight = Math.ceil(target.getBoundingClientRect().height + 36);&#xA;    workspace.style.height = `${Math.min(1400, Math.max(minimum, previewHeight))}px`;&#xA;  };&#xA;&#xA;  const observer = new ResizeObserver(() =&gt; requestAnimationFrame(updateWorkspaceHeight));&#xA;  observer.observe(target);&#xA;  widthInput?.addEventListener(&#34;input&#34;, () =&gt; requestAnimationFrame(updateWorkspaceHeight));&#xA;  requestAnimationFrame(updateWorkspaceHeight);&#xA;  setTimeout(updateWorkspaceHeight, 200);&#xA;})();&#xA;&lt;/script&gt;</description>
			</item>
			<item>
				<title>图片背景移除</title>
				<link>/pages/bgremover/</link>
				<pubDate>Thu, 16 Jul 2026 08:17:00 +0800</pubDate>
				<guid>/pages/bgremover/</guid>
				<description>&lt;style&gt;&#xA;.bgremover-tool { padding: 16px; color: var(--page-ink); font-family: -apple-system, BlinkMacSystemFont, &#34;Segoe UI&#34;, sans-serif; }&#xA;.bgremover-panel { width: 100%; max-width: 896px; margin: 0 auto; padding: 24px; background: #fff; border: 2px solid var(--page-line); box-shadow: 3px 3px 0 rgba(212,107,145,.35); }&#xA;.bgremover-panel &gt; div:first-child { margin-bottom: 24px; text-align: center; }&#xA;.bgremover-panel h1 { margin: 0; color: var(--page-accent); font-size: 28px; line-height: 1.25; }&#xA;.bgremover-panel h1 + p { margin: 8px 0 0; color: var(--page-muted); }&#xA;.bgremover-controls { justify-content: center; margin-bottom: 18px; }&#xA;.bgremover-controls input[type=&#34;file&#34;] { display: none; }&#xA;.bgremover-controls label, .bgremover-controls button, .bgremover-download a { display: inline-block; padding: 7px 12px; color: #fff; background: #2fa888; border: 1px solid var(--page-accent); box-shadow: 1px 1px 0 rgba(31,106,90,.25); cursor: pointer; font-weight: 700; }&#xA;.bgremover-controls button { background: #5fa8d0; border-color: #2a6a8a; }&#xA;.bgremover-controls button:disabled { color: #fff; background: #9aaeb1; border-color: #84989a; cursor: not-allowed; }&#xA;.bgremover-controls input[type=&#34;range&#34;] { accent-color: var(--page-pink); }&#xA;.bgremover-tool #infoMessage { margin: 0 0 20px; padding: 8px 10px; color: var(--page-muted); background: var(--page-yellow); border: 1px dashed #dbbd68; text-align: center; }&#xA;.bgremover-canvases { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }&#xA;.bgremover-canvases &gt; div { min-width: 0; text-align: center; }&#xA;.bgremover-canvases h2 { margin: 0 0 8px; color: var(--page-accent); font-size: 18px; }&#xA;.bgremover-tool canvas { max-width: 100%; height: auto; border: 1px solid var(--page-line); box-shadow: 2px 2px 0 rgba(31,106,90,.15); }&#xA;.bgremover-download { margin-top: 22px; text-align: center; }&#xA;.bgremover-download a { background: #d96286; border-color: var(--page-pink); text-decoration: none; }&#xA;.bgremover-tool .hidden { display: none; }&#xA;@media (max-width: 768px) { .bgremover-tool { padding: 8px; } .bgremover-panel { padding: 16px; } .bgremover-canvases { grid-template-columns: 1fr; } }&#xA;&lt;/style&gt;&lt;div class=&#34;bgremover-tool page-surface page-surface--sky&#34;&gt;&lt;div class=&#34;bgremover-panel&#34;&gt;&#xA;&#xA;    &#xA;        &lt;div class=&#34;text-center mb-8&#34;&gt;&#xA;            &lt;h1 class=&#34;text-3xl md:text-4xl font-bold text-gray-900&#34;&gt;图片背景移除&lt;/h1&gt;&#xA;            &lt;p class=&#34;text-gray-600 mt-2&#34;&gt;上传单色背景图片，将背景处理为透明。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
