Vyntek
规格机器视觉规格

多格式图像模型与公共接口

www 工作副本 · M2(Arden · 2026-10-21 Asia/Shanghai)
双轨:本页已迁入 Vyntek www;mvdocs image-model 仍在线作权威对照,直至 Vernon 下线。未迁专题链到 mvdocs。
实现边界:公开头树 include/vyntek/imaging/** 已落地外形(对拍 tip e46c042;伞头自 1c03617)。ImageInfo::captured_at 已有。多数 NON-STABLE ABI / STUB——有声明 ≠ 契约验收。Arden 不改 include/ / src/。详见文末「本仓实现对拍」。
关联:memory-management · TC-MEM 摘录 · cpp-headers · overview · 预览 http://127.0.0.1:8792

成像权威框(Alive):像素/句柄基建权威在 C++ vyntek::imaging(公开头 <vyntek/imaging/...>)。.NET/C# 仅为绑定/显示投影(如 IPixelImage);禁止「Imaging 仅依赖 .NET」或第二套像素真相。ImageDisplay 仅 C#,经绑定消费句柄,见 image-display.md。头文件见 cpp-headers.md。

编排权威见 toolflow.md(Tool / ToolFlow)。本文只负责图像 Info/格式/版本/接口与工厂等像素与句柄模型;不定义工具流执行、列表序或链接调度。工具流消费本文句柄:发布后稳定只读;链接赋值不是 DAG 调度。交接可测对照见 toolflow §3.4。

语言:下文 API 示意为 C++(vyntek::imaging)。示意、非已发布 ABI。风格:class/struct、std::span、std::expected/状态码、句柄语义。

本文负责 Info、格式与颜色/深度语义、内容版本、图像接口、类型化访问与工厂。图像端口传递一个图像值。

关联:内存 · ToolFlow(编排) · 头文件 · 示例 · 验证

一份 ImageInfo 描述图像

宽高、像素在内存中的排列方式、像素格式及可选采集信息合并为一个不可变 ImageInfo。调用方创建一份信息对象,直接交给图像工厂,不再组合多份描述对象。

// 示意、非已发布 ABI。<vyntek/imaging/image_info.hpp>
namespace vyntek::imaging {

enum class PixelFormat : std::uint8_t {
  Gray8 = 0,
  Rgb24 = 1,
  Bgr24 = 2,
  Depth16 = 3
};

enum class ColorEncoding : std::uint8_t {
  Unspecified = 0,
  Srgb = 1,
  LinearRgb = 2
};

struct ImageInfo {
  ImageInfo(int width, int height,
            PixelFormat pixel_format = PixelFormat::Gray8,
            std::optional<std::int64_t> row_step_bytes = std::nullopt,
            std::int64_t start_offset_bytes = 0);

  int width() const;
  int height() const;
  PixelFormat pixel_format() const;
  ColorEncoding color_encoding() const;
  std::int64_t row_step_bytes() const;
  std::int64_t start_offset_bytes() const;
  int pixel_bytes_per_row() const;
  std::int64_t pixel_byte_count() const;

  std::optional<std::int64_t> image_id;
  std::optional<std::chrono::system_clock::time_point> captured_at;
  int origin_x = 0;
  int origin_y = 0;
  std::optional<double> depth_unit_meters;
  std::optional<std::uint16_t> invalid_depth_value;

  void ValidateCapacity(std::int64_t capacity) const;
  ImageInfo GetRegion(int x, int y, int width, int height) const;
};

}  // namespace vyntek::imaging

最常用的创建方式只有 ImageInfo(width, height):默认 Gray8、无行尾额外字节、起始偏移为零,不必提供编号和时间。需要采集编号时:ImageInfo info(width, height); info.image_id = 7;。

成员调用方可直接理解的含义
Width / Height图像宽高,单位为像素
PixelFormat每个像素如何解释:Gray8、Rgb24、Bgr24 或 Depth16
ColorEncodingRGB/BGR 的编码声明:Unspecified、Srgb 或 LinearRgb;不等于通道顺序
RowStepBytes从本行起点到下一行起点的字节距离,包含行尾空隙;负值表示倒序行
StartOffsetBytes逻辑第一行在缓冲区中的起始字节位置
PixelBytesPerRow一行有效像素占用的字节数,不包括行尾空隙
PixelByteCount全部有效像素的字节数,不代表整份分配成本
ImageId / CapturedAt可选业务编号与采集时间,不参与显示排序
OriginX / OriginY当前视图左上角在原始采集坐标中的位置
DepthUnitMetersDepth16 原始值每单位对应的米数;为空表示未声明尺度,不能假定毫米
InvalidDepthValueDepth16 的可选无效码;为空表示未声明,不默认把零判为无效

rowStepBytes 为 null 时取 PixelBytesPerRow;显式零步进、无效尺寸、未知格式或算术溢出均拒绝。ValidateCapacity 再检查完整像素范围没有超出存储,但不授予读取权限。

ImageInfo 不拥有内存,也不绑定某个内容版本。PixelImageHandle::info() 保存信息,实际访问对象的 Version 表示已经取得的内容;因此图像信息与访问寿命不会混在一起。ImageInfo 在构造后尺寸与字节排列固定;业务字段在提交图像前设定,已经提交的图像不会被后续原地改写信息(派生用 GetRegion / 拷贝构造新 Info)。

GetRegion 检查区域位于父图像内,保留 RowStepBytes,按每像素字节数增加起始偏移,并增加 OriginX/OriginY;保留 ImageId/CapturedAt、ColorEncoding 与深度解释,返回新 ImageInfo,不复制像素。可以用有效 reader 和新信息创建另一张共享同一内容的图像。非 RGB/BGR 的首版格式只接受 ColorEncoding.Unspecified,未知枚举拒绝。

Gray8/Rgb24/Bgr24/Depth16 的每像素字节数分别为 1/3/3/2,PixelBytesPerRow 为 checked(Width * 每像素字节数)。Depth16 定义为小端无符号整数;初版类型化零复制访问要求运行平台为小端,其他平台显式拒绝,不静默进行字节交换。外部大端数据由适配器转换后导入。ushort 行视图不额外要求偏移或行步长为偶数;若 native 算法要求地址对齐,由 native 桥接单独验证或复制。

深度尺度在声明时必须为有限正数,有效原始值的物理深度为 raw * DepthUnitMeters。无效码先于尺度换算判定。非 Depth16 格式不得携带深度解释字段;构造与 with 派生的信息在创建图像、克隆、ROI、Open 和显示适配入口统一校验。多种无效码、置信度平面、相机内参和非线性标定不在这两个字段中隐式表达,后续按实际算法扩展。

native buffer 可使用长容量与长偏移,每行 span 长度仍为 int。目标 Display 的单视图 PixelByteCount 不超过 int.MaxValue,超限明确拒绝。Gray8/RGB24/BGR24/Depth16 均建立对应渲染路径,未知格式明确拒绝,不静默按 Gray8 解释。ImageFramePixelFormat 的迁移属于旧 API 清理。

像素范围计算

rowDelta = (info.Height - 1) * info.RowStepBytes
lowestByte = info.StartOffsetBytes + min(0, rowDelta)
endExclusive = info.StartOffsetBytes + max(0, rowDelta) + info.PixelBytesPerRow
0 <= lowestByte < endExclusive <= allocationCapacity
abs(info.RowStepBytes) >= info.PixelBytesPerRow

内容与显示身份

// <vyntek/imaging/version.hpp>
namespace vyntek::imaging {
struct ImageContentVersion {
  BufferId buffer_id;       // 一次有效分配/导入的身份(实现可为 UUID)
  std::int64_t generation;
};
}  // namespace vyntek::imaging
身份意义是否约束图像显示顺序
BufferId一次有效分配或导入的身份否
Generation同一存储的内容代次,每次成功 Complete 后增加否,不是业务帧号或显示请求代次
ContentVersion同一存储的内容修订,来源于有效 reader否,不跨图像比较大小
Info.ImageId可选业务编号,可空、可重复、可倒退否
Info.CapturedAt可选采集时间否
UpdateId一次显示请求的唯一 Guid否,不是公共帧序号
内部请求代次阻止旧异步工作覆盖新请求仅限控件内部

保留的历史静态图像可以再次显示;原内存已覆盖且没有保留副本的内容,无法凭图像编号恢复。ImageInfo 不能冒充 reader,也不能让已关闭图像重新获得像素访问权。

期望版本是访问条件

ImageContentVersion 由 BufferId 与 Generation 共同确定,表示哪份存储的哪一代完整内容。BufferId 在建立底层协调实体时生成,不使用数组地址或 SDK 指针代替;池或 SDK 以后复用相同地址建立新图像时取得新 BufferId。Generation 由内存层维护,调用方不设置。已初始化导入的首次 Generation 为 1;Rent 首次 Complete 后为 1;之后每次 Complete 严格增加,即使写回相同字节也视为一次新提交。Generation 不表示业务帧号、采集顺序、显示顺序或控件内部请求代次。

expectedVersion 是可选的精确匹配条件,不是目标帧号、等待未来版本的命令或读取历史内容的句柄。校验顺序为:验证令牌与 BufferId,等待所需读/写权限,确认内容有效,在同一个同步边界比较完整版本并授予权限。不能先比较版本再排队,不能用“大于等于期望值”代替相等。不提供期望版本时,申请取得实际授予时的内容。

版本值只记录身份,不保留内存,不阻止后续写入,也不提供回滚。句柄不提供看似稳定的当前 Version 属性;可靠版本从有效 ReadOnlyView::version()、WritableView::Complete / CompleteAndOpenRead 或安装结果取得。调用方可以保存值,但在下次申请成功前,不能据此假定原内容还存在。

Share 与 ROI 不提交内容,仍使用同一 BufferId 与 Generation。任意 ROI 完成写入都会推进整份分配的 Generation,其他 ROI 的旧期望版本也随之过期。Clone/Copy 分配新存储,使用新的 BufferId,Generation 从 1 开始,不能把原图令牌直接用于副本。写入中止使内容 Invalid,旧令牌不能继续读取;恢复写入成功后的 Generation 继续推进,不复用旧的有效令牌。

例如算法提交版本 (A, 6),随后调用 SetImage(image, expectedVersion: version)。若控件实际取得读取前另一写者提交了 (A, 7),显示请求以 VersionMismatch 失败;不会悄悄改成显示版本 7,也不会等待版本 6 再次出现。是否重新提交最新内容由宿主决定。若必须保证版本 6 可被捕获,应保持该阶段不被再次修改,或复制成独立图像再提交;仅传版本令牌不能代替这项生命周期安排。

读取阶段结束后再原地写入也可使用 expectedVersion:保存读取对象的 Version,关闭读取,再以该版本申请写入。授予时若已有其他写者修改内容,抛 Status::VersionMismatch(或带 expected/actual 的错误类型),工具自行决定重算或失败,不静默覆盖别人的处理结果。

Snapshot/Detach 对显示创建私有副本后,公开 CurrentVersion 继续表示来源内容身份;内部副本的读取版本另行记录。原图之后改写不使已经完成捕获的显示请求失败,也不改变旧画面。VersionMismatch 仅针对授予原图访问时的条件,不是对未来全部时间持续成立的保证。显示层按异常类型映射失败类别,不解析异常消息来区分版本过期与无效内容。

图像接口、像素类型与临时访问实例

工具流终端(或属性)传递一个 PixelImageHandle;需要特定像素格式的工具声明 Gray8Handle、Rgb24Handle、Bgr24Handle 或 Depth16Handle。非类型化根基与模板特化表达具体像素类型;Pixel 表明可访问像素,避免与 Avalonia 的 IImage 混淆。Gray 统一采用这一拼写。C# IPixelImage 等仅为绑定投影说明,语义以本文 C++ 契约为准;不构成独立 Imaging 核心。

句柄类型像素类型格式与语义
Gray8Handlestd::uint8_t8 位无符号灰度,每像素 1 字节
Rgb24HandleRgb2424 位彩色,内存顺序 R、G、B,每通道 8 位
Bgr24HandleBgr2424 位彩色,内存顺序 B、G、R,每通道 8 位
Depth16Handlestd::uint16_t16 位无符号原始深度,需要结合单位与无效值规则解释

不采用含糊的 Color24 句柄;RGB 与 BGR 不能混用。以后增加 Gray16Handle 时即使同样使用 uint16_t,也不能当成 Depth16Handle。像素位数描述存储,句柄类型还表达语义。

// 示意、非已发布 ABI。<vyntek/imaging/handle.hpp>;句柄关闭即释放本端引用(RAII)
namespace vyntek::imaging {

struct Rgb24 { std::uint8_t r, g, b; };
struct Bgr24 { std::uint8_t b, g, r; };

enum class BufferAccess : std::uint8_t { ReadOnly = 0, ReadWrite = 1 };

// 非类型化根基句柄;格式特化为 Gray8Handle / Rgb24Handle / …
class PixelImageHandle {
 public:
  const ImageInfo& info() const;
  int width() const;
  int height() const;
  BufferId buffer_id() const;
  BufferAccess access() const;
  std::int64_t retained_byte_length() const;

  PixelImageHandle Share() const;
  PixelImageHandle GetRegion(int x, int y, int width, int height) const;
  std::expected<PixelImageHandle, Status> Clone(CancelToken cancel = {}) const;

  std::expected<ReadOnlyViewBase, Status> OpenRead(CancelToken cancel = {}) const;
  std::expected<ReadOnlyViewBase, Status> OpenRead(
      ImageContentVersion expected, CancelToken cancel = {}) const;
  std::expected<WritableViewBase, Status> OpenWrite(CancelToken cancel = {});
  std::expected<WritableViewBase, Status> OpenWrite(
      ImageContentVersion expected, CancelToken cancel = {});
};

template <class TPixel>
class PixelImageHandleT : public /* 桥接 */ PixelImageHandle {
 public:
  PixelImageHandleT Share() const;
  PixelImageHandleT GetRegion(int x, int y, int width, int height) const;
  std::expected<PixelImageHandleT, Status> Clone(CancelToken cancel = {}) const;

  std::expected<ReadOnlyView<TPixel>, Status> OpenRead(CancelToken cancel = {}) const;
  std::expected<ReadOnlyView<TPixel>, Status> OpenRead(
      ImageContentVersion expected, CancelToken cancel = {}) const;
  std::expected<WritableView<TPixel>, Status> OpenWrite(CancelToken cancel = {});
  std::expected<WritableView<TPixel>, Status> OpenWrite(
      ImageContentVersion expected, CancelToken cancel = {});
};

using Gray8Handle   = PixelImageHandleT<std::uint8_t>;
using Rgb24Handle   = PixelImageHandleT<Rgb24>;
using Bgr24Handle   = PixelImageHandleT<Bgr24>;
using Depth16Handle = PixelImageHandleT<std::uint16_t>;

}  // namespace vyntek::imaging

公共图像实现封装存储引用和不可变 ImageInfo。Width/Height 是 Info 的转发,Access 是当前 handle 的能力上限,不是实际是否已经持有写锁。ReadWrite 图像仅保持存储寿命,可按契约修改;ReadOnly 图像还承诺 handle 有效期内内容稳定。稳定性由底层只读存储的不可改写约束,或从已授予读取派生的持久读取引用保证。不可仅把可写图像换个 Access 返回值就声称稳定。

工具依据自己的算法契约调用 OpenRead/OpenWrite;执行器不预判读写、不代为提交,也不在返回时替工具关闭临时访问。ReadOnly 图像申请写入立即抛 Status::NotSupported(或等价错误);需要修改时工具显式 Clone 得到 ReadWrite 图像,再自行申请写入。ReadWrite 图像上的 OpenWrite 仍按既定互斥规则等待,不隐式复制。

模板特化提供类型更精确的成员;实现需显式桥接非类型化与格式特化入口。非类型化与模板入口须桥接为同一次授予;无论经哪个入口调用,一次 Open 都只授予一份权限,桥接不得重复打开。Share/GetRegion/Clone 保留实际格式,精确接口上的返回值保留语义类型,避免灰度工具复制后退化为普通字节图像。

// 非类型化入口用于通用工具、序列化和显示适配。<vyntek/imaging/access.hpp>
namespace vyntek::imaging {

class ReadOnlyViewBase {
 public:
  const ImageInfo& info() const;
  int width() const;
  int height() const;
  ImageContentVersion version() const;
  std::span<const std::uint8_t> GetPixelBytes(int row) const;
  ReadOnlyViewBase Share() const;
  PixelImageHandle ShareImage() const;   // Access = ReadOnly
  ImageBufferPin Pin() const;
  // 析构 / close 释放本端读权限
};

template <class TPixel>
class ReadOnlyView : public ReadOnlyViewBase {
 public:
  std::span<const TPixel> GetPixelRow(int row) const;
  ReadOnlyView Share() const;
  PixelImageHandleT<TPixel> ShareImage() const;
};

class WritableViewBase {
 public:
  const ImageInfo& info() const;
  int width() const;
  int height() const;
  std::span<std::uint8_t> GetPixelBytes(int row);
  ImageBufferPin Pin();
  ImageContentVersion Complete();
  ReadOnlyViewBase CompleteAndOpenRead();
};

template <class TPixel>
class WritableView : public WritableViewBase {
 public:
  std::span<TPixel> GetPixelRow(int row);
  ReadOnlyView<TPixel> CompleteAndOpenRead();
};

}  // namespace vyntek::imaging

临时视图没有公开构造函数,由句柄的 OpenRead/OpenWrite 创建。GetPixelRow 每行返回 Width 个像素;GetPixelBytes 返回 PixelBytesPerRow 个字节,两者均排除行尾空隙。RGB24 的 row[x] 是 Rgb24 而不是某一个通道字节;Depth16 的 row[x] 是 ushort 原始深度值。

ReadOnlyView 与 WritableView 是两条独立链,不能通过转型升级读权限。WritableView 修改的是工具自己构建的输出或流程外可写存储,不允许改变绑定的尺寸、格式或步长。工具流输入统一为 Access=ReadOnly,不能因持有句柄就申请输入写入。公共表面仍可有 OpenWrite,输入对象以能力上限立即拒绝;不宣称格式特化已在编译期隐藏该方法。

只接受库已登记、布局明确的像素类型与格式组合。unmanaged 约束本身不能证明任意结构体可解释为某种图像;禁止用相同 sizeof 绕过格式验证,禁止默认把 Depth16 解释为灰度。类型化行访问使用原存储的行起点,支持负步长和行尾空隙,不要求把整个分配直接转换为一个连续 std::span<TPixel>。

// PixelImage 为工厂命名空间/类,不再是工具依赖的具体图像类。<vyntek/imaging/factory.hpp>
namespace vyntek::imaging {

struct PixelImage {
  static PixelImageHandle Create(ImageBuffer buffer, const ImageInfo& info);
  static PixelImageHandle Copy(
      std::span<const std::uint8_t> pixels, const ImageInfo& info,
      BufferAccess access = BufferAccess::ReadOnly,
      MemoryPool* pool = nullptr);
  static std::expected<PixelImageHandle, Status> Clone(
      const PixelImageHandle& image, MemoryPool& pool, CancelToken cancel = {});
  static Gray8Handle   RentGray8(const ImageInfo& info, MemoryPool* pool = nullptr);
  static Rgb24Handle   RentRgb24(const ImageInfo& info, MemoryPool* pool = nullptr);
  static Bgr24Handle   RentBgr24(const ImageInfo& info, MemoryPool* pool = nullptr);
  static Depth16Handle RentDepth16(const ImageInfo& info, MemoryPool* pool = nullptr);
};

}  // namespace vyntek::imaging

Create 根据 info.PixelFormat 返回实现对应语义接口的对象,校验格式和容量,成功时复制 buffer 生命周期引用,不消费调用方 handle。Rent 系列校验 Info 与工厂指定格式完全一致,按有效地址范围分配未初始化存储;首次写入完成前不能读取。无效范围、未知格式或超出托管租用容量限制时抛错,不偷偷修改 Info。具体实现类可以内部封装,不要求每个格式公开一个类。

Share/GetRegion 返回各自独立关闭的对象,不复制像素,并保持原 handle 的能力与内容稳定性:ReadWrite 的 Share 不固定内容;ReadOnly 的 Share/ROI 继续保留同一稳定版本。Clone 复制逻辑像素,始终返回已初始化、可写、格式相同的新图像,整理排列并保留 ColorEncoding、业务信息及深度解释。失败清理新分配;克隆不是格式转换。

ReadWrite 图像不是不可变快照。需要固定阶段结果时,工具在稳定读取上调用 ShareImage,取得同格式、Access=ReadOnly 的独立图像句柄。该方法复制现有读取引用,不复制字节、不消费原读取、也不重新排队;返回对象可以跨后续工具 Run、观察与显示消费者寿命存活(非任务图阶段调度)。实际对象继续实现相应语义接口,泛型入口保留像素类型。ReadOnly 图像 OpenRead 复制其已授予读取,不排在等待写者之后;其 Share/ROI 同样不得退化为可写存储。

可写根对象仍然存在时,对同一分配的写入会等待全部稳定发布引用退出。只读发布不是原图回滚或自动复制策略。Clone 在稳定读取上复用现有权限,不重复申请;调用方也不应持有可写根的临时读取再调用根对象 Clone,以免排队写者造成等待环。

期望版本用于输出构建/流程外 ReadWrite 图像的阶段竞争校验,不替代稳定发布。工具流内已交给下游的输入句柄已固定内容,通常无需再带期望版本。执行器检查发布契约但不为工具申请像素权限,生产者负责在输出交接前稳定发布。

ReadOnlyView::Share 复制当前已取得的读取权限与 Info,不排队申请新版本,关闭其中一个不影响其余对象。读取的 Share 和稳定图像的 Share 都延长禁止写入的范围,必须显式关闭;只有可写根图像的 Share 不保留读取。控件内部从稳定读取派生任务时使用已有权限,不重新 OpenRead 排到等待写者后面而自锁。

格式扩展边界

首版为单平面、逐行可寻址的 Gray8、RGB24、BGR24、Depth16。ImageInfo 与接口共同校验语义和布局;明确每像素字节数、类型大小、小端解释、行步长、ROI 范围和无效值规则。只修改 PixelFormat 枚举不能算完成一个新格式:还需工厂、类型桥接、复制/ROI、native 访问、序列化/解码适配及使用者能力声明。

图像模型允许某格式不被某个算法或显示后端支持,消费者明确拒绝,不把无法实现的成员做成静默 no-op。未来 Gray16/Float32Depth/BGRA/Bayer 等按真实语义增加接口和显式转换;平面 YUV、GPU-only 与设备 fence 需要新的平面或设备访问能力,不硬塞进现有 GetPixelRow。首版不承诺这些未来格式可以只加枚举就无破坏接入。

RGB/BGR 的字节顺序不等于色彩空间。Info 增加可选 ColorEncoding,至少区分 Unspecified、Srgb 和 LinearRgb;灰度与深度不借该字段冒充标定。显示适配对未知编码保留显式状态/诊断,不悄悄宣称完成色彩管理。核心保存内容,转换在明确的算法/解码/显示适配层进行。相机标定矩阵、置信度平面和复杂深度模型按实际需要扩展,不混入 BufferId/Generation。


本仓实现对拍(tip e46c042 · 按实)

对照 include/vyntek/imaging/**。禁止把 STUB 写成已验收。缺口 → 问题单。

规格概念(本文)本仓已有stub / 缺口边界
ImageInfo / PixelFormat / ColorEncoding已有 image_info.hppcaptured_at 已有(optional<system_clock::time_point>);ValidateCapacity / GetRegion 声明在
ImageContentVersion(BufferId + Generation)已有 version.hpp诊断行可读 generation;完整跟踪验收未齐
PixelImageHandle Share / OpenRead / OpenWrite已有 handle.hppNON-STABLE;H1–H10 验收未齐
类型化 Gray8Handle / Rgb24Handle / Bgr24Handle / Depth16Handle已有 PixelImageHandleT<>外形齐
ReadOnlyView / WritableView已有 access.hppGetSpan 公开面薄
PixelImage 工厂 / MemoryPool工厂在 factory.hpp;池在 memory_pool.hpp池为虚基类,默认 CanRent 乐观
便利伞头 <vyntek/imaging.hpp> / vyntek.h已有优先嵌套头;无稳定 ABI

Reed ALG 边界(头注释按实)

标记位置含义(按注释)
HDR-ALG-01image_info.hpp ValidateCapacity容量校验;细节可走 detail::ValidateCapacityOrThrow
HDR-ALG-02access.hpp GetPixelBytes / Pin真实 span/pin;Reed 可经 protected + friend 扩展
HDR-ALG-03/04WritableViewBasebuffer_id/access_id;未 Complete 的 close/dtor → AbortWriter(对 TC-MEM-10)
HDR-ALG-05handle.hpp 类型化句柄与本文类型化临时图像对齐
HDR-ALG-06/07handle / buffer / StatusOpenResult、VersionMismatch、三工厂与归还态

文档状态:www M2 工作副本(2026-10-21 Asia/Shanghai)。示意 API ≠ 已发布 ABI。对拍 tip e46c042。

On this page