Skip to content

Commit 2909662

Browse files
committed
feat(pkg): compat.opencv unifont feature — CJK putText via font asset package (R4)
- pkgs/c/compat.opencv-unifont.lua: data-only asset package for the upstream WenQuanYiMicroHei.ttf.gz (GLOBAL = the pinned opencv_3rdparty raw url, CN = mcpp-res/opencv@unifont-1.0.0, sha256-pinned; raw .gz payloads are parked byte-preserved in the store's shared runtimedir, so the descriptor carries an asio-style anchor-TU mcpp shell). - compat.opencv feature `unifont` (mcpp 0.0.97 features now gate deps + defines): pulls the asset package and defines HAVE_UNIFONT; the embedded build.mcpp sees MCPP_FEATURE_UNIFONT=1 and hex-embeds the compressed font as builtin_font_uni.h (OcvBuiltinFontUni), byte- faithful to cmake's ocv_blob2hdr. Payload located via the store runtimedir convention (no MCPP_DEP_<NAME>_DIR contract var yet). - tests/examples/opencv-unifont member: long-form feature dependency; asserts FontFace("uni") usability (that builtin only exists under HAVE_UNIFONT — the probe itself) + real CJK putText ink. Passes locally; default member regression clean.
1 parent c610e07 commit 2909662

9 files changed

Lines changed: 190 additions & 0 deletions

File tree

.agents/docs/2026-07-19-compat-opencv-unification.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@
4747
- tests/examples/opencv5 成员与 pkgs/c/compat.opencv5.lua 过渡期保留
4848
(已发布 opencv 0.0.2 模块 tarball 依赖它),opencv-m v0.0.3 切换后删除。
4949

50+
## R4:unifont feature(随本 PR)
51+
52+
- `pkgs/c/compat.opencv-unifont.lua`:数据资产包 —— 上游 opencv_3rdparty 原始
53+
`WenQuanYiMicroHei.ttf.gz`(GLOBAL 直取 raw.githubusercontent,CN 镜像
54+
mcpp-res/opencv@unifont-1.0.0,sha256 钉,MD5 与上游 CMake pin 一致)。
55+
裸 .gz 不是归档:安装器把它字节保真地放到 store 共享 `data/runtimedir/`
56+
(实测),verdir 只有元数据 → 描述符带 asio 式 anchor-TU 空壳 mcpp 段。
57+
- `compat.opencv` 新 feature `unifont`(0.0.97 features 已支持 deps/defines
58+
门控):`deps = { ["compat.opencv-unifont"] = "1.0.0" }` +
59+
`defines = { "HAVE_UNIFONT" }`;build.mcpp 见 `MCPP_FEATURE_UNIFONT=1` 时按
60+
`MCPP_MANIFEST_DIR/../../../runtimedir/<fname>`(fallback:verdir 扫描)找到
61+
字体并 blob2hdr 成 `builtin_font_uni.h`(符号 OcvBuiltinFontUni,与 cmake
62+
ocv_blob2hdr 逐字节同构)。无 MCPP_DEP_<NAME>_DIR 契约变量是已知空洞
63+
(待提 mcpp 增强)。
64+
- 成员 tests/examples/opencv-unifont:长式依赖
65+
`opencv = { version = "5.0.0", features = ["unifont"] }`,断言
66+
`FontFace("uni")` 可用(该内建字体面只在 HAVE_UNIFONT 下存在——本身即
67+
feature 探针)且 CJK putText 出墨;默认成员回归不受影响。
68+
5069
## 合并门槛(先决条件)
5170

5271
**mcpp#240**:#233 消歧后可执行目标的链接输入未跟随改名——依赖包与消费者源文件

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
3535
| 原生模块库(Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua)(模块层,源码经 `compat.ffmpeg` 直编) · [`opencv`](pkgs/o/opencv.lua)(模块层,源码经 `compat.opencv5` 直编) |
3636
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
3737
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
38+
| 数据资产包(feature 依赖专用) | [`compat.opencv-unifont`](pkgs/c/compat.opencv-unifont.lua)(CJK 字体,由 `compat.opencv``unifont` feature 拉取) |
3839
| 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) |
3940
| 全源码直编(config 快照 + 源列表,零外部构建系统) | [`compat.ffmpeg`](pkgs/c/compat.ffmpeg.lua)(2281 TU 含 NASM 汇编,28 个目录 glob 声明) |
4041
| 全源码直编 + `build.mcpp` 消费端合成 | [`compat.opencv`](pkgs/c/compat.opencv.lua)(OpenCV 5,458 TU 真实路径直编,SIMD dispatch 保留,字体/内核/jpeg12/16 由包内 build.mcpp 生成,依赖 `compat.ffmpeg` 提供 videoio FFmpeg 后端;旧 install() CMake 形态已移除,`compat.opencv5` 为过渡别名待删) |

mcpp.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ members = [
2626
"tests/examples/openblas",
2727
"tests/examples/opencv",
2828
"tests/examples/opencv5",
29+
"tests/examples/opencv-unifont",
2930
"tests/examples/opencv-module",
3031
"tests/examples/spdlog",
3132
"tests/examples/spdlog-compiled",

pkgs/c/compat.opencv-unifont.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
-- Data-only asset package: the CJK/Unicode fallback font OpenCV embeds when
2+
-- built WITH_UNIFONT (WenQuanYiMicroHei.ttf.gz, pinned to the same
3+
-- opencv_3rdparty commit as upstream's modules/imgproc/CMakeLists.txt,
4+
-- upstream MD5 fb79cf5b4f4c89414f1233f14c2eb273). Consumers never depend on
5+
-- it directly — compat.opencv's `unifont` feature pulls it and its
6+
-- build.mcpp hex-embeds the COMPRESSED bytes (builtin_font_uni.h, symbol
7+
-- OcvBuiltinFontUni), exactly like cmake's ocv_blob2hdr. The payload is a
8+
-- raw .gz (not an archive): the installer parks it byte-preserved in the
9+
-- store's shared data/runtimedir/, where compat.opencv's build.mcpp finds
10+
-- it by name.
11+
package = {
12+
spec = "1",
13+
namespace = "compat",
14+
name = "compat.opencv-unifont",
15+
description = "WenQuanYi Micro Hei font asset for OpenCV putText Unicode/CJK rendering (unifont feature)",
16+
licenses = {"Apache-2.0", "GPL-3.0-only WITH Font-exception-2.0"},
17+
repo = "https://github.com/vpisarev/opencv_3rdparty",
18+
type = "package",
19+
20+
xpm = {
21+
linux = {
22+
["1.0.0"] = {
23+
url = {
24+
GLOBAL = "https://raw.githubusercontent.com/vpisarev/opencv_3rdparty/cc7d85179d69a704bee209aa37ce8a657f2f8b34/WenQuanYiMicroHei.ttf.gz",
25+
CN = "https://gitcode.com/mcpp-res/opencv/releases/download/unifont-1.0.0/WenQuanYiMicroHei.ttf.gz",
26+
},
27+
sha256 = "70c5634fe8326a20a18f4d634d08c510f2c05f6613d2d5aa3566f162cc02804f",
28+
},
29+
},
30+
},
31+
32+
-- data-only: the payload is the font blob itself (parked in the store's
33+
-- shared runtimedir — a raw .gz is not an archive). The mcpp segment is
34+
-- a header-only shell so the resolver can treat it as an ordinary
35+
-- build dependency; nothing is compiled or included from it.
36+
mcpp = {
37+
language = "c++23",
38+
c_standard = "c11",
39+
include_dirs = {},
40+
sources = { "mcpp_generated/opencv_unifont_anchor.c" },
41+
-- data-only packages still need a buildable target in mcpp (asio
42+
-- anchor precedent): one empty TU, nothing else.
43+
generated_files = {
44+
["mcpp_generated/opencv_unifont_anchor.c"] = [==[/* compat.opencv-unifont: data-only font asset package (see descriptor). */
45+
typedef int opencv_unifont_anchor_t;
46+
]==],
47+
},
48+
},
49+
}

pkgs/c/compat.opencv.lua

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ package = {
9393
targets = {
9494
opencv = { kind = "lib" },
9595
},
96+
-- `unifont`: Unicode/CJK putText coverage. Pulls the font asset
97+
-- package and defines HAVE_UNIFONT (drawing_text.cpp gates on it);
98+
-- build.mcpp sees MCPP_FEATURE_UNIFONT=1 and hex-embeds the font
99+
-- (builtin_font_uni.h). Not part of the reference profile — the
100+
-- embed machinery is byte-faithful to cmake's ocv_blob2hdr either way.
101+
features = {
102+
["unifont"] = {
103+
deps = { ["compat.opencv-unifont"] = "1.0.0" },
104+
defines = { "HAVE_UNIFONT" },
105+
},
106+
},
96107
linux = {
97108
ldflags = { "-lpthread", "-ldl" },
98109
},
@@ -377,6 +388,36 @@ int main() {
377388
blob2hdr(wrap / "modules/imgproc/fonts/Rubik.ttf.gz", out / "builtin_font_sans.h", "OcvBuiltinFontSans");
378389
blob2hdr(wrap / "modules/imgproc/fonts/Rubik-Italic.ttf.gz", out / "builtin_font_italic.h", "OcvBuiltinFontItalic");
379390
391+
// 1b. unifont feature: hex-embed the CJK font pulled in by the
392+
// compat.opencv-unifont dependency. Its payload is a raw .gz the
393+
// installer parks byte-preserved in the store's shared
394+
// data/runtimedir/ (no MCPP_DEP_<NAME>_DIR contract var yet), so
395+
// resolve it relative to this package's store location, with a
396+
// verdir sweep as fallback.
397+
if (std::getenv("MCPP_FEATURE_UNIFONT")) {
398+
const char* fname = "WenQuanYiMicroHei.ttf.gz";
399+
fs::path font;
400+
// <data>/xpkgs/<pkg>/<ver> -> <data>/runtimedir/<fname>
401+
fs::path rt = man.parent_path().parent_path().parent_path() / "runtimedir" / fname;
402+
if (fs::exists(rt)) font = rt;
403+
if (font.empty()) {
404+
std::error_code ec;
405+
for (auto& e : fs::directory_iterator(man.parent_path().parent_path(), ec)) {
406+
if (e.path().filename().string().find("opencv-unifont") == std::string::npos) continue;
407+
for (auto& v : fs::recursive_directory_iterator(e.path(), ec))
408+
if (v.path().filename() == fname) { font = v.path(); break; }
409+
if (!font.empty()) break;
410+
}
411+
}
412+
if (font.empty()) {
413+
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found near %s\n",
414+
fname, man.string().c_str());
415+
return 1;
416+
}
417+
blob2hdr(font, out / "builtin_font_uni.h", "OcvBuiltinFontUni");
418+
std::printf("compat.opencv build.mcpp: unifont embedded from %s\n", font.string().c_str());
419+
}
420+
380421
// 2. OpenCL kernel embeddings (inert under this profile, byte-faithful)
381422
for (std::string m : { "core", "imgproc", "geometry" }) {
382423
fs::path cl_dir = wrap / "modules" / m / "src" / "opencl";
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# compat.opencv `unifont` feature test: long-form dependency requesting the
2+
# feature — pulls the compat.opencv-unifont font asset, build.mcpp embeds it
3+
# (builtin_font_uni.h) and HAVE_UNIFONT rides the package defines, so
4+
# putText gains Unicode/CJK coverage (the "uni" builtin FontFace exists).
5+
# Linux-only like the base package; no-op main elsewhere.
6+
[package]
7+
name = "opencv-unifont-tests"
8+
version = "0.1.0"
9+
10+
[indices]
11+
compat = { path = "../../.." }
12+
13+
[target.'cfg(linux)'.dependencies.compat]
14+
opencv = { version = "5.0.0", features = ["unifont"] }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// unifont feature assertion: the "uni" builtin font face only exists when
2+
// compat.opencv was built with HAVE_UNIFONT (drawing_text.cpp gates the
3+
// builtinFontData entry), so its usability IS the feature probe; CJK
4+
// rendering through it must produce real ink. Linux-only (see mcpp.toml).
5+
#ifdef __linux__
6+
#include <opencv2/core.hpp>
7+
#include <opencv2/imgproc.hpp>
8+
#include <cstdio>
9+
10+
int main() {
11+
cv::FontFace uni("uni");
12+
cv::Mat img(64, 256, CV_8UC1, cv::Scalar(0));
13+
cv::putText(img, "中文字体", cv::Point(8, 44), cv::Scalar(255), uni, 28);
14+
int ink = cv::countNonZero(img);
15+
if (ink < 100) {
16+
std::printf("unifont: CJK ink %d too low — font not embedded?\n", ink);
17+
return 1;
18+
}
19+
std::printf("unifont ok: CJK putText ink=%d\n", ink);
20+
return 0;
21+
}
22+
#else
23+
int main() { return 0; }
24+
#endif

tools/compat-opencv/build_mcpp_template.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,36 @@ int main() {
229229
blob2hdr(wrap / "modules/imgproc/fonts/Rubik.ttf.gz", out / "builtin_font_sans.h", "OcvBuiltinFontSans");
230230
blob2hdr(wrap / "modules/imgproc/fonts/Rubik-Italic.ttf.gz", out / "builtin_font_italic.h", "OcvBuiltinFontItalic");
231231

232+
// 1b. unifont feature: hex-embed the CJK font pulled in by the
233+
// compat.opencv-unifont dependency. Its payload is a raw .gz the
234+
// installer parks byte-preserved in the store's shared
235+
// data/runtimedir/ (no MCPP_DEP_<NAME>_DIR contract var yet), so
236+
// resolve it relative to this package's store location, with a
237+
// verdir sweep as fallback.
238+
if (std::getenv("MCPP_FEATURE_UNIFONT")) {
239+
const char* fname = "WenQuanYiMicroHei.ttf.gz";
240+
fs::path font;
241+
// <data>/xpkgs/<pkg>/<ver> -> <data>/runtimedir/<fname>
242+
fs::path rt = man.parent_path().parent_path().parent_path() / "runtimedir" / fname;
243+
if (fs::exists(rt)) font = rt;
244+
if (font.empty()) {
245+
std::error_code ec;
246+
for (auto& e : fs::directory_iterator(man.parent_path().parent_path(), ec)) {
247+
if (e.path().filename().string().find("opencv-unifont") == std::string::npos) continue;
248+
for (auto& v : fs::recursive_directory_iterator(e.path(), ec))
249+
if (v.path().filename() == fname) { font = v.path(); break; }
250+
if (!font.empty()) break;
251+
}
252+
}
253+
if (font.empty()) {
254+
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found near %s\n",
255+
fname, man.string().c_str());
256+
return 1;
257+
}
258+
blob2hdr(font, out / "builtin_font_uni.h", "OcvBuiltinFontUni");
259+
std::printf("compat.opencv build.mcpp: unifont embedded from %s\n", font.string().c_str());
260+
}
261+
232262
// 2. OpenCL kernel embeddings (inert under this profile, byte-faithful)
233263
for (std::string m : { "core", "imgproc", "geometry" }) {
234264
fs::path cl_dir = wrap / "modules" / m / "src" / "opencl";

tools/compat-opencv/gen_descriptor.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,17 @@ def defines_lua(defset):
356356
targets = {{
357357
opencv = {{ kind = "lib" }},
358358
}},
359+
-- `unifont`: Unicode/CJK putText coverage. Pulls the font asset
360+
-- package and defines HAVE_UNIFONT (drawing_text.cpp gates on it);
361+
-- build.mcpp sees MCPP_FEATURE_UNIFONT=1 and hex-embeds the font
362+
-- (builtin_font_uni.h). Not part of the reference profile — the
363+
-- embed machinery is byte-faithful to cmake's ocv_blob2hdr either way.
364+
features = {{
365+
["unifont"] = {{
366+
deps = {{ ["compat.opencv-unifont"] = "1.0.0" }},
367+
defines = {{ "HAVE_UNIFONT" }},
368+
}},
369+
}},
359370
linux = {{
360371
ldflags = {{ "-lpthread", "-ldl" }},
361372
}},

0 commit comments

Comments
 (0)