ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

libvips 基础类型体系全解:VipsArea 内存块、数组容器与 GValue 辅助函数实战指南

libvips 基础类型体系全解:VipsArea 内存块、数组容器与 GValue 辅助函数实战指南 图像处理【免费下载链接】libvipsA fast image processing library with low memory needs.项目地址https://gitcode.com/gh_mirrors/li/libvips点击查看免费下载libvips 的 API 参考将一组贯穿整个库的基础数据类型与辅助工具归入 Basic 一节见 doc/libvips-basic.md它们不是图像处理算子而是 libvips 全部操作、图像元数据与语言绑定所依赖的地基——包括引用计数的内存块VipsArea、由其派生的VipsBlob/VipsRefString/VipsArrayInt/VipsArrayDouble/VipsArrayImage/VipsSaveString等容器类型、基础别名VipsPel、若干回调函数类型以及一批用于在GValue与这些容器之间搬运数据的辅助函数。读完本文你将掌握这些类型的内存管理契约谁 ref、谁 unref、各自的适用场景字符串、二进制、数值数组、图像数组以及如何在 C 代码和语言绑定中安全地读写它们。一、从索引页到源码Basic 一节的完整构成doc/libvips-basic.md是 libvips API 文档中 Operator index By section Basic 的入口页它把该节内容划分为五类分类成员StructsArea、ArrayDouble、ArrayImage、ArrayInt、Blob、RefString、SaveStringAliasesPelCallbacksCallbackFn、SListMap2Fn、SListMap4Fn、SListFold2FnFunctionsArea的 copy/free_cb/unref/new/new_array/new_array_object/get_dataRefString的 new/getBlob的 new/copy/get/setArrayDouble、ArrayInt、ArrayImage的 new/newv/get/empty/append以及 20 个value_*GValue 辅助函数Function macrosDEPRECATED_FOR、DEPRECATED_MACRO_FOR、ARRAY_ADDR这些声明集中在两个头文件中libvips/include/vips/type.h各 GType 的定义与函数原型与 libvips/include/vips/basic.hVipsPel、回调类型、弃用宏实现则位于 libvips/iofuncs/type.c约 2000 行文件头注释明确写着 array type: unlike GArray, this has fixed length, tracks a GType for elements, and has a per-element free function。所有的类型注册统一由vips__meta_init_types()type.c在vips_init()时完成。二、地基引用计数的内存块 VipsAreaVipsArea是 Basic 一节中最核心的结构注释称其为 A ref-counted area of memory. Can hold arrays of things as welltype.h。它在裸指针之上增加了引用计数、可选长度、可选元素类型信息和一个可自定义的释放函数typedef struct _VipsArea { void *data; /* 数据指针 */ size_t length; /* 字节长度0 表示未知 */ int n; /* 若表示数组元素个数 length / sizeof(元素) */ int count; /* 引用计数 */ GMutex lock; /* 保护 count 的锁 */ VipsCallbackFn free_fn; /* 自定义释放函数如 ICC profile 需要特制的 free */ void *client; /* 客户端数据VipsArea 自身不使用 */ GType type; /* 若持有数组元素的 GType */ size_t sizeof_type; /* 若持有数组元素的 sizeof */ } VipsArea;2.1 生命周期new / copy / unrefvips_area_new(free_fn, data)创建一块引用计数为 1 的区域data的所有权随free_fn转移。实现中count初始化为 1、锁被初始化type.c因此文档注释特别提醒Initial count 1, soArea.unrefafter attaching somewhere即把 area 挂载到某个对象上后必须自己 unref 一次。vips_area_copy(area)在锁内把count 1并返回同一个指针是浅拷贝语义的引用计数增加type.c。vips_area_unref(area)count - 1减到 0 时先调用free_fn(data, area)释放数据再清理锁并释放 area 本身type.c。若开启了泄漏检查vips__leak每个 area 还会登记在全局链表vips_area_all上配合vips__type_leak()可报告存活数量、引用计数与字节数——这是 libvips 自检内存泄漏的机制之一。2.2 数组化new_array 与 new_array_objectvips_area_new_array(GType type, size_t sizeof_type, int n)分配n * sizeof_type字节并挂上vips_area_free_cb即g_free同时填充n、length、type、sizeof_type四个字段type.c。返回值transfer full用完必须 unref。vips_area_new_array_object(int n)持有GObject *数组的特殊版本。它额外多分配一个NULL结尾元素注释说明这是为vips_image_pipeline_array等函数准备的释放时通过vips_area_free_array_object对每个元素调用g_object_unreftype.c。VipsArrayImage就是建立在它之上。2.3 取数据vips_area_get_datavips_area_get_data(area, length, n, type, sizeof_type)一次性返回数据指针并可选择性地带回长度、元素个数、元素 GType 与元素大小全部参数均可为 NULLtype.c。返回值不增加引用transfer none调用方不得释放。三、七种容器类型选型与用法Basic 一节定义了七个 boxed 结构其中除VipsSaveString外其余六个都是把VipsArea作为首成员VipsRefString、VipsBlob、VipsArrayInt、VipsArrayDouble、VipsArrayImage的声明都是typedef struct _VipsXxx { VipsArea area; } VipsXxx;因此它们与VipsArea之间可安全互转VIPS_AREA(X)宏就是一次强转type.h。3.1 VipsRefString引用计数的不可变字符串用于在图像元数据中保存字符串type.c。特点vips_ref_string_new(str)内部用g_utf8_make_valid强制字符串为合法 UTF-8并把长度缓存到area-length注释明确Strings must be valid utf-8; use blob for binary data。vips_ref_string_get(refstr, length)返回内部 C 字符串指针transfer none。它注册了与G_TYPE_STRING、VIPS_TYPE_SAVE_STRING之间的双向 GValue 变换函数因此元数据里的字符串可以被自由地读到普通 GString 中。相比普通 GValue 字符串refstring 在图像之间复制时只复制引用计数指针开销小得多见vips_value_set_ref_string的注释。3.2 VipsBlob带长度的二进制块用于 ICC profile、EXIF 等二进制数据type.cvips_blob_new(free_fn, data, length)像Area.new一样接管data但额外追踪length若不想转移所有权传NULL的free_fn。vips_blob_copy(data, length)内部g_mallocmemcpy一份拷贝对难以写回调的语言绑定更友好Useful for bindings which struggle with callbacks。vips_blob_get(blob, length)取数据指针与长度。vips_blob_set(blob, free_fn, data, length)先释放旧数据再挂新数据用于先创建空 blob 后填充的场景。Blob 是可迁移的保存到 VIPS 文件时会被编码为 XML 内的 base64 字符串transform_blob_save_string/transform_save_string_blob用g_base64_encode/g_base64_decode实现复制时同样是复制引用计数指针。3.3 VipsArrayInt / VipsArrayDouble数值数组参数libvips 大量操作的参数是一个数组例如vips_linear的 a/b 向量。两个类型的 API 完全对称type.cvips_array_int_new(array, n)/vips_array_double_new(array, n)拷贝入数组transfer full。vips_array_int_newv(n, ...)/vips_array_double_newv(n, ...)变参版本从参数列表逐个取值填入。vips_array_int_get(array, n)/vips_array_double_get(array, n)取回指针与元素个数内部g_assert(area-type G_TYPE_INT/G_TYPE_DOUBLE)校验元素类型然后通过VIPS_ARRAY_ADDR(array, 0)返回首元素地址。它们注册了大量 GValue 变换与G_TYPE_STRING双向字符串用\t;,作分隔符、经vips_break_token分词解析、与VIPS_TYPE_SAVE_STRING双向、与G_TYPE_INT/G_TYPE_DOUBLE单项把标量扩成单元素数组、VIPS_TYPE_ARRAY_INT与VIPS_TYPE_ARRAY_DOUBLE互相转换。这也是为什么 CLI 与 Python 绑定里能用1 2 3这样的字符串直接给数组参数赋值。3.4 VipsArrayImage图像数组用于把多个图像一次性传给操作如拼接类算子是VipsArea 对象数组的组合type.c声明在 image.hvips_array_image_new(VipsImage **array, int n)/vips_array_image_newv(int n, ...)对每个元素执行g_object_ref数组释放时自动 unrefThe images will all be reffed by this function. They will be automatically unreffed for you by Area.unref同样追加NULL结尾元素。vips_array_image_new_from_string(string, access)按空白/换行分隔的文件名列表逐个vips_image_new_from_file加载任一失败则整体回滚unref 已建数组并返回 NULL。vips_array_image_empty()与vips_array_image_append(array, image)为不方便传对象数组的语言绑定提供空数组 逐次追加的替代路径。vips_array_image_get(array, n)取回VipsImage **与个数同样有g_assert(area-type VIPS_TYPE_IMAGE)校验。3.5 VipsSaveString写入文件头的字符串VipsSaveString是为把元数据字段保存到 VIPS 文件 XML 头而设计的新字符串类型type.c。它本身只是{ char *s; }的 boxed 类型copy 用g_strdupfree 用g_free关键在于注册了与G_TYPE_INT、G_TYPE_DOUBLE、G_TYPE_FLOAT之间的双向变换整数/浮点字段在保存到文件头时先转成字符串double/float 用g_ascii_dtostr保证与 locale 无关读回时再解析还原。这就是 VIPS 文件头能以文本形式持久化数值元数据的底层机制。四、基础别名与回调类型VipsPelpicture element像素元素被定义为unsigned char源码注释提醒Cast this to whatever the associatedVipsBandFormatsays to get the valuebasic.h。它遍布图像像素与VIPS_ARRAY_ADDR的指针运算中——例如VIPS_ARRAY_ADDR宏就是用(VipsPel *) data sizeof_type * i计算第 i 个元素的地址type.h。四个回调类型都定义在 basic.h类型签名用途VipsCallbackFnint (*)(void *a, void *b)通用回调VipsArea的free_fn、vips_area_free_cb均属此类VipsSListMap2Fnvoid *(*)(void *item, void *a, void *b)类似GFunc但返回值的链表映射VipsSListMap4Fnvoid *(*)(void *item, void *a, void *b, void *c, void *d)4 参数版本链表映射VipsSListFold2Fnvoid *(*)(void *item, void *a, void *b, void *c)链表折叠此外basic.h还定义了VipsPrecision枚举INTEGER/FLOAT/APPROXIMATE以及VIPS_API_VIPS_PUBLIC extern导出宏。五、GValue 辅助函数在绑定与元数据之间搬运数据value_*系列函数约 20 个是 Basic 一节中数量最大的一类作用是让这些容器类型可以放入 GLib 的GValue从而进入 libvips 的 GObject 属性系统、操作参数系统与图像元数据存储。它们两两成对约定如下Area 类vips_value_set_area(value, free_fn, data)建 area 并装箱内部vips_area_new→g_value_set_boxed→ 立即vips_area_unref移交引用type.cvips_value_get_area(value, length)取回指针与长度。字符串类vips_value_set_save_string/vips_value_get_save_string/vips_value_set_save_stringfprintf 格式化写入带G_GNUC_PRINTF(2, 3)检查处理SAVE_STRINGvips_value_set_ref_string/vips_value_get_ref_string处理REF_STRING。两个 set 函数都会校验 UTF-8非法时分别替换为占位符或经g_utf8_make_valid修正。Blob 类vips_value_set_blob(value, free_fn, data, length)自定义释放与vips_value_set_blob_free(value, data, length)直接用vips_area_free_cb即g_free绑定调用更省事对称于vips_value_get_blob(value, length)。数组类vips_value_set_array/vips_value_get_array是通用底座需显式给出n、GType、sizeof_type且allocates memory but does not initialise the contents: get the pointer and write instead其上是带类型的具体封装——array_int、array_double、array_image、array_object四对 set/get。其中vips_value_set_array_int/vips_value_set_array_double在数组指针非 NULL 时会用memcpy拷贝数据vips_value_set_array_image与vips_value_set_array_object则只建空槽元素需调用方逐个填VipsImage */GObject *。这些函数构成了语言绑定的关键通道例如 Python 里Vips.Image.linear(a, b)的a/b最终就是通过vips_value_set_array_double进入 GValue 的。六、函数宏弃用标记与带越界检查的数组寻址VIPS_DEPRECATED_FOR(f)与VIPS_DEPRECATED_MACRO_FOR(f)弃用声明宏basic.h。若编译前定义VIPS_DISABLE_DEPRECATION_WARNINGS必须在包含vips/vips.h之前定义两者退化为纯VIPS_API否则展开为 GLib 的G_DEPRECATED_FOR(f)/ 编译器#pragma GCC warning提示调用方用f替换被弃用符号。VIPS_ARRAY_ADDR(X, I)type.h按sizeof_type步长计算第I个元素地址。在VIPS_DEBUG下会先检查0 I n越界则向stderr打印含文件名、行号、越界值的诊断信息并返回 NULL——这正是vips_array_int_get/vips_array_double_get/vips_array_image_get内部取首元素地址所用的宏。七、实战基础类型在真实操作中的位置这些类型并非纸上谈兵它们在算子实现中被高频使用。仅举几例数值数组参数vips_linear在 libvips/arithmetic/linear.c 中用VIPS_ARRAY(linear, n, double)分配 a/b 系数数组并在 L453-L484 把操作参数声明为VIPS_TYPE_ARRAY_DOUBLE、用vips_array_double_new构造随后通过VIPS_AREA()宏访问——VipsArrayDouble是每波段一个系数这类向量参数的官方载体。像素值参数vips_insert的背景色与vips_flood的 ink 色都经VIPS_ARRAY_ADDR取出后交给底层处理见 libvips/conversion/insert.c、libvips/draw/draw_flood.c。图像数组参数vips_array_image_new_array_object生成的VipsArrayImage是拼接/合并类操作接收多张输入的标准途径NULL结尾元素专为vips_image_pipeline_array等内部管道函数预留。元数据存储VipsRefString与VipsBlob配合vips_value_set_ref_string/vips_value_set_blob构成图像元数据如 ICC profile、EXIF、描述字符串的存取通道字符串走 UTF-8 校验的 refstring二进制走带 base64 序列化的 blob。八、总结Basic 一节虽然不包含任何图像处理算法却是 libvips 中最底层的公共基础设施VipsArea以引用计数 自定义释放函数统一了内存所有权VipsBlob/VipsRefString/VipsArrayInt/VipsArrayDouble/VipsArrayImage/VipsSaveString在其上分别解决了二进制块、不可变字符串、数值数组、图像数组与文件头字符串的存储与传递value_*系列函数则把这一切接入 GLibGValue体系。理解它们的内存契约初始引用计数为 1、挂载后须 unref、transfer full/none 语义、NULL结尾元素约定是在 C 层开发 libvips 操作、编写语言绑定或调试元数据问题时不可或缺的基础。赞分享图像处理【免费下载链接】libvipsA fast image processing library with low memory needs.项目地址https://gitcode.com/gh_mirrors/li/libvips点击查看免费下载相关推荐MNN 的 Pymnn 基础模块 MNN子模块体系、核心数据类型与基础函数详解MNN 的 Pymnn 基础模块 MNN子模块体系、核心数据类型与基础函数详解 PymnnMNN 的 Python 接口层中 MNN 是最基础的顶层 M人工智能大模型推理引擎深度学习本地部署模型量化模型优化多模态计算机视觉嵌入式CUTLASS 基础类型指南数值类型、容器与函数对象Fundamental Types深度解析CUTLASS 基础类型指南数值类型、容器与函数对象Fundamental Types深度解析 本文以 media/docs/cpp/fundamenta算子库高性能计算Apache Spark PySpark SQL 内置函数全览pyspark.sql.functions 模块分类体系与实战指南Apache Spark PySpark SQL 内置函数全览pyspark.sql.functions 模块分类体系与实战指南 导读 pyspark.sql大数据数据分析批处理流处理机器学习图计算上一篇Mobile ALOHA架构解密低成本全身遥操作机器人的系统设计哲学下一篇智能角色引擎SillyTavern如何重新定义AI对话的深度与广度创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表