使用 dart ffi 和 libpng 读取 png
Reading png using dart ffi and libpng
我正在尝试使用 libpng1.6
从文件加载 png,但执行失败并出现分段错误。
我加载库和 libpng
函数 png_image_begin_read_from_file
,如图所示:
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
这是重现问题的完整代码段。
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
class png_controlp extends ffi.Opaque {}
// Fields taken from "png.h"
class PngImage extends ffi.Struct {
@ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
@ffi.Array(64)
external ffi.Array<ffi.Char> message;
external ffi.Pointer<png_controlp> opaque;
}
// native type
typedef native_function_t = ffi.Int32 Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
// dart type
typedef dart_function_t = int Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
void main() {
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
final path = "my_image.png";
ffi.Pointer<PngImage> p_pngImage = calloc<PngImage>();
p_pngImage.ref.version = 1;
final res = png_image_begin_read_from_file(p_pngImage, path.toNativeUtf8());
}
===== CRASH =====
si_signo=Segmentation fault: 11(11), si_code=2, si_addr=0x11
version=2.17.0-266.7.beta (beta) (Mon Apr 25 14:54:53 2022 +0000) on "macos_arm64"
pid=42862, thread=20995, isolate_group=main(0x123810200), isolate=main(0x122034200)
isolate_instructions=10263d8c0, vm_instructions=10263d8c0
pc 0x00000001051b6604 fp 0x000000016e1be830 png_image_free+0x24
pc 0x00000001051b66c8 fp 0x000000016e1be850 png_image_error+0x38
看起来 Dart 结构的顺序错误 - 检查 C header:
2672 typedef struct
2673 {
2674 png_controlp opaque; /* Initialize to NULL, free with png_image_free */
2675 png_uint_32 version; /* Set to PNG_IMAGE_VERSION */
2676 png_uint_32 width; /* Image width in pixels (columns) */
2677 png_uint_32 height; /* Image height in pixels (rows) */
2678 png_uint_32 format; /* Image format as defined below */
2679 png_uint_32 flags; /* A bit mask containing informational flags */
2680 png_uint_32 colormap_entries;
2681 /* Number of entries in the color-map */
....
2704
2705 png_uint_32 warning_or_error;
2706
2707 char message[64];
2708 } png_image, *png_imagep;
所以,Dart 结构应该是:
class PngImage extends ffi.Struct {
external ffi.Pointer<png_controlp> opaque;
@ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
@ffi.Array(64)
external ffi.Array<ffi.Char> message;
}
另请注意 header 中的注释:
2976 * The png_image passed to the read APIs must have been initialized by setting
2977 * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
确保将 opaque
指针设置为 nullPtr
- 虽然这可能是不必要的,因为您正在使用 calloc
创建它 - 这将为您将其归零。 (还要记住,您可能需要对 read_from_file
方法分配的空闲内容进行另一个 C 调用,以及 free
您 calloc
分配的任何内容。)
我正在尝试使用 libpng1.6
从文件加载 png,但执行失败并出现分段错误。
我加载库和 libpng
函数 png_image_begin_read_from_file
,如图所示:
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
这是重现问题的完整代码段。
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
class png_controlp extends ffi.Opaque {}
// Fields taken from "png.h"
class PngImage extends ffi.Struct {
@ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
@ffi.Array(64)
external ffi.Array<ffi.Char> message;
external ffi.Pointer<png_controlp> opaque;
}
// native type
typedef native_function_t = ffi.Int32 Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
// dart type
typedef dart_function_t = int Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
void main() {
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
final path = "my_image.png";
ffi.Pointer<PngImage> p_pngImage = calloc<PngImage>();
p_pngImage.ref.version = 1;
final res = png_image_begin_read_from_file(p_pngImage, path.toNativeUtf8());
}
===== CRASH =====
si_signo=Segmentation fault: 11(11), si_code=2, si_addr=0x11
version=2.17.0-266.7.beta (beta) (Mon Apr 25 14:54:53 2022 +0000) on "macos_arm64"
pid=42862, thread=20995, isolate_group=main(0x123810200), isolate=main(0x122034200)
isolate_instructions=10263d8c0, vm_instructions=10263d8c0
pc 0x00000001051b6604 fp 0x000000016e1be830 png_image_free+0x24
pc 0x00000001051b66c8 fp 0x000000016e1be850 png_image_error+0x38
看起来 Dart 结构的顺序错误 - 检查 C header:
2672 typedef struct
2673 {
2674 png_controlp opaque; /* Initialize to NULL, free with png_image_free */
2675 png_uint_32 version; /* Set to PNG_IMAGE_VERSION */
2676 png_uint_32 width; /* Image width in pixels (columns) */
2677 png_uint_32 height; /* Image height in pixels (rows) */
2678 png_uint_32 format; /* Image format as defined below */
2679 png_uint_32 flags; /* A bit mask containing informational flags */
2680 png_uint_32 colormap_entries;
2681 /* Number of entries in the color-map */
....
2704
2705 png_uint_32 warning_or_error;
2706
2707 char message[64];
2708 } png_image, *png_imagep;
所以,Dart 结构应该是:
class PngImage extends ffi.Struct {
external ffi.Pointer<png_controlp> opaque;
@ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
@ffi.Array(64)
external ffi.Array<ffi.Char> message;
}
另请注意 header 中的注释:
2976 * The png_image passed to the read APIs must have been initialized by setting
2977 * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
确保将 opaque
指针设置为 nullPtr
- 虽然这可能是不必要的,因为您正在使用 calloc
创建它 - 这将为您将其归零。 (还要记住,您可能需要对 read_from_file
方法分配的空闲内容进行另一个 C 调用,以及 free
您 calloc
分配的任何内容。)