城市画像(双页:产业 + 高校)
> 首次使用先自检:python scripts/check_env.py
> 本包(skillHub 版)不含字体二进制,毛笔字体以 base64 分片存放在 assets/fonts/part-*.txt,
> 缺失时 check_env.py 会自动调用 scripts/restore_font.py 还原(约 2 秒)。
> 如需含字体的版本,请向作者要 city-core-poster-share.zip。
> 出品标准见 references/standards.md(v1.1):画布、字号阶梯、卡片高度、数量上限、排序、
> 配色、数据来源、素材规则、命名、六条禁令。任何城市图都要过 scripts/check_standard.py 才算交付。
产出什么
两张竖版长图(宽固定 1080,高度按内容自动加长,出图 ×2):
| 图 | 顶部 | 主体 | 底部 |
|---|---|---|---|
-产业.png |
毛笔字城市名(朱红印章、墨色肌理)+ 省份 + 拼音 + 一句话定位 + 3~4 个指标 | 产业卡片列表(名称、规模量级、一句话、性质标签、代表企业 2~6 家,放不下自动折行),最多 12 项 | 城市地标剪影 + 水面倒影 |
-manifest.json |
— | 记录数据哈希、配色/素材参数、输出尺寸、全部质检项(用于系列一致性与复检) | |
-高校.png |
同款毛笔字印记 + 章节备注 | 高校卡片列表(关键字印章、序号、校名、层次标签、优势专业),按 985→211→双一流→省重点 自上而下,最多 20 所 | 同款剪影 + 层次图例 |
高度不固定:内容少时按 9:16(1920 高)出,内容多时自动加长——6 项产业约 2025,18 所高校约 3331(1:3.1),
手机上就是往下滑,不需要翻页。宽度始终 1080,保证字号在手机屏上够大。
为什么不做表格:表格要在 1080 宽里塞 5 列,正文只能给到 11px;单列卡片能把正文提到 25px。
工作流(四步,不可跳步)
第 1 步 · 锁定城市
规范成地级市及以上正式名(南京市、苏州市、深圳市)。县级市并入其地级市,或按用户意图保留并在 city 写全称。用户给省份时反问具体城市。
第 2 步 · 联网核实(强制)
用 WebSearch 查两类事实,不许凭记忆填数字:
- 核心产业:
<城市> 2025 主导产业 产值 规模 国家级先进制造业集群
- 取政府工作报告 / 统计局公报 / 工信局年度报告
- 每项要有「规模量级」(1 万亿+、5000 亿+)或明确集群身份;查不到就换产业
- 数量:一般 5~8 项;产业门类齐全的大城市可到 10 项 - 核心高校 + 优势专业:
<城市> 双一流 高校 名单、<城市> 985 211 大学
- 只算本市校区,异地校区不冒充
- 层次标签:985/211/双一流(可叠加);省属重点写省重点
-majors优先用教育部双一流建设学科名单里的学科名(最权威、可核验);名校再补 1~2 个公认王牌方向
- 排序:985 → 211 → 双一流 → 省重点;同层次按一流学科数量降序
- 数量:上限 20 所(超出的在uni_note里交代总数),全部排进同一张图 - 顺带核实 2~4 个 KPI:GDP、三产占比、规上工业/高新技术产业产值
查证结果写进 source。
第 2.5 步 · 院校核验(底线,不可跳过)
每年都有学校更名,写错校名比写错数字更伤信任。 逐所核一遍再写数据:
- 现行校名:以教育部《全国高等学校名单》(最新年度)+ 学校官网首页标题为准,写全称。
- 近三年更名:搜
<旧校名> 更名 教育部 批复。常见两类:学院→大学、独立学院→公办本科。 - 机器拦截:
assets/school-renames.json存了已知更名对照,渲染时用旧名会直接告警。
例:常熟理工学院→ 2025 年已更名为苏州工学院(教发函〔2025〕26 号)。 - 依据落库:数据里填
verified_at(核验日期)与schools_source(依据),缺了会告警。 - 优势专业按可信度取:双一流建设学科 > 国家级一流本科专业建设点 > 学科评估 > 定性描述;
拿不准就写"XX 见长",不要编具体专业名。
第 3 步 · 写数据 JSON
字段细节见 references/data-spec.md。最小形态:
{
"city": "南京市", "en": "NANJING", "province": "江苏省",
"tagline": "全国首个「中国软件名城」 · 长三角科教重镇",
"industries": [{"name": "软件和信息服务", "scale": "1 万亿+", "tag": "国家级集群",
"desc": "首个中国软件名城,涉软企业超 6 万家",
"players": ["华为南京研究所", "中兴通讯"]}],
"universities": [{"name": "南京大学", "tags": ["985","211","双一流"],
"majors": "天文学、地质学、中国语言文学 等 16 个"}],
"source": "南京市统计局 2025 年公报;教育部第二轮双一流名单"
}
写到临时文件,如 /tmp/<城市>.json。
第 4 步 · 一键出图 + 质检
不要手工拼命令,用 make_city.py:它按标准依次做完「校验 → 素材 → 渲染 → 质检 → 记录」,
任何一步不过都会明确打出来,并按结果返回退出码。
PY=/Users/davidtqy/.workbuddy/binaries/python/envs/default/bin/python
SK=~/.workbuddy/skills/city-core-poster
$PY $SK/scripts/make_city.py --data /tmp/nanjing.json --out ~/WorkBuddy/南京市
输出:
── 出图:南京市 ──
① 数据校验 ✓ 字段与来源均合规
② 素材 页头大图:缓存命中 · 南京.jpg
底部剪影:实图蒙版 · 南京.png(缓存命中)
③ 渲染 ✓ 南京市-产业.png 2160×4338 884KB
✓ 南京市-高校.png 2160×6662 1201KB
④ 质检 ✓ 全部合格
⑤ 记录 南京市-manifest.json
✓ 出品合格|南京市|2160×4338 / 2160×6662
- 退出码
0= 合格(可能有警告);1= 有硬性不合格(来源非官方、超上限、长宽比超限…)。
退出码非 0 就不要交付,先按提示修数据。 --strict:有警告也算不合格(自己严格把关时用)。- 事后复检:
$PY $SK/scripts/check_standard.py --manifest ~/WorkBuddy/南京市-manifest.json
第 5 步 · 交付
用 present_files 把两张图一起给出,附一句结论(最硬的产业 / 最强的学校),
并把 -manifest.json 一并留给用户——里面记着数据哈希、参数、素材出处、所有质检项,
下次同一座城市重出图时可以对比参数,保证系列一致。
数据来源(硬性要求)
所有数据必须来自官方公开发布的文件。 这是这个技能的底线,不是建议。
只认这些来源(白名单)
| 类别 | 具体文件 |
|---|---|
| 经济与产业 | 市/省统计局《国民经济和社会发展统计公报》《经济运行情况》;政府工作报告;统计年鉴 |
| 产业专项 | 工信局/发改委年度报告、产业集群名单(国家级先进制造业集群)、产业链行动方案 |
| 高校与学科 | 教育部《双一流建设高校及建设学科名单》、全国高校名单、学科评估结果 |
| 城市定位 | 国务院/发改委规划批复(如"国家中心城市""综合性国家科学中心") |
| 企业 | 上市公司公告、企业官网/官网招聘页;不要用招聘网站的二手信息 |
这些一律不用(黑名单)
百度百科、维基百科、知乎、公众号、小红书、自媒体榜单、"XX 之最"类营销稿、招聘/房产网站、
培训机构宣传页。这些可以作为找线索的起点,但必须回到官方原文核对才能写进数据。
三条硬规则
- 每个数字都要能指回一份官方文件。
source字段写清「文件名 + 年份 + 发布单位」,
例:南京市统计局《2025 年南京经济运行情况》;教育部《第二轮双一流建设高校及建设学科名单》。 - 年份必须标注且统一。
year写数据年份;产业规模、GDP 用同一年份,不要混用 2024 与 2025。 - 查不到就留空,不许估算、不许转述"据说"。宁可少一条产业,也不能出现无法溯源的数字。
交付前自检(逐条过)
- [ ]
source是否写明发布单位与年份?是否含"统计局/教育部/政府工作报告"等官方字样? - [ ] 每个
scale数字能否在source对应的文件里找到? - [ ] 高校名单是否来自教育部双一流名单(而不是学校招生简章)?
- [ ]
majors是否取自建设学科名单,而非自拟专业名? - [ ] 是否有任何一条来自百科/自媒体却未回原文核对?
渲染时会自动检查 source 是否包含官方字样,缺失或不含官方关键词会打印 ⚠ 提示。
关键字印章(学校前面那个圈)
每所高校卡片左侧是一个圆形印章:纸白圆盘 + 城市色描边 + 书法字。不贴真实校徽。
取字规则(按优先级,三步)
① 先看学科方向——这类字最直观,一眼能认出学校是干什么的:
| 校名含 | 取字 | 校名含 | 取字 | 校名含 | 取字 |
|---|---|---|---|---|---|
| 医科 / 医学 | 医 | 工业 / 工程 | 工 | 师范 | 师 |
| 中医药 | 中 | 理工 | 理 | 农业 | 农 |
| 药科 / 药学 | 药 | 科技 | 科 | 林业 | 林 |
| 财经 | 财 | 建筑 | 建 | 商业 | 商 |
| 政法 | 法 | 外国语 | 外 | 金融 | 金 |
| 经济 | 经 | 音乐 | 音 | 体育 | 体 |
② 再看校名主干:跳过「南京/北京/中国/华东/东北」等地名与大区前缀,取第一个有辨识度的字。
例:河海→河、南京邮电→邮、南京审计→审、黑龙江大学→黑。
③ 同册重字时扩成两字(按以下顺序级联,保证一定收敛、绝不出三字以上):
学科关键词原样(2字) → 前缀+学科字 → 学科字+主干末字 → 学科字+"大" → 主干末两字 → 主干前两字 → 校名前两字
例(哈尔滨册):哈尔滨工业大学→工业、哈尔滨工程大学→工程(同属"工",故用关键词全称区分)、
哈尔滨医科大学→医、黑龙江中医药大学→中、东北林业大学→林、黑龙江科技大学→科、
黑龙江工程学院→黑工("工"已被占用,退到第 2 档)。结果必须无重复、无三字。
> 想手工指定某一所,直接在数据里加 "badge": "医" 字段,优先级最高(渲染时不再推导)。
> 为什么不贴真校徽:实测自动抓取命中率约 3/17,大量抓到校门照片、「LOGO 代找」广告和城市夜景,
> 贴错比不贴更伤可信度;而逐校人工核对成本过高。印章方案识别度够、永不出错。
顶部地标大图(默认自动抓取)
页头会铺一张城市实景照片:约占设计高 384px(1080 宽基准),整体压暗 + 带内自下而上再压暗
+ 设计 y≈305 处彻底淡出,毛笔字压在上面,章节标题与所有卡片都落在干净底上。
取图顺序(--hero 参数)
| 取值 | 行为 |
|---|---|
auto(默认) |
缓存有合格图就用缓存;没有或分辨率不足(<1280×480)→ 现场自动抓一张 |
none |
不用照片,返回「地标剪影底纹」版式(不是纯色板,仍有城市轮廓) |
<路径> |
用指定图片(人工挑选时用) |
抓图自带两级门槛:先按「清晰档」1280×480 挑,全军覆没才退到「勉强档」900×340 并标注偏小;
两档都没有就回退剪影底纹,命令行会明确提示可用 --hero 路径 手动补图。绝不把糊图铺上去。
照片择优维度:够宽 ≥1920 优先、横版、上部 26% 区域越均匀越好(毛笔字要压得住)。
取景竖向偏上(HERO_CROP_BIAS=0.30),多留天空、避开地面灯火 —— 夜景城市(如哈尔滨)
最容易出现"灯火把标题冲成一片灰",这个偏移就是为它设的。
- 照片要求:横版、2000px 宽以上、主体在中部或右侧(左上角会被毛笔字压住)。
- 不要用轮廓线稿冒充照片,糊成一片反而更难看。
> 可调旋钮集中在 render_city_poster.py 顶部 HERO_* 常量:深度、取景偏置、压暗量、
> 下沿额外压暗、完全不透明/彻底透明的设计 y。改一处即全局生效。
城市印记与剪影
- 顶部毛笔字用马善政毛笔楷书(
assets/fonts/MaShanZheng-Regular.ttf,SIL OFL 1.1,见同目录OFL.txt),
配朱红印章与墨色噪点肌理;字体缺失时自动退到宋体粗。
底部剪影:优先用矢量库,可被实图替换
内置 18 城(北京/上海/广州/深圳/杭州/南京/苏州/成都/重庆/武汉/西安/天津/长沙/青岛/厦门/哈尔滨/南昌/郑州),
每城按「一个主标志物当锚点(占高 0.75~1.0)+ 背景楼群压低」绘制:
南京是紫峰+明城墙+南京眼双环,广州是小蛮腰,青岛是太平山电视塔,哈尔滨是圣索菲亚,
苏州是东方之门……没用收录的城市走程序化天际线。
想换成实图剪影:把「白形状 + 透明底」的 PNG 放到 ~/.cache/city-core-poster/skylines/<城市>.png,
渲染时自动优先使用;也可以 --skyline-image 路径 --skyline-dir 目录 指定。
抓取素材:scripts/fetch_city_art.py
PY=/Users/davidtqy/.workbuddy/binaries/python/envs/default/bin/python
$PY scripts/fetch_city_art.py --city 南京 # 抓剪影 → 蒙版
$PY scripts/fetch_city_art.py --city 南京 --kind photo # 抓实景照片(页头大图)
$PY scripts/fetch_city_art.py --data <json> --sheet /tmp/qc.png # 出核对图
实测结论(2026-10):
| 目标 | 成功率 | 说明 |
|---|---|---|
| 实景照片(做页头大图) | 约 100% | 城市风光照片充足、多无水印,2000px 以上可挑 |
| 剪影图(做底部蒙版) | ~1/17 | 搜到的"城市剪影"绝大多数其实是照片或带水印的商稿;只有少数设计图可用 |
所以默认路线是:页头用实拍照片 + 底部用矢量剪影。剪影抓取当"碰运气",抓到好的就换掉。
关于水印(重要)
不做任何"擦水印"处理。 带水印的素材要么整张不用,要么只取它真正的剪影本体
(阈值 + 只保留最大连通块,淡色水印与文字会自然被排除,不是"抹掉")。
抓到的素材只在本地缓存(~/.cache/city-core-poster/),交付图里建议在 source 里附一句素材出处;
这些图仅供小范围非商业使用,公开发布前请自行确认授权。
配色:一城一色(默认,不用手挑)
每座城市有一个固定色相,取自这座城市最被认得的视觉符号,并归入 8 个色系,避免深底上发脏的黄绿区。
同一座城市永远同色——同一批图发出去,家长一眼能看出是"一套城市系列"。
| 城市 | 色相 | 取色依据 | 城市 | 色相 | 取色依据 |
|---|---|---|---|---|---|
| 北京 | 6° 朱红 | 故宫宫墙 | 深圳 | 210° 科技青 | 鹏城 · 科创 |
| 广州 | 18° 陶红 | 木棉花 | 苏州 | 220° 黛瓦青 | 园林屋瓦 |
| 西安 | 30° 赭石 | 城墙与黄土 | 天津 | 236° 海河靛 | 海河夜景 |
| 重庆 | 46° 琥珀 | 山城灯火 | 武汉 | 250° 长江蓝 | 长江 · 江城 |
| 郑州 | 168° 青铜绿 | 二七塔铜锈 | 上海 | 268° 霓虹紫蓝 | 外滩霓虹 |
| 成都 | 126° 竹青 | 望江楼竹海 | 南京 | 286° 紫金 | 紫金山 · 金陵 |
| 杭州 | 152° 湖绿 | 西湖 | 长沙 | 325° 湘绣品红 | 湘绣 · 辣椒 |
| 厦门 | 178° 海碧 | 环岛路海色 | 南昌 | 345° 红都红 | 八一 · 红都 |
| 青岛 | 188° 海蓝 | 黄海海天 | 哈尔滨 | 198° 冰蓝 | 冰雪节 |
- 未收录城市:归入同色系(如济南 214°、合肥 232°),或按城市名 CRC32 哈希取色。
- 自动做两件补偿:紫/品红区间降饱和(深底易发荧光)、第二强调色冷暖对撞(冷色配金、暖色配冰蓝)。
- 背景亮度默认 1.15(明亮但不刺眼);要更亮
--brightness 1.3,要更沉0.95。 - 需要整册统一色调时仍可
--theme ocean|ink|pine|ember(此时忽略城市取色)。 - 改某城颜色:编辑
scripts/render_city_poster.py的CITY_HUE,改一个 0~360 的数字。
常用参数
make_city.py(推荐入口):
--data x.json 城市数据(必填)
--out ~/WorkBuddy/南京市 输出前缀(必填)
--scale 2 输出倍率(2=2160 宽手机高清,默认;1=1080 快速预览)
--hero auto 页头实景图:auto(默认,缺图自动抓)/ none / 图片路径
--skyline auto 底部剪影:auto(有缓存蒙版就用)/ none(用矢量)/ 图片路径
--format jpg jpg(默认,体积小、微信直发)/ png(文字最锐,印刷或二次编辑)
--brightness 1.15 背景亮度(1.3 更亮 / 0.95 更沉)
--theme ink 固定风格,覆盖城市取色
--strict 有警告也算不合格
render_city_poster.py(单页调试用,多了这几个):
--pages both 产业 + 高校(默认);industry / university 单出
--width / --height 默认 1080×1920;版式按宽度等比缩放,改宽不失衡
--ss 1.4 额外超采样,边缘更柔(耗时 ×2)
--no-reflect 关闭水面倒影
排障
| 现象 | 处理 |
|---|---|
| 某行文字被「…」截断 | 该字段过长:产业 desc ≤20 字、高校 majors ≤30 字(超了会告警) |
| 页头是纯色板、没有实景图 | 抓图没成功。看命令行 页头大图: 那行;--hero 图片路径 手动补一张横版大图 |
| 页头照片糊 | 抓到的图分辨率不够(应 ≥1280×480);换一张 2000px 宽的,或 --hero 指定 |
| 页头把标题/数据卡冲成一片灰 | 照片亮区正好在文字位。默认已做自适应压暗;换主体偏右下的图更快 |
| 印章字是「黑龙」这类地名 | 旧版行为,现已按学科方向取字(医/工/师/农…);也可在数据里写 "badge": "医" |
| 图太长 | 正常:条目多时自动加长,宽度不变、字号不变;嫌长就减条目 |
| 想固定比例 | --height 1920 会强制裁到 9:16,条目多时会被压缩,不建议 |
| 质检报「长宽比超限」 | 高/宽 > 4.3,说明条目太多;按标准精简到产业 ≤12、高校 ≤20 |
| 质检报「数据来源」 | source 必须含统计局/教育部/政府工作报告等官方字样,且不能带百科/自媒体 |
| 毛笔字变成宋体 | assets/fonts/MaShanZheng-Regular.ttf 缺失,跑 scripts/restore_font.py |
| 剪影不像该城市 | 该城未收录,用 --skyline-image 或按 references/skyline-authoring.md 新增 |
| 中文全成方块 | 系统缺字体,回退链为 STHeiti → Hiragino Sans GB → Songti,macOS 均内置 |