{"slug":"story-cover-2","title":"story-cover","summary":"小说封面生成。根据书名、作者名自动分析题材风格，调用 GPT-Image-2 生成含标题和署名的专业级网文封面；Codex CLI 优先使用内置 ImageGen，无需单独 API Key。触发方式：/story-cover、/封面、「帮我做个封面」「生成封面图」「做个小说封面」「封面设计」。","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-10-02T16:32:44.944195Z","repo":{"url":"https://github.com/zenstory-ai/oh-story-dsh","stars":433,"forks":74,"license":"MIT","updatedAt":"2026-10-02T11:40:12Z"},"bodyHtml":"<hr>\n<h2>name: story-cover\nversion: 1.0.0\ndescription: \"小说封面生成。根据书名、作者名自动分析题材风格，调用 GPT-Image-2 生成含标题和署名的专业级网文封面；Codex CLI 优先使用内置 ImageGen，无需单独 API Key。触发方式：/story-cover、/封面、「帮我做个封面」「生成封面图」「做个小说封面」「封面设计」。\"\nmetadata: {\"openclaw\":{\"requires\":{\"env\":[\"GPT_IMAGE_API_KEY\"],\"bins\":[\"curl\",\"jq\",\"base64\"]},\"primaryEnv\":\"GPT_IMAGE_API_KEY\",\"source\":\"https://github.com/zenstory-ai/oh-story-claudecode\"}}</h2>\n<h1>story-cover：小说封面生成</h1>\n<p>你是小说封面设计师。根据书名和题材，调用 GPT-Image-2 一次性生成包含书名和作者名的完整封面。</p>\n<p><strong>核心原则：封面是读者的第一印象，一眼传达题材和氛围。</strong></p>\n<hr>\n<h2>生成通路</h2>\n<ul>\n<li><strong>Codex 内置（优先）</strong>：当前 Codex CLI 会话可调用 <code>$imagegen</code> / <code>image_gen</code> 时，直接生成并落盘；计入 Codex 通用用量，无需 <code>OPENAI_API_KEY</code> 或 <code>GPT_IMAGE_API_KEY</code>，也不运行 <code>curl</code>。<code>story-cover</code> 自行调用工具，不让用户另开命令。</li>\n<li><strong>API 回退</strong>：仅在会话没有内置工具或用户明确指定 API 时使用，需要 <code>GPT_IMAGE_API_KEY</code>。工具缺失不等于 Codex 订阅不支持生图；内置调用失败时先报告错误，不静默切换到可能收费的 API。</li>\n</ul>\n<h2>输出参数与 API 回退环境变量</h2>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">变量</th>\n<th style=\"text-align: center\">必填</th>\n<th style=\"text-align: left\">默认</th>\n<th style=\"text-align: left\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\"><code>GPT_IMAGE_API_KEY</code></td>\n<td style=\"text-align: center\">API 回退必填</td>\n<td style=\"text-align: left\">—</td>\n<td style=\"text-align: left\">OpenAI 或兼容代理的 API Key；Codex 内置通路不用</td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>GPT_IMAGE_BASE_URL</code></td>\n<td style=\"text-align: center\"></td>\n<td style=\"text-align: left\"><code>https://api.openai.com/v1</code></td>\n<td style=\"text-align: left\">兼容代理时改这个</td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>GPT_IMAGE_MODEL</code></td>\n<td style=\"text-align: center\"></td>\n<td style=\"text-align: left\"><code>gpt-image-2</code></td>\n<td style=\"text-align: left\">仅在测试新模型时覆盖</td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>GPT_IMAGE_SIZE</code></td>\n<td style=\"text-align: center\"></td>\n<td style=\"text-align: left\"><code>1024x1536</code></td>\n<td style=\"text-align: left\">API 回退的目标比例提示（番茄 3:4→<code>768x1024</code>，默认 2:3→<code>1024x1536</code>）。官方 gpt-image-2 认任意 16 倍数尺寸（比例≤3:1），但<strong>很多中转代理会忽略 size、按预设返回约 2:3</strong>（已实测）——平台尺寸不靠它，由「导出平台上传尺寸」步骤兜底</td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>UPLOAD_SIZE</code></td>\n<td style=\"text-align: center\"></td>\n<td style=\"text-align: left\">—</td>\n<td style=\"text-align: left\">平台固定上传像素（番茄 <code>600x800</code>）；设置后由「导出平台上传尺寸」步骤居中裁剪+缩放出上传版（不变形、不依赖出图尺寸）</td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>BOOK_DIR</code></td>\n<td style=\"text-align: center\">✅</td>\n<td style=\"text-align: left\">—</td>\n<td style=\"text-align: left\">输出目录，建议 <code>./covers/&lt;书名&gt;</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\"><code>REF_IMAGE</code></td>\n<td style=\"text-align: center\"></td>\n<td style=\"text-align: left\">—</td>\n<td style=\"text-align: left\">参考图本地路径或 URL；内置通路先把图片载入会话，API 回退走 <code>images/edits</code> 图生图</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>生成流程</h2>\n<h3>Step 1：收集信息</h3>\n<p>必填：书名、作者名（笔名）、目标平台、输出目录 <code>BOOK_DIR</code>（建议 <code>./covers/&lt;书名&gt;</code>；API 回退用环境变量，内置通路直接使用当前任务值）。问作者时说「封面存在哪？默认 <code>./covers/&lt;书名&gt;</code>」，不把变量名当问题抛给作者\n选填：参考图 <code>REF_IMAGE</code>（本地路径或 URL，设置后切换到图生图）、风格偏好、尺寸</p>\n<blockquote>\n<p><strong>书名和笔名是封面必需信息</strong>：缺任一必须先用 AskUserQuestion 问用户补全，不得编造或留空。</p>\n</blockquote>\n<p><strong>按目标平台定封面尺寸</strong>：番茄上传 600×800 是 <strong>3:4</strong>（不是 2:3），出图比例不对、平台二次裁剪就会切掉书名/笔名。</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">平台</th>\n<th style=\"text-align: left\">上传尺寸</th>\n<th style=\"text-align: left\">比例</th>\n<th style=\"text-align: left\">生成 <code>GPT_IMAGE_SIZE</code>（尽量）</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">番茄小说</td>\n<td style=\"text-align: left\">600×800</td>\n<td style=\"text-align: left\">3:4</td>\n<td style=\"text-align: left\"><code>768x1024</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">其他平台（默认竖版）</td>\n<td style=\"text-align: left\">按平台规格</td>\n<td style=\"text-align: left\">2:3</td>\n<td style=\"text-align: left\"><code>1024x1536</code></td>\n</tr>\n</tbody>\n</table>\n<p>内置通路把目标比例写进提示词；API 回退再 <code>export GPT_IMAGE_SIZE</code>（很多代理会忽略、返回约 2:3）。平台有固定上传像素时设置 <code>UPLOAD_SIZE</code>（番茄 <code>600x800</code>）。<strong>平台尺寸最终由「导出平台上传尺寸」步骤居中裁剪+缩放保证，不依赖实际出图尺寸。</strong> 平台与题材风格见 <a href=\"references/cover-styles.md\">references/cover-styles.md</a>。</p>\n<h3>Step 2：题材判定</h3>\n<p>扫描书名（必要时简介）中的关键词，对照 <a href=\"references/cover-styles.md\">references/cover-styles.md</a> 的「题材推断规则」表选定题材。</p>\n<ul>\n<li>单题材命中 → 直接采用</li>\n<li>多题材命中 → 按优先级取一：仙侠 &gt; 西幻 &gt; 古言 &gt; 现言 &gt; 都市 &gt; 悬疑 &gt; 科幻 &gt; 历史 &gt; 灵异 &gt; 轻小说</li>\n<li>零命中 → 默认 <code>都市</code></li>\n</ul>\n<h3>Step 3：构建提示词</h3>\n<p>提示词 = <strong>文字层</strong> + <strong>风格层</strong> + <strong>画面层</strong>，全部用英文编写。</p>\n<h4>文字层：书名 + 作者名字体设计</h4>\n<p>在提示词中直接包含中文书名和作者名，GPT-Image-2 可直接渲染。<strong>重点描述字体风格</strong>：</p>\n<pre><code>Title text '书名' at top center in [书名字体风格].\nAuthor name '作者名' at bottom center in [作者名字体风格].\n</code></pre>\n<h4>书名字体风格</h4>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">题材</th>\n<th style=\"text-align: left\">描述关键词</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">玄幻/仙侠</td>\n<td style=\"text-align: left\"><code>bold golden brush calligraphy with metallic glow and sharp strokes</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">都市</td>\n<td style=\"text-align: left\"><code>modern bold sans-serif with metallic silver finish</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">古言/宫斗</td>\n<td style=\"text-align: left\"><code>elegant golden traditional Kai script with ornate decoration</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">现言/甜宠</td>\n<td style=\"text-align: left\"><code>soft rounded handwritten style in white with pink glow</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">悬疑/推理</td>\n<td style=\"text-align: left\"><code>distorted bold cracked letters in blood red</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">科幻/末世</td>\n<td style=\"text-align: left\"><code>neon glowing futuristic font in electric blue</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">西幻</td>\n<td style=\"text-align: left\"><code>metallic embossed fantasy lettering with glow effect</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">历史/军事</td>\n<td style=\"text-align: left\"><code>heavy stone-carved seal script in deep red</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">灵异/恐怖</td>\n<td style=\"text-align: left\"><code>eerie dripping handwritten font in sickly green</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">轻小说</td>\n<td style=\"text-align: left\"><code>colorful cartoon outlined bubbly font</code></td>\n</tr>\n</tbody>\n</table>\n<h4>作者名字体风格（重点：作者名必须精心设计，不能只是\"小字\"）</h4>\n<p>作者名虽小，但是封面专业感的关键。必须指定：<strong>字体 + 颜色 + 装饰元素</strong>，让作者名与书名风格呼应但不抢焦点。</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">题材</th>\n<th style=\"text-align: left\">作者名风格提示词</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">玄幻/仙侠</td>\n<td style=\"text-align: left\"><code>small refined white serif text with faint golden glow, flanked by delicate cloud-scroll ornaments on both sides, resting on a thin horizontal gold line</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">都市</td>\n<td style=\"text-align: left\"><code>small clean white modern text with subtle drop shadow, positioned above a thin silver horizontal divider line</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">古言/宫斗</td>\n<td style=\"text-align: left\"><code>small elegant dark red traditional text inside a thin golden rectangular border frame with corner decorations</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">现言/甜宠</td>\n<td style=\"text-align: left\"><code>small soft pink-white handwritten text with a tiny heart motif on the left side, light sparkle effect</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">悬疑/推理</td>\n<td style=\"text-align: left\"><code>small pale grey text with slight blur effect, almost hidden in the shadows, a thin cracked line underneath</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">科幻/末世</td>\n<td style=\"text-align: left\"><code>small crisp white monospace text with subtle cyan scanline overlay, flanked by small geometric brackets</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">西幻</td>\n<td style=\"text-align: left\"><code>small bronze medieval script text with aged parchment texture, enclosed in a small decorative shield or banner shape</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">历史/军事</td>\n<td style=\"text-align: left\"><code>small dignified white Song typeface text above a double horizontal line in dark red</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">灵异/恐怖</td>\n<td style=\"text-align: left\"><code>small faded grey-green text slightly tilted, with a thin dripping ink line above</code></td>\n</tr>\n<tr>\n<td style=\"text-align: left\">轻小说</td>\n<td style=\"text-align: left\"><code>small playful rounded white text with pastel color outline, tiny star decorations on both sides</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>作者名通用规则</strong>：</p>\n<ul>\n<li>大小：<code>small</code>（不能太大抢书名焦点，也不能太小看不清）</li>\n<li>位置：<code>at bottom center</code>，与画面底部保持适当间距</li>\n<li>必须有装饰元素：线条/边框/小图标/光效中至少一种</li>\n<li>颜色与背景形成对比但不刺眼</li>\n</ul>\n<h4>风格层：平台风格</h4>\n<p>平台风格的描述关键词统一来自 <a href=\"references/cover-styles.md\">references/cover-styles.md</a> 的「平台风格」节，按目标平台直接取对应关键词串使用，不在本文件维护副本以免与参考文件漂移。</p>\n<h4>画面层：题材 + 构图</h4>\n<p>从 <a href=\"references/cover-styles.md\">references/cover-styles.md</a> 读取题材对应的风格标签、色彩、人物、背景描述。</p>\n<p>构图变体（首次输出 2-3 个方案）：</p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">方案</th>\n<th style=\"text-align: left\">构图</th>\n<th style=\"text-align: left\">适合题材</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">A</td>\n<td style=\"text-align: left\">人物特写 + 场景</td>\n<td style=\"text-align: left\">全题材通用</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">B</td>\n<td style=\"text-align: left\">全身像 + 动态姿势</td>\n<td style=\"text-align: left\">玄幻、都市、西幻</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">C</td>\n<td style=\"text-align: left\">纯场景/氛围图</td>\n<td style=\"text-align: left\">悬疑、科幻、历史</td>\n</tr>\n</tbody>\n</table>\n<h4>完整提示词模板</h4>\n<pre><code>Chinese web novel cover design, [平台风格].\nTitle text '{书名}' at top center in [书名字体风格].\nAuthor name '{作者名}' at bottom center in [作者名字体风格 — 从上表选择].\n[题材风格标签]. [人物描述]. [背景描述].\n[色彩指令]. [光效指令].\nProfessional book cover, high detail digital painting, portrait [平台比例：番茄=3:4，默认=2:3] ratio, keep title and author name inside the central safe area away from edges (inner ~85%), no watermark\n</code></pre>\n<h4>提示词技巧（实测验证）</h4>\n<ul>\n<li>人物描述越具体越好：服饰、姿态、发型、表情、道具每个维度都指定</li>\n<li>背景分层：前景（人物）→ 中景（场景）→ 远景（氛围）</li>\n<li>光效是指定光源方向 + 颜色（如 <code>dramatic golden light from above</code>）</li>\n<li>用 <code>digital painting style</code> 而非 <code>photo</code>，避免真人照片感</li>\n</ul>\n<h3>Step 4：生成并保存</h3>\n<h4>Codex 内置 ImageGen（优先）</h4>\n<ol>\n<li>用 Step 3 的完整提示词调用 <code>image_gen</code>。比例和安全区写进提示词，不传 <code>GPT_IMAGE_MODEL</code>、<code>GPT_IMAGE_SIZE</code>、<code>response_format</code> 等 API 参数。</li>\n<li>有 <code>REF_IMAGE</code> 时，本地文件先用图片查看工具载入会话；URL 先下载再载入。说明它是编辑目标还是风格参考，并列出必须保持的内容。</li>\n<li>每个构图方案单独调用一次。先创建 <code>BOOK_DIR/封面/</code>，再把工具返回的图片复制为 <code>封面_vN.png</code>，<code>N</code> 自增且不覆盖旧版；保留 <code>$CODEX_HOME/generated_images/</code> 原文件，同时保存同名 <code>.prompt.txt</code>，有参考图再保存 <code>.ref.txt</code>。确认图片可读，并把原图绝对路径交给 Step 5。</li>\n</ol>\n<h4>API 回退</h4>\n<p><code>gpt-image-2</code> 始终返回 base64，请求体不要带 <code>response_format</code>（旧 DALL-E 参数，gpt-image 系列不支持）。<code>$PROMPT</code> 为「构建提示词」步骤拼出的完整提示词。</p>\n<p>两种调用方式二选一：未设置 <code>REF_IMAGE</code> → 走「文生图」；设置了 → 走「图生图」。</p>\n<h4>文生图（默认）</h4>\n<pre><code>set -euo pipefail\n: \"${GPT_IMAGE_API_KEY:?请设置 export GPT_IMAGE_API_KEY=你的key}\"\n: \"${PROMPT:?请先 export PROMPT=构建提示词步骤拼好的完整提示词}\"\nBASE_URL=\"${GPT_IMAGE_BASE_URL:-https://api.openai.com/v1}\"\nMODEL=\"${GPT_IMAGE_MODEL:-gpt-image-2}\"\nSIZE=\"${GPT_IMAGE_SIZE:-1024x1536}\"\nBOOK_DIR=\"${BOOK_DIR:?请先 export BOOK_DIR=./covers/&lt;书名&gt;}\"\n\nmkdir -p \"$BOOK_DIR/封面\"\n\n# 自增版本号，避免覆盖之前生成的封面\ni=1\nwhile [ -f \"$BOOK_DIR/封面/封面_v${i}.png\" ]; do i=$((i+1)); done\nOUT=\"$BOOK_DIR/封面/封面_v${i}.png\"\nRESP=$(mktemp)\ntrap 'rm -f \"$RESP\"' EXIT\n\n# 用 jq 拼 JSON 体，避免 PROMPT 里的引号/换行/中文把 shell 字符串撑破\nBODY=$(jq -n \\\n  --arg m \"$MODEL\" \\\n  --arg p \"$PROMPT\" \\\n  --arg s \"$SIZE\" \\\n  '{model:$m, prompt:$p, size:$s}')\n\ncurl -fsS --max-time 180 --retry 2 --retry-delay 5 \\\n  \"$BASE_URL/images/generations\" \\\n  -H \"Authorization: Bearer $GPT_IMAGE_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"$BODY\" &gt; \"$RESP\"\n\n# API 出错时早退，避免把 error JSON 当成 base64 写成损坏 PNG\nif jq -e '.error' \"$RESP\" &gt;/dev/null 2&gt;&amp;1; then\n  echo \"API error:\" &gt;&amp;2\n  jq '.error' \"$RESP\" &gt;&amp;2\n  exit 1\nfi\n\n# `// empty` 让缺失字段输出空串而非 \"null\"，配合下面的 -s 检查避免写出 3 字节假 PNG\njq -er '.data[0].b64_json // empty' \"$RESP\" | base64 --decode &gt; \"$OUT\"\n[ -s \"$OUT\" ] || { echo \"empty or malformed output: $OUT\" &gt;&amp;2; head -c 300 \"$RESP\" &gt;&amp;2; exit 1; }\n\n# 落地提示词副本，方便迭代时基于上一次微调\nprintf '%s\\n' \"$PROMPT\" &gt; \"${OUT%.png}.prompt.txt\"\n\nfile \"$OUT\"\nls -lt \"$BOOK_DIR/封面/\"\n</code></pre>\n<h4>图生图（提供参考图时）</h4>\n<p><code>/v1/images/edits</code> 走 <code>multipart/form-data</code>，<strong>不能</strong> 用 <code>Content-Type: application/json</code>。文本字段用 <code>--form-string</code>（避免 <code>@</code> 被误判为文件引用），图片字段用 <code>-F image=@path</code>。</p>\n<pre><code>set -euo pipefail\n: \"${GPT_IMAGE_API_KEY:?请设置 export GPT_IMAGE_API_KEY=你的key}\"\n: \"${PROMPT:?请先 export PROMPT=构建提示词步骤拼好的完整提示词}\"\nBASE_URL=\"${GPT_IMAGE_BASE_URL:-https://api.openai.com/v1}\"\nMODEL=\"${GPT_IMAGE_MODEL:-gpt-image-2}\"\nSIZE=\"${GPT_IMAGE_SIZE:-1024x1536}\"\nBOOK_DIR=\"${BOOK_DIR:?请先 export BOOK_DIR=./covers/&lt;书名&gt;}\"\nREF_IMAGE=\"${REF_IMAGE:?请先 export REF_IMAGE=本地路径或 URL}\"\n\nmkdir -p \"$BOOK_DIR/封面\"\n\n# 自增版本号\ni=1\nwhile [ -f \"$BOOK_DIR/封面/封面_v${i}.png\" ]; do i=$((i+1)); done\nOUT=\"$BOOK_DIR/封面/封面_v${i}.png\"\nRESP=$(mktemp)\nREF_TMP=\"\"\ntrap '[ -n \"$REF_TMP\" ] &amp;&amp; rm -f \"$REF_TMP\"; rm -f \"$RESP\"' EXIT\n\n# URL 先下载到临时文件，本地路径直接用。用裸 mktemp 以保证 macOS/Linux 行为一致。\ncase \"$REF_IMAGE\" in\n  http://*|https://*)\n    REF_TMP=$(mktemp)\n    curl -fsSL --max-time 60 -o \"$REF_TMP\" \"$REF_IMAGE\"\n    REF_LOCAL=\"$REF_TMP\"\n    ;;\n  *)\n    [ -f \"$REF_IMAGE\" ] || { echo \"参考图不存在: $REF_IMAGE\" &gt;&amp;2; exit 1; }\n    REF_LOCAL=\"$REF_IMAGE\"\n    ;;\nesac\n\ncurl -fsS --max-time 240 --retry 2 --retry-delay 5 \\\n  \"$BASE_URL/images/edits\" \\\n  -H \"Authorization: Bearer $GPT_IMAGE_API_KEY\" \\\n  --form-string \"model=$MODEL\" \\\n  --form-string \"size=$SIZE\" \\\n  --form-string \"prompt=$PROMPT\" \\\n  -F \"image=@$REF_LOCAL\" &gt; \"$RESP\"\n\nif jq -e '.error' \"$RESP\" &gt;/dev/null 2&gt;&amp;1; then\n  echo \"API error:\" &gt;&amp;2\n  jq '.error' \"$RESP\" &gt;&amp;2\n  exit 1\nfi\n\n# `// empty` 让缺失字段输出空串而非 \"null\"，配合 -s 检查避免写出 3 字节假 PNG\njq -er '.data[0].b64_json // empty' \"$RESP\" | base64 --decode &gt; \"$OUT\"\n[ -s \"$OUT\" ] || { echo \"empty or malformed output: $OUT\" &gt;&amp;2; head -c 300 \"$RESP\" &gt;&amp;2; exit 1; }\n\nprintf '%s\\n' \"$PROMPT\"    &gt; \"${OUT%.png}.prompt.txt\"\nprintf '%s\\n' \"$REF_IMAGE\" &gt; \"${OUT%.png}.ref.txt\"\n\nfile \"$OUT\"\nls -lt \"$BOOK_DIR/封面/\"\n</code></pre>\n<h3>Step 5：导出平台上传尺寸（平台有固定像素时）</h3>\n<p>平台有固定上传像素（番茄 600×800）时，把原图<strong>居中裁剪+缩放</strong>成上传尺寸——不论出图是 2:3 还是 3:4 都裁成平台精确像素，不变形，避免平台再裁切掉书名/笔名。原图保留、另存 <code>_上传</code> 版；<code>SRC</code> 和 <code>TARGET</code> 直接使用前序步骤的任务值，不依赖跨 shell 的临时变量：</p>\n<pre><code>SRC='&lt;Step 4 生成的原图绝对路径&gt;'\nTARGET='&lt;Step 1 确定的平台上传尺寸；无则留空&gt;'\n[ -f \"$SRC\" ] || { echo \"封面原图不存在: $SRC\" &gt;&amp;2; exit 1; }\nif [ -n \"$TARGET\" ] &amp;&amp; [ -f \"$SRC\" ]; then\n  UP=\"${SRC%.png}_上传.png\"; W=\"${TARGET%x*}\"; H=\"${TARGET#*x}\"\n  if command -v magick &gt;/dev/null 2&gt;&amp;1; then M=magick\n  elif command -v convert &gt;/dev/null 2&gt;&amp;1; then M=convert; else M=\"\"; fi\n  if [ -n \"$M\" ]; then\n    \"$M\" \"$SRC\" -resize \"${W}x${H}^\" -gravity center -extent \"${W}x${H}\" \"$UP\"  # 缩放填满后居中裁\n  elif command -v sips &gt;/dev/null 2&gt;&amp;1; then\n    cp \"$SRC\" \"$UP\"\n    sw=$(sips -g pixelWidth \"$UP\" | awk '/pixelWidth/{print $NF}')\n    sh=$(sips -g pixelHeight \"$UP\" | awk '/pixelHeight/{print $NF}')\n    if [ $((sw*H)) -ge $((sh*W)) ]; then sips --resampleHeight \"$H\" \"$UP\" &gt;/dev/null\n    else sips --resampleWidth \"$W\" \"$UP\" &gt;/dev/null; fi\n    sips -c \"$H\" \"$W\" \"$UP\" &gt;/dev/null   # sips -c 是 高 宽，居中裁\n  else\n    echo \"无 magick/convert/sips，跳过；手动把 $SRC 居中裁剪+缩放到 $TARGET 再上传\" &gt;&amp;2\n  fi\n  [ -f \"$UP\" ] &amp;&amp; file \"$UP\"\nfi\n</code></pre>\n<blockquote>\n<p>书名/笔名已在提示词里留中心安全区，居中裁剪不会切到。</p>\n</blockquote>\n<h3>Step 6：质量检查 + 迭代</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">检查项</th>\n<th style=\"text-align: left\">标准</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">文字渲染</td>\n<td style=\"text-align: left\">书名清晰可辨，字体风格匹配题材</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">题材匹配</td>\n<td style=\"text-align: left\">视觉风格与书名题材一致</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">构图合理</td>\n<td style=\"text-align: left\">主体突出，文字不遮挡核心画面</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">平台适配</td>\n<td style=\"text-align: left\">符合目标平台的封面风格调性</td>\n</tr>\n<tr>\n<td style=\"text-align: left\">平台尺寸</td>\n<td style=\"text-align: left\">比例与平台一致；缩放到上传尺寸后书名、笔名完整可见、未被裁切</td>\n</tr>\n</tbody>\n</table>\n<p>不满意时调整方向：更换构图、调整色调、换字体风格、换平台风格。</p>\n<p>交付时这样告诉作者；命令、环境变量和接口报错不贴给作者，失败时用一句话说原因和办法（如「生图接口没配好，需要先设置 API Key」）：</p>\n\n<pre><code>封面做好了：`{封面图路径}`{；{平台}上传版（{上传尺寸}）：`{上传版路径}`}\n这版的思路：{构图 + 色调 + 书名字体，一句话}\n想调的话可以说：{2-3 个具体方向，如「换成人物特写」「书名改成毛笔字」}\n</code></pre>\n<hr>\n<h2>参考资料</h2>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">文件</th>\n<th style=\"text-align: left\">何时加载</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\"><a href=\"references/cover-styles.md\">references/cover-styles.md</a></td>\n<td style=\"text-align: left\">题材→视觉风格映射、平台风格详情、提示词模板</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>语言</h2>\n<ul>\n<li>跟随用户的语言回复，用户用什么语言就用什么语言回复</li>\n<li>中文回复遵循《中文文案排版指北》</li>\n</ul>\n","files":[{"path":"references/cover-styles.md","sizeBytes":8992,"isText":true},{"path":"SKILL.md","sizeBytes":16881,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-10-02T16:33:27.964592Z","sha256":"97AD56DA2795695C273571DBBDE6073B728797E0BB0280DB820D0A5228A83846","sizeBytes":12882},"review":null,"source":{"repositoryUrl":"https://github.com/zenstory-ai/oh-story-dsh","path":"packages/knowledge/oh-story/skills/story-cover","license":"MIT","commit":"d734089bae893783d8bfaf09f8e8fa0a99723ef0","subtreeSha":"2103D1F977D544908CB839A99C67C5DC7E8623D018493F91BAD53FB6B45E0692","lastSyncedAt":"2026-10-02T16:32:40.531554Z"},"reviewedAt":"2026-10-02T16:34:37.625718Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/zenstory-ai/oh-story-dsh/tree/main/packages/knowledge/oh-story/skills/story-cover"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install zenstory-ai-oh-story-dsh@llmmart"},{"target":"git","command":"git clone https://github.com/zenstory-ai/oh-story-dsh.git"}]}