固化水印自动对比色与 alpha70 默认规则

main
MAOMOMO Skill Bot 2026-06-29 13:42:06 +00:00
parent 846715d173
commit 80f95f9ce5
4 changed files with 26 additions and 16 deletions

View File

@ -141,7 +141,7 @@ GitHub 交付配置:
- 多张 3:4 或 9:16 独立 PNG - 多张 3:4 或 9:16 独立 PNG
- `prompts/`、`slide_jobs.json`、`slide_run_state.json` - `prompts/`、`slide_jobs.json`、`slide_run_state.json`
- `final_manifest.json` - `final_manifest.json`
- 可选 `watermarked_assets/`:用 `uv run python scripts/maomomo_tile_watermark.py` 生成 `MAOMOMO.COM` 45° 色半透明平铺水印版 - 可选 `watermarked_assets/`:用 `uv run python scripts/maomomo_tile_watermark.py` 生成 `MAOMOMO.COM` 45° 自动对比色半透明平铺水印版
- GitHub 分批链接 - GitHub 分批链接
GitHub 分批交付前,技能会先引导配置: GitHub 分批交付前,技能会先引导配置:
@ -188,7 +188,7 @@ GitHub 分批交付前,技能会先引导配置:
- 涉及金融、券商、银行、数字货币和合规内容时,保留谨慎措辞 - 涉及金融、券商、银行、数字货币和合规内容时,保留谨慎措辞
- 配图统一使用白橘猫、暖橙色、干净金融科技教程风 - 配图统一使用白橘猫、暖橙色、干净金融科技教程风
- 如果用户没有指定配图风格,先在 `recommended-styles.md``image-styles/` 中按文章类型推荐 2-3 个方向,例如 `clean-professional`、`data-card-dashboard`、`handdrawn-note`、`e-ink-editorial` 或 `xiaohongshu-vertical` - 如果用户没有指定配图风格,先在 `recommended-styles.md``image-styles/` 中按文章类型推荐 2-3 个方向,例如 `clean-professional`、`data-card-dashboard`、`handdrawn-note`、`e-ink-editorial` 或 `xiaohongshu-vertical`
- 小红书卡片出图前必须确认 `2D 扁平风` / `3D 轻拟物风``3:4` / `9:16`;用户没指定时默认推荐 2D并按原生竖版重新构图不能把横版图压进竖图。用户要求防盗图 / 水印时,可用 `uv run python scripts/maomomo_tile_watermark.py --input assets --output watermarked_assets` 生成 `MAOMOMO.COM` 45° 色半透明平铺水印版,并保留无水印原图。 - 小红书卡片出图前必须确认 `2D 扁平风` / `3D 轻拟物风``3:4` / `9:16`;用户没指定时默认推荐 2D并按原生竖版重新构图不能把横版图压进竖图。用户要求防盗图 / 水印时,可用 `uv run python scripts/maomomo_tile_watermark.py --input assets --output watermarked_assets` 生成 `MAOMOMO.COM` 45° 自动对比色半透明平铺水印版,并保留无水印原图。
文章不应当: 文章不应当:

View File

@ -17,7 +17,7 @@ description: 生成或优化符合 maomomo / 猫MOMO 风格的中文出海金融
- 活动规则整理、开户教程、转账 / 入金 / 出金教程、保号方案、用卡姿势、对比总结、避坑经验。 - 活动规则整理、开户教程、转账 / 入金 / 出金教程、保号方案、用卡姿势、对比总结、避坑经验。
- 已有文章 SEO 优化、发布用 Markdown、配图规划、独立配图、ZIP 打包和后续改稿。 - 已有文章 SEO 优化、发布用 Markdown、配图规划、独立配图、ZIP 打包和后续改稿。
- 小红书卡片、多图信息卡、3:4 或 9:16 竖版 PNG 系列图、封面 / 内容卡 / 结尾卡分批交付。 - 小红书卡片、多图信息卡、3:4 或 9:16 竖版 PNG 系列图、封面 / 内容卡 / 结尾卡分批交付。
- 对最终配图批量或单张叠加 `MAOMOMO.COM` 45° 色半透明平铺水印。 - 对最终配图批量或单张叠加 `MAOMOMO.COM` 45° 自动对比色半透明平铺水印。
不适合: 不适合:
@ -51,7 +51,7 @@ description: 生成或优化符合 maomomo / 猫MOMO 风格的中文出海金融
- 图片交付完成后必须生成或更新 `final_manifest.json`,最终推送、打包或链接交付只能读取 `final_manifest.json` 或状态文件里明确标记为 final 的 assets不得把 `draft`、`v2`、旧比例、失败图或未通过 QA 的图一起交付。 - 图片交付完成后必须生成或更新 `final_manifest.json`,最终推送、打包或链接交付只能读取 `final_manifest.json` 或状态文件里明确标记为 final 的 assets不得把 `draft`、`v2`、旧比例、失败图或未通过 QA 的图一起交付。
- 面向 Telegram / 聊天渠道的大文件交付默认改为 GitHub 分批推送:例如 `batch-01-cover`、`batch-02-content-cards`、`batch-03-final-assets`。Telegram 只负责通知进度和给 GitHub 文件路径、commit、release 或下载链接,不承载大 ZIP 或大图片包。 - 面向 Telegram / 聊天渠道的大文件交付默认改为 GitHub 分批推送:例如 `batch-01-cover`、`batch-02-content-cards`、`batch-03-final-assets`。Telegram 只负责通知进度和给 GitHub 文件路径、commit、release 或下载链接,不承载大 ZIP 或大图片包。
- 需要 GitHub 分批交付,或用户提到 GitHub 仓库、专用 KEY、token、PAT、deploy key 时,必须先读 `references/github-delivery.md`,引导配置专用私有交付仓库和最小权限凭据;不得要求用户在聊天里粘贴密钥,不得把 token / 私钥写入 prompt、manifest、状态文件、README、日志或提交记录。 - 需要 GitHub 分批交付,或用户提到 GitHub 仓库、专用 KEY、token、PAT、deploy key 时,必须先读 `references/github-delivery.md`,引导配置专用私有交付仓库和最小权限凭据;不得要求用户在聊天里粘贴密钥,不得把 token / 私钥写入 prompt、manifest、状态文件、README、日志或提交记录。
- 用户要求“水印”“平铺水印”“防盗图”“打水印”时,先读 `references/visual-assets.md` 的平铺水印规则;水印只处理最终 QA 通过的交付图或交付副本,默认保留无水印原图。水印必须用 `uv run python scripts/maomomo_tile_watermark.py` 生成,不得手工覆盖。 - 用户要求“水印”“平铺水印”“防盗图”“打水印”时,先读 `references/visual-assets.md` 的平铺水印规则;水印只处理最终 QA 通过的交付图或交付副本,默认保留无水印原图。水印必须用 `uv run python scripts/maomomo_tile_watermark.py` 生成,不得手工覆盖。默认自动对比色:浅底黑字、深底白字;默认 alpha=70、font-size=50、spacing=28每张图至少可见 2 个完整 `MAOMOMO.COM`
- 每张图都必须在状态文件记录prompt 文件、生成结果、QA 状态、是否进入 `assets/`、是否已推送 GitHub。中断恢复时先读状态文件和 `final_manifest.json`,不要依赖聊天记忆。 - 每张图都必须在状态文件记录prompt 文件、生成结果、QA 状态、是否进入 `assets/`、是否已推送 GitHub。中断恢复时先读状态文件和 `final_manifest.json`,不要依赖聊天记忆。
- 配图文件必须是独立 PNG不要用一张大拼图代替多张图不要只给提示词冒充图片文件。 - 配图文件必须是独立 PNG不要用一张大拼图代替多张图不要只给提示词冒充图片文件。
- 后续改稿必须更新文件本体;影响图片、来源区、标题、摘要或 ZIP 时同步更新。 - 后续改稿必须更新文件本体;影响图片、来源区、标题、摘要或 ZIP 时同步更新。

View File

@ -28,10 +28,11 @@
- 水印文字:`MAOMOMO.COM` - 水印文字:`MAOMOMO.COM`
- 角度45° - 角度45°
- 颜色:白色 `#FFFFFF` - 颜色:自动对比色:浅底黑字 `#000000`,深底白字 `#FFFFFF`
- 透明度:半透明,默认 alpha `72/255` - 透明度:半透明,默认 alpha `70/255`
- 排列:对角线平铺 - 排列:对角线平铺
- 工具:`uv run python scripts/maomomo_tile_watermark.py` - 工具:`uv run python scripts/maomomo_tile_watermark.py`
- 密度:每张图至少可见 2 个完整 `MAOMOMO.COM`;默认 `font-size=50`、`spacing=28`。
执行示例: 执行示例:
@ -54,7 +55,7 @@ uv run python scripts/maomomo_tile_watermark.py \
- 水印只加到最终 QA 通过的 `assets/` 或交付副本;不要在样张确认前加水印,避免影响用户判断画面文字质量。 - 水印只加到最终 QA 通过的 `assets/` 或交付副本;不要在样张确认前加水印,避免影响用户判断画面文字质量。
- 默认保留无水印原图在 `origin_image/` 和 / 或 `assets/`;水印图输出到 `watermarked_assets/`,或 GitHub 交付批次中的 `watermarked/` - 默认保留无水印原图在 `origin_image/` 和 / 或 `assets/`;水印图输出到 `watermarked_assets/`,或 GitHub 交付批次中的 `watermarked/`
- 不要对官方截图证据原图、需要继续发给图片模型编辑的素材、尚未 QA 的图直接覆盖水印。 - 不要对官方截图证据原图、需要继续发给图片模型编辑的素材、尚未 QA 的图直接覆盖水印。
- `final_manifest.json` 应记录 `watermark` 字段,至少包含 `text`、`angle`、`color`、`alpha`、`output_dir` 和水印文件清单。 - `final_manifest.json` 应记录 `watermark` 字段,至少包含 `text`、`angle`、`color_rule`、`brightness_threshold`、`alpha`、`font_size`、`spacing`、`density_rule`、`output_dir` 和水印文件清单。
- 交付回复中说明是否提供水印版,以及无水印原图是否保留。 - 交付回复中说明是否提供水印版,以及无水印原图是否保留。
## 可见文字与 prompt 边界 ## 可见文字与 prompt 边界

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""为 MAOMOMO 配图叠加 45° 平铺半透明水印。 """为 MAOMOMO 配图叠加 45° 平铺半透明水印。
默认水印MAOMOMO.COM白色半透明45° 对角线平铺 默认水印MAOMOMO.COM45° 对角线平铺自动对比色浅底黑字深底白字
用法 用法
uv run python scripts/maomomo_tile_watermark.py --input assets --output watermarked_assets uv run python scripts/maomomo_tile_watermark.py --input assets --output watermarked_assets
@ -48,14 +48,24 @@ def ensure_pillow() -> Tuple[Any, Any, Any]:
def parse_color(value: str) -> Tuple[int, int, int]: def parse_color(value: str) -> Tuple[int, int, int]:
text = value.strip() text = value.strip()
if text.lower() == "auto":
die("auto color must be resolved after reading each image")
if text.startswith("#"): if text.startswith("#"):
text = text[1:] text = text[1:]
if len(text) != 6: if len(text) != 6:
die("颜色必须是 #RRGGBB例如 #FFFFFF") die("颜色必须是 auto 或 #RRGGBB例如 #000000 / #FFFFFF")
try: try:
return tuple(int(text[i : i + 2], 16) for i in (0, 2, 4)) # type: ignore[return-value] return tuple(int(text[i : i + 2], 16) for i in (0, 2, 4)) # type: ignore[return-value]
except ValueError: except ValueError:
die("颜色必须是有效十六进制,例如 #FFFFFF") die("颜色必须是有效十六进制,例如 #000000 / #FFFFFF")
def auto_contrast_color(image_path: Path, threshold: float = 150.0) -> Tuple[int, int, int]:
Image, _, _ = ensure_pillow()
with Image.open(image_path) as src:
r, g, b = src.convert("RGB").resize((1, 1)).getpixel((0, 0))
luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
return (0, 0, 0) if luminance >= threshold else (255, 255, 255)
def load_font(ImageFont: Any, font_path: Optional[str], font_size: int) -> Any: def load_font(ImageFont: Any, font_path: Optional[str], font_size: int) -> Any:
@ -173,11 +183,11 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("--output", required=True, help="输出图片文件或目录。目录模式会保持相对路径。") parser.add_argument("--output", required=True, help="输出图片文件或目录。目录模式会保持相对路径。")
parser.add_argument("--text", default="MAOMOMO.COM", help="水印文字,默认 MAOMOMO.COM。") parser.add_argument("--text", default="MAOMOMO.COM", help="水印文字,默认 MAOMOMO.COM。")
parser.add_argument("--angle", type=float, default=45.0, help="水印旋转角度,默认 45。") parser.add_argument("--angle", type=float, default=45.0, help="水印旋转角度,默认 45。")
parser.add_argument("--alpha", type=int, default=72, help="透明度 0-255默认 72") parser.add_argument("--alpha", type=int, default=70, help="透明度 0-255默认 70")
parser.add_argument("--color", default="#FFFFFF", help="水印颜色,默认 #FFFFFF。") parser.add_argument("--color", default="auto", help="水印颜色,默认 auto浅底黑字、深底白字也可指定 #000000 / #FFFFFF。")
parser.add_argument("--font-size", type=int, default=42, help="字体大小,默认 42") parser.add_argument("--font-size", type=int, default=50, help="字体大小,默认 50")
parser.add_argument("--font", default=None, help="可选字体路径。") parser.add_argument("--font", default=None, help="可选字体路径。")
parser.add_argument("--spacing", type=int, default=120, help="水印间距 / 内边距,默认 120") parser.add_argument("--spacing", type=int, default=28, help="水印间距 / 内边距,默认 28目标是每张图至少可见 2 个完整 MAOMOMO.COM")
parser.add_argument("--quality", type=int, default=95, help="JPG/WEBP 输出质量,默认 95。") parser.add_argument("--quality", type=int, default=95, help="JPG/WEBP 输出质量,默认 95。")
return parser return parser
@ -187,7 +197,6 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
args = parser.parse_args(list(argv) if argv is not None else None) args = parser.parse_args(list(argv) if argv is not None else None)
input_path = Path(args.input).expanduser().resolve() input_path = Path(args.input).expanduser().resolve()
output_path = Path(args.output).expanduser().resolve() output_path = Path(args.output).expanduser().resolve()
color = parse_color(args.color)
images = list(iter_images(input_path)) images = list(iter_images(input_path))
if not images: if not images:
die(f"没有找到支持的图片:{input_path}") die(f"没有找到支持的图片:{input_path}")
@ -202,7 +211,7 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
text=args.text, text=args.text,
angle=args.angle, angle=args.angle,
alpha=args.alpha, alpha=args.alpha,
color=color, color=auto_contrast_color(image_path) if str(args.color).lower() == "auto" else parse_color(args.color),
font_size=args.font_size, font_size=args.font_size,
font_path=args.font, font_path=args.font,
spacing=args.spacing, spacing=args.spacing,