18 次代码提交
作者 SHA1 备注 提交日期
dayu 58f09e5756 Record installed notarized 1.3.0 release, cleanup scope and source recovery; native visual QA remains with user 2026-10-22 15:18:06 +08:00
dayu 730d1755ca Record notarized 1.3.0 candidate and independently verified source recovery; installation waits for active user hosts 2026-10-22 15:08:58 +08:00
dayu 2f2c081980 Migrate new beauty controls with continuous protection, local detail recovery and legacy state compatibility; 1636 checks passed 2026-10-22 15:07:02 +08:00
dayu 2e79602761 Record new reference identity and unresolved body-slimming migration target 2026-10-22 14:12:30 +08:00
dayu 13821366a5 Add project handoff with verified release and development guidance 2026-10-22 14:01:12 +08:00
dayu 189a5d7634 Record verified public GitHub history and Release recovery; add GitHub links to article and restore instructions 2026-10-22 03:33:09 +08:00
dayu 356683b41a Prepare GitHub public source entry and consistent OpenAI/Codex writing attribution 2026-10-22 03:29:43 +08:00
dayu bea9bdfc0a Prepare explicit GitHub publication target and audited history; await target repository write authentication 2026-10-22 03:10:53 +08:00
dayu dffa547d92 Verify live article credits OpenAI and Codex and preserves download, SEO and publication settings 2026-10-22 02:02:36 +08:00
dayu acbe115c8a Clarify article code attribution to OpenAI and Codex; credit site owner only for debugging and testing 2026-10-22 02:01:00 +08:00
dayu abaea2b1df Finalize 1.2.0 public article, free download hashes, source snapshot and remote recovery evidence 2026-10-22 01:49:54 +08:00
dayu 788ba0d551 Validate source archive before upload and correct fixture attribution filename 2026-10-22 01:45:21 +08:00
dayu 2f7702fa20 Correct publisher REST prefix and standard media filename header before first upload 2026-10-22 01:44:24 +08:00
dayu 3c7261c3a8 Add notarized 1.2.0 release installer, isolated update/rollback verification and publication materials 2026-10-22 01:43:55 +08:00
dayu 5ac0e5833c Record signed 1.2.0 install, launcher exit QA, locked template and public-repository gateway limitation 2026-10-22 01:40:30 +08:00
dayu 696d5f39b3 Prepare 1.2.0 classical artwork, free launcher with three-second exit and open-source licensing 2026-10-22 01:32:01 +08:00
dayu 906f770805 Record user acceptance of continuous slider preview in 1.1.2 build13 2026-10-22 00:55:37 +08:00
dayu fcfd8b0ddc Record independent v1.1.2 tag recovery and exact release SHA 2026-10-22 00:33:18 +08:00
共修改 71 个文件,包含 1862 行新增和 68 行删除

没有与搜索条件相匹配的文件

+3
查看文件
@@ -37,3 +37,6 @@ venv/
# Local reference binaries stay outside source history
reference-binaries/
# Reviewed signed release installer (intentional distribution artifact)
!releases/1.2.0/*.pkg
二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 2.6 MiB

+21
查看文件
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Dayu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+17 -3
查看文件
@@ -2,11 +2,15 @@
基于本仓库的 FxPlug4 初始工程制作的人像美化滤镜,支持 Motion 和 Final Cut Pro。源码使用 Objective-C、Vision、Core Image 与 Metal。
代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。
功能包括磨皮、肤色、细节、牙齿美白、眼睛提亮、九类脸型调整、自动人脸跟随和多人处理。原版 MSE18V2 的静态分析依据、近似实现与尚未对齐的部分见 [分析说明](docs/analysis/REA-分析与复刻说明.md)。本版尚未完成原版逐像素与复杂运动跟踪对照。
## 使用
正式安装路径为 `/Library/Plug-Ins/FxPlug/beatygril.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。
正式安装路径为 `/Library/Plug-Ins/FxPlug/beatygril.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。
1.3.0 的磨皮卡片依次提供「磨皮程度、微细锐化、五官保护、非肤色区保护」。两种保护默认 100%;降低五官保护让五官区域参与更多磨皮,降低非肤色区保护则扩大磨皮范围,均不扩大肤色提亮范围。微细锐化在局部支持区域恢复纹理;旧全局磨皮和全局锐化仍保留在更多设置,旧工程的参数与归档继续兼容。迁移证据、实现边界与验证见[新版磨皮参数迁移](docs/analysis/新版磨皮参数迁移.md)。1.3.0(15)APP 已完成签名、公证及正式安装,1636 项自动检查通过;原生宿主效果由用户实测。1.2.0 下载链接仍对应原发行包,本次未更新文章或安装包。
## 开发和恢复
@@ -21,7 +25,9 @@ xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application'
工程从 `/Library/Developer/SDKs/FxPlug.sdk` 读取头文件与链接信息,从 `/Library/Developer/Frameworks` 嵌入可运行的 Apple 框架。构建默认使用团队 B3W25FX5H5 的 Developer ID Application 身份;正式交付使用 `python3 scripts/deliver.py` 完成公证、粘附和安装;安装前先关闭 Motion 与 FCP,脚本在检测到宿主仍运行时保留原安装版并停止。原生验收完成后继续脚本的清理阶段,清除临时注册与 APP 副本。
私有源码仓库:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。
公开源码:[GitHub · FCP-BeatyGril](https://github.com/FAMEDaYu/FCP-BeatyGril)。大鱼站备份:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。
继续开发或移交时先读[项目交接文档](docs/项目交接.md),包含当前发布状态、源码入口、坐标与交互约定、验收边界,以及签名打包和双远端保存流程。
## 1.0.5 瘦脸修复
@@ -49,4 +55,12 @@ xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application'
面板改为先在真实视图的宿主 action 内取得读写接口,修复控件一直禁用的问题。短脸改用76点下半脸闭合区域和鼻梁位移轴,下颌骨改为六组相邻轮廓半径的局部位移,移除旧脸框近似场;详见[分析](docs/analysis/短脸与下颌骨分析.md)。其余五项脸型仍保留近似实现,不能将局部算法恢复视为全部效果逐像素一致。
1551项回归通过,含335项宿主适配、98项OSC和157项面板ASan检查;28种控制/原点组合均核验实际解剖位置,改变原点标签时逐字节一致。额外真实帧ASan专项886项通过,含重复基础用例。1.1.2(13)已完成正式签名、公证、票据、唯一正式路径安装及副本清理。Motion/FCP原生数值、重置和隔离画面响应已验证,Motion保存重开与撤销通过;按住滑杆时画布持续刷新的实际观感仍等待用户反馈。连续步进在松手前提交已通过独立模拟宿主验证,不能将它等同于每个鼠标事件都排出一帧。
1551项回归通过,含335项宿主适配、98项OSC和157项面板ASan检查;28种控制/原点组合均核验实际解剖位置,改变原点标签时逐字节一致。额外真实帧ASan专项886项通过,含重复基础用例。1.1.2(13)已完成正式签名、公证、票据、唯一正式路径安装及副本清理。Motion/FCP原生数值、重置和隔离画面响应已验证,Motion保存重开与撤销通过;用户于2026-10-22实测确认“拖动中已持续更新”;未指定测试宿主,不扩张为两个宿主分别完成动态排帧验收。连续步进在松手前提交已通过独立模拟宿主验证,不能将它等同于每个鼠标事件都排出一帧。
## 1.2.0 免费开源发布
采用 MIT 许可(第三方资源边界见 THIRD_PARTY_NOTICES.md)。安装包同时包含唯一正式 FxPlug4 APP 和 FCP 效果模板;自动注册,无需账号、激活码或付费激活。主 APP 显示古风说明图,窗口显示三秒后自动退出,不影响独立的宿主插件服务。封面人物是生成的宣传插画,非效果前后对比。
`large.png`(640×360)和 `small.png`(192×108)与 `.moef` 同目录,安装器安装后重新锁定。手动复制或从 Git 恢复模板时,需对这两个 PNG 重新执行 `chflags uchg`,不能锁定整个模板目录。FCP 当前分类为「大鱼磨皮瘦脸」,Motion 原生滤镜分类仍为「大鱼」。
GitHub 提供公开源码、提交历史和版本标签;[1.2.0 Release](https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0) 提供正式签名公证安装包。大鱼站 Git 备份仍受站点登录与会员网关限制,发布文章另提供公开源码快照;安装包始终免费。
+31 -3
查看文件
@@ -1,6 +1,7 @@
# 恢复说明
- 私有远程:`https://dayu.media/git/dayu/paintfcp-fxplug.git`
- 大鱼备份远程(origin):`https://dayu.media/git/dayu/paintfcp-fxplug.git`
- GitHub 公开远程(github):`https://github.com/FAMEDaYu/FCP-BeatyGril.git`
- 本地项目根:`/Users/dayu/Documents/PaintFCP`
- 工作分支:`main`
- 修改前版本标签:`baseline-20261021`,完整 SHA:`1746f38398588e2367abb37a5c2b31cb64042429`
@@ -12,7 +13,7 @@
```sh
git clone https://dayu.media/git/dayu/paintfcp-fxplug.git
cd paintfcp-fxplug
git switch --detach v1.1.2
git switch --detach v1.2.0
```
需要继续编辑时,基于该提交创建新分支。安装 Xcode 与 Apple FxPlug 4 SDK;盘点版本和构建入口见 README.md。SDK/framework 为 Apple 外部开发依赖,应重新安装匹配版本。证书、私钥和公证凭据需从独立加密备份恢复或重新申请;Git 不包含它们。
@@ -85,4 +86,31 @@ FCP模板从 `Templates/大鱼人像美化/` 恢复,将 `.moef` 和 `Drop Zone
正式Release已使用固定团队逐层签名,Apple公证Accepted `5f5ce378-8430-467b-ae97-048e6bc81573`,票据、Gatekeeper、通用架构和PluginKit正式路径全部通过。唯一正式安装APP为`/Library/Plug-Ins/FxPlug/beatygril.app`,模板moef SHA256为`e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15`,TIFF逐字节一致。临时APP、旧APP和公证ZIP已清理,有界目录及现存Spotlight索引产品路径中仅发现正式APP,扫描错误0,不宣称扫描了所有卷。
Motion/FCP原生验收范围及未完成项见`docs/verification/v1.1.2/native-qa.json`:数值、重置、隔离短脸/下颌骨响应通过;Motion撤销和保存关闭重开通过。连续步进已改为每步完整宿主action,模拟宿主确认鼠标松开前可发布中间设置;原生按住鼠标期间的画布时序仍待用户反馈。后续人脸素材和全AX只保留本机build,不是产品依赖或上传资源。
Motion/FCP原生验收范围及未完成项见`docs/verification/v1.1.2/native-qa.json`:数值、重置、隔离短脸/下颌骨响应通过;Motion撤销和保存关闭重开通过。连续步进已改为每步完整宿主action,模拟宿主确认鼠标松开前可发布中间设置;用户于2026-10-22实测确认拖动中持续更新;未指定宿主,未测量逐事件排帧时序。后续人脸素材和全AX只保留本机build,不是产品依赖或上传资源。
最终标签`v1.1.2`完整提交SHA为`e9fddda5e13042f761755762fa39dfe090853c6a`,已独立从远端恢复,158文件的bytes/blob/mode与strict/full fsck通过,产品目录与签名源码a2e33e8逐字节一致,无LFS或子模块,恢复临时目录已清理。详见`docs/verification/v1.1.2/final-tag-recovery.json`;后续main仅补充恢复报告和用户验收记录,产品源码保持不变。
## 1.2.0 恢复入口
源码构建节点为 `696d5f39b30404ed5d1d4c25f61d17475c7fc91b`,版本1.2.0(14)。使用同一 Apple SDK、签名团队与正式安装路径;本次仅改变外层启动器、版本及宣传资源,渲染和面板保留1.1.2验收实现。最终安装包和验证记录随 `v1.2.0` 保存。无 LFS / 子模块。正式 APP 只保留 `/Library/Plug-Ins/FxPlug/beatygril.app`;源代码不包含私钥。
模板恢复到 `~/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/`,需同时保留 `.moef`、`Drop Zone.tiff`、`large.png`、`small.png`。Git 不保存 BSD 文件标志,手工复制后对两张 PNG 执行 `chflags uchg` 并核对 `ls -lO`;不要锁目录和工程。自动安装 PKG 会恢复这两个锁。
仓库已为公开属性,但当前网站 Git 网关仍执行登录 / 会员校验。匿名 `ls-remote` 未通过,不宣称无需登录的 Git 恢复已通过;认证的远端克隆和文章的公开源码快照分别核验。服务端备份边界与前文相同。
1.2.0 的最终标签完整 SHA 为 `3c7261c3a861b9f4704cfb36055d7b500c239dab`,已从认证远端独立克隆恢复并比对183个受跟踪文件,strict/full fsck、Xcode工程读取、恢复出的PKG签名和票据验证通过。正式PKG SHA-256 为 `5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243`。后续main修正发布助手和补充文档,不改变已签名产品源码696d5f3或正式包。
公开文章:https://dayu.media/15593/ ,包含免费安装包、免登录源码快照与仓库链接。源码快照对应 `788ba0d5514595cf349af33074055d70b0754185`;它包含完整构建源码,排除PKG二进制,不包含Git历史。完整历史可从仓库恢复,仍需满足当前站点Git网关登录条件。
## GitHub 公开恢复副本
GitHub 远端 `https://github.com/FAMEDaYu/FCP-BeatyGril.git` 已完成完整历史与七个标签的推送,`origin` 及其 main 上游保持大鱼仓库。独立匿名克隆恢复节点为 `356683b41af702d6c0143ad7fa5f540d752d6e14`,197 文件逐字节核验、strict/full fsck 和全部标签回读通过。后续 main 补充发布说明与验证文档,产品源码保持相同。GitHub Release 的公证安装包已匿名下载核对哈希、签名和票据。详见 `docs/GitHub同步说明.md` 和 `docs/verification/github/`。
## 1.3.0 新面板参数恢复
签名源码节点 `2f2c081980dc610ac810f8daf92da8966f310802` 已推送并读回核验 origin 与 github 的 `codex/new-beauty-controls` 分支。两个远端地址沿用本文既有配置。独立远端克隆与 strict/full fsck、205 个受跟踪文件逐字节比较通过,见 `docs/verification/v1.3.0/recovery-verification.json`。无 LFS、子模块;依赖与签名凭据仍需单独恢复。
本节点增加五官保护强度、非肤色区保护和局部微细锐化,PGBeautySettings v2 兼容旧 160 字节 v1 状态,面板归档仍为 schema 1。测试命令不变,1636 项通过。恢复签名源码时克隆并切换该分支,或 `git switch --detach 2f2c081980dc610ac810f8daf92da8966f310802`。
1.3.0(15)已正式安装到 `/Library/Plug-Ins/FxPlug/beatygril.app`。签名、通用架构、公证票据、Gatekeeper 和 PluginKit 正式路径均通过,已清理本次构建、旧 APP 备份和公证 ZIP。最终回执见 `docs/verification/v1.3.0/delivery-receipt.json`、`installed-verification.json`;`prepared-release.json` 保留安装前状态。`v1.3.0` 标签包含签名源码及后续交付文档。本次没有生成新 PKG 或更新文章,1.2.0 的公开发行资料继续有效;新滑杆的原生宿主视觉仍由用户测试。
+12
查看文件
@@ -0,0 +1,12 @@
# 第三方资料与许可边界
代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。项目代码、脚本及文档按根目录 MIT License 提供。署名 Dayu 不表示第三方代码、样本与 SDK 的版权转移。
- Apple FxPlug / PluginManager SDK 和随正式插件分发的运行框架属于 Apple;受 Apple 相应 SDK 与再分发条款约束,源码仓库不包含这些框架。编译需自行安装 Xcode 与 FxPlug SDK。macOS Vision、AppKit、CoreImage 属于系统组件。
- `Templates/大鱼人像美化/Drop Zone.tiff` 是 Motion 工程的标准占位资源,随模板保留;不将其声明为 Dayu 原创作品或另行授予 MIT 权利。
- `tests/fixtures/astronaut.png` 来源于 NASA 的 Eileen Collins 图像,经 scikit-image 样本分发,详见同目录 ATTRIBUTION.txt。相关分析预览由该公开样本生成。
- `docs/analysis` 中的对照分析、符号和反汇编摘录是互操作研究材料,不包括目标商业 APP、模型或 metallib。MIT 不为其原权利人的内容重新授权。本项目不声称与目标商业插件的模型或画面逐像素一致。
- `Assets/Artwork/portrait-cover.png`、APP 中 `LauncherInfo.png` 及两张模板缩略图由内置图像生成工具创作。人物为虚构成年古风人物,封面是宣传插画,不是真实滤镜前后效果对比;生成说明和提示词见 `docs/design`。未使用目标插件的宣传人像。
- 不包含用户测试素材、用户工程、真实人脸坐标数据、签名私钥、公证密码或账号令牌。签名证书与公证凭据不属于源码恢复范围。
免费发布版本无需激活码、付费注册或联网授权。安装时执行系统插件注册;主 APP 打开后显示说明并在三秒后退出,宿主内的 FxPlug 服务独立运行。
+1 -1
查看文件
@@ -62,7 +62,7 @@
"build": "13",
"Motion": "pass: native number/reset/undo and save-close-reopen; isolated shape/profile images inspected with identical geometry source",
"FCP": "pass: formal load, number/reset and same-frame isolated short/jaw render",
"continuousPreview": "per-step host completion verified automatically; native held-mouse canvas timing pending user observation"
"continuousPreview": "pass: user confirmed held-drag continuous preview on 2026-10-22 (Asia/Shanghai), version1.1.2 build13; host not specified, per-event frame timing not instrumented"
},
"customParameter": {
"id": 210,
二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 444 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 44 KiB

@@ -82,6 +82,7 @@
"/Localized: Wrapper Application/MainMenu.xib",
Plugin/Info.plist,
"Wrapper Application/AppDelegate.m",
"Wrapper Application/Resources/LauncherInfo.png",
"Wrapper Application/Info.plist",
"Wrapper Application/main.m",
);
@@ -355,6 +356,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements";
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
CODE_SIGN_STYLE = Manual;
@@ -372,6 +374,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements";
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
CODE_SIGN_STYLE = Manual;
+4 -4
查看文件
@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.1.2</string>
<string>1.3.0</string>
<key>CFBundleVersion</key>
<string>13</string>
<string>15</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>PlugInKit</key>
@@ -72,7 +72,7 @@
<key>uuid</key>
<string>FB14B0E6-59B2-4836-916F-CD0C559E9241</string>
<key>version</key>
<string>1.1.2</string>
<string>1.3.0</string>
</dict>
<dict>
<key>className</key>
@@ -84,7 +84,7 @@
<key>uuid</key>
<string>E0E432C8-3D71-4ABA-B006-E7F519E06C87</string>
<key>version</key>
<string>1.1.2</string>
<string>1.3.0</string>
<key>protocolNames</key>
<array>
<string>FxOnScreenControl</string>
+48 -4
查看文件
@@ -82,6 +82,26 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
"kernel vec4 pgMaskedMix(__sample source,__sample effect,__sample mask,float amount) {"
"vec4 s=unpremultiply(source); vec4 e=unpremultiply(effect);"
"return premultiply(vec4(mix(s.rgb,e.rgb,clamp(mask.r*amount,0.0,1.0)),s.a)); }");
// Keep smoothing support separate from the exposure/color mask. The
// two new controls independently release feature cutouts and background.
k[@"smoothingSupport"] = PGKernel(@
"kernel vec4 pgSmoothingSupport(__sample protectedMask,__sample baseMask,float featureProtection,float skinProtection) {"
"float base=clamp(baseMask.r,0.0,1.0);float protectedValue=clamp(protectedMask.r,0.0,1.0);"
"float value=mix(base,protectedValue,featureProtection);"
"if(skinProtection<1.0){float extended=1.0-skinProtection*(1.0-base);"
"float retention=base>0.00001?clamp(protectedValue/base,0.0,1.0):1.0;"
"value=extended*mix(1.0,retention,featureProtection);}"
"return vec4(value,value,value,1.0); }");
k[@"microDetail"] = PGKernel(@
"kernel vec4 pgMicroDetail(__sample processed,__sample original,__sample low,__sample coverage,float amount) {"
"vec4 outPixel=unpremultiply(processed);vec3 src=unpremultiply(original).rgb;"
"vec3 high=src-unpremultiply(low).rgb;vec3 weights=vec3(0.299,0.587,0.114);"
"float y=dot(src,weights);float detailY=dot(high,weights);float size=length(high);"
"float lightGate=smoothstep(0.07,0.22,y)*(1.0-smoothstep(0.86,0.99,y));"
"float textureGate=smoothstep(0.0015,0.010,size)*(1.0-smoothstep(0.16,0.36,size));"
"float gain=amount*clamp(coverage.r,0.0,1.0)*lightGate*textureGate*1.18;"
"vec3 detail=vec3(detailY*0.92)+(high-vec3(detailY))*0.28;"
"return premultiply(vec4(clamp(outPixel.rgb+detail*gain,0.0,1.0),outPixel.a)); }");
k[@"colorCoverage"] = PGKernel(@
"kernel vec4 pgColorCoverage(__sample coverage,__sample image,float invert) {"
"vec3 c=unpremultiply(image).rgb; float y=dot(c,vec3(0.299,0.587,0.114));"
@@ -157,7 +177,7 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
float mix = PGClamp(s.mix, 0, 1);
if (mix == 0 && !s.showMask) return image;
NSDictionary *k = PGKernels();
if (k.count != 11) {
if (k.count != 13) {
if (error) *error = [NSError errorWithDomain:@"PGBeautyRenderer" code:2
userInfo:@{NSLocalizedDescriptionKey:@"The beauty image kernels could not be compiled."}];
return nil;
@@ -173,7 +193,10 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
float sharpness = PGClamp(s.sharpness,0,2);
float teeth = PGClamp(s.teethWhitening,0,1);
float eyes = PGClamp(s.eyeBrightening,0,1);
BOOL needsSkin = local*amount>0 || brightness>0 || hue!=0 || saturation!=0 || even>0 ||
float protection = s.featureProtection ? PGClamp(s.featureProtectionAmount,0,1) : 0;
float skinProtection = PGClamp(s.nonSkinProtection,0,1);
float micro = PGClamp(s.microDetail,0,1)*amount;
BOOL needsSkin = local*amount>0 || micro>0 || brightness>0 || hue!=0 || saturation!=0 || even>0 ||
(s.skinTonePreset>0 && s.skinTonePreset<=6) || (s.showMask && s.debugChannel==0);
CIImage *black = [[CIImage imageWithColor:[CIColor colorWithRed:0 green:0 blue:0 alpha:1]] imageByCroppingToRect:extent];
CIImage *teethInput = teethMask ? [teethMask imageByCroppingToRect:extent] : black;
@@ -200,12 +223,29 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
float invert = s.debugChannel==1 || s.debugChannel==2 ? (s.invertMask ? 1 : 0) : 0;
return PGApply(k[@"debug"],extent,@[image,preview,@(invert)]);
}
CIImage *smoothingMask=mask;
if((local*amount>0 || micro>0) && (protection<1 || skinProtection<1)) {
CIImage *baseRaw=colorMask ? [colorMask imageByCroppingToRect:extent] : raw;
float soft=PGClamp(s.maskSoftness,0,1);
CIImage *baseMask=PGApply(k[@"mask"],extent,@[baseRaw,PGBlur(baseRaw,0.35+soft*radius*0.35,extent),
image,PGBlur(image,1.5,extent),eyeInput,teethInput,
@(PGClamp(s.maskThreshold,0,255)/255.f),@(soft),@(PGClamp(s.maskEdgeProtect,0,1)),@0,@(s.invertMask?1:0)]);
smoothingMask=PGApply(k[@"smoothingSupport"],extent,@[mask,baseMask,@(protection),@(skinProtection)]);
}
// Detail protection may contain small eye, brow, nose and lip cutouts.
// Exposure and color must not reuse those holes or sharpen a face ellipse
// with the detail threshold; that creates visible rings and islands.
CIImage *toneMask=mask;
BOOL changesColor=brightness>0 || hue!=0 || saturation!=0 || even>0 ||
(s.skinTonePreset>0 && s.skinTonePreset<=6);
if(!colorMask && changesColor && s.featureProtection) {
// Standalone callers may not supply the separate uncut coverage.
// At least keep our eye/teeth cutouts out of their color adjustment.
float soft=PGClamp(s.maskSoftness,0,1);
toneMask=PGApply(k[@"mask"],extent,@[raw,PGBlur(raw,0.35+soft*radius*0.35,extent),
image,PGBlur(image,1.5,extent),eyeInput,teethInput,
@(PGClamp(s.maskThreshold,0,255)/255.f),@(soft),@(PGClamp(s.maskEdgeProtect,0,1)),@0,@(s.invertMask?1:0)]);
}
if(colorMask && changesColor) {
CGFloat feather=MAX(3,MIN(extent.size.width,extent.size.height)*0.03);
CIImage *support=[colorMask imageByCroppingToRect:extent];
@@ -219,8 +259,12 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
CGFloat broad = fmin(16,(2.55+0.45*local)*fine+1.1+1.3*local);
float compression = 0.12+2.4*powf(local,2.15)+1.25*local;
CIImage *detail = PGApply(k[@"detail"],extent,@[result,PGBlur(result,fine,extent),
PGBlur(result,broad,extent),@(compression),@(s.featureProtection ? 1 : 0)]);
result = PGApply(k[@"maskedMix"],extent,@[result,detail,mask,@(amount)]);
PGBlur(result,broad,extent),@(compression),@(protection)]);
result = PGApply(k[@"maskedMix"],extent,@[result,detail,smoothingMask,@(amount)]);
}
if(micro>0) {
CGFloat fine=fmin(7.4,2.275+3.15*pow(local,0.72)+0.95*local);
result=PGApply(k[@"microDetail"],extent,@[result,image,PGBlur(image,fine,extent),smoothingMask,@(micro)]);
}
CIImage *color = result;
if (brightness>0) {
+11 -1
查看文件
@@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <math.h>
// Persisted FxPlug render state. Append fields and bump version for migrations.
typedef struct {
@@ -12,11 +14,17 @@ typedef struct {
float faceJumpGuardRange, selectionX, selectionY;
uint32_t featureProtection, skinTonePreset, showMask, invertMask, debugChannel;
uint32_t showFaceBoxes, showTrackBox, singleFace, fastMultiFace, trackingEnabled, targetIndex;
// v2 keeps the entire 160-byte v1 prefix, including legacy bool/strength IDs.
float featureProtectionAmount, nonSkinProtection, microDetail;
} PGBeautySettings;
enum { PGBeautySettingsV1Size = 160, PGBeautySettingsVersion = 2 };
_Static_assert(offsetof(PGBeautySettings,featureProtectionAmount)==PGBeautySettingsV1Size,
"The v1 render-state prefix must remain stable");
static inline PGBeautySettings PGBeautyDefaults(void) {
PGBeautySettings s = {0};
s.version = 1;
s.version = PGBeautySettingsVersion;
s.amount = 1.0f;
s.radius = 8.0f;
s.mix = 1.0f;
@@ -24,6 +32,8 @@ static inline PGBeautySettings PGBeautyDefaults(void) {
s.maskSoftness = 0.6f;
s.maskEdgeProtect = 0.4f;
s.featureProtection = 1;
s.featureProtectionAmount = 1;
s.nonSkinProtection = 1;
s.faceJumpGuardRange = 1.8f;
s.selectionX = s.selectionY = 0.5f;
return s;
+29 -8
查看文件
@@ -11,9 +11,10 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
#define ITEM(ID,NAME,FIELD,SECTION,KIND,FORMAT,MIN,MAX,BYPASS,STORAGE) \
[items addObject:@{@"id":@(ID),@"name":@NAME,@"section":@SECTION,@"kind":@KIND,@"format":@FORMAT,@"min":@(MIN),@"max":@(MAX),@"default":@(defaults.FIELD),@"bypass":@(BYPASS),@"offset":@(offsetof(PGBeautySettings,FIELD)),@"storage":@STORAGE}]
ITEM(PGSmoothingEnabled,"磨皮",featureProtection,"smooth","master","integer",0,1,NO,"master");
ITEM(PGMidtone,"局部磨皮",midtoneDetail,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGHighPass,"全局磨皮",highPassDetail,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGFeatureProtect,"五官保护",featureProtection,"smooth","toggle","integer",0,1,NO,"uint");
ITEM(PGMidtone,"磨皮程度",midtoneDetail,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGMicroDetail,"微细锐化",microDetail,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGFeatureProtectionAmount,"五官保护",featureProtectionAmount,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGNonSkinProtection,"非肤色区保护",nonSkinProtection,"smooth","slider","percent",0,1,YES,"float");
ITEM(PGColorEnabled,"美白",featureProtection,"color","master","integer",0,1,NO,"master");
ITEM(PGTonePreset,"肤色",skinTonePreset,"color","preset","integer",0,6,NO,"uint");
NSMutableDictionary *preset=[items.lastObject mutableCopy];
@@ -22,9 +23,10 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
ITEM(PGTeeth,"白牙",teethWhitening,"color","slider","percent",0,1,YES,"float");
ITEM(PGHue,"皮肤色相",skinHue,"color","slider","degrees",-30,30,YES,"float");
ITEM(PGShapeEnabled,"瘦脸",featureProtection,"shape","master","integer",0,1,NO,"master");
ITEM(PGTrackBoxes,"人脸框预览",showTrackBox,"shape","toggle","integer",0,1,NO,"uint");
ITEM(PGTrackBoxes,"检测框预览",showTrackBox,"shape","toggle","integer",0,1,NO,"uint");
ITEM(PGFastMulti,"多人模式",fastMultiFace,"shape","toggle","integer",0,1,NO,"uint");
ITEM(PGJumpGuard,"防跳脸范围",faceJumpGuardRange,"shape","slider","percent",1,4,NO,"float");
NSMutableDictionary *multi=[items.lastObject mutableCopy];
multi[@"tooltip"]=@"多人模式易抖动,请谨慎使用";items[items.count-1]=multi;
ITEM(PGThin,"瘦脸",faceThin,"shape","slider","signed",0,1,YES,"float");
ITEM(PGBigEye,"大眼",faceBigEye,"shape","slider","signed",0,1,YES,"float");
ITEM(PGShort,"短脸",faceShort,"shape","slider","signed",-1,1,YES,"float");
@@ -36,11 +38,13 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
ITEM(PGSmallHead,"小头",faceSmallHead,"shape","slider","signed",0,1,YES,"float");
ITEM(PGSmallHeadRange,"小头范围",faceSmallHeadRange,"shape","slider","percent",0,1,NO,"float");
ITEM(PGAmount,"磨皮强度",amount,"more","slider","percent",0,1,YES,"float");
ITEM(PGHighPass,"全局磨皮",highPassDetail,"more","slider","percent",0,1,YES,"float");
ITEM(PGRadius,"磨皮半径",radius,"more","slider","radius",1,30,NO,"float");
ITEM(PGSaturation,"肤色饱和度",skinSaturation,"more","slider","percent",-100,100,YES,"float");
ITEM(PGEvenTone,"均匀肤色",skinEvenTone,"more","slider","percent",0,1,YES,"float");
ITEM(PGEyeBright,"眼睛提亮",eyeBrightening,"more","slider","percent",0,1,YES,"float");
ITEM(PGSharpness,"锐化",sharpness,"more","slider","percent",0,1,YES,"float");
ITEM(PGJumpGuard,"防跳脸范围",faceJumpGuardRange,"more","slider","percent",1,4,NO,"float");
ITEM(PGMix,"整体混合",mix,"more","slider","percent",0,1,NO,"float");
#undef ITEM
controls=[items copy];
@@ -62,7 +66,12 @@ static double PGControlValue(id raw,NSDictionary *d) {
+ (instancetype)stateWithValues:(NSDictionary *)values disabledParameters:(NSSet *)disabled hasEdits:(BOOL)edited {
PGInspectorState *state=[self new]; NSMutableDictionary *safe=[NSMutableDictionary new];NSMutableSet *bypassed=[NSMutableSet new];
for(NSDictionary *d in PGInspectorControls()) {
NSNumber *key=d[@"id"];safe[key]=@(PGControlValue(values[key],d));
NSNumber *key=d[@"id"];id raw=values[key];
// Schema 1 documents stored five-feature protection as the legacy bool.
// New numeric values win when present; old archives gain its exact 0/1.
if(key.unsignedIntValue==PGFeatureProtectionAmount && !raw && [values[@(PGFeatureProtect)] isKindOfClass:NSNumber.class])
raw=@([values[@(PGFeatureProtect)] boolValue]?1:0);
safe[key]=@(PGControlValue(raw,d));
if([d[@"bypass"] boolValue] && [disabled containsObject:key]) [bypassed addObject:key];
}
state->_values=[safe copy];state->_disabledParameters=[bypassed copy];state->_hasEdits=edited;return state;
@@ -115,7 +124,8 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
if([storage isEqual:@"float"]) *(float *)((uint8_t *)&s+offset)=value;
else *(uint32_t *)((uint8_t *)&s+offset)=(uint32_t)value;
}
if(![state valueForParameter:PGSmoothingEnabled])s.amount=s.midtoneDetail=s.highPassDetail=0;
s.featureProtection=s.featureProtectionAmount>0;
if(![state valueForParameter:PGSmoothingEnabled])s.amount=s.midtoneDetail=s.highPassDetail=s.microDetail=0;
if(![state valueForParameter:PGColorEnabled]) {s.skinBrightness=s.skinHue=s.skinSaturation=s.skinEvenTone=s.teethWhitening=s.eyeBrightening=0;s.skinTonePreset=0;}
if(![state valueForParameter:PGShapeEnabled]) {s.faceThin=s.faceBigEye=s.faceShort=s.faceNarrow=s.faceChin=s.faceV=s.faceJaw=s.faceCheekbone=s.faceSmallHead=0;s.showTrackBox=0;}
return s;
@@ -189,6 +199,12 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
else [api getFloatValue:&value fromParameter:key atTime:time];
values[@(key)]=@(value);
}
// The old bool can still disable protection. A true value must preserve a
// numeric setting already read above; its registered default is one for
// old documents that have no independently stored numeric parameter.
BOOL legacyFeatureProtection=YES;
if([api getBoolValue:&legacyFeatureProtection fromParameter:PGFeatureProtect atTime:time] && !legacyFeatureProtection)
values[@(PGFeatureProtectionAmount)]=@0;
BOOL legacyDetail=YES;[api getBoolValue:&legacyDetail fromParameter:PGDetailEnabled atTime:time];
NSMutableSet *disabled=legacyDetail?[NSMutableSet set]:[NSMutableSet setWithObjects:@(PGHighPass),@(PGSharpness),nil];
// Earlier versions put high-pass smoothing under a different group. Keep
@@ -196,7 +212,7 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
// off, rather than turning a still-active global effect off on first edit.
if(![values[@(PGSmoothingEnabled)] boolValue] && legacyDetail && [values[@(PGHighPass)] doubleValue]>0) {
values[@(PGSmoothingEnabled)]=@YES;
[disabled addObject:@(PGMidtone)];[disabled addObject:@(PGAmount)];
[disabled addObject:@(PGMidtone)];[disabled addObject:@(PGAmount)];[disabled addObject:@(PGMicroDetail)];
}
_state=[PGInspectorState stateWithValues:values disabledParameters:disabled hasEdits:NO];
}
@@ -232,6 +248,11 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
else if([d[@"kind"] isEqual:@"toggle"] || [d[@"kind"] isEqual:@"master"]) [api setBoolValue:value!=0 toParameter:key atTime:time];
else [api setFloatValue:value toParameter:key atTime:time];
}
BOOL featureProtection=[next isParameterEnabled:PGFeatureProtectionAmount] && [next valueForParameter:PGFeatureProtectionAmount]>0;
id<FxParameterRetrievalAPI_v6> reader=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)];
BOOL previousProtection=!featureProtection;
if(![reader getBoolValue:&previousProtection fromParameter:PGFeatureProtect atTime:time] || previousProtection!=featureProtection)
[api setBoolValue:featureProtection toParameter:PGFeatureProtect atTime:time];
_state=next;_pendingUntil=NSDate.timeIntervalSinceReferenceDate+.35;_pendingTime=time;_statusMessage=@"";return YES;
}
- (BOOL)setValue:(double)value forParameter:(UInt32)identifier {
+5 -3
查看文件
@@ -202,6 +202,8 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
}
}
NSString *key=[descriptor[@"id"]stringValue];
NSString *tooltip=descriptor[@"tooltip"];
if(tooltip.length){self.toolTip=tooltip;_label.toolTip=tooltip;_toggle.toolTip=tooltip;_slider.toolTip=tooltip;_valueField.toolTip=tooltip;}
_slider.identifier=[@"pg.value."stringByAppendingString:key];_valueField.identifier=[@"pg.number."stringByAppendingString:key];
_toggle.identifier=[@"pg.toggle."stringByAppendingString:key];_eye.identifier=[@"pg.enable."stringByAppendingString:key];_reset.identifier=[@"pg.reset."stringByAppendingString:key];
}return self;
@@ -282,11 +284,11 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
@implementation PGInspectorCard
- (BOOL)isFlipped { return YES; }
- (CGFloat)heightForWidth:(CGFloat)width {
if(!_expanded)return 44;CGFloat height=49;for(PGInspectorRow *row in _rows){height+=[row heightForWidth:MAX(0,width-24)];if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard)height+=8;}return height+7;
if(!_expanded)return 44;CGFloat height=49;for(PGInspectorRow *row in _rows){height+=[row heightForWidth:MAX(0,width-24)];if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti)height+=8;}return height+7;
}
- (void)layout {
[super layout];CGFloat w=NSWidth(self.bounds);_titleLabel.frame=NSMakeRect(25,13,MAX(70,w-80),22);_master.frame=NSMakeRect(w-39,10,25,25);
CGFloat y=49;for(PGInspectorRow *row in _rows){row.hidden=!_expanded;if(!_expanded)continue;CGFloat h=[row heightForWidth:w-24];row.frame=NSMakeRect(12,y,w-24,h);y+=h;if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard)y+=8;}
CGFloat y=49;for(PGInspectorRow *row in _rows){row.hidden=!_expanded;if(!_expanded)continue;CGFloat h=[row heightForWidth:w-24];row.frame=NSMakeRect(12,y,w-24,h);y+=h;if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti)y+=8;}
}
- (void)drawRect:(NSRect)dirtyRect {
(void)dirtyRect;NSBezierPath *shape=[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(self.bounds,.5,.5) xRadius:13 yRadius:13];
@@ -294,7 +296,7 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
[[_accent colorWithAlphaComponent:.22]setStroke];shape.lineWidth=.8;[shape stroke];
NSRect pill=NSMakeRect(12,10,MAX(53,[_heading length]*13+20),25);[[_accent colorWithAlphaComponent:.10]setFill];NSBezierPath *p=[NSBezierPath bezierPathWithRoundedRect:pill xRadius:8 yRadius:8];[p fill];[[_accent colorWithAlphaComponent:.32]setStroke];p.lineWidth=.7;[p stroke];
if(_expanded){[[PGUIMuted() colorWithAlphaComponent:.20]setStroke];NSBezierPath *line=[NSBezierPath bezierPath];[line moveToPoint:NSMakePoint(12,43)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,43)];line.lineWidth=.5;[line stroke];
for(PGInspectorRow *row in _rows)if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard){CGFloat y=NSMaxY(row.frame)+4;[line removeAllPoints];[line moveToPoint:NSMakePoint(12,y)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,y)];[line stroke];}
for(PGInspectorRow *row in _rows)if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti){CGFloat y=NSMaxY(row.frame)+4;[line removeAllPoints];[line moveToPoint:NSMakePoint(12,y)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,y)];[line stroke];}
}
}
@end
@@ -14,5 +14,6 @@ enum {
PGTrackData1=60, PGTrackData2=61, PGTrackData3=62,
PGSmoothingEnabled=70, PGColorEnabled=71, PGShapeEnabled=72,
PGDetailEnabled=73, PGHelp=74,
PGFeatureProtectionAmount=75, PGNonSkinProtection=76, PGMicroDetail=77,
PGInspectorPanel=210
};
+15 -4
查看文件
@@ -30,6 +30,9 @@ static const PGSlider PGSliders[] = {
PGS(PGEyeBright,"眼睛提亮",eyeBrightening,0,1,.01,YES),
PGS(PGHighPass,"高频细节平滑",highPassDetail,0,1,.01,YES),
PGS(PGSharpness,"锐化",sharpness,0,1,.01,YES),
PGS(PGFeatureProtectionAmount,"五官保护强度",featureProtectionAmount,0,1,.01,YES),
PGS(PGNonSkinProtection,"非肤色区保护",nonSkinProtection,0,1,.01,YES),
PGS(PGMicroDetail,"微细锐化",microDetail,0,1,.01,YES),
PGS(PGThin,"瘦脸",faceThin,0,1,.01,YES),
PGS(PGBigEye,"大眼",faceBigEye,0,1,.01,YES),
PGS(PGShort,"短脸",faceShort,-1,1,.01,NO),
@@ -141,6 +144,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
void (^end)(void)=^{ok=[api endParameterSubGroup]&&ok;};
group(@"磨皮",100); toggle(@"启用磨皮",PGSmoothingEnabled,YES);
slider(PGAmount); slider(PGMidtone); slider(PGRadius); toggle(@"保护五官",PGFeatureProtect,YES); end();
group(@"磨皮保护与细节",106); slider(PGFeatureProtectionAmount); slider(PGNonSkinProtection); slider(PGMicroDetail); end();
group(@"肤色",101); toggle(@"启用肤色",PGColorEnabled,YES);
ok=[api addPopupMenuWithName:@"肤色风格" parameterID:PGTonePreset defaultValue:0 menuEntries:@[@"原色",@"自然白",@"冷白",@"暖白",@"红润白",@"小麦",@"古铜"] parameterFlags:kFxParameterFlag_HIDDEN]&&ok;
slider(PGBrightness); slider(PGHue); slider(PGSaturation); slider(PGEvenTone); slider(PGTeeth); slider(PGEyeBright); end();
@@ -207,7 +211,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
double x=.5,y=.5; [api getXValue:&x YValue:&y fromParameter:PGSelection atTime:time];
s.selectionX=isfinite(x)?fmin(1,fmax(0,x)):.5; s.selectionY=isfinite(y)?fmin(1,fmax(0,y)):.5;
BOOL enabled=YES;
[api getBoolValue:&enabled fromParameter:PGSmoothingEnabled atTime:time]; if(!enabled) s.amount=s.midtoneDetail=0;
[api getBoolValue:&enabled fromParameter:PGSmoothingEnabled atTime:time]; if(!enabled) s.amount=s.midtoneDetail=s.microDetail=0;
enabled=YES; [api getBoolValue:&enabled fromParameter:PGColorEnabled atTime:time];
if(!enabled) {s.skinBrightness=s.skinHue=s.skinSaturation=s.skinEvenTone=s.teethWhitening=s.eyeBrightening=0;s.skinTonePreset=0;}
enabled=YES; [api getBoolValue:&enabled fromParameter:PGDetailEnabled atTime:time]; if(!enabled) s.highPassDetail=s.sharpness=0;
@@ -263,9 +267,16 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
- (BOOL)renderDestinationImage:(FxImageTile *)destination sourceImages:(NSArray<FxImageTile *> *)sources pluginState:(NSData *)state atTime:(CMTime)time error:(NSError **)error {
if(sources.count==0||!sources.firstObject.ioSurface||!destination.ioSurface||![state isKindOfClass:NSData.class]||state.length==0||state.length>320*1024*1024) return PGFail(error,@"宿主传入的画面或状态无效。");
NSDictionary *plist=[NSPropertyListSerialization propertyListWithData:state options:NSPropertyListImmutable format:nil error:error];
if(![plist isKindOfClass:NSDictionary.class]||![plist[@"settings"] isKindOfClass:NSData.class]||[plist[@"settings"] length]!=sizeof(PGBeautySettings)) return PGFail(error,@"渲染状态版本无效。");
PGBeautySettings s;[plist[@"settings"] getBytes:&s length:sizeof(s)];
if(s.version!=1) return PGFail(error,@"此版本不支持保存的渲染状态。");
if(![plist isKindOfClass:NSDictionary.class]||![plist[@"settings"] isKindOfClass:NSData.class]) return PGFail(error,@"渲染状态版本无效。");
NSData *encoded=plist[@"settings"]; uint32_t version=0;
if(encoded.length<sizeof(version)) return PGFail(error,@"渲染状态版本无效。");
[encoded getBytes:&version length:sizeof(version)];
PGBeautySettings s=PGBeautyDefaults();
if(version==1 && encoded.length==PGBeautySettingsV1Size) {
[encoded getBytes:&s length:PGBeautySettingsV1Size];s.version=PGBeautySettingsVersion;
} else if(version==PGBeautySettingsVersion && encoded.length==sizeof(s)) {
[encoded getBytes:&s length:sizeof(s)];
} else return PGFail(error,@"此版本不支持保存的渲染状态。");
s.trackingEnabled=0;s.singleFace=0;
CIImage *input=PGImageFromTile(sources.firstObject); if(!input) return PGFail(error,@"无法读取 IOSurface。");
@synchronized(self) {
@@ -1,34 +1,45 @@
#import "AppDelegate.h"
#import <CoreServices/CoreServices.h>
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (strong) NSTimer *exitTimer;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
self.window.title=@"大鱼人像美化";
[self.window setContentSize:NSMakeSize(600,360)];
NSView *content=[NSView new];self.window.contentView=content;
NSStackView *stack=[NSStackView new];stack.orientation=NSUserInterfaceLayoutOrientationVertical;
stack.alignment=NSLayoutAttributeLeading;stack.spacing=16;stack.translatesAutoresizingMaskIntoConstraints=NO;
[content addSubview:stack];
[NSLayoutConstraint activateConstraints:@[[stack.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:32],[stack.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-32],[stack.topAnchor constraintEqualToAnchor:content.topAnchor constant:30]]];
NSTextField *title=[NSTextField labelWithString:@"大鱼人像美化"];
title.font=[NSFont systemFontOfSize:28 weight:NSFontWeightSemibold];[stack addArrangedSubview:title];
NSTextField *subtitle=[NSTextField labelWithString:@"beatygril · FxPlug 4"];
subtitle.textColor=NSColor.secondaryLabelColor;[stack addArrangedSubview:subtitle];
NSTextField *description=[NSTextField wrappingLabelWithString:@"在 Motion 的滤镜资源库中选择「大鱼 → 大鱼人像美化」。Final Cut Pro 的效果浏览器中也可使用配套效果。\n\n美化会随画面人脸自动更新,无需先点分析。脸型默认跟随主要人脸,多人模式可处理多张脸。启用「只处理选中人脸」后,可点击画面更换目标。向前/向后分析为可选功能,结果可随工程保存。"];
description.font=[NSFont systemFontOfSize:13];[stack addArrangedSubview:description];
NSStackView *buttons=[NSStackView new];buttons.orientation=NSUserInterfaceLayoutOrientationHorizontal;buttons.spacing=12;
[buttons addArrangedSubview:[NSButton buttonWithTitle:@"打开 Motion" target:self action:@selector(openMotion:)]];
[buttons addArrangedSubview:[NSButton buttonWithTitle:@"打开 Final Cut Pro" target:self action:@selector(openFinalCut:)]];
[stack addArrangedSubview:buttons];
NSTextField *note=[NSTextField wrappingLabelWithString:@"建议先调高中频磨皮,再按需调节肤色与脸型。肤色风格为本插件独立调色预设。"];
note.textColor=NSColor.secondaryLabelColor;note.font=[NSFont systemFontOfSize:11];[stack addArrangedSubview:note];
[self.window center];
self.window.title = @"大鱼人像美化 · 免费开源";
[self.window setContentSize:NSMakeSize(800, 450)];
self.window.styleMask &= ~NSWindowStyleMaskResizable;
self.window.backgroundColor = [NSColor colorWithRed:0.94 green:0.92 blue:0.85 alpha:1];
NSImageView *card = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 800, 450)];
card.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
card.imageScaling = NSImageScaleProportionallyUpOrDown;
NSURL *artwork = [NSBundle.mainBundle URLForResource:@"LauncherInfo" withExtension:@"png"];
card.image = [[NSImage alloc] initWithContentsOfURL:artwork];
card.accessibilityLabel = @"大鱼人像美化,免费开源,自动注册,无需激活码。主程序启动三秒后自动退出;Final Cut Pro 和 Motion 中的滤镜继续独立运行。";
self.window.contentView = card;
if (!card.image) {
NSTextField *fallback = [NSTextField wrappingLabelWithString:card.accessibilityLabel];
fallback.frame = NSMakeRect(48, 160, 704, 130);
fallback.font = [NSFont systemFontOfSize:24 weight:NSFontWeightSemibold];
[card addSubview:fallback];
}
- (void)openMotion:(id)sender {[self openApplication:@"com.apple.motionapp"];}
- (void)openFinalCut:(id)sender {[self openApplication:@"com.apple.FinalCut"];}
- (void)openApplication:(NSString *)identifier {
NSURL *url=[NSWorkspace.sharedWorkspace URLForApplicationWithBundleIdentifier:identifier];
if(url) [NSWorkspace.sharedWorkspace openApplicationAtURL:url configuration:NSWorkspaceOpenConfiguration.configuration completionHandler:nil];
[self.window center];
[self.window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
// Only this launcher exits. The FxPlug service has its own process/lifetime.
self.exitTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:NO block:^(NSTimer *timer) {
[NSApp terminate:nil];
}];
// Re-register our own bundle. There is no paid activation or account step.
NSURL *bundleURL = NSBundle.mainBundle.bundleURL;
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
OSStatus status = LSRegisterURL((__bridge CFURLRef)bundleURL, true);
if (status != noErr) NSLog(@"LaunchServices registration status: %d", (int)status);
});
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
@end
@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.1.2</string>
<string>1.3.0</string>
<key>CFBundleVersion</key>
<string>13</string>
<string>15</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 2.9 MiB

+23
查看文件
@@ -0,0 +1,23 @@
# GitHub 同步与恢复
公开源码:https://github.com/FAMEDaYu/FCP-BeatyGril
正式安装包:https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0
本地 `github` 远端指向上述 GitHub 仓库,`origin` 继续指向大鱼仓库,`main` 仍跟随 `origin/main`。当前项目的完整提交历史、main 和七个版本标签已推送,两端引用与本地一致;未改写历史或覆盖标签。后续更新需要分别推送到 origin 和 github,不会自动定时同步。
## 已验证的 GitHub 恢复节点
匿名恢复提交:`356683b41af702d6c0143ad7fa5f540d752d6e14`。在关闭凭据助手和交互登录的独立临时目录中成功克隆 GitHub,197 个受跟踪文件逐字节一致、七个标签引用一致,strict/full fsck 通过。正式 PKG 的源码内副本与 GitHub Release 匿名下载副本 SHA-256 相同,下载副本的 Installer 签名与公证票据通过。后续 main 提交补充文章和验证记录,产品源码与该恢复节点一致。
安装包:`Dayu-Portrait-1.2.0.pkg`,5,011,005 bytes,SHA-256 `5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243`。Release 标签 `v1.2.0` 仍指向 `3c7261c3a861b9f4704cfb36055d7b500c239dab`,没有重新编译或改动正式安装包。
```sh
git clone https://github.com/FAMEDaYu/FCP-BeatyGril.git
cd FCP-BeatyGril
git switch --detach 356683b41af702d6c0143ad7fa5f540d752d6e14
```
本项目没有 LFS 或子模块。编译仍需自行安装 Xcode 和 Apple FxPlug SDK;签名私钥与公证凭据不在 Git 内。GitHub 公共克隆无需登录;大鱼备份仍受站点登录和会员网关限制。两边都只承诺已经提交、推送并核验的节点。
源代码编写署名:代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。
+37
查看文件
@@ -0,0 +1,37 @@
# 2.4.0 面板参数迁移
2026-10-22(Asia/Shanghai)。用户通过截图纠正原需求:迁移新版面板参数,并非新增身体瘦身。此前[瘦身目标核对](瘦身迁移目标核对.md)保留为历史调查;本次继续工作使用 `codex/new-beauty-controls`,不再等待其他目标包。
## 参考与证据
目标:`/Users/dayu/Downloads/MSE18V2.app`,2.4.0 / 20260724150000;插件通用二进制 SHA-256:`577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`;arm64 切片:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。分析使用 Ghidra 12.1.4 与只读 Mach-O 元数据/反汇编,原文件未改。
| 参考面板 | 目标字段/转换 | 本项目入口 |
| --- | --- | --- |
| 磨皮程度 | ID12 → midtoneDetail,直接 0–100% | 保留 PGMidtone 12,调整名称 |
| 微细锐化 | ID4 → sharpness,局部细节恢复 | 新 PGMicroDetail 77;原全局锐化 4 留在更多设置 |
| 五官保护 | ID30 → featureProtectionRelease = 1 − UI;旧 bool 随 release 接近 1 而关闭 | 新 PGFeatureProtectionAmount 75,直接保护量;旧 bool 30 保留类型与读取 |
| 非肤色区保护 | ID17 → highPassDetail = 1 − UI;新主路径用于肤色蒙版扩展 | 新 PGNonSkinProtection 76;原独立全局磨皮 17 留在更多设置 |
| 白牙、检测框预览、多人及脸型 | 截图中的这些项已经存在 | 保留;检测框名称调整、多人模式增加提示 |
两个新保护量默认为 100%,微细锐化默认为 0%。内部使用直接保护量,不直接复用参考包的反向 release 数值。
`setFloatValue:parameterID:minValue:maxValue:`(`0x1000116d8`)分别反转 17/30 的输入;Evidence:`ev_1fb7d2361dabf814edd6f22d217265b63efa9af24739741772ad5f579e0c67e3`。`valuesForControlPanelValue:` 返回相应原始字段;Evidence:`ev_20da8abf4eb5101b0902627255c643a783b7a15337aa4a757820ab71616f33e7`。显示格式 `strength` 是直接乘 100,只有 `protectionInverse` 格式自身反转;17/30 在绘制与交互同步时提前反转,不能把所有 strength 控制都解释为反向。格式函数汇编 Evidence:`ev_8e2a143f81d173c7643ecee2f1dac4a02145edbf82f113c8a48271428baf747c`。
目标原生处理入口 `applySkinSmoothingToImage:…`(`0x1000358d8`)把 params+0x50 用于非肤色参与,把 params+0x48 用于五官保护释放。Evidence:`ev_34eb4fe26dbaed9fc37d664d9363db903339c1447b6cd7fdb1980dcd61e99572`。可读 CI 内核字符串建立两个关键关系:肤色蒙版向白色线性扩展;保护蒙版与未保护蒙版按 release 线性混合。细节恢复使用原画与低频图的差,并受局部蒙版和亮度/纹理门控。字符串证据:`ev_d02bfe8046953e9287bd46c5403e6585354a5aa6df782a775d6a6fd0d96f1d62`。这里只记录公式和含义,不提交目标模型、metallib 或资源。
## 实施与兼容
本项目继续使用自研 Vision 几何蒙版与 Core Image 管线。新的平滑支持蒙版通过现有未保护/已保护覆盖率恢复五官衰减比例,再对非肤色区域扩展;两个控制独立于曝光/肤色蒙版。默认 100%/100% 直接沿用原覆盖路径。微细锐化在局部支持区域恢复亮度细节与少量色彩细节,可在磨皮量为零时独立使用。
原目标的语义蒙版、特征形状、纹理处理和复杂组合尚未全链对齐,因此本次是参数含义、连续控制和对应局部处理的迁移,不表示整个新版已逐像素复刻。旧版全局磨皮/全局锐化仍可通过更多设置使用,不与新保护项偷换含义;历史工程保留原强度。
PGBeautySettings v2 尾部增加三个 float,保留 v1 的 160 字节前缀。解码只接受 v1+160 字节或 v2+新完整长度;旧状态补中性默认值。PGInspectorState 仍使用 schema 1 数值字典,旧 bool 30 迁移到缺失的 75,新数值存在时优先采用新值。面板提交先保存权威对象 210,成功后再镜像旧 bool;每次拖动步进仍使用独立宿主 action。
模板继续发布原 210 对象与两项署名。新隐藏参数由插件注册和缺省值补齐,原 `.moef` 字节未改,无须覆盖用户模板。固定 Bundle ID、滤镜 UUID、安装路径及宣传资源不变。
## 验证
最终通过 1636 项:Beauty 57、Face 116、几何 796、宿主适配 ASan 341、OSC ASan 98、Inspector ASan 228(其中 1 项为可选离屏 PNG 输出)。新增检查包含保护量 0/50/100 的像素响应、非肤色保护只改变局部磨皮支持、微细锐化区域、颜色覆盖隔离、v1 状态迁移与错误长度拒绝、新滑杆归档/插值/输入/重置/旁路/主开关、松手前中间状态发布。离屏 AppKit 面板在多种宽度检查;原生宿主视觉验收需另记实际结果。
完整 REA 证据仅在忽略的 `build/body-analysis/new-controls-evidence.json`。本文保留目标身份、入口、公式与边界,恢复构建不依赖该本地调查目录。
+53
查看文件
@@ -0,0 +1,53 @@
# 瘦身迁移:目标版本核对
核对日期:2026-10-22(Asia/Shanghai)。开发分支:`codex/body-slimming`;源码基线:`13821366a5baee9beea40972118d7fe634b5c735`。
**后续已澄清**:用户通过截图确认记错了,实际需求是迁移新增面板参数。后续以[新版磨皮参数迁移](新版磨皮参数迁移.md)为准,下面保留纠正前的有界调查结论,不再表示当前等待其他插件包。
## 当前结果
用户指定的新目标为 `/Users/dayu/Downloads/MSE18V2.app`。已读取项目交接并检查目标包,**尚未定位到可迁移的新增“瘦身”板块**。当前只完成目标核对与接入点调查,未修改产品源码、模板或正式安装的 1.2.0 APP,未编译或执行目标程序。
接续时先请用户确认瘦身控制的具体名称、面板画面或包含该功能的目标包路径。不能把现有“瘦脸”误当作“瘦身”,也不能自行设计身体变形后称为已迁移原版算法。
## 目标身份
| 项目 | 新下载目标 | 旧安装参考 |
| --- | --- | --- |
| APP 路径 | `/Users/dayu/Downloads/MSE18V2.app` | `/Applications/MSE18V2.app` |
| 外层与插件版本 | `2.4.0` / `20260724150000` | `1.0.20260617-170517` / `20260617170517` |
| 插件 Bundle ID | `com.ms.plugins.mse18v2` | `com.ms.plugins.mse18v2` |
| 插件通用二进制 SHA-256 | `577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109` | `6c5d74bc844a5c5f745718b48ea10ec6635d08aa08a5b6dc6e62653980849f8a` |
新插件 arm64 切片 SHA-256:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。插件二进制位于各 APP 的 `Contents/PlugIns/MSE18V2.pluginkit/Contents/MacOS/MSE18V2`。
## 已观察证据与范围
- 对新旧包的外层和插件、arm64 与 x86_64 切片,静态检查 `__ustring`、`__cstring`、`__objc_methname`、`__objc_classname`。在这些段内未发现“瘦身、瘦腰、瘦腿、身体”及对应 body/slim/waist/slender/stretch/shoushen 功能命名。可读板块仍为磨皮、美白、瘦脸;新包另有“预览设置、肤色范围、非肤色区保护”等文字。这是有界字符串检查,不能排除动态生成或其他未解释数据。
- 新插件 arm64 的 Ghidra 参数注册函数 `MSSuperSkinSmoothingPlugIn::addParametersWithError:`(`0x10001fc10`)注册面板 210、磨皮/肤色/现有脸型参数和三模块开关,所见注册列表没有身体参数。Evidence:`ev_4d3e7e7dc8aa21347adbd0f0847fab13e8b69462bd5e6adf3657cbc0c1998266`。
- 面板值类的方法包括 `faceThin`、`faceNarrow`、`faceChin`、`faceJaw`、`faceSmallHead` 等,以及 skin/tone/face 三个模块开关。过程名称搜索没有返回身体变形入口;不能由名称负结果断言所有匿名函数均不存在身体算法。Evidence:`ev_446e4a969ff46db0600fe15988d0f396f394641aaeac760d6372a0c0509bf177`、`ev_157df22ee7802216f3581c9842a9629c69ee66097db068b825695bdfd99385d1`。
- 所见几何 GPU 管线仍为 `faceThin*`;新旧 metallib 的 12 个命名函数集合相同。文件变大不能证明新增身体算法,也不能由相同函数名断言函数内容相同。
- REA 对提供者已定义字符串对象的搜索只返回无关的 `URLRequest.httpBody`。Ghidra 未在该搜索中解码中文 UTF-16 常量,因此中文检查另使用实际 Mach-O 字节,未把 REA 空结果当作整个包不含中文的证据。Evidence:`ev_015a585ce5565d874f5b55af0c363bed634f09a29088ef660d3ca1c547626c26`。
REA 使用 Ghidra 12.1.4。通用 Mach-O 不支持该提供者直接选架构,故只读提取 arm64 切片分析。会话已关闭;切片、完整证据和快照仅保存在忽略的 `build/body-analysis/`,不作为构建或远端恢复依赖,不上传原版 APP、模型或 metallib。上述地址与 Evidence ID 仅对应本次 SHA,目标改变后需重新核对。
## 已完成与待定事项
| 问题 | 状态 |
| --- | --- |
| 项目交接、Git 基线、现有正式安装身份 | 已核对,产品源码未改 |
| 新下载包身份及与旧包差异 | 已核对;确为不同内容 |
| 新增瘦身控制、默认值、范围、画布操作 | 未定位,需确认正确目标 |
| 身体算法、处理顺序、跟随与蒙版行为 | 未建立证据,未实施 |
| 产品编译、回归、签名、公证、安装 | 本次未执行 |
## 确认目标后的接入提示
现有工程只有人脸几何,新增身体效果应有独立状态与总开关,不能依赖人脸检测成功。具体控制数量、范围、算法和顺序以正确目标的证据为准。
- `PGInspectorState.m` 的描述表同时驱动面板、归档和插值。保留参数 210 及既有 ID;数值字典缺失项会补默认值。新增卡片时,`PGInspectorView.m` 需按 section 识别“更多设置”,不能继续依赖 `index==3`。
- `PGBeautySettings` 当前是 160 字节 v1 裸结构体。若追加字段,应保留旧前缀并明确接受旧版本/长度组合,补齐新默认值;同步修改宿主解码,拒绝截断、超长或未知版本。不要只更改 `sizeof` 检查。
- OSC 必须同步完整面板对象 210,单写隐藏参数会被已编辑的面板状态覆盖。OSC 回调使用宿主已建立的参数上下文,不能套用面板的 `startAction/endAction` 路径;保留原选脸 ID 和 UUID。
- 身体变形需核对与外观处理、四类蒙版及整体混合的先后关系;验证无人脸、非零 extent、原点标签、极端参数、旧归档、撤销、连续拖动与保存重开。
本次分支基线已在 `origin` 和 `github` 读回核验。两端的最新研究记录以当前分支引用为准;尚无瘦身功能交付标签。
+41
查看文件
@@ -0,0 +1,41 @@
{
"generator": "built-in image_gen",
"type": "generated promotional artwork, not an actual effect-output comparison",
"style": "宋式青绿古风;成年女性面部近景;金色瘦脸轮廓线与内收箭头",
"thumbnail_text": [
"大鱼人像美化",
"自动瘦脸",
"自动跟随",
"自动美颜",
"免费开源"
],
"app_card_text": [
"大鱼人像美化",
"免费开源",
"自动注册 · 无需激活码",
"启动 3 秒后自动退出",
"Final Cut Pro · Motion",
"dayu.media"
],
"files": [
{
"path": "Assets/Artwork/portrait-cover.png",
"sha256": "a346f06e7793b4e5483ccd4b3b86f34c2036bbe6bbddb7ad9cc70c47e7d014ab"
},
{
"path": "beatygril/beatygril/Wrapper Application/Resources/LauncherInfo.png",
"sha256": "239552eeea738a32fafa70922d3cd1d4c115ff75d672574fa4c5acd941381fba"
},
{
"path": "Templates/大鱼人像美化/large.png",
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97"
},
{
"path": "Templates/大鱼人像美化/small.png",
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
}
],
"thumbnail_lock": "uchg on both PNGs only; installer must restore flags",
"template_sha256": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"revision": "User feedback: reduce three feature lines by approximately one third and increase negative space."
}
+5
查看文件
@@ -0,0 +1,5 @@
{
"mode": "built-in image_gen",
"cover_prompt": "Use case: ads-marketing. Asset type: final 16:9 wide Chinese classical portrait beautification FxPlug product cover and very small Final Cut Pro effect thumbnail.\nEdit the supplied previous cover. Preserve its original jade-green, ivory and antique-gold Song-dynasty Chinese painting direction and the fictional adult Chinese hanfu woman identity, but redesign the composition for thumbnail legibility.\nPrimary request: CLOSE-UP FACE portrait dominates the RIGHT 52 percent; crop from the ornate updo to just below shoulders, face itself very large (about 65 percent of image height), almost frontal with slight elegant three-quarter angle, both cheeks and jaw clearly visible, natural skin texture and beautiful natural proportion. No fan, no hands, no full-body or waist framing. Gold/jade hairpin and small part of hanfu collar retain classical character. Background quiet dark jade and understated distant misty Chinese mountains; remove busy koi and flowers near lettering.\nDraw precise elegant luminous antique-gold contour curves along BOTH cheeks and jaw (following the skin outline, from below cheekbones toward chin) plus two short inward arrows on each side, unmistakably communicating automatic face slimming. Add a few restrained dotted jade landmark points and four fine rounded face-following corner marks. These overlays are design graphics only and must not distort the portrait. Avoid modern blue sci-fi HUD, grids covering eyes, and competitor likeness.\nLEFT 46 percent: extremely clear bold warm ivory Chinese display lettering, restrained gold border, generous spacing and high contrast. Text verbatim and only:\nTop compact brand line: \"大鱼人像美化\"\nThree equally prominent large feature lines stacked vertically:\n\"自动瘦脸\"\n\"自动跟随\"\n\"自动美颜\"\nSmall vermilion seal: \"免费开源\"\nSmall bottom line: \"Final Cut Pro · Motion\"\nNo tiny explanatory paragraphs and no extra slogans. Main three feature lines must be very large and remain distinguishable after downscaling to 192x108. Keep all key text and facial features inside 6 percent edge-safe margins. Refined classical poster with realistic close-up portrait, contemporary clear Chinese typography integrated into antique jade/gold aesthetics. Output a polished landscape 16:9 master image.\n",
"final_refinement_prompt": "Edit this exact cover, changing ONLY the oversized typography layout. Preserve the classical jade-green/gold Chinese backdrop, the SAME adult hanfu woman's close-up face, all natural facial proportions, gold jaw-slimming contour arrows and tracking marks, 16:9 canvas, portrait placement. User says the feature text is too large.\nReduce the three feature lines \"自动瘦脸\", \"自动跟随\", \"自动美颜\" to approximately 62 percent of their current font height and width. Make the type refined, medium-weight warm ivory/gold rather than massive heavy gold brush blocks. Set them as three compact clean evenly spaced lines centered within the left column, with substantial calm dark-jade negative space above, below and around. Entire feature text group should occupy roughly 26 percent of total canvas width and 35 percent of canvas height, not the current 40 percent width and 57 percent height.\nKeep the product name \"大鱼人像美化\" at the top left but reduce it slightly (about 15 percent), preserving visual hierarchy: product name slightly larger than each feature line. Small red \"免费开源\" seal and small \"Final Cut Pro · Motion\" footer remain at bottom left. Remove the horizontal rules between the three feature lines; keep only subtle fine gold divider beneath product name and near footer. No new text. No giant lettering. Quiet elegant premium classical poster with FACE as the main visual focus. Exact required text retained: 大鱼人像美化 / 自动瘦脸 / 自动跟随 / 自动美颜 / 免费开源 / Final Cut Pro · Motion.\n"
}
@@ -0,0 +1,17 @@
{
"article_id": 15593,
"url": "https://dayu.media/15593/",
"status": "publish",
"github_repository": "https://github.com/FAMEDaYu/FCP-BeatyGril",
"github_release": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0",
"anonymous_frontend_http": 200,
"both_github_links_present_in_frontend": true,
"code_writing_credit_retained": "代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。",
"resource_price_download_cover_seo_and_author_preserved": true,
"only_content_requested": true,
"frontend_seo_unique_and_exact": true,
"idempotency_key": "55e60cc5-509a-4ae9-ba96-c0d25b2c575a",
"before_content_sha256": "2701991a543b80114c062cc7ee68b83afff505dd9456cfe82f0b8819ea81b119",
"after_content_sha256": "c66e1ddb374714a938442cd24cf5034482ea4e67d6f8dd79c07d43ba74ad1b1d",
"verified_at_utc": "2026-10-21T19:32:48.060004+00:00"
}
+15
查看文件
@@ -0,0 +1,15 @@
{
"target": "https://github.com/FAMEDaYu/FCP-BeatyGril.git",
"source_commit": "dffa547d92478dd471fb4926579df91084581756",
"all_reachable_blobs_scanned": 406,
"secret_pattern_matches": [],
"package_sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"connector_target_push_permission": false,
"local_https_credential_present": false,
"status": "prepared_waiting_for_GitHub_write_authentication",
"github_visibility": "public",
"github_repository_id": "1428817365",
"github_repository_initial_state": "empty",
"origin_retained": "https://dayu.media/git/dayu/paintfcp-fxplug.git",
"github_remote_added": true
}
+19
查看文件
@@ -0,0 +1,19 @@
{
"repository": "https://github.com/FAMEDaYu/FCP-BeatyGril",
"repository_id": 1428817365,
"visibility": "public",
"source_commit": "356683b41af702d6c0143ad7fa5f540d752d6e14",
"local_refs": {
"refs/heads/main": "356683b41af702d6c0143ad7fa5f540d752d6e14",
"refs/tags/baseline-20261021": "4124c350ce288b5fa3cf843ec0e9751e9db19b4c",
"refs/tags/v1.0.4": "302dc20c0a90c0b8934c4341d65c2467d4ed3386",
"refs/tags/v1.0.5": "1008651f6e2111a26d1420021c49f40d6f728b3a",
"refs/tags/v1.0.6": "5793e3de499bfe320b5e9a9db16ef7bc79a5243d",
"refs/tags/v1.1.0": "3bb33818eaa8033b8b1d140eb64e31f38ec3fa75",
"refs/tags/v1.1.2": "e9fddda5e13042f761755762fa39dfe090853c6a",
"refs/tags/v1.2.0": "3c7261c3a861b9f4704cfb36055d7b500c239dab"
},
"github_refs_verified": true,
"main_upstream_retained": "origin",
"auth_storage": "macOS keyring through GitHub CLI; no token included"
}
+14
查看文件
@@ -0,0 +1,14 @@
{
"remote": "https://github.com/FAMEDaYu/FCP-BeatyGril.git",
"anonymous_clone": true,
"credentials_disabled_for_clone": true,
"commit": "356683b41af702d6c0143ad7fa5f540d752d6e14",
"tracked_files_compared": 197,
"all_tag_refs_equal": true,
"tag_count": 7,
"git_fsck_full_strict": true,
"package_sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"lfs": false,
"submodules": false,
"temporary_clone_removed": true
}
+18
查看文件
@@ -0,0 +1,18 @@
{
"repository": "FAMEDaYu/FCP-BeatyGril",
"url": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0",
"release_id": 419972270,
"tag": "v1.2.0",
"draft": false,
"prerelease": false,
"asset": {
"id": 663571667,
"name": "Dayu-Portrait-1.2.0.pkg",
"size": 5011005,
"digest": "sha256:5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"browser_download_url": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/download/v1.2.0/Dayu-Portrait-1.2.0.pkg"
},
"sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"anonymous_asset_download_hash_matches": true,
"downloaded_pkg_signature_and_ticket_valid": true
}
@@ -10,7 +10,14 @@
"status": "operator_confirmed",
"performedByScript": false,
"scopeDocument": "native-qa.json",
"heldMouseCanvasTiming": "pending user observation"
"heldMouseCanvasTiming": "User confirmed continuous visible updates while dragging on 2026-10-22 (Asia/Shanghai); host not specified, no per-event frame timing claim.",
"userConfirmation": {
"date": "2026-10-22",
"timezone": "Asia/Shanghai",
"response": "拖动中已持续更新",
"version": "1.1.2",
"build": "13"
}
},
"source": {
"commit": "a2e33e8e00a99b95dc29d67a819cb0897eda5756",
@@ -0,0 +1,16 @@
{
"remote": "https://dayu.media/git/dayu/paintfcp-fxplug.git",
"tag": "v1.1.2",
"sourceCommit": "a2e33e8e00a99b95dc29d67a819cb0897eda5756",
"passed": true,
"testsNotRepeated": "Source is byte-identical to the independently recovered and Inspector-ASan-tested signed source node.",
"tagCommit": "e9fddda5e13042f761755762fa39dfe090853c6a",
"productSourceIdenticalToSignedNode": true,
"trackedFiles": 158,
"allBytesBlobsModesMatch": true,
"gitFsck": "",
"lfs": false,
"submodules": false,
"temporaryCloneRemoved": true,
"completedAt": "2026-10-21T16:32:45.814667+00:00"
}
+10 -1
查看文件
@@ -27,7 +27,16 @@
"continuousPreview": {
"production": "Each changed continuous step finishes its FxPlug host action before mouse-up; repeated equal steps are deduplicated.",
"automated": "Three intermediate snapshots published before gesture end; production view/controller exercised under action-scoped mock.",
"nativePointerObservation": "Pending user answer: CUA coordinate drag did not reliably exercise the displayed slider; no native mid-drag frame timing claim."
"nativePointerObservation": "User confirmed on 2026-10-22 (Asia/Shanghai): 拖动中已持续更新. Native held-drag visual behavior is accepted by the user; the host was not specified and per-event frame timing was not instrumented.",
"userAcceptance": {
"date": "2026-10-22",
"timezone": "Asia/Shanghai",
"version": "1.1.2",
"build": "13",
"response": "拖动中已持续更新",
"passed": true,
"scope": "User-observed continuous preview during held slider drag in at least one native host; does not establish separate held-drag acceptance in both Motion and FCP or a frame for every mouse event."
}
},
"limits": [
"No claim that every mouse event is presented as a separate host frame. Host scheduling and render speed can coalesce rapid updates.",
@@ -0,0 +1,36 @@
{
"article_id": 15593,
"url": "https://dayu.media/15593/",
"status": "publish",
"updated_fields": [
"content"
],
"attribution": "代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。",
"removed_original_authorship_wording": true,
"anonymous_frontend_http": 200,
"frontend_attribution_verified": true,
"unrelated_settings_unchanged": true,
"preserved": [
"title",
"author account (article publisher)",
"excerpt",
"categories",
"tags",
"featured_media",
"resource including all free-download settings and URLs",
"seo",
"fcpx configuration",
"installation instructions and native code block"
],
"automatic_derived_change": {
"field": "fcpx.article_state.checked_at",
"before": "2026-10-22 01:52:41",
"after": "2026-10-22 02:01:36",
"meaning": "Content save hook refreshed check timestamp; sync remains disabled."
},
"frontend_seo_exact_and_unique": true,
"idempotency_key": "66b51f0d-24ed-4ed9-82fd-e61e626cec4b",
"before_content_sha256": "5968a343e8a9116a5adb7885eafd487acb23608be32d422144196454b1434290",
"after_content_sha256": "2701991a543b80114c062cc7ee68b83afff505dd9456cfe82f0b8819ea81b119",
"verification_time_utc": "2026-10-21T18:02:35.974219+00:00"
}
@@ -0,0 +1,44 @@
{
"status": "complete",
"bundleIdentifier": "com.dayu.beatygril",
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
"options": {
"waitForHosts": false,
"userTests": false
},
"nativeEffectQA": {
"status": "operator_confirmed",
"performedByScript": false
},
"source": {
"commit": "696d5f39b30404ed5d1d4c25f61d17475c7fc91b",
"trackedWorktreeChanges": []
},
"updatedAt": "2026-10-21T17:39:12.166311+00:00",
"version": "1.2.0",
"build": "14",
"stagingSignature": "Executable=/private/tmp/paintfcp-build-20261021/Build/Products/Release/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220\nCandidateCDHashFull sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97\nHash choices=sha256\nCMSDigest=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97\nCMSDigestType=2\nCDHash=c229cfbd5d26e1215ace1dd36e4442a412b52220\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 01:32:31\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
"notarization": {
"status": "Accepted",
"id": "3999fe91-a80e-49d3-9ed0-4003b82f6f54",
"message": "Processing complete"
},
"signingVerified": true,
"stapleValidated": true,
"stagingPluginUnregistered": true,
"runningHosts": [],
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220\nCandidateCDHashFull sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97\nHash choices=sha256\nCMSDigest=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97\nCMSDigestType=2\nCDHash=c229cfbd5d26e1215ace1dd36e4442a412b52220\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 01:32:31\nNotarization Ticket=stapled\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
"installedSignatureVerified": true,
"installedStapleValidated": true,
"gatekeeperAccepted": true,
"pluginDiscovery": {
"bundleIdentifier": "com.dayu.beatygril.fxplug",
"formalPath": "/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
"output": " com.dayu.beatygril.fxplug(1.1)\tDECE2AF1-8D68-43B9-BE2E-6C97FB9EE96D\t2026-10-21 17:33:00 +0000\t/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit\n (1 plug-in)\n"
},
"removedGeneratedPaths": [
"/Users/dayu/Documents/PaintFCP/build/delivery/previous-beatygril.app",
"/tmp/paintfcp-build-20261021",
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
]
}
@@ -0,0 +1,17 @@
{
"roots": [
"/Applications",
"/Library/Plug-Ins/FxPlug",
"/Users/dayu/Library/Plug-Ins/FxPlug",
"/Users/dayu/Documents/PaintFCP",
"/tmp/paintfcp-build-20261021"
],
"product_paths": [
"/Library/Plug-Ins/FxPlug/beatygril.app"
],
"errors": [],
"removed": [
"build/pkg-expanded"
],
"scope": "bounded scan; not all mounted volumes"
}
@@ -0,0 +1,13 @@
{
"tag": "v1.2.0",
"commit": "3c7261c3a861b9f4704cfb36055d7b500c239dab",
"files_verified": 183,
"fsck_full_strict": true,
"package_sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"recovered_package_signature_and_ticket": true,
"xcode_project_readable": true,
"lfs": false,
"submodules": false,
"authentication": "saved member Git credential; anonymous gateway access remains restricted",
"temporary_clone_removed": true
}
@@ -0,0 +1,22 @@
[
{
"path": "/Users/dayu/Documents/PaintFCP/Templates/大鱼人像美化/large.png",
"uchg": true,
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97"
},
{
"path": "/Users/dayu/Documents/PaintFCP/Templates/大鱼人像美化/small.png",
"uchg": true,
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
},
{
"path": "/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/large.png",
"uchg": true,
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97"
},
{
"path": "/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/small.png",
"uchg": true,
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
}
]
@@ -0,0 +1,2 @@
com.dayu.beatygril.fxplug(1.1) DECE2AF1-8D68-43B9-BE2E-6C97FB9EE96D 2026-10-21 17:33:00 +0000 /Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit
(1 plug-in)
@@ -0,0 +1,24 @@
Executable=/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril
Identifier=com.dayu.beatygril
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220
CandidateCDHashFull sha256=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97
Hash choices=sha256
CMSDigest=c229cfbd5d26e1215ace1dd36e4442a412b52220f48215bd108107e1affb0b97
CMSDigestType=2
CDHash=c229cfbd5d26e1215ace1dd36e4442a412b52220
Signature size=8968
Authority=Developer ID Application: zhong luo (B3W25FX5H5)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Oct 22, 2026 at 01:32:31
Notarization Ticket=stapled
Info.plist entries=22
TeamIdentifier=B3W25FX5H5
Runtime Version=27.0.0
Sealed Resources version=2 rules=13 files=5
Internal requirements count=1 size=180
Total signatures=1
Chosen signature=1
@@ -0,0 +1,14 @@
[
{
"elapsed": 13.717,
"running": true,
"processes": [
"33709 /Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril"
]
},
{
"elapsed": 17.944,
"running": false,
"processes": []
}
]
+16
查看文件
@@ -0,0 +1,16 @@
{
"version": "1.2.0",
"build": "14",
"source_commit": "696d5f39b30404ed5d1d4c25f61d17475c7fc91b",
"native_app_card": "Observed correct classical information card, with accessible text",
"exit_timer_seconds_after_window_shown": 3.0,
"observed_process_lifetime_seconds": 4.227,
"process_lifetime_note": "Includes process initialization before didFinishLaunching/window presentation. Not a measurement of timer drift.",
"automatic_registration": "Own bundle registered via LSRegisterURL; installed PluginKit entry remains at unique formal path",
"host_validation": {
"FCP": "Fresh launch, new locked thumbnail visible in 大鱼磨皮瘦脸; applied ours to second clip in existing QA project; panel loaded, brightness set to20%, picture rendered without black output.",
"Motion": "No fresh 1.2.0 UI test; renderer and inspector source unchanged from user-accepted 1.1.2."
},
"screenshots": "Native app and FCP screenshots kept local under ignored build/delivery; user stock imagery not published",
"bounded_duplicate_inventory": "Final cleanup removed known build and backup app paths; final inventory follows in packaging verification."
}
@@ -0,0 +1 @@
{"status":"Accepted","id":"3999fe91-a80e-49d3-9ed0-4003b82f6f54","message":"Processing complete"}
@@ -0,0 +1,6 @@
{
"name": "大鱼人像美化-1.2.0.pkg",
"id": "96a3d1be-a751-4fb8-b062-33a09c01ddf2",
"status": "Accepted",
"createdDate": "2026-10-21T17:39:18.173Z"
}
@@ -0,0 +1,36 @@
{
"package": "releases/1.2.0/大鱼人像美化-1.2.0.pkg",
"bytes": 5011005,
"sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"version": "1.2.0",
"build": "14",
"app_files_compared": 34,
"app_byte_and_symlink_equality": true,
"template_files": {
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
},
"locked_relative_paths": [
"大鱼人像美化/large.png",
"大鱼人像美化/small.png"
],
"script_sha256": {
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
"postinstall": "eeada4e07a284726d70772591c481f6ae12bfda12ed9ae3035d1089bca0bd59b"
},
"isolated_script_tests": [
"fresh install",
"replace old locked thumbnail",
"partial copy failure restores old bytes and locks"
],
"isolation_changes": [
"Console identity/home redirected to task fixture",
"chown replaced with true",
"FxPlug verification skipped; formal app signature and discovery verified separately"
],
"real_installer_execution": false,
"app_and_template_installed": "APP installed through signed delivery workflow; user thumbnail directory updated separately, not by running this PKG",
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
}
@@ -0,0 +1,11 @@
{
"checked_commit": "906f770805fdbe8329c9d4ecd3594310e23bca6a",
"reachable_blobs_scanned": 356,
"secret_pattern_matches": [],
"disallowed_extensions": [],
"notes": [
"No original competitor app, metallib, model or user stock video is included.",
"NASA astronaut sample retains its source attribution.",
"Tool-generated promotional art is labeled as illustration."
]
}
@@ -0,0 +1,59 @@
{
"article_id": 15593,
"url": "https://dayu.media/15593/",
"status": "publish",
"anonymous_http": 200,
"category": 3,
"free_for_all": true,
"featured_media": 15595,
"native_code_block_present": true,
"seo_tags": {
"title": [
"大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件"
],
"description": [
"大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,支持磨皮、美白、自动人脸跟随及瘦脸调整。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,并附具体安装、使用及红色警告排查说明。"
],
"keywords": [
"大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源"
],
"unique_and_exact": true
},
"assets": [
{
"role": "package",
"url": "https://dayu.media/wp-content/uploads/2026/10/1792604749-1ea4dca3cc5a5c3.pkg",
"anonymous_http": 200,
"bytes": 5011005,
"sha256": "5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243",
"matches_local": true
},
{
"role": "source",
"url": "https://dayu.media/wp-content/uploads/2026/10/1792604741-f6e09da5b67c006.zip",
"anonymous_http": 200,
"bytes": 9607987,
"sha256": "a235fb3168c09a1e3a4fc5f347b3957cbd9ee2a1c3848e2af1dda2e64afbb870",
"matches_local": true
},
{
"role": "cover",
"url": "https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png",
"anonymous_http": 200,
"bytes": 2776027,
"sha256": "a346f06e7793b4e5483ccd4b3b86f34c2036bbe6bbddb7ad9cc70c47e7d014ab",
"matches_local": true
},
{
"role": "card",
"url": "https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png",
"anonymous_http": 200,
"bytes": 3065968,
"sha256": "239552eeea738a32fafa70922d3cd1d4c115ff75d672574fa4c5acd941381fba",
"matches_local": true
}
],
"source_article_click_anonymous_verified": true,
"fcpx_app_sync_requested": false,
"git_visibility": "Gitea public attribute verified; anonymous gateway access still requires membership as disclosed in article"
}
@@ -0,0 +1,85 @@
{
"article": {
"id": 15593,
"url": "https://dayu.media/15593/",
"edit_url": "https://dayu.media/wp-admin/post.php?post=15593&action=edit",
"status": "publish",
"title": "大鱼人像美化 1.2.0:FCP / Motion 免费开源自动美颜插件",
"content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\" /><figcaption class=\"wp-element-caption\">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n\n<!-- wp:list {\"className\":\"wp-block-list\"} -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>磨皮:局部磨皮、全局磨皮与五官保护,强度分别控制。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.2.0(14)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>本次更新加入古风封面与锁定缩略图、免费开源说明页和主 APP 三秒自动退出。人脸处理与面板交互沿用 1.1.2 已验收实现,不需要重新运行手动分析。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\" /></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">常见问题</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,Line truncated
"excerpt": "磨皮、美白、瘦脸与自动人脸跟随,原生卡片面板实时预览。免费开源,自动注册,无需激活码;提供签名公证安装包和源码。",
"author": 1,
"categories": [
3
],
"tags": [],
"featured_media": 15595,
"resource": {
"cao_status": "1",
"cao_close_novip_pay": "0",
"cao_is_boosvip": "",
"cao_video": "",
"cao_is_video_free": "",
"cao_price": "0",
"cao_vip_rate": "1",
"cao_ref_bonus_rate": "0.25",
"cao_expire_day": "0",
"cao_downurl": "https://dayu.media/wp-content/uploads/2026/10/1792604749-1ea4dca3cc5a5c3.pkg",
"cao_downurl_bak": "",
"cao_demourl": "",
"video_url": "",
"video_poster_url": "",
"cao_pwd": "",
"cao_original_filename": "1792604749-1ea4dca3cc5a5c3.pkg",
"post_style": "sidebar",
"cao_info": [
{
"title": "版本",
"desc": "1.2.0(14)"
},
{
"title": "宿主",
"desc": "Final Cut Pro / Motion"
},
{
"title": "系统",
"desc": "macOS 13 或更高版本"
},
{
"title": "架构",
"desc": "Apple Silicon / Intel"
},
{
"title": "授权",
"desc": "免费开源,无需激活码"
}
]
},
"seo": {
"title": {
"enabled": true,
"value": "大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件"
},
"description": {
"enabled": true,
"value": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,支持磨皮、美白、自动人脸跟随及瘦脸调整。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,并附具体安装、使用及红色警告排查说明。"
},
"keywords": {
"enabled": true,
"value": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源"
}
},
"fcpx": {
"enabled": "0",
"kinds": [],
"version": "",
"entry": "",
"article_state": {
"code": "hidden",
"message": "未同步到 APP",
"checked_at": "2026-10-22 03:32:39"
},
"file_check": "",
"product_id": ""
}
}
}
+7
查看文件
@@ -0,0 +1,7 @@
# 1.2.0 / build 14
本次只修改外层启动器、版本和宣传资源;PGFaceProcessor、PGBeautyRenderer、PGInspectorView、PGInspectorState 与 Metal 渲染算法保持 1.1.2 用户验收版本。缩略图以用户指定的生成宣传画为来源,不冒充真实渲染静帧。
安装分类使用当前用户已移动后的 `Effects.localized/大鱼磨皮瘦脸/大鱼人像美化`。本地磁盘 moef 与源码基线 SHA-256 均为 e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15,未覆盖任何最新手改。只为 large.png / small.png 设置 uchg。
待验证:正式 Release 构建、双架构、APP 签名 / 公证 / 票据 / 安装 / 插件发现、启动器三秒退出、PKG 签名公证与有效载荷 / 缩略图锁定脚本、远端发布与文章。
@@ -0,0 +1,8 @@
{
"id": 1,
"name": "Dayu-Portrait-1.2.0.pkg",
"size": 5011005,
"browser_download_url": "https://dayu.media/git/attachments/2d27be42-6380-421c-8475-7524574ec889",
"uuid": "2d27be42-6380-421c-8475-7524574ec889",
"created_at": "2026-10-22T01:48:05+08:00"
}
@@ -0,0 +1,10 @@
{
"id": 128,
"tag_name": "v1.2.0",
"name": "大鱼人像美化 1.2.0",
"html_url": "https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.2.0",
"url": "https://dayu.media/git/api/v1/repos/dayu/paintfcp-fxplug/releases/128",
"draft": false,
"prerelease": false,
"body": "大鱼人像美化 1.2.0(14)\n\n免费开源。自动跟随、人像磨皮、美白和脸型调整。新增古风宣传封面与缩略图,主 APP 显示免费开源说明并在窗口显示三秒后退出。\n\nAPP 和 PKG 均已正式签名、Apple 公证并粘附票据。\n\n免费安装包与免 Git 登录源码快照:https://dayu.media/15593/\n\n安装包仓库位置:releases/1.2.0/大鱼人像美化-1.2.0.pkg\nSHA-256:5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243\n\n当前站点 Git 网关仍需登录;仓库公开属性已设为 public,站外读者可通过文章免费下载源码快照。"
}
@@ -0,0 +1,13 @@
{
"patch": "accepted",
"id": 36,
"private": false,
"url": "https://dayu.media/git/dayu/paintfcp-fxplug",
"anonymous_access": {
"html_http": 302,
"api_http": 401,
"git_ls_remote": "credential request denied in anonymous mode",
"reason": "Site-wide WordPress Git membership gateway is evaluated before Gitea public-repository permissions.",
"server_code_changed": false
}
}
@@ -0,0 +1,9 @@
{
"source_click_url": "https://dayu.media?cao_direct_download=1&file_url=https%3A%2F%2Fdayu.media%2Fwp-content%2Fuploads%2F2026%2F10%2F1792604741-f6e09da5b67c006.zip",
"http": 200,
"content_type": "application/octet-stream",
"final_url": "https://dayu.media?cao_direct_download=1&file_url=https%3A%2F%2Fdayu.media%2Fwp-content%2Fuploads%2F2026%2F10%2F1792604741-f6e09da5b67c006.zip",
"bytes": 9607987,
"sha256": "a235fb3168c09a1e3a4fc5f347b3957cbd9ee2a1c3848e2af1dda2e64afbb870",
"click_download_matches_source": true
}
@@ -0,0 +1,8 @@
{
"commit": "788ba0d5514595cf349af33074055d70b0754185",
"files": 182,
"package_excluded": true,
"filename": "Dayu-Portrait-1.2.0-source.zip",
"bytes": 9607987,
"sha256": "a235fb3168c09a1e3a4fc5f347b3957cbd9ee2a1c3848e2af1dda2e64afbb870"
}
@@ -0,0 +1,26 @@
{
"installationCategory": "大鱼磨皮瘦脸",
"template": "大鱼人像美化.moef",
"files": {
"大鱼人像美化.moef": {
"size": 23073,
"sha256": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"locked": false
},
"Drop Zone.tiff": {
"size": 420128,
"sha256": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
"locked": false
},
"large.png": {
"size": 454742,
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
"locked": true
},
"small.png": {
"size": 45373,
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5",
"locked": true
}
}
}
@@ -0,0 +1,29 @@
{
"date": "2026-10-22",
"timezone": "Asia/Shanghai",
"version": "1.3.0",
"build": "15",
"status": "passed",
"checks": {
"beauty": 57,
"face": 116,
"geometry": 796,
"host_adapter_asan": 341,
"osc_asan": 98,
"inspector_asan_including_optional_preview": 228
},
"total": 1636,
"commands": [
"./scripts/test.sh",
"PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh",
"PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh",
"PAINTFCP_INSPECTOR_ASAN=1 PAINTFCP_INSPECTOR_PNG=<local-path> ./scripts/test-inspector.sh"
],
"notes": [
"OSC passed before the later standalone beauty fallback and legacy inspector numeric-read fixes; those fixes do not change OSC code.",
"Core, host adapter and inspector rerun after all source fixes.",
"Inspector includes one optional offscreen PNG write assertion.",
"No native Motion/FCP interaction test performed for this version; active user hosts are preserved.",
"Reference interpretation and implementation limitations are in docs/analysis/新版磨皮参数迁移.md."
]
}
@@ -0,0 +1,44 @@
{
"status": "installed_user_qa_pending",
"bundleIdentifier": "com.dayu.beatygril",
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
"options": {
"waitForHosts": true,
"userTests": true
},
"nativeEffectQA": {
"status": "pending_user",
"performedByScript": false
},
"source": {
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
"trackedWorktreeChanges": []
},
"updatedAt": "2026-10-22T07:15:35.383726+00:00",
"version": "1.3.0",
"build": "15",
"stagingSignature": "Executable=/private/tmp/paintfcp-build-20261021/Build/Products/Release/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nCandidateCDHashFull sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nHash choices=sha256\nCMSDigest=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nCMSDigestType=2\nCDHash=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 15:07:35\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
"notarization": {
"id": "ca96837f-bf33-44fa-8d58-799026ce5c7d",
"message": "Processing complete",
"status": "Accepted"
},
"signingVerified": true,
"stapleValidated": true,
"stagingPluginUnregistered": true,
"runningHosts": [],
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nCandidateCDHashFull sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nHash choices=sha256\nCMSDigest=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nCMSDigestType=2\nCDHash=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 15:07:35\nNotarization Ticket=stapled\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
"installedSignatureVerified": true,
"installedStapleValidated": true,
"gatekeeperAccepted": true,
"pluginDiscovery": {
"bundleIdentifier": "com.dayu.beatygril.fxplug",
"formalPath": "/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
"output": " com.dayu.beatygril.fxplug(1.1)\t97262612-DD61-47F2-B25E-D82B95C893EE\t2026-10-22 07:15:35 +0000\t/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit\n (1 plug-in)\n"
},
"removedGeneratedPaths": [
"/Users/dayu/Documents/PaintFCP/build/delivery/previous-beatygril.app",
"/tmp/paintfcp-build-20261021",
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
]
}
@@ -0,0 +1,38 @@
{
"status": "verified",
"date": "2026-10-22",
"timezone": "Asia/Shanghai",
"installedProduct": {
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
"version": "1.3.0",
"build": "15"
},
"signatureAllArchitecturesVerified": true,
"duplicateInventory": {
"scope": "Listed local paths and existing explicit related PaintFCP paths on mounted volumes; Spotlight additionally queried. Not a full scan of every volume.",
"roots": [
"/Applications",
"/Library/Plug-Ins/FxPlug",
"/Users/dayu/Library/Plug-Ins/FxPlug",
"/Users/dayu/Documents/PaintFCP",
"/Users/dayu/Desktop",
"/Users/dayu/Downloads",
"/Users/dayu/Library/Developer/Xcode/DerivedData",
"/tmp/paintfcp-build-20261021"
],
"products": [
{
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
"version": "1.3.0",
"build": "15"
}
],
"errors": []
},
"temporaryPathsRemoved": [
"/tmp/paintfcp-build-20261021",
"build/delivery/previous-beatygril.app",
"build/delivery/notarization.zip"
],
"nativeEffectQA": "pending_user"
}
@@ -0,0 +1,21 @@
{
"status": "waiting_for_host_exit",
"bundleIdentifier": "com.dayu.beatygril",
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
"version": "1.3.0",
"build": "15",
"source": {
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
"trackedWorktreeChanges": []
},
"notarization": {
"id": "ca96837f-bf33-44fa-8d58-799026ce5c7d",
"message": "Processing complete",
"status": "Accepted"
},
"signingVerified": true,
"stapleValidated": true,
"stagingPluginUnregistered": true,
"nativeEffectQA": "pending_user",
"note": "Prepared Release is Accepted and stapled; installation is waiting for existing user hosts to close. The installed product has not been replaced."
}
@@ -0,0 +1,12 @@
{
"status": "verified",
"date": "2026-10-22",
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
"remote": "https://dayu.media/git/dayu/paintfcp-fxplug.git",
"branch": "codex/new-beauty-controls",
"trackedFilesCompared": 205,
"gitFsckFullStrict": true,
"lfs": false,
"submodules": false,
"resources": "All tracked source, template and artwork bytes match; user QA media/signing credentials are external and not required to compile source."
}
+287
查看文件
@@ -0,0 +1,287 @@
# 大鱼人像美化项目交接
更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。
当前正式安装的 APP 为 **1.3.0(构建 15)**,已完成通用 Release 编译、正式签名、Apple 公证、票据验证及唯一正式路径安装。新增磨皮参数迁移与 1636 项自动检查已完成,原生效果视觉仍待用户实测。公开文章、PKG 与 GitHub Release 继续对应 **1.2.0**;本次未更新这些发行资料,也未覆盖模板或宣传图。
代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。
1.2.0 交接整理前,工作区干净,`main`、`origin/main` 与 `github/main` 均为 `189a5d7634aa69db54330c90f8711b05d8e44b10`。这是文档新增前的基线;最新文档节点以 `git log -1` 和远端引用为准。
## 先读和先查
接手时先查看 `git status --short --branch`、`git remote -v` 和最新提交,确认没有其他聊天的未提交改动。只读核对正式 APP 版本与模板目录,再决定是否需要编译或操作宿主。单纯修改文档不需要重建、重新公证或打开 Motion/FCP。
当前状态以本交接、[恢复说明](../RECOVERY.md)、[验证记录](验证记录.md) 和最新版本回执为入口。`docs/analysis` 与旧版本回执保留了研究过程,其中“待修复”“待测试”可能是历史状态;例如 1.2.0 的 `release-plan.md` 是发布前计划,实际完成情况看 `native-qa.json` 和交付回执。
| 入口 | 用途 |
| --- | --- |
| [1.3.0 交付回执](verification/v1.3.0/delivery-receipt.json) | 当前安装版、签名源码、公证、清理及原生视觉待测范围 |
| [README](../README.md) | 产品介绍、使用与版本变化 |
| [恢复说明](../RECOVERY.md) | 精确源码节点、依赖、远端恢复记录 |
| [GitHub 同步说明](GitHub同步说明.md) | 两个远端、公开克隆及 Release 验证 |
| [1.2.0 交付回执](verification/v1.2.0/delivery-receipt.json) | 签名源码、公证、正式安装与清理结果 |
| [1.2.0 原生验收](verification/v1.2.0/native-qa.json) | 启动器与 FCP 实测范围 |
| [1.1.2 原生验收](verification/v1.1.2/native-qa.json) | 面板、短脸、下颌骨和连续预览验收 |
| [第三方资料与许可](../THIRD_PARTY_NOTICES.md) | MIT 范围、Apple 依赖与宣传素材边界 |
## 固定身份与安装位置
| 项目 | 当前值 |
| --- | --- |
| 显示名称 | 大鱼人像美化 |
| Xcode 产品名 | `beatygril`,保留现有拼写 |
| APP 版本 | `1.3.0` / `15`,arm64 与 x86_64 通用版本 |
| 唯一正式 APP | `/Library/Plug-Ins/FxPlug/beatygril.app` |
| 主 Bundle ID | `com.dayu.beatygril` |
| 嵌套插件 | `Contents/PlugIns/beatygril XPC Service.pluginkit` |
| 插件 Bundle ID | `com.dayu.beatygril.fxplug` |
| 滤镜 UUID | `FB14B0E6-59B2-4836-916F-CD0C559E9241` |
| 自定义面板参数 ID | `210` |
| FCP 效果分类 | 大鱼磨皮瘦脸 → 大鱼人像美化 |
| Motion 原生滤镜分类 | 大鱼 → 大鱼人像美化 |
| 签名团队 | `B3W25FX5H5` |
当前 FCP 模板为:
```text
/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/大鱼人像美化.moef
```
源码模板仍在 `Templates/大鱼人像美化/`,脚本和测试使用这个路径。磁盘安装分类与源码目录层级不同是有意保留。旧的 `Effects.localized/大鱼/大鱼人像美化` 不是当前安装位置。
不要在 `/Applications`、用户级 FxPlug、Debug 或其他目录再留同产品外层 APP。替换前核对 Bundle ID 和来源;嵌套插件、Framework 及安装包内封装的有效载荷不属于重复安装。
## 源码结构
Xcode 工程:`beatygril/beatygril.xcodeproj`。外层 scheme 为 `Wrapper Application`,插件 target 为 `XPC Service`。
下表插件文件均位于 `beatygril/beatygril/Plugin/`。
| 文件或目录 | 职责与修改入口 |
| --- | --- |
| `beatygrilPlugIn.m` | FxPlug 参数、宿主 action、图像适配、渲染状态与整体混合 |
| `PGFaceProcessor.m` | Vision 检测、76 点、自动跟随、几何稳定、局部变形和几何蒙版 |
| `PGBeautyRenderer.m` | 磨皮、肤色、细节、牙齿和眼睛等外观处理 |
| `PGInspectorView.m` | AppKit 卡片、滑杆、数值框、开关、重置和连续提交 |
| `PGInspectorState.m` | 面板完整状态、NSSecureCoding、复制与插值 |
| `PGFaceSelectOSC.m` | 画布选脸与检测框等屏幕控件 |
| `PGParameterIDs.h`、`PGBeautyTypes.h` | 稳定参数 ID 和共享设置结构 |
| `../Wrapper Application/AppDelegate.m` | 主 APP 说明图、系统注册与三秒退出 |
| `../Wrapper Application/Resources/LauncherInfo.png` | 主 APP 古风说明图 |
| `Templates/大鱼人像美化/`(仓库根) | FCP 效果工程、标准占位图及缩略图 |
| `tests/`、`scripts/test*.sh`(仓库根) | 离屏像素、几何、宿主适配与面板测试 |
几何和外观内核由 Objective-C 源码构造 Core Image kernel;没有复制目标插件的 metallib 或私有模型。Xcode 使用文件系统同步分组,添加文件时核对 target 排除项,防止把插件实现编入外层 APP,或把启动器资源与 `AppDelegate.m` 编入插件。
## 自动跟随与脸型修复
### 识别和转脸
当前使用 Apple Vision `VNDetectFaceLandmarksRequestRevision3` 与 `VNRequestFaceLandmarksConstellation76Points`。实时渲染自动检测并关联主要人脸,结合防跳范围、关键点稳定、失检保持和几何历史;不需要先点击分析。多人模式另走多人几何处理。
目标插件的静态证据支持 Vision 点阵与局部二维变形,已检查的瘦脸路径没有证明存在显式 yaw 切换或完整 3D 姿态模型。侧脸适应主要来自轮廓与五官点随姿态改变,不能宣称已确定某个第三方神经网络或完全恢复原版模型。证据入口见[脸型与转脸分析](analysis/脸型变形与转脸分析.md)和[自动跟随报告](analysis/auto-follow-report.json)。
本项目几何历史只取当前请求之前的近时记录,原版还存在近未来历史分支;冷启动、热缓存、乱序渲染、同尺寸换源和多人交叉仍有差异边界。旧离线分析字段保留兼容,但当前新面板的渲染统一使用实时自动跟随。
### 已完成的四项局部算法
| 控制项 | 当前实现 | 防止回归的要点 |
| --- | --- | --- |
| 瘦脸 | 76 点、17 组轮廓到鼻部或瞳孔锚点的局部逆向采样 | 不恢复整脸框水平挤压;保留尺寸增益、组顺序和逐步 clamp |
| 下巴 | `68→38`、`67→37`、`66→36` 三组局部位移 | 正值上收、负值延伸,保留正负不同系数 |
| 下颌骨 | 六组相邻轮廓半径的顺序局部位移 | 半径来自相邻轮廓点,方向锚点为 P29;不能同时求和替代逐步更新 |
| 短脸 | P62 至 P72 的下半脸闭合区域,沿 P46−P48 鼻梁轴位移 | 正值收短、负值延长;不是太阳穴区域或脸框纵向压缩 |
这四项共享由实际图像像素尺寸计算的增益。完整合法 76 点缺失时,四项安全直通,不退回猜测的脸框场。图像与磨皮、肤色、牙齿、眼睛蒙版共用几何变形路径,避免效果与蒙版错位。
**仍为近似实现的五项:大眼、窄脸、V 脸、颧骨、小头。** 原版完整链为 `thin → narrow → V → jaw → cheek → chin → short → small-head → eyes`,本项目尚未完全恢复整条组合链的数学及顺序。用户单项验收不代表所有参数组合逐像素等价。详细索引、系数和独立数值场验证见[下巴与坐标分析](analysis/下巴与坐标分析.md)、[短脸与下颌骨分析](analysis/短脸与下颌骨分析.md)。
### 坐标约定
宿主 CI/IOSurface 链统一按 Y 向上处理;归档坐标标记为 `hostCoordinateSpace=iosurface-ci-y-up-v1`。不要仅看到 `TOP_LEFT` 标志就再翻转图像。局部几何中需要的归一化 Y 向下 UV 在同一 kernel 内成对转换,不改变宿主图像方向。
旧无标记分析档案不能靠补字符串伪装为新坐标。涉及位置的修改应同时检查非零 extent、图像宽高比、真实侧脸、歪头、正负参数和上下原点标签。历史“下巴作用在眼睛”“短脸和下颌骨作用在太阳穴”的问题已有相应修复,不应再用移动检测框来掩盖坐标或点索引问题。
## 面板与连续预览
界面由 AppKit 自绘磨皮、美白、瘦脸卡片及原生输入控件构成。FCP 模板只发布自定义面板 210 和两项署名信息,手动分析和多余平铺参数已隐藏;隐藏参数 ID 与旧归档仍须保留,以免破坏工程兼容。
面板交互必须在真实视图对应的 **宿主 action 内** 获取读写接口,不能缓存接口后在 action 外使用。每个发生变化的拖动步进都要在松手之前完成自己的 action;把整次拖动包在一个直到 mouse-up 才结束的 action 中,会再次造成松手后才更新。重复相同步进可去重。
`PGInspectorState` 保存完整且可安全归档的状态。未编辑面板时兼容旧文档参数,首次编辑采集当前设置;旧版各项独立关键帧曲线尚未自动迁移为新面板曲线。修改时同时检查数值 Return 提交、焦点切换、单项重置、宿主撤销和保存重开,不只看滑杆外观。
用户于 2026-10-22 明确确认“拖动中已持续更新”。该回复未指定宿主,覆盖至少一个原生宿主的按住拖动体验;宿主调度可能合并快速更新,不能写成每个鼠标事件必定显示一帧。
## 验证状态与开发命令
在项目根执行:
```sh
./scripts/test.sh
PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh
PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh
PAINTFCP_INSPECTOR_ASAN=1 ./scripts/test-inspector.sh
python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼人像美化.moef'
```
1.1.2 完整回归为 **1551 项**:Beauty 49、Face 116、几何 796、宿主适配 ASan 335、OSC ASan 98、Inspector ASan 157。额外真实帧 ASan 专项 886 项包含重复基础用例,未计入 1551。28 种控制与原点组合核对了解剖位置,改变原点标签时输出逐字节一致。详见[自动验证汇总](verification/v1.1.2/automated-tests.json)。
| 验证范围 | 已完成结果与边界 |
| --- | --- |
| Motion 1.1.2 | 正式插件、数值输入、重置、撤销、焦点和保存关闭重开;短脸与下颌骨隔离画面检查 |
| FCP 1.1.2 | 正式面板启用、数值与重置;短脸和下颌骨分别隔离渲染,画面有响应 |
| 连续预览 | 模拟宿主确认 mouse-up 前发布中间状态;用户实际拖动已确认 |
| 主 APP 1.2.0 | 古风说明图和无障碍文字正确,窗口显示后计时三秒退出,系统注册成功 |
| FCP 1.2.0 | 新启动后显示新缩略图,QA 工程加载滤镜、亮度调到 20%,画面正常无黑屏 |
| Motion 1.2.0 | 未重新进行该版界面视觉验收;渲染和面板源码沿用已验收 1.1.2 |
| 安装包 | 有效载荷与正式 APP、四个模板文件一致;隔离脚本验证初装、替换锁定图和失败回滚 |
1.2.0 只修改外层启动器、版本与宣传资源,没有重新运行全部 1.1.2 自动测试,不能把历史测试写成该版全量重跑。原生 VoiceOver、旧独立关键帧迁移、多脸交叉、重遮挡和所有极端姿态仍未完整验收。
现有 PKG **未通过真实 installer 再次安装到当前用户目录**:APP 由 `deliver.py` 安装,缩略图另行同步;PKG 的安装脚本在隔离目录执行,重定向用户身份、替代 chown 并跳过其中的真实 FxPlug 验证。正式 APP 的签名与发现另有真实验证。不要把隔离测试表述成完整系统安装实测。
用户测试视频位于:
```text
/Volumes/DayuMedia 4TB/LCQ荒野乱斗/LCQ赛事回放/teen-with-blue-hair-smiling-at-beach-2026-10-02-18-55-48-utc.mov
```
该视频、宿主 QA 工程、截图、完整 AX 和人脸坐标仅保留在本机或忽略的 `build/` 下,不是构建依赖,不要上传。仓库自动测试另有带来源说明的 NASA 公共领域样本。宿主验收在独立 QA 工程进行,避免修改用户工作时间线。
## 宣传图和缩略图
最终设计为虚构成年古风人物的面部近景,深青玉色与金色、下颌收缩线和箭头、跟随角标。文字包含“自动瘦脸、自动跟随、自动美颜”,已按用户反馈减小字号。保持与目标宣传人物的区别,不回用目标肖像。
| 资源 | 文件 |
| --- | --- |
| 项目封面 | `Assets/Artwork/portrait-cover.png` |
| APP 说明图 | `beatygril/beatygril/Wrapper Application/Resources/LauncherInfo.png` |
| 大缩略图 | `Templates/大鱼人像美化/large.png`,640×360 |
| 小缩略图 | `Templates/大鱼人像美化/small.png`,192×108 |
| 生成记录 | `docs/design/artwork-manifest.json`、`artwork-prompt.json` |
这些是生成的宣传插画,不是真实美颜效果前后对比。文字已烘焙进 PNG,没有需要额外分发的可编辑字体依赖。
运行时模板目录必须包含 `.moef`、`Drop Zone.tiff`、`large.png`、`small.png` 四个文件。仅两张 PNG 设置 BSD `uchg`,不锁工程或目录。Git 和普通 ZIP 不保存该标志,手工恢复后需要重新设置:
```sh
chflags uchg "$HOME/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/large.png" "$HOME/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化/small.png"
ls -lO "$HOME/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化"
```
替换图前仅解除对应 PNG 的 `uchg`,替换后重锁。同步 `.moef` 前先比较用户磁盘最新文件与源码,保留手改,不能盲目覆盖。当前四文件 SHA-256 见[安装包验证](verification/v1.2.0/pkg-verification.json)。本次交接核对时,正式 APP 为 1.2.0(14),两张安装缩略图均有 `uchg`。
## Release 构建签名与安装
依赖为 Xcode 27.1、FxPlug SDK 4.3.4、PluginManager 1.7.4,最低 macOS 13。头文件和链接信息来自 `/Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks`;嵌入的可运行框架来自 `/Library/Developer/Frameworks`。不要把 SDK 链接存根当作运行框架。
完整正式交付入口:
```sh
python3 scripts/deliver.py
```
脚本获取 `/Users/dayu/.codex/app-delivery-locks/com.dayu.beatygril.lock`,使用固定暂存 `/tmp/paintfcp-build-20261021`,记录到 `build/delivery/`。它构建通用 Release,由内到外签名 Framework、嵌套插件、外层 APP,验证严格签名,提交公证并要求 `Accepted`,粘附并验证票据,等待宿主退出后替换唯一正式路径,检查 Gatekeeper 与 PluginKit。默认停在 `HOST_VALIDATION_PENDING`,完成实际宿主验收及副本盘点后才回车进入清理。
| 选项 | 用途 |
| --- | --- |
| `--wait-for-hosts` | 保持交付锁,只读等待 Motion/FCP 自行退出,不操作或结束宿主 |
| `--user-tests` | 静态安装验证后清理已知生成副本,把原生效果验收明确保留给用户 |
| `--resume-prepared` | 仅恢复已有 Accepted、stapled 暂存产物;核对 CDHash、版本和产品源码未改变 |
运行脚本前先提交并推送待交付源码。用户已长期授权正式 Release 的签名、公证、安装,不必对相同范围重复询问。用户曾明确授权接手 Motion/FCP 验收,并允许需要释放插件时直接退出 Motion;涉及 FCP 工作工程仍应保护用户内容。本次交接没有操作宿主。
签名身份为 `Developer ID Application: zhong luo (B3W25FX5H5)`,安装包身份为同团队的 `Developer ID Installer`。每次重新检查有效证书和私钥,不能退回临时签名。公证使用登录钥匙串中的 profile `codex-dayu-notary-B3W25FX5H5`;密码和私钥不在仓库,不能输出到聊天、日志或命令行参数。
1.2.0 APP 公证 ID:`3999fe91-a80e-49d3-9ed0-4003b82f6f54`;PKG 公证 ID:`96a3d1be-a751-4fb8-b062-33a09c01ddf2`,两者状态均为 Accepted。完整记录在 `docs/verification/v1.2.0/`。
交付锁不能绕过,也不能删除活跃持有者的锁。签名、公证或权限失败时保留原安装版。完成后只清理核对身份属于本产品的生成 APP、旧 APP 和公证 ZIP;最后的有界扫描覆盖 `/Applications`、两个 FxPlug 目录、项目及固定暂存路径,只发现正式 APP,不代表已经扫描所有卷。
## PKG 与发布资料
正式包:`releases/1.2.0/大鱼人像美化-1.2.0.pkg`,**5,011,005 bytes**。
```text
SHA-256 5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243
```
GitHub Release 下载名为 `Dayu-Portrait-1.2.0.pkg`,字节相同,已匿名下载并核对哈希、Installer 签名和公证票据。
后续打包使用 `/Applications/PKG工坊.app/Contents/MacOS/PKG工坊`,本次版本为 CLI 1.4(8)。先读 `/Users/dayu/.codex/skills/dayu-publish-article/SKILL.md` 的当前打包规范及 CLI 帮助,使用独立发布副本。
资源输入应是分类根 `大鱼磨皮瘦脸`,内含 `大鱼人像美化` 和上述四文件;另外加入唯一正式已公证 APP。不要把更外层“发布版”容器作为分类输入,也不要把 `PARAMETERS.json`、`VALIDATION.json`、开发 README 混入运行模板。PKG postinstall 负责备份、解除旧图锁、复制、重锁并验证;失败回滚当前模板项目,不能扩大为整个安装包的原子回滚。
`scripts/verify-release-package.py` 是 **1.2.0 专用验证脚本**:依赖已展开的 `build/pkg-expanded/Payload.pkg`、当前正式 APP 和固定 `build/pkg-isolation`;不是接收任意包路径的通用工具。先阅读源码并准备展开目录,验证后清理展开出的额外 APP。当前 `.gitignore` 只为 `releases/1.2.0/*.pkg` 放行,下一版本的二进制入库或 Release 附件策略需明确处理。
文章及发布入口:
- [公开源码仓库](https://github.com/FAMEDaYu/FCP-BeatyGril)
- [1.2.0 GitHub Release](https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0)
- [大鱼站文章 15593](https://dayu.media/15593/)
- [大鱼 Git 备份](https://dayu.media/git/dayu/paintfcp-fxplug)
文章为“免费资源”,价格为 0,非会员可获取,特色封面为当前古风图;正文已有 GitHub 仓库和 Release 链接,保留免费开源、安装注册、三秒退出、故障排查及准确署名。FCPX APP 列表同步本次未启用。
文章另附历史源码 ZIP,对应 `788ba0d5514595cf349af33074055d70b0754185`,包含构建源码,排除 PKG 和 Git 历史;不是最新 main 快照。后续源码和署名修订以 GitHub main 为准。
`scripts/publish-release.py` 用于首次发布并保留 `build/publish-operation.json` 状态;已有 `post_id` 时不会重新提交正文,不要将它当成通用文章更新器。更新 15593 时先读最新正文及元数据,只提交所需字段,保持免费权限、下载、SEO 和其他未改字段;密钥只在进程内存中使用。具体发布流程继续遵循上述技能,不因接手文档自动重发。
## Git 保存与恢复
| 本地远端 | 地址 | 说明 |
| --- | --- | --- |
| `origin` | `https://dayu.media/git/dayu/paintfcp-fxplug.git` | 保持为原远端及 main 上游;网站 Git 网关仍要求登录和有效会员 |
| `github` | `https://github.com/FAMEDaYu/FCP-BeatyGril.git` | 公开仓库,匿名克隆可用,完整历史和七个标签已保存 |
本项目没有 LFS 或子模块。不要改写原远端、强推、覆盖现有标签或把双端同步描述成自动定时同步。
| 节点 | 完整提交 SHA |
| --- | --- |
| 1.3.0 正式签名源码(codex/new-beauty-controls) | `2f2c081980dc610ac810f8daf92da8966f310802` |
| 1.2.0 正式签名源码 | `696d5f39b30404ed5d1d4c25f61d17475c7fc91b` |
| `v1.2.0` 发布标签 | `3c7261c3a861b9f4704cfb36055d7b500c239dab` |
| 1.1.2 已验收渲染及面板源码 | `a2e33e8e00a99b95dc29d67a819cb0897eda5756` |
| GitHub 独立匿名恢复节点 | `356683b41af702d6c0143ad7fa5f540d752d6e14` |
标签包含相应发布资料,签名源码节点表示实际构建代码;两者不同是正常的。后续文章、署名、GitHub 和交接文档提交没有改变已签名产品。GitHub 恢复核验覆盖 197 个受跟踪文件、全部七标签及 strict/full fsck;大鱼 `v1.2.0` 恢复核验为该历史节点的 183 文件,不把不同节点的文件数混用。
恢复正式发行源码可以:
```sh
git clone https://github.com/FAMEDaYu/FCP-BeatyGril.git
cd FCP-BeatyGril
git switch --detach v1.2.0
```
需要最新文档时留在 main。继续开发则基于所需节点创建 `codex/` 前缀分支。Apple SDK、有效签名证书和公证凭据需在新机器单独安装或恢复;Git 不包含它们。
保存本任务文件可用 `python3 scripts/checkpoint.py '提交说明' <明确文件...>`,该脚本只对当前分支提交、推送并核验 **origin**,不会推送 GitHub,也不要在外层已持有同一 origin 锁时嵌套调用它。GitHub 还需单独推送当前分支,发布时明确推送新的标签,两端都读回对应引用与本地 SHA 比较。
提交和推送使用 `/Users/dayu/.codex/git-backup-locks/` 中的共享互斥锁。锁名为无凭据、转小写并去尾斜线的完整 HTTPS 仓库地址(保留 `.git`)的 SHA-256 加 `.lock`,`owner.json` 记录 PID、cwd、remote;不清理其他仍在工作的持有者。
本机 GitHub CLI 为 `/opt/homebrew/bin/gh`,本次已由用户登录 `FAMEDaYu`,HTTPS 凭据在钥匙串中。接手时用 `gh auth status` 确认;连接器曾使用其他只读账号,不能用连接器权限推断 CLI 登录失效,也不打印令牌。大鱼仓库管理使用 `dayu-git` CLI,指南在 `/Users/dayu/Documents/dayu-git/README.md` 与 `API.md`。
恢复范围仅覆盖已经提交、推送并核验的节点与实际上传的必要资源。用户素材、忽略的 build、私钥不在此范围。大鱼服务器当前只有手动备份,不能据此承诺本机与服务器同时损坏也可恢复。
## 后续开发优先入口
当前无需自动执行以下工作;收到相应需求后再开展。
1. 用户继续反馈脸型差异时,先隔离单项、核对实际加载版本、原点与 76 点解剖索引,再分析目标对应局部数学。优先补齐仍近似的五项及组合顺序,不能仅调大整体强度。
2. 跟随异常时,围绕多人交叉、遮挡、切镜、冷缓存、乱序和同尺寸换源制作明确样本,比较主体关联和历史选择,而不是先增加手动分析按钮。
3. 面板改动时,覆盖真实 action 生命周期、持续步进、输入焦点、撤销、重置、保存重开及旧工程;补充原生 VoiceOver 和实际关键帧交互验收。
4. 新版本发布时,沿用固定身份和唯一正式路径,记录本次真实签名源码,完成 APP/PKG 公证与恢复验证,更新原文章和两个远端,不覆盖旧标签。
目标参考为 `/Applications/MSE18V2.app` 及用户原 MS 模板,仅用于只读分析。现有 REA、CPU 和 AIR 证据在 `docs/analysis/`;新分析按 `reverse-engineer-anything` 技能继续。不上传或打包原版 APP、模型、metallib、用户视频和完整人脸坐标。
2026-10-22 用户已纠正“瘦身”为新增面板参数,目标仍是 `/Users/dayu/Downloads/MSE18V2.app`(2.4.0 / 20260724150000)。现沿 `codex/new-beauty-controls` 接入连续五官保护、非肤色区保护和局部微细锐化,保留旧 30/17/4 参数及归档;见[新版磨皮参数迁移](analysis/新版磨皮参数迁移.md)。1.3.0(15)已正式安装,签名、票据、Gatekeeper、PluginKit 正式路径和已知临时副本清理均验证通过。原生视觉由用户测试,见新交付回执。[原瘦身目标核对](analysis/瘦身迁移目标核对.md)只保留历史,不再是待澄清项。
## 1.3.0 接续说明
用户已保存并退出 Motion/FCP,交付脚本在宿主全部退出后安装新 APP。Apple 公证 ID 为 `ca96837f-bf33-44fa-8d58-799026ce5c7d`,状态 Accepted;最终签名源码为 `2f2c081980dc610ac810f8daf92da8966f310802`。交付标签 `v1.3.0` 包含后续回执和恢复文档,源码分支为 `codex/new-beauty-controls`,main 仍保留原发行状态。
新增稳定 float ID:75 五官保护量、76 非肤色区保护、77 局部微细锐化。旧 bool 30、独立全局磨皮 17 和全局锐化 4 均保留;后两项在更多设置中,不能重新解释其历史数值。PGBeautySettings v2 只追加三个 float,接受明确的 v1/160 字节旧状态。PGInspectorState 仍为 schema 1,缺 75 时从旧 bool 导入;旧 bool 为 true 时不得覆盖已读到的新浮点值。
1636 项检查与离屏面板已验,含 ASan 宿主/OSC/Inspector;本次未在原生宿主中重新操作新滑杆或验收效果视觉。正式插件发现只核验 PluginKit 路径,不把它写作 FCP 或 Motion 实际加载/画面通过。当前无需重新安装、重做封面或更新 1.2.0 安装包;用户反馈实际效果后继续针对性处理。
+11
查看文件
@@ -127,3 +127,14 @@ Motion:独立普通视频项目,源PTS0、1920×1080/25fps/10秒,媒体通
实际操作均在独立测试文档/时间线内:Motion最终版数值输入、重置同时更新slider/text、宿主撤销、切换输入不复活旧值、保存关闭重开(短脸0.5/下颌骨0)通过。相同几何源码在build11中已做单独短脸正负、下颌骨、停用同帧对照及侧脸/歪头图像检查;final build13继续沿用相同几何字节。FCP最终版原生面板启用、数值输入、单击重置同步显示、清零其他脸型后分别短脸1/下颌骨1的同帧画面响应通过。截图、完整AX和物理坐标差只留本机,不上传用户影像。
连续预览:生产NSSlider continuous保持开启,view不再把整个拖动包在同一次controller action里;每个有效步进独立结束宿主参数上下文。模拟宿主中三个中间状态在mouse-up前完成发布(旧实现3失败,修复后通过)。CUA坐标拖动未能可靠操纵显示中的滑杆,未记录到可信的原生按住期间排帧证据,已请求用户直接观察;此项保留待反馈,不写作原生连续预览通过。快速更新可能被宿主合并,各项其余五类近似算法和全部组合不宣称原版逐像素一致。详细范围在verification/v1.1.2/native-qa.json。
## 1.1.2 连续预览用户验收补充(2026-10-22)
用户明确回复“拖动中已持续更新”,确认最终1.1.2(13)按住滑杆拖动时画面能够持续更新,关闭上节待反馈项。此项证据来自用户原生实测;未指定具体宿主,不声称两个宿主分别完成按住拖动验收,也没有测量每个鼠标事件的独立排帧。本次仅更新验收记录,不改变产品源码、安装版或既有发布标签。
## 1.3.0(15)新增磨皮参数与正式安装
按用户纠正后的截图需求,迁移连续五官保护、非肤色区保护和局部微细锐化;保留旧 bool、全局磨皮/锐化 ID 与旧工程行为。正式签名源码 `2f2c081980dc610ac810f8daf92da8966f310802`。1636 项通过:57 Beauty、116 Face、796 几何、341 宿主适配 ASan、98 OSC ASan、228 Inspector ASan(含 1 项可选 PNG 输出)。保护 0/50/100 像素响应、色彩覆盖隔离、透明度、v1 状态迁移、新控件归档/插值/输入/重置/旁路/松手前发布均有检查;离屏面板已查看。
通用 Release 正式签名、公证 Accepted(`ca96837f-bf33-44fa-8d58-799026ce5c7d`)、票据、双架构严格签名、安装身份、Gatekeeper、PluginKit 正式路径与临时副本清理通过。独立从 origin 克隆签名源码节点,205 个受跟踪文件逐字节匹配且 strict/full fsck 通过。本次没有原生新滑杆/效果视觉验收,也没有生成新 PKG 或更新文章;用户已保存并退出宿主后才执行安装。详见 `verification/v1.3.0/` 与 `analysis/新版磨皮参数迁移.md`。
+22
查看文件
@@ -0,0 +1,22 @@
# 大鱼人像美化 1.2.0(14)
- 发布文章:https://dayu.media/15593/
- 公开源码:https://github.com/FAMEDaYu/FCP-BeatyGril
- 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug
- GitHub Release:https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0
- 大鱼 Release:https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.2.0
- 标签完整 SHA:3c7261c3a861b9f4704cfb36055d7b500c239dab
- 正式 APP 源码:696d5f39b30404ed5d1d4c25f61d17475c7fc91b
- 源码快照节点:788ba0d5514595cf349af33074055d70b0754185
- PKG:大鱼人像美化-1.2.0.pkg,5,011,005 bytes
- PKG SHA-256:5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243
- APP Apple 公证:Accepted 3999fe91-a80e-49d3-9ed0-4003b82f6f54
- PKG Apple 公证:Accepted 96a3d1be-a751-4fb8-b062-33a09c01ddf2
安装包本体已推入 Git,并附在 Release 下载区;文章另有免费安装包和免 Git 登录源码快照。仓库属性为 public,但站点统一 Git 网关仍要求登录 / 会员;这不是已解决的匿名 Git 访问。
APP 与 PKG 均完成正式签名、公证、票据和 Gatekeeper 核验。APP 已安装到唯一正式路径;PKG 做了解包、逐字节载荷对照及隔离模板脚本测试,没有在用户当前模板目录运行本 PKG 安装器。实际模板目录中的两张图已直接更新并锁定。FCP 已显示新缩略图,正式插件可加载并修改亮度;Motion未重新进行1.2.0原生视觉测试,渲染/面板保持1.1.2验收源码。
验证详情见 docs/verification/v1.2.0。生成宣传图与提示词见 docs/design,未使用目标商业插件人像。
GitHub 提供完整历史和七个版本标签;独立匿名克隆恢复节点356683b41af702d6c0143ad7fa5f540d752d6e14核验197文件,Release安装包匿名下载哈希、签名和票据均通过。GitHub源码与Release链接已补充至文章15593。代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。
+55
查看文件
@@ -0,0 +1,55 @@
{
"title": "大鱼人像美化 1.2.0:FCP / Motion 免费开源自动美颜插件",
"slug": "dayu-portrait-beauty",
"status": "publish",
"content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"{{media.cover.url}}\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\"/><figcaption>古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n<!-- wp:list -->\n<ul class=\"wp-block-list\"><li>磨皮:局部磨皮、全局磨皮与五官保护,强度分别控制。</li><li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li><li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li><li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li><li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li></ul>\n<!-- /wp:list -->\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.2.0(14)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本次更新加入古风封面与锁定缩略图、免费开源说明页和主 APP 三秒自动退出。人脸处理与面板交互沿用 1.1.2 已验收实现,不需要重新运行手动分析。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\"/></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">常见问题</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>\n<!-- /wp:paragraph -->\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>open '/Library/Plug-Ins/FxPlug/beatygril.app'</code></pre>\n<!-- /wp:code -->\n<!-- wp:paragraph -->\n<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、Line truncated
"excerpt": "磨皮、美白、瘦脸与自动人脸跟随,原生卡片面板实时预览。免费开源,自动注册,无需激活码;提供签名公证安装包和源码。",
"categories": [
3
],
"tags": [],
"resource": {
"cao_status": true,
"cao_price": 0,
"cao_vip_rate": 1,
"cao_close_novip_pay": false,
"cao_expire_day": 0,
"cao_pwd": "",
"cao_info": [
{
"title": "版本",
"desc": "1.2.0(14)"
},
{
"title": "宿主",
"desc": "Final Cut Pro / Motion"
},
{
"title": "系统",
"desc": "macOS 13 或更高版本"
},
{
"title": "架构",
"desc": "Apple Silicon / Intel"
},
{
"title": "授权",
"desc": "免费开源,无需激活码"
}
]
},
"seo": {
"title": {
"enabled": true,
"value": "大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件"
},
"description": {
"enabled": true,
"value": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,支持磨皮、美白、自动人脸跟随及瘦脸调整。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,并附具体安装、使用及红色警告排查说明。"
},
"keywords": {
"enabled": true,
"value": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源"
}
}
}
+69
查看文件
@@ -0,0 +1,69 @@
<!-- wp:paragraph -->
<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="{{media.cover.url}}" alt="大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜"/><figcaption>古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">可以做什么</h2>
<!-- /wp:heading -->
<!-- wp:list -->
<ul class="wp-block-list"><li>磨皮:局部磨皮、全局磨皮与五官保护,强度分别控制。</li><li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li><li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li><li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li><li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li></ul>
<!-- /wp:list -->
<!-- wp:paragraph -->
<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">版本与下载</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>当前版本 <strong>1.2.0(14)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>本次更新加入古风封面与锁定缩略图、免费开源说明页和主 APP 三秒自动退出。人脸处理与面板交互沿用 1.1.2 已验收实现,不需要重新运行手动分析。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">安装</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="{{card_url}}" alt="主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出"/></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">使用</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">常见问题</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>
<!-- /wp:paragraph -->
<!-- wp:code -->
<pre class="wp-block-code"><code>open '/Library/Plug-Ins/FxPlug/beatygril.app'</code></pre>
<!-- /wp:code -->
<!-- wp:paragraph -->
<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、宿主版本及安装包完整性;不要只复制单个 .moef 文件,配套程序与 Drop Zone.tiff 也需要保留。当前仅提供上述一个效果模板。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">源码与开源许可</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>公开源码仓库:<a href="https://github.com/FAMEDaYu/FCP-BeatyGril" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeatyGril</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0" target="_blank" rel="noreferrer noopener">1.2.0 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.2.0 源码快照 ZIP</a>,源码与安装包均免费提供。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>项目代码按仓库中的 MIT 许可文件提供,源码包含 Xcode 工程、Objective-C / Metal 实现、模板及构建与验证说明。Apple SDK、运行框架及样本按各自许可使用,详见源码中的 LICENSE 和 THIRD_PARTY_NOTICES.md。自行编译需要 Xcode 与 FxPlug SDK;证书和签名私钥不包含在源码中。</p>
<!-- /wp:paragraph -->
二进制文件未显示。
+70
查看文件
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Publish this reviewed release through the connected Dayu article publisher.
Secrets are read from macOS Keychain into memory; no auth material is persisted.
"""
from pathlib import Path
import base64,hashlib,html,json,mimetypes,ssl,subprocess,urllib.error,urllib.parse,urllib.request,uuid,zipfile
ROOT=Path(__file__).resolve().parent.parent
STATE=ROOT/'build/publish-operation.json';STATE.parent.mkdir(exist_ok=True)
state=json.loads(STATE.read_text()) if STATE.exists() else {'operation':str(uuid.uuid4())}
def save():STATE.write_text(json.dumps(state,ensure_ascii=False,indent=2)+'\n')
save()
secret=subprocess.run(['security','find-generic-password','-s','dayu-article-publisher','-a','dayu','-w'],text=True,capture_output=True,check=True).stdout.strip()
auth='Basic '+base64.b64encode(('dayu:'+secret).encode()).decode()
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self,*args,**kwargs):return None
opener=urllib.request.build_opener(NoRedirect,urllib.request.HTTPSHandler(context=ssl.create_default_context(cafile='/etc/ssl/cert.pem')))
def request(path,method='GET',body=None,headers=None):
assert path.startswith(('/wp/v2/','/dayu-publisher/v1/')) and '\n' not in path
h={'Authorization':auth,'Accept':'application/json'};h.update(headers or {})
if isinstance(body,dict):body=json.dumps(body,ensure_ascii=False).encode();h['Content-Type']='application/json'
req=urllib.request.Request('https://dayu.media/wp-json'+path,data=body,headers=h,method=method)
with opener.open(req,timeout=180) as f:return json.load(f)
def upload(name,path,mime):
if name in state:return state[name]
filename=path.name
matches=request('/wp/v2/media?search='+urllib.parse.quote(path.stem)+'&per_page=30&context=edit')
for item in matches:
if urllib.parse.unquote(item.get('source_url','')).endswith('/'+filename):
# Only reuse a byte-identical previous upload.
with urllib.request.urlopen(item['source_url'],context=ssl.create_default_context(cafile='/etc/ssl/cert.pem'),timeout=90) as r:data=r.read()
if hashlib.sha256(data).digest()==hashlib.sha256(path.read_bytes()).digest():
state[name]={'id':item['id'],'url':item['source_url']};save();return state[name]
result=request('/wp/v2/media','POST',path.read_bytes(),{'Content-Type':mime,'Content-Disposition':'attachment; filename="'+filename+'"'})
state[name]={'id':result['id'],'url':result['source_url']};save();return state[name]
source_zip=ROOT/'build/Dayu-Portrait-1.2.0-source.zip'
assert zipfile.is_zipfile(source_zip), 'Build a valid reviewed source ZIP before any upload'
with zipfile.ZipFile(source_zip) as z:
assert z.testzip() is None and any(n.endswith('/Wrapper Application/AppDelegate.m') for n in z.namelist())
status=request('/dayu-publisher/v1/status');assert status['can_publish'] and status['can_upload'] and 'seo' in status['fields']
source=upload('source',ROOT/'build/Dayu-Portrait-1.2.0-source.zip','application/zip')
card=upload('card',ROOT/'beatygril/beatygril/Wrapper Application/Resources/LauncherInfo.png','image/png')
content=(ROOT/'releases/1.2.0/article.html').read_text().replace('{{source_url}}',html.escape(source['url'],quote=True)).replace('{{card_url}}',html.escape(card['url'],quote=True))
seo={
'title':{'enabled':True,'value':'大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件'},
'description':{'enabled':True,'value':'大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,支持磨皮、美白、自动人脸跟随及瘦脸调整。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,并附具体安装、使用及红色警告排查说明。'},
'keywords':{'enabled':True,'value':'大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源'}
}
payload={'title':'大鱼人像美化 1.2.0:FCP / Motion 免费开源自动美颜插件','slug':'dayu-portrait-beauty','status':'publish','content':content,'excerpt':'磨皮、美白、瘦脸与自动人脸跟随,原生卡片面板实时预览。免费开源,自动注册,无需激活码;提供签名公证安装包和源码。','categories':[3],'tags':[], 'resource':{'cao_status':True,'cao_price':0,'cao_vip_rate':1,'cao_close_novip_pay':False,'cao_expire_day':0,'cao_pwd':'','cao_info':[{'title':'版本','desc':'1.2.0(14)'},{'title':'宿主','desc':'Final Cut Pro / Motion'},{'title':'系统','desc':'macOS 13 或更高版本'},{'title':'架构','desc':'Apple Silicon / Intel'},{'title':'授权','desc':'免费开源,无需激活码'}]},'seo':seo}
(ROOT/'releases/1.2.0/article-payload.json').write_text(json.dumps(payload,ensure_ascii=False,indent=2)+'\n')
if 'post_id' not in state:
existing=request('/wp/v2/posts?slug=dayu-portrait-beauty&context=edit');assert not existing,'Matching post exists; inspect and continue its ID instead of creating a duplicate'
boundary='DayuRelease'+uuid.uuid4().hex;parts=[]
def part(name,data,filename=None,mime=None):
head='--'+boundary+'\r\nContent-Disposition: form-data; name="'+name+'"'
if filename:head+='; filename="'+filename+'"'
head+='\r\n'
if mime:head+='Content-Type: '+mime+'\r\n'
parts.append(head.encode()+b'\r\n'+data+b'\r\n')
part('payload',json.dumps(payload,ensure_ascii=False).encode())
part('package',(ROOT/'releases/1.2.0/大鱼人像美化-1.2.0.pkg').read_bytes(),'Dayu-Portrait-1.2.0.pkg','application/octet-stream')
part('cover',(ROOT/'Assets/Artwork/portrait-cover.png').read_bytes(),'Dayu-Portrait-Cover.png','image/png')
body=b''.join(parts)+('--'+boundary+'--\r\n').encode()
result=request('/dayu-publisher/v1/posts','POST',body,{'Content-Type':'multipart/form-data; boundary='+boundary,'Idempotency-Key':state['operation']})
state['response']=result;save()
# Response schema may vary; resolve the exact saved slug through standard REST.
rows=request('/wp/v2/posts?slug=dayu-portrait-beauty&context=edit');assert len(rows)==1
state['post_id']=rows[0]['id'];state['url']=rows[0]['link'];save()
saved=request('/dayu-publisher/v1/posts/'+str(state['post_id']))
(ROOT/'docs/verification/v1.2.0/published-article.json').write_text(json.dumps(saved,ensure_ascii=False,indent=2)+'\n')
print(json.dumps({'post_id':state['post_id'],'url':state['url'],'source':source,'card':card,'snapshot_saved':True},ensure_ascii=False))
+67
查看文件
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""Verify an expanded release payload and run template-only update/rollback in isolation."""
from pathlib import Path
import hashlib,json,os,plistlib,shutil,subprocess,sys
root=Path(__file__).resolve().parent.parent
expanded=root/'build/pkg-expanded/Payload.pkg';payload=expanded/'Payload'
formal=Path('/Library/Plug-Ins/FxPlug/beatygril.app');packed=payload/'Library/Plug-Ins/FxPlug/beatygril.app'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
def files(p):
return {str(x.relative_to(p)):('symlink:'+os.readlink(x) if x.is_symlink() else sha(x)) for x in p.rglob('*') if x.is_file() or x.is_symlink()}
assert files(formal)==files(packed),'APP differs from signed installed product'
subprocess.run(['codesign','--verify','--deep','--strict',str(packed)],check=True)
subprocess.run(['xcrun','stapler','validate',str(packed)],check=True,capture_output=True)
source=root/'Templates/大鱼人像美化';template=next(payload.rglob('大鱼人像美化.moef')).parent
runtime=['大鱼人像美化.moef','Drop Zone.tiff','large.png','small.png']
assert sorted(x.name for x in template.iterdir())==sorted(runtime)
assert all(sha(source/n)==sha(template/n) for n in runtime)
post=(expanded/'Scripts/postinstall').read_text();pre=(expanded/'Scripts/preinstall').read_text()
for p in [expanded/'Scripts/postinstall',expanded/'Scripts/preinstall']:
subprocess.run(['/bin/zsh','-n',str(p)],check=True)
locks=[l for l in post.splitlines() if l.startswith('/usr/bin/chflags uchg "${FINAL_TARGET}')]
assert len(locks)==2 and any('/large.png' in l for l in locks) and any('/small.png' in l for l in locks)
assert 'Template Backups' in post and 'restore_original_locks' in post
# Keep the exact generated functions and template body. Only identity lookup,
# chown and external FxPlug registration are replaced to confine execution.
base=root/'build/pkg-isolation';base.mkdir(exist_ok=False)
volume=base/'volume';home=base/'user';home.mkdir()
start=post.index('CURRENT_ACTIVE=0')
isolated='#!/bin/zsh\nset -eu\nTARGET_VOLUME="'+str(volume)+'"\nCONSOLE_USER="'+os.getlogin()+'"\nCONSOLE_UID="'+str(os.getuid())+'"\nCONSOLE_GROUP="staff"\nUSER_HOME="'+str(home)+'"\n'+post[start:]
isolated=isolated[:isolated.index('fx_verify_app "${TARGET_VOLUME%/}/Library/Plug-Ins/FxPlug/beatygril.app"')]+'exit 0\n'
isolated=isolated.replace('/usr/sbin/chown -R','/usr/bin/true')
new_copy=next(l for l in isolated.splitlines() if l.startswith('/usr/bin/ditto "${TARGET_VOLUME%/}'))
def refill():
target=volume/template.parent.relative_to(payload)
if target.exists():
subprocess.run(['chflags','-R','nouchg',str(target)],check=True);shutil.rmtree(target)
target.parent.mkdir(parents=True,exist_ok=True);shutil.copytree(template.parent,target,symlinks=True)
def run_script(name,text,success):
p=base/name;p.write_text(text)
proc=subprocess.run(['/bin/zsh',str(p)],text=True,capture_output=True)
(base/(name+'.output')).write_text(proc.stdout+proc.stderr)
assert (proc.returncode==0)==success,(name,proc.returncode,proc.stderr)
return proc.returncode
final=home/'Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸/大鱼人像美化'
refill();run_script('fresh-install.zsh',isolated,True)
assert all(sha(final/n)==sha(source/n) for n in runtime)
assert all((final/n).stat().st_flags & 2 for n in ['large.png','small.png'])
# Locked old images are overwritten, then protected again.
subprocess.run(['chflags','nouchg',str(final/'large.png')],check=True)
(final/'large.png').write_bytes(b'old locked thumbnail');subprocess.run(['chflags','uchg',str(final/'large.png')],check=True)
refill();run_script('update-locked.zsh',isolated,True)
assert all(sha(final/n)==sha(source/n) for n in runtime)
assert all((final/n).stat().st_flags & 2 for n in ['large.png','small.png'])
# Simulate a failed payload copy after corrupting one new file; the actual EXIT
# trap must restore the previous bytes and previous immutable flags.
original=files(final);refill()
failing=isolated.replace(new_copy,'/bin/echo partial > "${FINAL_TARGET}/大鱼人像美化/large.png"\n/usr/bin/false',1)
run_script('failed-copy-rollback.zsh',failing,False)
assert files(final)==original
assert all((final/n).stat().st_flags & 2 for n in ['large.png','small.png'])
backups=list((home/'Library/Application Support/PKGForge/Template Backups').rglob('.locked-paths'))
assert backups and all('/Movies/' not in str(x) for x in backups)
package=root/'releases/1.2.0/大鱼人像美化-1.2.0.pkg'
report={'package':str(package.relative_to(root)),'bytes':package.stat().st_size,'sha256':sha(package),'version':'1.2.0','build':'14','app_files_compared':len(files(formal)),'app_byte_and_symlink_equality':True,'template_files':{n:sha(template/n) for n in runtime},'locked_relative_paths':['大鱼人像美化/large.png','大鱼人像美化/small.png'],'script_sha256':{'preinstall':sha(expanded/'Scripts/preinstall'),'postinstall':sha(expanded/'Scripts/postinstall')},'isolated_script_tests':['fresh install','replace old locked thumbnail','partial copy failure restores old bytes and locks'],'isolation_changes':['Console identity/home redirected to task fixture','chown replaced with true','FxPlug verification skipped; formal app signature and discovery verified separately'],'real_installer_execution':False,'app_and_template_installed':'APP installed through signed delivery workflow; user thumbnail directory updated separately, not by running this PKG','fonts':'No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed.'}
(root/'docs/verification/v1.2.0/pkg-verification.json').write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');print(json.dumps(report,ensure_ascii=False,indent=2))
# This fixture belongs solely to this verifier; remove its locks before cleanup.
subprocess.run(['chflags','-R','nouchg',str(base)],check=True);shutil.rmtree(base)
+41
查看文件
@@ -103,6 +103,46 @@ int main(void) { @autoreleasepool {
s=PGBeautyDefaults();s.midtoneDetail=1;s.maskSoftness=0;s.maskEdgeProtect=0;s.featureProtection=1;
float *protected=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:nil eyeMask:half error:&error],extent);
Check(Difference(base,protected,6,40)<0.00001 && Texture(protected,56,88)<Texture(base,56,88)*0.82,@"Feature protection retains eye detail while smoothing nearby skin");free(protected);
// Independent protection controls use fractional coverage; neither changes
// exposure coverage nor invents smoothing when the smoothing amount is zero.
s=PGBeautyDefaults();s.midtoneDetail=1;s.maskSoftness=0;s.maskEdgeProtect=0;
float *featureFull=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:nil eyeMask:half error:&error],extent);
s.featureProtectionAmount=.5;
float *featureHalf=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:nil eyeMask:half error:&error],extent);
s.featureProtectionAmount=0;
float *featureNone=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:nil eyeMask:half error:&error],extent);
float fullDelta=Difference(base,featureFull,6,40),halfDelta=Difference(base,featureHalf,6,40),noneDelta=Difference(base,featureNone,6,40);
Check(fullDelta<.00001 && halfDelta>fullDelta+.001 && noneDelta>halfDelta+.001,@"Five-feature protection has distinct ordered 0/50/100 percent pixel effects");
Check(Difference(featureFull,featureNone,56,88)<noneDelta*.25,@"Feature slider primarily changes marked features rather than nearby skin texture");
free(featureFull);free(featureHalf);free(featureNone);
s=PGBeautyDefaults();s.midtoneDetail=1;s.maskSoftness=0;s.maskEdgeProtect=0;s.featureProtection=0;
float *skinFull=Render(context,[renderer processImage:source settings:s skinMask:half teethMask:nil eyeMask:nil error:&error],extent);
s.nonSkinProtection=.5;
float *skinHalf=Render(context,[renderer processImage:source settings:s skinMask:half teethMask:nil eyeMask:nil error:&error],extent);
s.nonSkinProtection=0;
float *skinNone=Render(context,[renderer processImage:source settings:s skinMask:half teethMask:nil eyeMask:nil error:&error],extent);
Check(Difference(base,skinFull,56,88)<.00001 && Difference(base,skinHalf,56,88)>.001 && Difference(base,skinNone,56,88)>Difference(base,skinHalf,56,88)+.001,@"Non-skin protection progressively admits background into the local smoothing mask");
Check(Difference(skinFull,skinNone,6,40)<.00001,@"Non-skin protection leaves already-covered skin strength unchanged");
free(skinFull);free(skinHalf);free(skinNone);
s.midtoneDetail=0;
float *noSmoothing=Render(context,[renderer processImage:source settings:s skinMask:half teethMask:nil eyeMask:nil error:&error],extent);
Check(Difference(base,noSmoothing,4,W-4)<.00001,@"Releasing non-skin protection alone does not enable an independent global smoothing effect");free(noSmoothing);
s=PGBeautyDefaults();s.microDetail=1;s.maskSoftness=0;s.maskEdgeProtect=0;
float *micro=Render(context,[renderer processImage:source settings:s skinMask:half teethMask:nil eyeMask:nil error:&error],extent);
Check(Texture(micro,6,40)>Texture(base,6,40)*1.05 && Difference(base,micro,56,88)<.00001,@"Micro detail recovers texture within smoothing support, including without smoothing");
free(micro);
s=PGBeautyDefaults();s.skinBrightness=.7;s.maskSoftness=0;s.maskEdgeProtect=0;
float *colorProtected=Render(context,[renderer processImage:source settings:s skinMask:half colorMask:half teethMask:nil eyeMask:nil error:&error],extent);
s.nonSkinProtection=0;s.featureProtectionAmount=0;
float *colorReleased=Render(context,[renderer processImage:source settings:s skinMask:half colorMask:half teethMask:nil eyeMask:nil error:&error],extent);
Check(Difference(colorProtected,colorReleased,4,W-4)<.00001,@"Both new protection sliders leave skin exposure coverage unchanged");
free(colorProtected);free(colorReleased);
s=PGBeautyDefaults();s.skinBrightness=.7;s.maskSoftness=0;s.maskEdgeProtect=0;
colorProtected=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:half eyeMask:half error:&error],extent);
s.featureProtectionAmount=0;s.featureProtection=0;s.nonSkinProtection=0;
colorReleased=Render(context,[renderer processImage:source settings:s skinMask:white teethMask:half eyeMask:half error:&error],extent);
Check(Difference(colorProtected,colorReleased,4,W-4)<.00001,@"Standalone renderer also keeps eye/teeth protection independent from exposure when the legacy bool changes");
free(colorProtected);free(colorReleased);
// A skin exposure adjustment must stay continuous across detail-protection
// holes. This models the eye/nose islands reported on the real beach clip.
s=PGBeautyDefaults();s.skinBrightness=1;s.featureProtection=1;
@@ -192,6 +232,7 @@ int main(void) { @autoreleasepool {
// Every operation must preserve transparency rather than creating halos/opaque pixels.
for(int i=0;i<W*H;i++){p[i*4]*=0.4;p[i*4+1]*=0.4;p[i*4+2]*=0.4;p[i*4+3]=0.4;}
CIImage *transparent=Image(p,extent);s=PGBeautyDefaults();s.midtoneDetail=1;s.skinBrightness=1;s.teethWhitening=1;s.eyeBrightening=1;s.skinTonePreset=3;s.highPassDetail=1;
s.microDetail=.7;s.nonSkinProtection=.3;s.featureProtectionAmount=.4;
float *alpha=Render(context,[renderer processImage:transparent settings:s skinMask:white teethMask:half eyeMask:half error:&error],extent);
BOOL alphaOK=YES,finite=YES;
for(int i=0;i<W*H;i++){if(fabsf(alpha[i*4+3]-0.4f)>0.0002)alphaOK=NO;for(int c=0;c<4;c++)if(!isfinite(alpha[i*4+c]))finite=NO;}
+11 -3
查看文件
@@ -469,7 +469,9 @@ int main(int argc, const char *argv[]) {
Check([plugin addParametersWithError:&error] && !error, @"host creates complete parameter set");
UInt32 identifiers[] = {PGAmount,PGBrightness,PGRadius,PGSharpness,PGMix,PGThreshold,PGSoftness,PGEdgeProtect,PGShowMask,PGMidtone,PGHue,PGSaturation,PGHighPass,PGThin,PGFaceBoxes,PGSingleFace,PGSelection,PGShort,PGNarrow,PGChin,PGVFace,PGJaw,PGCheekbone,PGSmallHead,PGSmallHeadRange,PGFeatureProtect,PGTeeth,PGEyeBright,PGBigEye,PGTrackBoxes,PGFastMulti,PGJumpGuard,PGEvenTone,PGTonePreset,PGInvertMask,PGDebugChannel,PGTrackEnabled,PGTarget,PGAnalyzeForward,PGAnalyzeBackward,PGClearTrack,PGStatus,PGTrackData1,PGTrackData2,PGTrackData3,PGSmoothingEnabled,PGColorEnabled,PGShapeEnabled,PGDetailEnabled,PGInspectorPanel};
for (NSUInteger i = 0; i < sizeof(identifiers) / sizeof(UInt32); i++) Check(api.definitions[@(identifiers[i])] != nil, [NSString stringWithFormat:@"required parameter %u exists", identifiers[i]]);
Check(api.depth == 0 && !api.duplicate && api.definitions.count == sizeof(identifiers) / sizeof(UInt32) + 6, @"parameter groups close and IDs are unique");
for(NSNumber *identifier in @[@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)])
Check(api.definitions[identifier]!=nil,@"new protection/detail float parameter is registered");
Check(api.depth == 0 && !api.duplicate && api.definitions.count == sizeof(identifiers) / sizeof(UInt32) + 10, @"parameter groups close and IDs are unique");
Check([api.values[@(PGMidtone)] doubleValue] == 0 && [api.values[@(PGMix)] doubleValue] == 1, @"default detail and mix form identity filter");
Check([api.definitions[@(PGShort)][@"min"] doubleValue] == -1 && [api.definitions[@(PGShort)][@"max"] doubleValue] == 1, @"signed face control exposes both directions");
Check([api.definitions[@(PGTrackData1)][@"flags"] unsignedLongLongValue] & kFxParameterFlag_HIDDEN, @"persistent tracking data stays hidden in host UI");
@@ -480,7 +482,7 @@ int main(int argc, const char *argv[]) {
NSDictionary *decoded = [NSPropertyListSerialization propertyListWithData:state options:0 format:nil error:nil];
Check([decoded[@"tracks"] count] == 3 && [decoded[@"settings"] length] == sizeof(PGBeautySettings), @"snapshot contains fixed settings schema and three target slots");
PGBeautySettings settings; [decoded[@"settings"] getBytes:&settings length:sizeof(settings)];
Check(settings.version == 1 && settings.mix == 1 && settings.midtoneDetail == 0, @"snapshot round-trips default numeric state");
Check(settings.version == PGBeautySettingsVersion && settings.mix == 1 && settings.midtoneDetail == 0 && settings.featureProtectionAmount==1 && settings.nonSkinProtection==1 && settings.microDetail==0, @"snapshot round-trips v2 with neutral defaults for the new controls");
api.values[@(PGThin)] = @5; api.values[@(PGRadius)] = @(-9); api.values[@(PGSelection)] = @[@(-1), @2];
settings = [plugin settingsAtTime:api.hostTime];
Check(settings.faceThin == 1 && settings.radius == 1 && settings.selectionX == 0 && settings.selectionY == 1, @"host parameter limits and normalized selection are enforced");
@@ -493,6 +495,12 @@ int main(int argc, const char *argv[]) {
NSUInteger difference = MaximumDifference(SurfaceBytes(source), SurfaceBytes(destination));
printf("Default IOSurface maximum byte difference: %lu\n", (unsigned long)difference);
Check(difference <= 1, @"default adapter output preserves gamma-video numeric samples");
PGBeautySettings old=PGBeautyDefaults();old.version=1;
NSData *legacy=PlistState(@{@"settings":[NSData dataWithBytes:&old length:PGBeautySettingsV1Size],@"tracks":@[@"",@"",@""]});
Check(Render(plugin,destination,@[source],legacy,kCMTimeZero,&error,NULL) && MaximumDifference(SurfaceBytes(source),SurfaceBytes(destination))<=1,@"160-byte v1 snapshots migrate with neutral new controls and preserve original pixels");
RejectState(plugin,destination,source,PlistState(@{@"settings":[NSData dataWithBytes:&old length:sizeof(old)],@"tracks":@[@"",@"",@""]}),@"v1 with the new structure length is rejected instead of guessing its layout");
old.version=PGBeautySettingsVersion;
RejectState(plugin,destination,source,PlistState(@{@"settings":[NSData dataWithBytes:&old length:PGBeautySettingsV1Size],@"tracks":@[@"",@"",@""]}),@"v2 with a truncated legacy-sized payload is rejected");
CGColorSpaceRelease(destination.space); destination.space = CGColorSpaceCreateWithName(kCGColorSpaceLinearSRGB);
Check(Render(plugin, destination, @[source], state, kCMTimeZero, &error, NULL), @"numeric host render accepts destination color-space metadata");
difference = MaximumDifference(SurfaceBytes(source), SurfaceBytes(destination));
@@ -510,7 +518,7 @@ int main(int argc, const char *argv[]) {
RejectState(plugin, destination, source, PlistState(@{@"settings":[NSData data], @"tracks":@[@"",@"",@""]}), @"wrong settings size is rejected safely");
settings = PGBeautyDefaults(); settings.version = 99;
RejectState(plugin, destination, source, PlistState(@{@"settings":[NSData dataWithBytes:&settings length:sizeof(settings)], @"tracks":@[@"",@"",@""]}), @"unknown saved settings version is rejected safely");
settings.version = 1;
settings.version = PGBeautySettingsVersion;
RejectState(plugin, destination, source, PlistState(@{@"settings":[NSData dataWithBytes:&settings length:sizeof(settings)], @"tracks":@[@"",@""]}), @"wrong target slot count is rejected safely");
RejectState(plugin, destination, source, PlistState(@{@"settings":[NSData dataWithBytes:&settings length:sizeof(settings)], @"tracks":@[@"",@7,@""]}), @"non-string target slot is rejected safely");
for (NSUInteger top = 0; top < 2; top++) {
+103 -5
查看文件
@@ -52,6 +52,9 @@ static NSControl *FindControl(NSView *view,Class type,NSString *label) {
}
static void Fire(NSControl *control) {[control sendAction:control.action to:control.target];}
static BOOL Near(double a,double b) {return fabs(a-b)<.00001;}
static PGInspectorState *State(NSDictionary *values,NSSet *disabled) {
return [PGInspectorState stateWithValues:values disabledParameters:disabled?:[NSSet set] hasEdits:YES];
}
static void RegistrationTests(void) {
PGHostAPI *api=[PGHostAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
NSUInteger visible=0;for(NSNumber *key in api.definitions){NSDictionary *d=api.definitions[key];if(!([d[@"flags"]unsignedIntValue]&kFxParameterFlag_HIDDEN)){visible++;Check(key.unsignedIntValue==PGInspectorPanel,@"only the custom panel is visible in the native parameter list");}}
@@ -65,11 +68,47 @@ static void RegistrationTests(void) {
NSNumber *key=d[@"id"];Check(api.definitions[key]!=nil,@"every inspector control maps to an existing stable parameter ID");
if([d[@"kind"]isEqual:@"slider"])Check(Near([d[@"min"]doubleValue],[api.definitions[key][@"min"]doubleValue]) && Near([d[@"max"]doubleValue],[api.definitions[key][@"max"]doubleValue]),@"UI and renderer enforce the same slider range");
}
NSMutableArray *smoothIDs=[NSMutableArray new];
for(NSDictionary *d in PGInspectorControls())if([d[@"section"]isEqual:@"smooth"] && ![d[@"kind"]isEqual:@"master"])[smoothIDs addObject:d[@"id"]];
Check([smoothIDs isEqual:@[@(PGMidtone),@(PGMicroDetail),@(PGFeatureProtectionAmount),@(PGNonSkinProtection)]],@"primary smoothing card exposes the four new controls in reference order");
Check(PGInspectorDescriptor(PGFeatureProtect)==nil && [PGInspectorDescriptor(PGHighPass)[@"section"]isEqual:@"more"] && [PGInspectorDescriptor(PGSharpness)[@"section"]isEqual:@"more"],@"legacy boolean stays hidden while legacy global smoothing and sharpening remain available in more settings");
api.values[@(PGTrackEnabled)]=@YES;api.values[@(PGSingleFace)]=@YES;api.values[@(PGShowMask)]=@YES;
PGBeautySettings s=[plugin settingsAtTime:kCMTimeZero];Check(!s.trackingEnabled && !s.singleFace && !s.showMask,@"old manual analysis, selection and debug flags cannot override automatic output");
NSData *snapshot=Snapshot(plugin,kCMTimeZero);NSDictionary *plist=[NSPropertyListSerialization propertyListWithData:snapshot options:0 format:nil error:nil];
Check([plist[@"tracks"]isEqual:@[@"",@"",@""]],@"automatic render snapshots do not transfer persisted manual-analysis payloads");
}
static void BeautyControlModelTests(void) {
PGInspectorState *defaults=State(@{},nil);
Check([defaults valueForParameter:PGFeatureProtectionAmount]==1 && [defaults valueForParameter:PGNonSkinProtection]==1 && [defaults valueForParameter:PGMicroDetail]==0,@"new controls default to full five-feature/non-skin protection and zero micro detail");
for(NSNumber *legacy in @[@NO,@YES]) {
PGInspectorState *migrated=State(@{@(PGFeatureProtect):legacy,@(PGHighPass):@.63},nil);
PGBeautySettings s=PGSettingsWithInspectorState(PGBeautyDefaults(),migrated);
Check([migrated valueForParameter:PGFeatureProtectionAmount]==legacy.boolValue && s.featureProtection==legacy.boolValue && Near(s.highPassDetail,.63) && s.nonSkinProtection==1,@"old schema dictionaries migrate five-feature bool without reinterpreting legacy global smoothing");
}
PGInspectorState *explicit=State(@{@(PGFeatureProtect):@NO,@(PGFeatureProtectionAmount):@.37},nil);
Check(Near([explicit valueForParameter:PGFeatureProtectionAmount],.37),@"an explicit numeric protection setting takes precedence over the old boolean");
NSDictionary *values=@{@(PGFeatureProtectionAmount):@.25,@(PGNonSkinProtection):@.6,@(PGMicroDetail):@.8,@(PGMidtone):@.7,@(PGHighPass):@.4,@(PGSharpness):@.5,@(PGHue):@12,@(PGBrightness):@.3,@(PGTonePreset):@2};
PGInspectorState *a=State(values,nil);
NSData *archive=[NSKeyedArchiver archivedDataWithRootObject:a requiringSecureCoding:YES error:nil];
PGInspectorState *restored=[NSKeyedUnarchiver unarchivedObjectOfClass:PGInspectorState.class fromData:archive error:nil];
Check([restored isEqual:a] && Near([restored valueForParameter:PGFeatureProtectionAmount],.25) && Near([restored valueForParameter:PGNonSkinProtection],.6) && Near([restored valueForParameter:PGMicroDetail],.8),@"secure document archive retains all three independent numeric controls");
NSMutableDictionary *right=[values mutableCopy];right[@(PGFeatureProtectionAmount)]=@.75;right[@(PGNonSkinProtection)]=@.2;right[@(PGMicroDetail)]=@.4;
PGInspectorState *mid=(PGInspectorState *)[a interpolateBetween:State(right,nil) withWeight:.5];
Check(Near([mid valueForParameter:PGFeatureProtectionAmount],.5) && Near([mid valueForParameter:PGNonSkinProtection],.4) && Near([mid valueForParameter:PGMicroDetail],.6),@"new floating-point protection and micro-detail keyframes interpolate independently");
for(NSNumber *key in @[@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)]) {
PGInspectorState *bypassed=State(values,[NSSet setWithObject:key]);
PGBeautySettings s=PGSettingsWithInspectorState(PGBeautyDefaults(),bypassed);
Check(Near(s.featureProtectionAmount,key.unsignedIntValue==PGFeatureProtectionAmount?0:.25) && Near(s.nonSkinProtection,key.unsignedIntValue==PGNonSkinProtection?0:.6) && Near(s.microDetail,key.unsignedIntValue==PGMicroDetail?0:.8),@"each new bypass affects only its own render setting");
Check(s.featureProtection==(s.featureProtectionAmount>0) && Near(s.skinHue,12) && Near(s.skinBrightness,.3) && s.skinTonePreset==2 && Near(s.highPassDetail,.4) && Near(s.sharpness,.5),@"protection bypass preserves color and legacy detail settings and derives the old feature bool");
}
NSMutableDictionary *off=[values mutableCopy];off[@(PGSmoothingEnabled)]=@0;
PGBeautySettings s=PGSettingsWithInspectorState(PGBeautyDefaults(),State(off,nil));
Check(s.amount==0 && s.midtoneDetail==0 && s.highPassDetail==0 && s.microDetail==0 && Near(s.skinHue,12) && Near(s.skinBrightness,.3),@"smoothing master bypass also disables micro detail while preserving color adjustments");
PGInspectorState *untouched=[PGInspectorState stateWithValues:@{@(PGFeatureProtect):@NO} disabledParameters:[NSSet set] hasEdits:NO];
PGBeautySettings original=PGBeautyDefaults();original.featureProtectionAmount=.8;original.nonSkinProtection=.2;original.microDetail=.7;
PGBeautySettings result=PGSettingsWithInspectorState(original,untouched);
Check(memcmp(&original,&result,sizeof(result))==0,@"an untouched migrated inspector still leaves existing document settings unchanged");
}
static void ModelTests(void) {
PGInspectorState *plain=[PGInspectorState stateWithValues:@{} disabledParameters:[NSSet set] hasEdits:NO];
PGBeautySettings original=PGBeautyDefaults();original.midtoneDetail=.5;original.faceChin=-.3;
@@ -191,13 +230,51 @@ static void ViewInteractionTests(void) {
Fire(number);
Check(number.currentEditor==nil && Near([(PGInspectorState *)api.values[@(PGInspectorPanel)] valueForParameter:PGChin],.25),@"Return commits once and releases the actual AppKit editor before host commands");
[window close];
NSButton *preview=(NSButton *)FindControl(view,NSButton.class,@"人脸框预览");preview.state=NSControlStateValueOn;Fire(preview);s=api.values[@(PGInspectorPanel)];Check([s valueForParameter:PGTrackBoxes]==1,@"preview switch events change the automatic face box setting");
NSButton *preview=(NSButton *)FindControl(view,NSButton.class,@"检测框预览");preview.state=NSControlStateValueOn;Fire(preview);s=api.values[@(PGInspectorPanel)];Check([s valueForParameter:PGTrackBoxes]==1,@"preview switch events change the automatic face box setting");
for(NSNumber *width in @[@280,@320,@380,@520]) {
[view setFrameSize:NSMakeSize(width.doubleValue,20)];[view layoutSubtreeIfNeeded];
Check(view.frame.size.height>500 && Near(view.frame.size.height,view.fittingSize.height) && Near(view.frame.size.height,view.intrinsicContentSize.height),@"width changes produce a complete consistent intrinsic/fitting height");
for(NSView *card in view.subviews)if(!card.hidden)Check(NSMaxY(card.frame)<=NSHeight(view.bounds)+1 && NSMaxX(card.frame)<=NSWidth(view.bounds)+1,@"every visible card and footer remains inside the panel at all inspector widths");
}
}
static void BeautyControlInteractionTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGFeatureProtectionAmount)]=@.37;api.values[@(PGHighPass)]=@.63;api.values[@(PGHue)]=@12;api.values[@(PGBrightness)]=@.3;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
Check(Near([view.controller.state valueForParameter:PGFeatureProtectionAmount],.37) && !view.controller.state.hasEdits,@"an untouched inspector preserves native fractional protection when the legacy boolean is enabled");
[view.controller setValue:.35 forParameter:PGBrightness];
Check(Near([(PGInspectorState *)api.values[@(PGInspectorPanel)] valueForParameter:PGFeatureProtectionAmount],.37) && Near([api.values[@(PGFeatureProtectionAmount)]doubleValue],.37),@"first unrelated edit captures native fractional protection without replacing it with the legacy true value");
api.values[@(PGInspectorPanel)]=[PGInspectorState stateWithValues:@{} disabledParameters:[NSSet set] hasEdits:NO];
api.values[@(PGFeatureProtect)]=@NO;[view hostParameterChanged];
Check([view.controller.state valueForParameter:PGFeatureProtectionAmount]==0 && !view.controller.state.hasEdits,@"untouched inspector imports the old host five-feature boolean into the new numeric control");
[view.controller setValue:.35 forParameter:PGBrightness];
Check(![api.values[@(PGFeatureProtect)]boolValue] && Near([view.controller.state valueForParameter:PGFeatureProtectionAmount],0),@"first unrelated edit preserves disabled legacy feature protection");
NSArray *ids=@[@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)],*names=@[@"五官保护",@"非肤色区保护",@"微细锐化"];
for(NSUInteger i=0;i<ids.count;i++) {
UInt32 key=[ids[i]unsignedIntValue];NSString *name=names[i];
NSSlider *slider=(NSSlider *)FindControl(view,NSSlider.class,name);
NSTextField *number=(NSTextField *)FindControl(view,NSTextField.class,[name stringByAppendingString:@"数值"]);
Check(slider && number && slider.enabled && number.enabled,@"each new control exposes an enabled native slider and numeric field");
number.stringValue=@"27%";Fire(number);
Check(Near([view.controller.state valueForParameter:key],.27) && [number.stringValue isEqual:@"27%"],@"new numeric controls accept direct percentages without inverse interpretation");
slider.doubleValue=.42;Fire(slider);
Check(Near([view.controller.state valueForParameter:key],.42) && [number.stringValue isEqual:@"42%"],@"actual new slider events publish their direct amount and update the percentage display");
NSButton *eye=(NSButton *)FindControl(view,NSButton.class,[@"启用 / 停用 · "stringByAppendingString:name]);Fire(eye);
Check(![view.controller.state isParameterEnabled:key] && Near([view.controller.state valueForParameter:key],.42) && !slider.enabled,@"new individual bypass preserves its value and disables its native controls");
if(key==PGFeatureProtectionAmount)Check(![api.values[@(PGFeatureProtect)]boolValue],@"bypassed numeric feature protection mirrors false into the legacy hidden boolean");
NSButton *reset=(NSButton *)FindControl(view,NSButton.class,[@"重置 · "stringByAppendingString:name]);Fire(reset);
Check([view.controller.state isParameterEnabled:key] && [view.controller.state valueForParameter:key]==(key==PGMicroDetail?0:1) && slider.enabled,@"new individual reset restores the proper default and clears bypass");
}
Check([api.values[@(PGFeatureProtect)]boolValue] && Near([view.controller.state valueForParameter:PGHighPass],.63) && Near([view.controller.state valueForParameter:PGHue],12) && Near([view.controller.state valueForParameter:PGBrightness],.35),@"new resets restore the legacy feature bool without modifying global smoothing, hue or brightness");
NSButton *multi=(NSButton *)FindControl(view,NSButton.class,@"多人模式");Check([multi.toolTip containsString:@"易抖动"],@"multi-face mode exposes its instability notice as a tooltip");
[view.controller setValue:.6 forParameter:PGMicroDetail];
NSButton *master=(NSButton *)FindControl(view,NSButton.class,@"磨皮");master.state=NSControlStateValueOff;Fire(master);
PGBeautySettings s=PGSettingsWithInspectorState(PGBeautyDefaults(),view.controller.state);
Check(s.microDetail==0 && s.midtoneDetail==0 && s.highPassDetail==0 && Near(s.skinHue,12) && Near(s.skinBrightness,.35),@"actual smoothing master event disables new detail processing independently from whitening");
master.state=NSControlStateValueOn;Fire(master);
Check(Near(PGSettingsWithInspectorState(PGBeautyDefaults(),view.controller.state).microDetail,.6),@"reenabling the master restores the stored micro-detail amount");
Check(api.actionDepth==0 && api.actionStarts==api.actionEnds && api.accessViolations==0,@"all new numeric, bypass, reset and master interactions use balanced host actions");
}
static void HostHandshakeTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGMidtone)]=@.5;
@@ -219,24 +296,45 @@ static void ContinuousPreviewTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
NSSlider *slider=(NSSlider *)FindControl(view,NSSlider.class,@"短脸");
NSArray *names=@[@"短脸",@"五官保护",@"非肤色区保护",@"微细锐化"],*ids=@[@(PGShort),@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)];
for(NSUInteger i=0;i<names.count;i++) {
UInt32 key=[ids[i]unsignedIntValue];NSSlider *slider=(NSSlider *)FindControl(view,NSSlider.class,names[i]);
void (^began)(void)=[slider valueForKey:@"interactionBegan"], (^ended)(void)=[slider valueForKey:@"interactionEnded"];
Check(slider.continuous && began && ended,@"native slider emits continuous events and exposes balanced gesture callbacks");
began();
for(NSNumber *value in @[@.2,@.5,@1]) {
NSUInteger publications=api.previewPublications;slider.doubleValue=value.doubleValue;Fire(slider);
PGInspectorState *visible=api.previewValues[@(PGInspectorPanel)];
Check(api.actionDepth==0 && api.previewPublications==publications+1 && Near([visible valueForParameter:PGShort],value.doubleValue),@"every drag step publishes a completed host snapshot before mouse-up");
Check(visible && Near(PGSettingsWithInspectorState(PGBeautyDefaults(),visible).faceShort,value.doubleValue),@"published frame settings contain each intermediate short-face value while gesture is still open");
Check(api.actionDepth==0 && api.previewPublications==publications+1 && Near([visible valueForParameter:key],value.doubleValue),@"every old and new slider step publishes a completed host snapshot before mouse-up");
PGBeautySettings s=PGSettingsWithInspectorState(PGBeautyDefaults(),visible);
double actual=key==PGShort?s.faceShort:key==PGFeatureProtectionAmount?s.featureProtectionAmount:key==PGNonSkinProtection?s.nonSkinProtection:s.microDetail;
Check(visible && Near(actual,value.doubleValue),@"published frame settings contain each intermediate new protection/detail value while gesture is still open");
}
NSUInteger publications=api.previewPublications;Fire(slider);
Check(api.previewPublications==publications,@"unchanged drag events do not enqueue redundant previews");
ended();
}
Check(api.actionDepth==0 && api.actionStarts==api.actionEnds && api.accessViolations==0 && api.invalidActionSenders==0,@"step-wise publication preserves action-scoped APIs and the actual view sender");
}
static void OptionalInspectorPreview(void) {
NSString *path=NSProcessInfo.processInfo.environment[@"PAINTFCP_INSPECTOR_PNG"];
if(!path.length)return;
PGHostAPI *api=[PGHostAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGMidtone)]=@.4;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
[view setFrameSize:NSMakeSize(380,20)];
NSWindow *window=[[NSWindow alloc]initWithContentRect:view.bounds styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO];
window.releasedWhenClosed=NO;window.appearance=[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];window.contentView=view;
[window setContentSize:view.frame.size];[view layoutSubtreeIfNeeded];[window displayIfNeeded];
NSBitmapImageRep *bitmap=[view bitmapImageRepForCachingDisplayInRect:view.bounds];
[view cacheDisplayInRect:view.bounds toBitmapImageRep:bitmap];
NSData *png=[bitmap representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
Check(png.length>0 && [png writeToFile:path atomically:YES],@"optional offscreen inspector PNG is written to the requested review path");
[window close];
}
int main(int argc,const char **argv) {@autoreleasepool {
[NSApplication sharedApplication];[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
RegistrationTests();ModelTests();ControllerTests();ViewInteractionTests();HostHandshakeTests();ContinuousPreviewTests();
RegistrationTests();ModelTests();BeautyControlModelTests();ControllerTests();ViewInteractionTests();BeautyControlInteractionTests();HostHandshakeTests();ContinuousPreviewTests();OptionalInspectorPreview();
if(argc>2) {
NSData *inner=[NSData dataWithContentsOfFile:@(argv[1])],*outer=[NSData dataWithContentsOfFile:@(argv[2])];NSError *error=nil;
NSKeyedUnarchiver *reader=[[NSKeyedUnarchiver alloc]initForReadingFromData:inner error:&error];reader.requiresSecureCoding=YES;