From 87688f828fc744b8786201c9fca0d506a013c73f Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 27 Jun 2022 13:13:37 +0200 Subject: [PATCH 1/6] Fix Windows and 32-bit support - Move FFI functions to a separate class. - Split the GLib and GObject symbols into a separate string. - Ensure `g_*` functions are called via `libglib-2.0-0.dll` or `libgobject-2.0-0.dll` on Windows. - Fix 32-bit support, use `PHP_INT_SIZE` to determine `GType`. - Remove debug code in `GValue::toEnum`. - Prefer to call `cast` on the static `\FFI` class. - Remove `Config::error()` in favor of `throw new Exception()`, move error buffer logic to `Vips\Exception`. - Remove `GsfOutputCsvQuotingMode` class. - Remove `Config::printAll`, already exists as `VipsObject::printAll`. - Move `Config::filenameGetFilename` and `Config::filenameGetOptions` to Utils class. --- README.md | 1 - composer.json | 9 +- examples/generate_phpdoc.py | 2 +- phpdoc.xml | 6 +- src/Config.php | 689 +---------------------------- src/Exception.php | 11 + src/FFI.php | 760 ++++++++++++++++++++++++++++++++ src/GObject.php | 6 +- src/GValue.php | 178 ++++---- src/GsfOutputCsvQuotingMode.php | 54 --- src/Image.php | 93 ++-- src/ImageAutodoc.php | 8 +- src/Interpolate.php | 12 +- src/Introspect.php | 18 +- src/Utils.php | 20 +- src/VipsObject.php | 32 +- src/VipsOperation.php | 30 +- 17 files changed, 1001 insertions(+), 928 deletions(-) create mode 100644 src/FFI.php delete mode 100644 src/GsfOutputCsvQuotingMode.php diff --git a/README.md b/README.md index 6ada06b1..93ecce90 100644 --- a/README.md +++ b/README.md @@ -174,4 +174,3 @@ $ vendor/bin/phpdoc $ cd src $ ../examples/generate_phpdoc.py ``` - diff --git a/composer.json b/composer.json index 2c612515..f0078719 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php-parallel-lint/php-parallel-lint": "^1.3", "phpdocumentor/shim": "^3.3", "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.6" + "squizlabs/php_codesniffer": "^3.7" }, "autoload": { "psr-4": { @@ -50,5 +50,10 @@ ] }, "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "config": { + "allow-plugins": { + "phpdocumentor/shim": true + } + } } diff --git a/examples/generate_phpdoc.py b/examples/generate_phpdoc.py index 7ad9eda6..9676c8e4 100755 --- a/examples/generate_phpdoc.py +++ b/examples/generate_phpdoc.py @@ -263,7 +263,7 @@ def add_nickname(gtype, a, b): f.write(' * @see {0} for possible values\n'.format(remove_prefix(type_name(gtype)))) f.write(' */\n') - f.write('abstract class ImageAutodoc\n') + f.write('abstract class ImageAutodoc extends VipsObject\n') f.write('{\n') f.write('}\n') diff --git a/phpdoc.xml b/phpdoc.xml index a37402d2..131e9646 100644 --- a/phpdoc.xml +++ b/phpdoc.xml @@ -1,16 +1,14 @@ - + php-vips + php-vips docs - docs - src - diff --git a/src/Config.php b/src/Config.php index b5230384..59dd4233 100644 --- a/src/Config.php +++ b/src/Config.php @@ -60,32 +60,6 @@ class Config */ private static $logger; - /** - * The FFI handle we use for the libvips binary. - * - * @internal - */ - private static \FFI $ffi; - private static $ffi_inited = false; - - /** - * The library version number we detect. - * - * @internal - */ - private static int $library_major; - private static int $library_minor; - private static int $library_micro; - - /** - * Look up these once. - * - * @internal - */ - private static array $ctypes; - private static array $gtypes; - private static array $ftypes; - /** * Sets a logger. This can be handy for debugging. For example: * @@ -122,7 +96,7 @@ public static function getLogger(): ?LoggerInterface */ public static function cacheSetMax(int $value): void { - Config::ffi()->vips_cache_set_max($value); + FFI::vips()->vips_cache_set_max($value); } /** @@ -136,7 +110,7 @@ public static function cacheSetMax(int $value): void */ public static function cacheSetMaxMem(int $value): void { - Config::ffi()->vips_cache_set_max_mem($value); + FFI::vips()->vips_cache_set_max_mem($value); } /** @@ -149,7 +123,7 @@ public static function cacheSetMaxMem(int $value): void */ public static function cacheSetMaxFiles(int $value): void { - Config::ffi()->vips_cache_set_max_files($value); + FFI::vips()->vips_cache_set_max_files($value); } /** @@ -163,7 +137,7 @@ public static function cacheSetMaxFiles(int $value): void */ public static function concurrencySet(int $value): void { - Config::ffi()->vips_concurrency_set($value); + FFI::vips()->vips_concurrency_set($value); } /** @@ -174,661 +148,12 @@ public static function concurrencySet(int $value): void */ public static function version(): string { - Config::ffi(); - - return self::$library_major . "." . - self::$library_minor . ".". - self::$library_micro; - } - - /** - * Handy for debugging. - */ - public static function printAll() - { - Config::ffi()->vips_object_print_all(); - } - - public static function ffi() - { - if (!self::$ffi_inited) { - self::init(); - self::$ffi_inited = true; - } - - return self::$ffi; - } - - public static function ctypes(string $name) - { - Config::ffi(); - - return self::$ctypes[$name]; - } - - public static function gtypes(string $name) - { - Config::ffi(); - - return self::$gtypes[$name]; + return FFI::version(); } - public static function ftypes(string $name) + public static function atLeast(int $need_major, int $need_minor): bool { - Config::ffi(); - - return self::$ftypes[$name]; - } - - /** - * Throw a vips error as an exception. - * - * @throws Exception - * - * @return void - * - * @internal - */ - public static function error(string $message = "") - { - if ($message == "") { - $message = Config::ffi()->vips_error_buffer(); - Config::ffi()->vips_error_clear(); - } - $exception = new Exception($message); - Utils::errorLog($message, $exception); - throw $exception; - } - - /** - * Shut down libvips. Call this just before process exit. - * - * @throws Exception - * - * @return void - * - * @internal - */ - public static function shutDown() - { - Config::ffi()->vips_shutdown(); - } - - public static function filenameGetFilename($name) - { - $pointer = Config::ffi()->vips_filename_get_filename($name); - $filename = \FFI::string($pointer); - Config::ffi()->g_free($pointer); - - return $filename; - } - - public static function filenameGetOptions($name) - { - $pointer = Config::ffi()->vips_filename_get_options($name); - $options = \FFI::string($pointer); - Config::ffi()->g_free($pointer); - - return $options; - } - - public static function atLeast($need_major, $need_minor) - { - return $need_major < self::$library_major || - ($need_major == self::$library_major && - $need_minor <= self::$library_minor); - } - - private static function libraryName($name, $abi) - { - switch (PHP_OS_FAMILY) { - case "Windows": - return "$name-$abi.dll"; - - case "OSX": - case "Darwin": - return "$name.$abi.dylib"; - - default: - // most *nix - return "$name.so.$abi"; - } - } - - private static function init() - { - $library = self::libraryName("libvips", 42); - - Utils::debugLog("init", ["libray" => $library]); - - /* FIXME ... maybe display a helpful message on failure? This will - * probably be the main point of failure. - */ - $ffi = \FFI::cdef(<<vips_init(""); - if ($result != 0) { - $msg = $ffi->vips_error_buffer(); - throw new Vips\Exception("libvips error: $msg"); - } - Utils::debugLog("init", ["vips_init" => $result]); - - # get the library version number, then we can build the API - self::$library_major = $ffi->vips_version(0); - self::$library_minor = $ffi->vips_version(1); - self::$library_micro = $ffi->vips_version(2); - Utils::debugLog("init", [ - "libvips version" => [ - self::$library_major, - self::$library_minor, - self::$library_micro - ] - ]); - - if (!self::atLeast(8, 7)) { - throw new Vips\Exception("your libvips is too old -- " . - "8.7 or later required"); - } - - if (PHP_INT_SIZE != 8) { - # we could maybe fix this if it's important ... it's mostly - # necessary since GType is the size of a pointer, and there's no - # easy way to discover if php is running on a 32 or 64-bit - # systems (as far as I can see) - throw new Vips\Exception("your php only supports 32-bit ints -- " . - "64 bit ints required"); - } - - # the whole libvips API, mostly adapted from pyvips - $header = <<vips_blend_mode_get_type(); - self::$ffi->vips_interpretation_get_type(); - self::$ffi->vips_operation_flags_get_type(); - self::$ffi->vips_band_format_get_type(); - self::$ffi->vips_token_get_type(); - self::$ffi->vips_saveable_get_type(); - self::$ffi->vips_image_type_get_type(); - - // look these up in advance - self::$ctypes = [ - "GObject" => self::$ffi->type("GObject*"), - "VipsObject" => self::$ffi->type("VipsObject*"), - "VipsOperation" => self::$ffi->type("VipsOperation*"), - "VipsImage" => self::$ffi->type("VipsImage*"), - "VipsInterpolate" => self::$ffi->type("VipsInterpolate*"), - ]; - - self::$gtypes = [ - "gboolean" => self::$ffi->g_type_from_name("gboolean"), - "gint" => self::$ffi->g_type_from_name("gint"), - "gint64" => self::$ffi->g_type_from_name("gint64"), - "guint64" => self::$ffi->g_type_from_name("guint64"), - "gdouble" => self::$ffi->g_type_from_name("gdouble"), - "gchararray" => self::$ffi->g_type_from_name("gchararray"), - "VipsRefString" => self::$ffi->g_type_from_name("VipsRefString"), - - "GEnum" => self::$ffi->g_type_from_name("GEnum"), - "GFlags" => self::$ffi->g_type_from_name("GFlags"), - "VipsBandFormat" => self::$ffi->g_type_from_name("VipsBandFormat"), - "VipsBlendMode" => self::$ffi->g_type_from_name("VipsBlendMode"), - "VipsArrayInt" => self::$ffi->g_type_from_name("VipsArrayInt"), - "VipsArrayDouble" => - self::$ffi->g_type_from_name("VipsArrayDouble"), - "VipsArrayImage" => self::$ffi->g_type_from_name("VipsArrayImage"), - "VipsBlob" => self::$ffi->g_type_from_name("VipsBlob"), - - "GObject" => self::$ffi->g_type_from_name("GObject"), - "VipsImage" => self::$ffi->g_type_from_name("VipsImage"), - ]; - - // map vips format names to c type names - self::$ftypes = [ - "char" => "char", - "uchar" => "unsigned char", - "short" => "short", - "ushort" => "unsigned short", - "int" => "int", - "uint" => "unsigned int", - "float" => "float", - "double" => "double", - "complex" => "float", - "dpcomplex" => "double", - ]; - - Utils::debugLog("init", ["done"]); + return FFI::atLeast($need_major, $need_minor); } } diff --git a/src/Exception.php b/src/Exception.php index d4c46722..8a08f857 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -51,6 +51,17 @@ */ class Exception extends \Exception { + public function __construct($message = "", $code = 0, \Throwable $previous = null) + { + if ($message == "") { + $message = "libvips error: " . FFI::vips()->vips_error_buffer(); + FFI::vips()->vips_error_clear(); + } + + // Utils::errorLog($message, self); + + parent::__construct($message, $code, $previous); + } } /* diff --git a/src/FFI.php b/src/FFI.php new file mode 100644 index 00000000..053125c9 --- /dev/null +++ b/src/FFI.php @@ -0,0 +1,760 @@ + + * @copyright 2016 John Cupitt + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/jcupitt/php-vips + */ + +namespace Jcupitt\Vips; + +/** + * This class contains the libvips FFI methods. + * + * @category Images + * @package Jcupitt\Vips + * @author John Cupitt + * @copyright 2016 John Cupitt + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/jcupitt/php-vips + */ +class FFI +{ + /** + * The FFI handle we use for the glib binary. + * + * @internal + */ + private static \FFI $glib; + + + /** + * The FFI handle we use for the gobject binary. + * + * @internal + */ + private static \FFI $gobject; + + /** + * The FFI handle we use for the libvips binary. + * + * @internal + */ + private static \FFI $vips; + + /** + * Are the above FFI handles initialized? + * + * @internal + */ + private static $ffi_inited = false; + + /** + * Look up these once. + * + * @internal + */ + private static array $ctypes; + private static array $gtypes; + private static array $ftypes; + + /** + * The library version number we detect. + * + * @internal + */ + private static int $library_major; + private static int $library_minor; + private static int $library_micro; + + public static function glib() + { + self::init(); + + return self::$glib; + } + + public static function gobject() + { + self::init(); + + return self::$gobject; + } + + public static function vips() + { + self::init(); + + return self::$vips; + } + + + public static function ctypes(string $name) + { + self::init(); + + return self::$ctypes[$name]; + } + + public static function gtypes(string $name) + { + self::init(); + + return self::$gtypes[$name]; + } + + public static function ftypes(string $name) + { + self::init(); + + return self::$ftypes[$name]; + } + + /** + * Gets the libvips version number as a string of the form + * MAJOR.MINOR.MICRO, for example "8.6.1". + * + * @return string + */ + public static function version(): string + { + self::init(); + + return self::$library_major . "." . + self::$library_minor . "." . + self::$library_micro; + } + + public static function atLeast(int $need_major, int $need_minor): bool + { + return $need_major < self::$library_major || + ($need_major == self::$library_major && + $need_minor <= self::$library_minor); + } + + /** + * Shut down libvips. Call this just before process exit. + * + * @throws Exception + * + * @internal + */ + public static function shutDown() + { + self::vips()->vips_shutdown(); + } + + private static function libraryName(string $name, $abi): string + { + switch (PHP_OS_FAMILY) { + case "Windows": + return "$name-$abi.dll"; + + case "OSX": + case "Darwin": + return "$name.$abi.dylib"; + + default: + // most *nix + return "$name.so.$abi"; + } + } + + private static function init() + { + // Already initialized. + if (self::$ffi_inited) { + return; + } + + $vips_libname = self::libraryName("libvips", 42); + if (PHP_OS_FAMILY === "Windows") { + $glib_libname = self::libraryName("libglib", "2.0-0"); + $gobject_libname = self::libraryName("libgobject", "2.0-0"); + } else { + $glib_libname = $vips_libname; + $gobject_libname = $vips_libname; + } + + Utils::debugLog("init", ["library" => $vips_libname]); + + /* FIXME ... maybe display a helpful message on failure? This will + * probably be the main point of failure. + */ + $vips = \FFI::cdef(<<vips_init(""); + if ($result != 0) { + throw new Vips\Exception(); + } + Utils::debugLog("init", ["vips_init" => $result]); + + # get the library version number, then we can build the API + self::$library_major = $vips->vips_version(0); + self::$library_minor = $vips->vips_version(1); + self::$library_micro = $vips->vips_version(2); + Utils::debugLog("init", [ + "libvips version" => [ + self::$library_major, + self::$library_minor, + self::$library_micro + ] + ]); + + if (!self::atLeast(8, 7)) { + throw new Vips\Exception("your libvips is too old -- " . + "8.7 or later required"); + } + + $is_64bits = PHP_INT_SIZE === 8; + + // GType is the size of a pointer + $gtype = $is_64bits ? "guint64" : "guint32"; + + // Typedefs shared across the libvips, GLib and GObject declarations + $typedefs = <<vips_blend_mode_get_type(); + self::$vips->vips_interpretation_get_type(); + self::$vips->vips_operation_flags_get_type(); + self::$vips->vips_band_format_get_type(); + self::$vips->vips_token_get_type(); + self::$vips->vips_saveable_get_type(); + self::$vips->vips_image_type_get_type(); + + // look these up in advance + self::$ctypes = [ + "GObject" => self::$gobject->type("GObject*"), + "GParamSpec" => self::$gobject->type("GParamSpec*"), + "VipsObject" => self::$vips->type("VipsObject*"), + "VipsOperation" => self::$vips->type("VipsOperation*"), + "VipsImage" => self::$vips->type("VipsImage*"), + "VipsInterpolate" => self::$vips->type("VipsInterpolate*"), + ]; + + self::$gtypes = [ + "gboolean" => self::$gobject->g_type_from_name("gboolean"), + "gint" => self::$gobject->g_type_from_name("gint"), + "gint64" => self::$gobject->g_type_from_name("gint64"), + "guint64" => self::$gobject->g_type_from_name("guint64"), + "gdouble" => self::$gobject->g_type_from_name("gdouble"), + "gchararray" => self::$gobject->g_type_from_name("gchararray"), + "VipsRefString" => self::$gobject->g_type_from_name("VipsRefString"), + + "GEnum" => self::$gobject->g_type_from_name("GEnum"), + "GFlags" => self::$gobject->g_type_from_name("GFlags"), + "VipsBandFormat" => self::$gobject->g_type_from_name("VipsBandFormat"), + "VipsBlendMode" => self::$gobject->g_type_from_name("VipsBlendMode"), + "VipsArrayInt" => self::$gobject->g_type_from_name("VipsArrayInt"), + "VipsArrayDouble" => + self::$gobject->g_type_from_name("VipsArrayDouble"), + "VipsArrayImage" => self::$gobject->g_type_from_name("VipsArrayImage"), + "VipsBlob" => self::$gobject->g_type_from_name("VipsBlob"), + + "GObject" => self::$gobject->g_type_from_name("GObject"), + "VipsImage" => self::$gobject->g_type_from_name("VipsImage"), + ]; + + // map vips format names to c type names + self::$ftypes = [ + "char" => "char", + "uchar" => "unsigned char", + "short" => "short", + "ushort" => "unsigned short", + "int" => "int", + "uint" => "unsigned int", + "float" => "float", + "double" => "double", + "complex" => "float", + "dpcomplex" => "double", + ]; + + Utils::debugLog("init", ["done"]); + self::$ffi_inited = true; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 + */ diff --git a/src/GObject.php b/src/GObject.php index 74c35ef6..3246e5c0 100644 --- a/src/GObject.php +++ b/src/GObject.php @@ -71,7 +71,7 @@ abstract class GObject */ public function __construct($pointer) { - $this->pointer = \FFI::cast(Config::ctypes("GObject"), $pointer); + $this->pointer = \FFI::cast(FFI::ctypes("GObject"), $pointer); } public function __destruct() @@ -86,12 +86,12 @@ public function __clone() public function ref() { - Config::ffi()->g_object_ref($this->pointer); + FFI::gobject()->g_object_ref($this->pointer); } public function unref() { - Config::ffi()->g_object_unref($this->pointer); + FFI::gobject()->g_object_unref($this->pointer); } // TODO signal marshalling to go in diff --git a/src/GValue.php b/src/GValue.php index c0ce60d6..a3b3778c 100644 --- a/src/GValue.php +++ b/src/GValue.php @@ -46,24 +46,24 @@ class GValue public function __construct() { # allocate a gvalue on the heap, and make it persistent between requests - $this->struct = Config::ffi()->new("GValue", true, true); + $this->struct = FFI::gobject()->new("GValue", true, true); $this->pointer = \FFI::addr($this->struct); # GValue needs to be inited to all zero \FFI::memset($this->pointer, 0, \FFI::sizeof($this->struct)); } - /* Turn a string into an enum value, if possible + /** + * Turn a string into an enum value, if possible + * @throws Exception */ - public static function toEnum($gtype, $value) + public static function toEnum(int $gtype, $value): int { if (is_string($value)) { - $enum_value = Config::ffi()-> + $enum_value = FFI::vips()-> vips_enum_from_nick("php-vips", $gtype, $value); if ($enum_value < 0) { - echo "gtype = " . $gtype . "\n"; - echo "value = " . $value . "\n"; - Config::error(); + throw new Exception(); } } else { $enum_value = $value; @@ -72,11 +72,15 @@ public static function toEnum($gtype, $value) return $enum_value; } - public static function fromEnum($gtype, $value) + /** + * Turn an enum into a string, if possible + * @throws Exception + */ + public static function fromEnum(int $gtype, int $value) { - $result = Config::ffi()->vips_enum_nick($gtype, $value); + $result = FFI::vips()->vips_enum_nick($gtype, $value); if ($result === null) { - Config::error("value not in enum"); + throw new Exception("value not in enum"); } return $result; @@ -84,12 +88,12 @@ public static function fromEnum($gtype, $value) public function __destruct() { - Config::ffi()->g_value_unset($this->pointer); + FFI::gobject()->g_value_unset($this->pointer); } public function setType(int $gtype) { - Config::ffi()->g_value_init($this->pointer, $gtype); + FFI::gobject()->g_value_init($this->pointer, $gtype); } public function getType(): int @@ -97,41 +101,48 @@ public function getType(): int return $this->pointer->g_type; } - public function set($value) + /** + * Set a GValue. + * + * @param mixed $value Value to be set. + * + * @throws Exception + */ + public function set($value): void { $gtype = $this->getType(); switch ($gtype) { - case Config::gtypes("gboolean"): - Config::ffi()->g_value_set_boolean($this->pointer, $value); + case FFI::gtypes("gboolean"): + FFI::gobject()->g_value_set_boolean($this->pointer, $value); break; - case Config::gtypes("gint"): - Config::ffi()->g_value_set_int($this->pointer, $value); + case FFI::gtypes("gint"): + FFI::gobject()->g_value_set_int($this->pointer, $value); break; - case Config::gtypes("gint64"): - Config::ffi()->g_value_set_int64($this->pointer, $value); + case FFI::gtypes("gint64"): + FFI::gobject()->g_value_set_int64($this->pointer, $value); break; - case Config::gtypes("guint64"): - Config::ffi()->g_value_set_uint64($this->pointer, $value); + case FFI::gtypes("guint64"): + FFI::gobject()->g_value_set_uint64($this->pointer, $value); break; - case Config::gtypes("gdouble"): - Config::ffi()->g_value_set_double($this->pointer, $value); + case FFI::gtypes("gdouble"): + FFI::gobject()->g_value_set_double($this->pointer, $value); break; - case Config::gtypes("gchararray"): - Config::ffi()->g_value_set_string($this->pointer, $value); + case FFI::gtypes("gchararray"): + FFI::gobject()->g_value_set_string($this->pointer, $value); break; - case Config::gtypes("VipsRefString"): - Config::ffi()-> + case FFI::gtypes("VipsRefString"): + FFI::vips()-> vips_value_set_ref_string($this->pointer, $value); break; - case Config::gtypes("VipsArrayInt"): + case FFI::gtypes("VipsArrayInt"): if (!is_array($value)) { $value = [$value]; } @@ -141,11 +152,11 @@ public function set($value) for ($i = 0; $i < $n; $i++) { $array[$i] = $value[$i]; } - Config::ffi()-> + FFI::vips()-> vips_value_set_array_int($this->pointer, $array, $n); break; - case Config::gtypes("VipsArrayDouble"): + case FFI::gtypes("VipsArrayDouble"): if (!is_array($value)) { $value = [$value]; } @@ -155,17 +166,17 @@ public function set($value) for ($i = 0; $i < $n; $i++) { $array[$i] = $value[$i]; } - Config::ffi()-> + FFI::vips()-> vips_value_set_array_double($this->pointer, $array, $n); break; - case Config::gtypes("VipsArrayImage"): + case FFI::gtypes("VipsArrayImage"): if (!is_array($value)) { $value = [$value]; } $n = count($value); - Config::ffi()->vips_value_set_array_image($this->pointer, $n); - $array = Config::ffi()-> + FFI::vips()->vips_value_set_array_image($this->pointer, $n); + $array = FFI::vips()-> vips_value_get_array_image($this->pointer, null); for ($i = 0; $i < $n; $i++) { $image = $value[$i]; @@ -174,7 +185,7 @@ public function set($value) } break; - case Config::gtypes("VipsBlob"): + case FFI::gtypes("VipsBlob"): # we need to set the blob to a copy of the data that vips_lib # can own and free $n = strlen($value); @@ -183,90 +194,96 @@ public function set($value) for ($i = 0; $i < $n; $i++) { $memory[$i] = $value[$i]; } - Config::ffi()-> + FFI::vips()-> vips_value_set_blob_free($this->pointer, $memory, $n); break; default: - $fundamental = Config::ffi()->g_type_fundamental($gtype); + $fundamental = FFI::gobject()->g_type_fundamental($gtype); switch ($fundamental) { - case Config::gtypes("GObject"): - Config::ffi()-> + case FFI::gtypes("GObject"): + FFI::gobject()-> g_value_set_object($this->pointer, $value->pointer); break; - case Config::gtypes("GEnum"): - Config::ffi()->g_value_set_enum( + case FFI::gtypes("GEnum"): + FFI::gobject()->g_value_set_enum( $this->pointer, self::toEnum($gtype, $value) ); break; - case Config::gtypes("GFlags"): + case FFI::gtypes("GFlags"): /* Just set as int. */ - Config::ffi()-> + FFI::gobject()-> g_value_set_flags($this->pointer, $value); break; default: - $typeName = Config::ffi()->g_type_name($gtype); + $typeName = FFI::gobject()->g_type_name($gtype); throw new \BadMethodCallException( "gtype $typeName ($gtype) not implemented" ); - break; } } } + /** + * Get the contents of a GValue. + * + * @return mixed The contents of this GValue. + * + * @throws Exception + */ public function get() { $gtype = $this->getType(); $result = null; switch ($gtype) { - case Config::gtypes("gboolean"): - $result = Config::ffi()->g_value_get_boolean($this->pointer); + case FFI::gtypes("gboolean"): + $result = FFI::gobject()->g_value_get_boolean($this->pointer); break; - case Config::gtypes("gint"): - $result = Config::ffi()->g_value_get_int($this->pointer); + case FFI::gtypes("gint"): + $result = FFI::gobject()->g_value_get_int($this->pointer); break; - case Config::gtypes("gint64"): - $result = Config::ffi()->g_value_get_int64($this->pointer); + case FFI::gtypes("gint64"): + $result = FFI::gobject()->g_value_get_int64($this->pointer); break; - case Config::gtypes("guint64"): - $result = Config::ffi()->g_value_get_uint64($this->pointer); + case FFI::gtypes("guint64"): + $result = FFI::gobject()->g_value_get_uint64($this->pointer); break; - case Config::gtypes("gdouble"): - $result = Config::ffi()->g_value_get_double($this->pointer); + case FFI::gtypes("gdouble"): + $result = FFI::gobject()->g_value_get_double($this->pointer); break; - case Config::gtypes("gchararray"): - $result = Config::ffi()->g_value_get_string($this->pointer); + case FFI::gtypes("gchararray"): + $result = FFI::gobject()->g_value_get_string($this->pointer); break; - case Config::gtypes("VipsRefString"): - $p_size = Config::ffi()->new("size_t[1]"); - $result = Config::ffi()-> + case FFI::gtypes("VipsRefString"): + $p_size = FFI::vips()->new("size_t[1]"); + $result = FFI::vips()-> vips_value_get_ref_string($this->pointer, $p_size); # $p_size[0] will be the string length, but assume it's null # terminated break; - case Config::gtypes("VipsImage"): - $pointer = Config::ffi()->g_value_get_object($this->pointer); + case FFI::gtypes("VipsImage"): + $pointer = FFI::gobject()->g_value_get_object($this->pointer); $result = new Image($pointer); // get_object does not increment the ref count $result->ref(); break; - case Config::gtypes("VipsArrayInt"): - $p_len = Config::ffi()->new("int[1]"); - $pointer = Config::ffi()-> + case FFI::gtypes("VipsArrayInt"): + $p_len = FFI::vips()->new("int[1]"); + $pointer = FFI::vips()-> vips_value_get_array_int($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -274,9 +291,9 @@ public function get() } break; - case Config::gtypes("VipsArrayDouble"): - $p_len = Config::ffi()->new("int[1]"); - $pointer = Config::ffi()-> + case FFI::gtypes("VipsArrayDouble"): + $p_len = FFI::vips()->new("int[1]"); + $pointer = FFI::vips()-> vips_value_get_array_double($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -284,9 +301,9 @@ public function get() } break; - case Config::gtypes("VipsArrayImage"): - $p_len = Config::ffi()->new("int[1]"); - $pointer = Config::ffi()-> + case FFI::gtypes("VipsArrayImage"): + $p_len = FFI::vips()->new("int[1]"); + $pointer = FFI::vips()-> vips_value_get_array_image($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -296,35 +313,34 @@ public function get() } break; - case Config::gtypes("VipsBlob"): - $p_len = Config::ffi()->new("size_t[1]"); - $pointer = Config::ffi()-> + case FFI::gtypes("VipsBlob"): + $p_len = FFI::vips()->new("size_t[1]"); + $pointer = FFI::vips()-> vips_value_get_blob($this->pointer, $p_len); $result = \FFI::string($pointer, $p_len[0]); break; default: - $fundamental = Config::ffi()->g_type_fundamental($gtype); + $fundamental = FFI::gobject()->g_type_fundamental($gtype); switch ($fundamental) { - case Config::gtypes("GEnum"): - $result = Config::ffi()-> + case FFI::gtypes("GEnum"): + $result = FFI::gobject()-> g_value_get_enum($this->pointer); $result = self::fromEnum($gtype, $result); break; - case Config::gtypes("GFlags"): + case FFI::gtypes("GFlags"): /* Just get as int. */ - $result = Config::ffi()-> + $result = FFI::gobject()-> g_value_get_flags($this->pointer); break; default: - $typeName = Config::ffi()->g_type_name($gtype); + $typeName = FFI::gobject()->g_type_name($gtype); throw new \BadMethodCallException( "gtype $typeName ($gtype) not implemented" ); - break; } } diff --git a/src/GsfOutputCsvQuotingMode.php b/src/GsfOutputCsvQuotingMode.php deleted file mode 100644 index a8a08f08..00000000 --- a/src/GsfOutputCsvQuotingMode.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @copyright 2016 John Cupitt - * @license https://opensource.org/licenses/MIT MIT - * @link https://github.com/jcupitt/php-vips - */ - -namespace Jcupitt\Vips; - -/** - * The GsfOutputCsvQuotingMode enum. - * @category Images - * @package Jcupitt\Vips - * @author John Cupitt - * @copyright 2016 John Cupitt - * @license https://opensource.org/licenses/MIT MIT - * @link https://github.com/jcupitt/php-vips - */ -abstract class GsfOutputCsvQuotingMode -{ - const NEVER = 'never'; - const AUTO = 'auto'; -} diff --git a/src/Image.php b/src/Image.php index 5a77d99b..1151bd7f 100644 --- a/src/Image.php +++ b/src/Image.php @@ -494,8 +494,7 @@ class Image extends ImageAutodoc implements \ArrayAccess */ public function __construct($pointer) { - $this->pointer = Config::ffi()-> - cast(Config::ctypes("VipsImage"), $pointer); + $this->pointer = \FFI::cast(FFI::ctypes("VipsImage"), $pointer); parent::__construct($pointer); } @@ -690,7 +689,7 @@ private function callEnum( */ public static function findLoad(string $filename): ?string { - $result = Config::ffi()->vips_foreign_find_load($filename); + $result = FFI::vips()->vips_foreign_find_load($filename); return $result; } @@ -709,12 +708,12 @@ public static function newFromFile( string $name, array $options = [] ): Image { - $filename = Config::filenameGetFilename($name); - $string_options = Config::filenameGetOptions($name); + $filename = Utils::filenameGetFilename($name); + $string_options = Utils::filenameGetOptions($name); $loader = self::findLoad($filename); if ($loader == null) { - Config::error(); + throw new Exception(); } if (strlen($string_options) != 0) { @@ -739,7 +738,7 @@ public static function newFromFile( */ public static function findLoadBuffer(string $buffer): ?string { - $result = Config::ffi()-> + $result = FFI::vips()-> vips_foreign_find_load_buffer($buffer, strlen($buffer)); return $result; @@ -764,7 +763,7 @@ public static function newFromBuffer( ): Image { $loader = self::findLoadBuffer($buffer); if ($loader == null) { - Config::error(); + throw new Exception(); } if (strlen($string_options) != 0) { @@ -814,15 +813,15 @@ public static function newFromArray( } } - $pointer = Config::ffi()-> + $pointer = FFI::vips()-> vips_image_new_matrix_from_array($width, $height, $a, $n); if ($pointer == null) { - Config::error(); + throw new Exception(); } $result = new Image($pointer); - $result->setType(Config::gtypes("gdouble"), 'scale', $scale); - $result->setType(Config::gtypes("gdouble"), 'offset', $offset); + $result->setType(FFI::gtypes("gdouble"), 'scale', $scale); + $result->setType(FFI::gtypes("gdouble"), 'offset', $offset); return $result; } @@ -851,7 +850,7 @@ public static function newFromMemory( * * TODO add a references system instead, see pyvips. */ - $pointer = Config::ffi()->vips_image_new_from_memory_copy( + $pointer = FFI::vips()->vips_image_new_from_memory_copy( $data, strlen($data), $width, @@ -860,7 +859,7 @@ public static function newFromMemory( $format ); if ($pointer == null) { - Config::error(); + throw new Exception(); } $result = new Image($pointer); @@ -928,12 +927,12 @@ public function newFromImage($value): Image */ public function writeToFile(string $name, array $options = []): void { - $filename = Config::filenameGetFilename($name); - $string_options = Config::filenameGetOptions($name); + $filename = Utils::filenameGetFilename($name); + $string_options = Utils::filenameGetOptions($name); - $saver = Config::ffi()->vips_foreign_find_save($filename); + $saver = FFI::vips()->vips_foreign_find_save($filename); if ($saver == "") { - Config::error(); + throw new Exception(); } if (strlen($string_options) != 0) { @@ -945,7 +944,7 @@ public function writeToFile(string $name, array $options = []): void $result = VipsOperation::call($saver, $this, [$filename], $options); if ($result === -1) { - Config::error(); + throw new Exception(); } } @@ -962,12 +961,12 @@ public function writeToFile(string $name, array $options = []): void */ public function writeToBuffer(string $suffix, array $options = []): string { - $filename = Config::filenameGetFilename($suffix); - $string_options = Config::filenameGetOptions($suffix); + $filename = Utils::filenameGetFilename($suffix); + $string_options = Utils::filenameGetOptions($suffix); - $saver = Config::ffi()->vips_foreign_find_save_buffer($filename); + $saver = FFI::vips()->vips_foreign_find_save_buffer($filename); if ($saver == "") { - Config::error(); + throw new Exception(); } if (strlen($string_options) != 0) { @@ -993,16 +992,16 @@ public function writeToMemory(): string $ctype = \FFI::arrayType(\FFI::type("size_t"), [1]); $p_size = \FFI::new($ctype); - $pointer = Config::ffi()-> + $pointer = FFI::vips()-> vips_image_write_to_memory($this->pointer, $p_size); if ($pointer == null) { - Config::error(); + throw new Exception(); } // string() takes a copy $result = \FFI::string($pointer, $p_size[0]); - Config::ffi()->g_free($pointer); + FFI::glib()->g_free($pointer); return $result; } @@ -1035,15 +1034,15 @@ public function writeToArray(): array $ctype = \FFI::arrayType(\FFI::type("size_t"), [1]); $p_size = \FFI::new($ctype); - $pointer = Config::ffi()-> + $pointer = FFI::vips()-> vips_image_write_to_memory($this->pointer, $p_size); if ($pointer == null) { - Config::error(); + throw new Exception(); } // wrap pointer up as a C array of the right type $n = $this->width * $this->height * $this->bands; - $type_name = Config::ftypes($this->format); + $type_name = FFI::ftypes($this->format); $ctype = \FFI::arrayType(\FFI::type($type_name), [$n]); $array = \FFI::cast($ctype, $pointer); @@ -1054,7 +1053,7 @@ public function writeToArray(): array } // the vips result is not PHP memory, so we must free it - Config::ffi()->g_free($pointer); + FFI::glib()->g_free($pointer); return $result; } @@ -1075,9 +1074,9 @@ public function writeToArray(): array */ public function copyMemory(): Image { - $pointer = Config::ffi()->vips_image_copy_memory($this->pointer); + $pointer = FFI::vips()->vips_image_copy_memory($this->pointer); if ($pointer == null) { - Config::error(); + throw new Exception(); } $result = new Image($pointer); @@ -1141,9 +1140,9 @@ public function __isset(string $name): bool public function get(string $name) { $gvalue = new GValue(); - if (Config::ffi()-> + if (FFI::vips()-> vips_image_get($this->pointer, $name, $gvalue->pointer) != 0) { - Config::error(); + throw new Exception(); } return $gvalue->get(); @@ -1160,7 +1159,7 @@ public function get(string $name) */ public function getType(string $name): int { - return Config::ffi()->vips_image_get_typeof($this->pointer, $name); + return FFI::vips()->vips_image_get_typeof($this->pointer, $name); } /** @@ -1198,27 +1197,27 @@ public function set(string $name, $value): void if ($gtype == 0) { if (is_array($value)) { if (is_int($value[0])) { - $gtype = Config::gtypes("VipsArrayInt"); + $gtype = FFI::gtypes("VipsArrayInt"); } elseif (is_float($value[0])) { - $gtype = Config::gtypes("VipsArrayDouble"); + $gtype = FFI::gtypes("VipsArrayDouble"); } else { - $gtype = Config::gtypes("VipsArrayImage"); + $gtype = FFI::gtypes("VipsArrayImage"); } } elseif (is_int($value)) { - $gtype = Config::gtypes("gint"); + $gtype = FFI::gtypes("gint"); } elseif (is_float($value)) { - $gtype = Config::gtypes("gdouble"); + $gtype = FFI::gtypes("gdouble"); } elseif (is_string($value)) { - $gtype = Config::gtypes("VipsRefString"); + $gtype = FFI::gtypes("VipsRefString"); } else { - $gtype = Config::gtypes("VipsImage"); + $gtype = FFI::gtypes("VipsImage"); } } $gvalue->setType($gtype); $gvalue->set($value); - Config::ffi()->vips_image_set($this->pointer, $name, $gvalue->pointer); + FFI::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); } /** @@ -1243,7 +1242,7 @@ public function setType($type, string $name, $value): void $gvalue = new GValue(); $gvalue->setType($type); $gvalue->set($value); - Config::ffi()->vips_image_set($this->pointer, $name, $gvalue->pointer); + FFI::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); } /** @@ -1257,8 +1256,8 @@ public function setType($type, string $name, $value): void */ public function remove(string $name): void { - if (!Config::ffi()->vips_image_remove($this->pointer, $name)) { - Config::error(); + if (!FFI::vips()->vips_image_remove($this->pointer, $name)) { + throw new Exception(); } } @@ -1936,7 +1935,7 @@ public function composite($other, $mode, array $options = []): Image # composite takes an arrayint, but it's really an array of blend modes # gvalue doesn't know this, so we must do name -> enum value mapping $mode = array_map(function ($x) { - return GValue::toEnum(Config::gtypes("VipsBlendMode"), $x); + return GValue::toEnum(FFI::gtypes("VipsBlendMode"), $x); }, $mode); return VipsOperation::call( diff --git a/src/ImageAutodoc.php b/src/ImageAutodoc.php index f9537ecb..531084af 100644 --- a/src/ImageAutodoc.php +++ b/src/ImageAutodoc.php @@ -203,6 +203,8 @@ * @throws Exception * @method string dzsave_buffer(array $options = []) Save image to dz buffer. * @throws Exception + * @method void dzsave_target(string $target, array $options = []) Save image to deepzoom target. + * @throws Exception * @method Image embed(integer $x, integer $y, integer $width, integer $height, array $options = []) Embed an image in a larger image. * @throws Exception * @method Image extract_area(integer $left, integer $top, integer $width, integer $height, array $options = []) Extract an area from an image. @@ -485,9 +487,9 @@ * @throws Exception * @method static Image pngload_source(string $source, array $options = []) Load png from source. * @throws Exception - * @method void pngsave(string $filename, array $options = []) Save image to png file. + * @method void pngsave(string $filename, array $options = []) Save image to file as PNG. * @throws Exception - * @method string pngsave_buffer(array $options = []) Save image to png buffer. + * @method string pngsave_buffer(array $options = []) Save image to buffer as PNG. * @throws Exception * @method void pngsave_target(string $target, array $options = []) Save image to target as PNG. * @throws Exception @@ -643,6 +645,8 @@ * @throws Exception * @method string tiffsave_buffer(array $options = []) Save image to tiff buffer. * @throws Exception + * @method void tiffsave_target(string $target, array $options = []) Save image to tiff target. + * @throws Exception * @method Image tilecache(array $options = []) Cache an image as a set of tiles. * @throws Exception * @method static Image tonelut(array $options = []) Build a look-up table. diff --git a/src/Interpolate.php b/src/Interpolate.php index c70b3279..19872bbc 100644 --- a/src/Interpolate.php +++ b/src/Interpolate.php @@ -62,8 +62,7 @@ class Interpolate extends VipsObject public function __construct($pointer) { - $this->pointer = Config::ffi()-> - cast(Config::ctypes("VipsInterpolate"), $pointer); + $this->pointer = \FFI::cast(FFI::ctypes("VipsInterpolate"), $pointer); parent::__construct($pointer); } @@ -81,13 +80,14 @@ public function __construct($pointer) * - `'lbb'`: Use LBB interpolation. * - `'vsqbs'`: Use the VSQBS interpolation. * - * @return resource|null The interpolator, or null on error. + * @return Interpolate The interpolator. + * @throws Exception If unable to make a new interpolator from $name. */ - public static function newFromName($name) + public static function newFromName(string $name) { - $pointer = Config::ffi()->vips_interpolate_new($name); + $pointer = FFI::vips()->vips_interpolate_new($name); if ($pointer == null) { - Config::error(); + throw new Exception(); } return new Interpolate($pointer); diff --git a/src/Introspect.php b/src/Introspect.php index b4aca433..7a1be5d8 100644 --- a/src/Introspect.php +++ b/src/Introspect.php @@ -97,13 +97,12 @@ public function __construct($name) $operation = VipsOperation::newFromName($name); $this->description = $operation->getDescription(); - $flags = Config::ffi()->vips_operation_get_flags($operation->pointer); - $p_names = Config::ffi()->new("char**[1]"); - $p_flags = Config::ffi()->new("int*[1]"); - $p_n_args = Config::ffi()->new("int[1]"); - $result = Config::ffi()->vips_object_get_args( - \FFI::cast(Config::ctypes("VipsObject"), $operation->pointer), + $p_names = FFI::vips()->new("char**[1]"); + $p_flags = FFI::vips()->new("int*[1]"); + $p_n_args = FFI::vips()->new("int[1]"); + $result = FFI::vips()->vips_object_get_args( + \FFI::cast(FFI::ctypes("VipsObject"), $operation->pointer), $p_names, $p_flags, $p_n_args @@ -146,9 +145,6 @@ public function __construct($name) foreach ($this->arguments as $name => $details) { $flags = $details["flags"]; - $blurb = $details["blurb"]; - $type = $details["type"]; - $typeName = Config::ffi()->g_type_name($type); if (($flags & ArgumentFlags::INPUT) && ($flags & ArgumentFlags::REQUIRED) && @@ -184,7 +180,7 @@ public function __construct($name) $this->member_this = ""; foreach ($this->required_input as $name) { $type = $this->arguments[$name]["type"]; - if ($type == Config::gtypes("VipsImage")) { + if ($type == FFI::gtypes("VipsImage")) { $this->member_this = $name; break; } @@ -211,7 +207,7 @@ public function __toString() $flags = $details["flags"]; $blurb = $details["blurb"]; $type = $details["type"]; - $typeName = Config::ffi()->g_type_name($type); + $typeName = FFI::gobject()->g_type_name($type); $result .= " $name:\n"; diff --git a/src/Utils.php b/src/Utils.php index d5ee0683..a9e45532 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -92,7 +92,25 @@ public static function errorLog(string $message, \Exception $exception): void */ public static function typeFromName(string $name): int { - return Config::ffi()->g_type_from_name($name); + return FFI::gobject()->g_type_from_name($name); + } + + public static function filenameGetFilename(string $name) + { + $pointer = FFI::vips()->vips_filename_get_filename($name); + $filename = \FFI::string($pointer); + FFI::glib()->g_free($pointer); + + return $filename; + } + + public static function filenameGetOptions(string $name) + { + $pointer = FFI::vips()->vips_filename_get_options($name); + $options = \FFI::string($pointer); + FFI::glib()->g_free($pointer); + + return $options; } } diff --git a/src/VipsObject.php b/src/VipsObject.php index 2a027cf1..d5db88b6 100644 --- a/src/VipsObject.php +++ b/src/VipsObject.php @@ -68,10 +68,8 @@ abstract class VipsObject extends GObject public function __construct($pointer) { - $this->pointer = Config::ffi()-> - cast(Config::ctypes("VipsObject"), $pointer); - $this->gObject = Config::ffi()-> - cast(Config::ctypes("GObject"), $pointer); + $this->pointer = \FFI::cast(FFI::ctypes("VipsObject"), $pointer); + $this->gObject = \FFI::cast(FFI::ctypes("GObject"), $pointer); parent::__construct($pointer); } @@ -79,12 +77,12 @@ public function __construct($pointer) // print a table of all active vipsobjects ... handy for debugging public static function printAll() { - Config::ffi()->vips_object_print_all(); + FFI::vips()->vips_object_print_all(); } public function getDescription() { - return Config::ffi()->vips_object_get_description($this->pointer); + return FFI::vips()->vips_object_get_description($this->pointer); } // get the pspec for a property @@ -93,10 +91,10 @@ public function getDescription() // FIXME add a cache for this thing public function getPspec(string $name) { - $pspec = Config::ffi()->new("GParamSpec*[1]"); - $argument_class = Config::ffi()->new("VipsArgumentClass*[1]"); - $argument_instance = Config::ffi()->new("VipsArgumentInstance*[1]"); - $result = Config::ffi()->vips_object_get_argument( + $pspec = FFI::gobject()->new("GParamSpec*[1]"); + $argument_class = FFI::vips()->new("VipsArgumentClass*[1]"); + $argument_instance = FFI::vips()->new("VipsArgumentInstance*[1]"); + $result = FFI::vips()->vips_object_get_argument( $this->pointer, $name, $pspec, @@ -118,7 +116,7 @@ public function getType(string $name) $pspec = $this->getPspec($name); if (\FFI::isNull($pspec)) { # need to clear any error, this is horrible - Config::ffi()->vips_error_clear(); + FFI::vips()->vips_error_clear(); return 0; } else { return $pspec->value_type; @@ -128,13 +126,13 @@ public function getType(string $name) public function getBlurb(string $name): string { $pspec = $this->getPspec($name); - return Config::ffi()->g_param_spec_get_blurb($pspec); + return FFI::gobject()->g_param_spec_get_blurb($pspec); } public function getArgumentDescription(string $name): string { $pspec = $this->getPspec($name); - return Config::ffi()->g_param_spec_get_description($pspec); + return FFI::gobject()->g_param_spec_get_description($pspec); } public function get(string $name) @@ -142,7 +140,7 @@ public function get(string $name) $gvalue = new GValue(); $gvalue->setType($this->getType($name)); - Config::ffi()-> + FFI::gobject()-> g_object_get_property($this->gObject, $name, $gvalue->pointer); $value = $gvalue->get(); @@ -159,13 +157,13 @@ public function set(string $name, $value) $gvalue->setType($this->getType($name)); $gvalue->set($value); - Config::ffi()-> + FFI::gobject()-> g_object_set_property($this->gObject, $name, $gvalue->pointer); } public function setString(string $string_options) { - $result = Config::ffi()-> + $result = FFI::vips()-> vips_object_set_from_string($this->pointer, $string_options); return $result == 0; @@ -173,7 +171,7 @@ public function setString(string $string_options) public function unrefOutputs() { - Config::ffi()->vips_object_unref_outputs($this->pointer); + FFI::vips()->vips_object_unref_outputs($this->pointer); } } diff --git a/src/VipsOperation.php b/src/VipsOperation.php index 5148e424..49ecc109 100644 --- a/src/VipsOperation.php +++ b/src/VipsOperation.php @@ -66,17 +66,17 @@ class VipsOperation extends VipsObject public function __construct($pointer) { - $this->pointer = Config::ffi()-> - cast(Config::ctypes("VipsOperation"), $pointer); + $this->pointer = FFI::vips()-> + cast(FFI::ctypes("VipsOperation"), $pointer); parent::__construct($pointer); } public static function newFromName($name) { - $pointer = Config::ffi()->vips_operation_new($name); + $pointer = FFI::vips()->vips_operation_new($name); if ($pointer == null) { - Config::error(); + throw new Exception(); } return new VipsOperation($pointer); @@ -88,9 +88,9 @@ public function setMatch($name, $match_image, $value) $gtype = $this->introspect->arguments[$name]["type"]; if ($match_image != null) { - if ($gtype == Config::gtypes("VipsImage")) { + if ($gtype == FFI::gtypes("VipsImage")) { $value = $match_image->imageize($value); - } elseif ($gtype == Config::gtypes("VipsArrayImage") && + } elseif ($gtype == FFI::gtypes("VipsArrayImage") && is_array($value)) { $new_value = []; foreach ($value as $x) { @@ -173,7 +173,7 @@ private static function unwrap(array $result): array private static function isImagePointer($value): bool { return $value instanceof \FFI\CData && - \FFI::typeof($value) == Config::ctypes("VipsImage"); + \FFI::typeof($value) == FFI::ctypes("VipsImage"); } /** @@ -229,7 +229,7 @@ private static function wrapResult($result) private static function errorIsArray($result): void { if (!is_array($result)) { - Config::error(); + throw new Exception(); } } @@ -286,22 +286,20 @@ public static function callBase( */ $n_required = count($operation->introspect->required_input); $n_supplied = count($arguments); - $used_instance = false; $n_used = 0; foreach ($operation->introspect->required_input as $name) { if ($name == $operation->introspect->member_this) { if (!$instance) { $operation->unrefOutputs(); - Config::error("instance argument not supplied"); + throw new Exception("instance argument not supplied"); } $operation->setMatch($name, $match_image, $instance); - $used_instance = true; } elseif ($n_used < $n_supplied) { $operation->setMatch($name, $match_image, $arguments[$n_used]); $n_used += 1; } else { $operation->unrefOutputs(); - Config::error("$n_required arguments required, " . + throw new Exception("$n_required arguments required, " . "but $n_supplied supplied"); } } @@ -316,7 +314,7 @@ public static function callBase( if ($n_supplied != $n_used) { $operation->unrefOutputs(); - Config::error("$n_required arguments required, " . + throw new Exception("$n_required arguments required, " . "but $n_supplied supplied"); } @@ -335,7 +333,7 @@ public static function callBase( if (!in_array($name, $operation->introspect->optional_input) && !in_array($name, $operation->introspect->optional_output)) { $operation->unrefOutputs(); - Config::error("optional argument '$name' does not exist"); + throw new Exception("optional argument '$name' does not exist"); } $operation->setMatch($name, $match_image, $value); @@ -343,11 +341,11 @@ public static function callBase( /* Build the operation */ - $pointer = Config::ffi()-> + $pointer = FFI::vips()-> vips_cache_operation_build($operation->pointer); if ($pointer == null) { $operation->unrefOutputs(); - Config::error(); + throw new Exception(); } $operation = new VipsOperation($pointer); $operation->introspect = self::introspect($operation_name); From 8c1ca0a2f9ac6477e91f0d615b86479f76058664 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 27 Jun 2022 13:50:30 +0200 Subject: [PATCH 2/6] Cleanup --- src/Config.php | 15 ++++++++----- src/Exception.php | 2 +- src/FFI.php | 29 +++++++++++++++--------- src/GObject.php | 2 +- src/Image.php | 43 ++++++++++++----------------------- src/Interpolate.php | 4 ++-- src/Introspect.php | 25 +++++++++++---------- src/Utils.php | 8 +++---- src/VipsObject.php | 12 +++++++--- src/VipsOperation.php | 52 +++++-------------------------------------- 10 files changed, 78 insertions(+), 114 deletions(-) diff --git a/src/Config.php b/src/Config.php index 59dd4233..f7824d7e 100644 --- a/src/Config.php +++ b/src/Config.php @@ -55,10 +55,8 @@ class Config /** * The logger instance. - * - * @var LoggerInterface */ - private static $logger; + private static ?LoggerInterface $logger = null; /** * Sets a logger. This can be handy for debugging. For example: @@ -151,9 +149,16 @@ public static function version(): string return FFI::version(); } - public static function atLeast(int $need_major, int $need_minor): bool + /** + * Is this at least libvips major.minor[.patch]? + * @param int $x Major component. + * @param int $y Minor component. + * @param int $z Patch component. + * @return bool `true` if at least libvips major.minor[.patch]; otherwise, `false`. + */ + public static function atLeast(int $x, int $y, int $z = 0): bool { - return FFI::atLeast($need_major, $need_minor); + return FFI::atLeast($x, $y, $z); } } diff --git a/src/Exception.php b/src/Exception.php index 8a08f857..ce5df1d4 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -58,7 +58,7 @@ public function __construct($message = "", $code = 0, \Throwable $previous = nul FFI::vips()->vips_error_clear(); } - // Utils::errorLog($message, self); + Utils::errorLog($message); parent::__construct($message, $code, $previous); } diff --git a/src/FFI.php b/src/FFI.php index 053125c9..07e6be34 100644 --- a/src/FFI.php +++ b/src/FFI.php @@ -77,7 +77,7 @@ class FFI * * @internal */ - private static $ffi_inited = false; + private static bool $ffi_inited = false; /** * Look up these once. @@ -97,21 +97,21 @@ class FFI private static int $library_minor; private static int $library_micro; - public static function glib() + public static function glib(): \FFI { self::init(); return self::$glib; } - public static function gobject() + public static function gobject(): \FFI { self::init(); return self::$gobject; } - public static function vips() + public static function vips(): \FFI { self::init(); @@ -155,11 +155,18 @@ public static function version(): string self::$library_micro; } - public static function atLeast(int $need_major, int $need_minor): bool + /** + * Is this at least libvips major.minor[.patch]? + * @param int $x Major component. + * @param int $y Minor component. + * @param int $z Patch component. + * @return bool `true` if at least libvips major.minor[.patch]; otherwise, `false`. + */ + public static function atLeast(int $x, int $y, int $z = 0): bool { - return $need_major < self::$library_major || - ($need_major == self::$library_major && - $need_minor <= self::$library_minor); + return self::$library_major > $x || + self::$library_major == $x && self::$library_minor > $y || + self::$library_major == $x && self::$library_minor == $y && self::$library_micro >= $z; } /** @@ -167,7 +174,7 @@ public static function atLeast(int $need_major, int $need_minor): bool * * @throws Exception * - * @internal + * @return void */ public static function shutDown() { @@ -219,7 +226,7 @@ private static function init() $result = $vips->vips_init(""); if ($result != 0) { - throw new Vips\Exception(); + throw new Exception(); } Utils::debugLog("init", ["vips_init" => $result]); @@ -236,7 +243,7 @@ private static function init() ]); if (!self::atLeast(8, 7)) { - throw new Vips\Exception("your libvips is too old -- " . + throw new Exception("your libvips is too old -- " . "8.7 or later required"); } diff --git a/src/GObject.php b/src/GObject.php index 3246e5c0..43d6f7df 100644 --- a/src/GObject.php +++ b/src/GObject.php @@ -69,7 +69,7 @@ abstract class GObject * * @internal */ - public function __construct($pointer) + public function __construct(\FFI\CData $pointer) { $this->pointer = \FFI::cast(FFI::ctypes("GObject"), $pointer); } diff --git a/src/Image.php b/src/Image.php index 1151bd7f..bda5198b 100644 --- a/src/Image.php +++ b/src/Image.php @@ -492,7 +492,7 @@ class Image extends ImageAutodoc implements \ArrayAccess * * @internal */ - public function __construct($pointer) + public function __construct(\FFI\CData $pointer) { $this->pointer = \FFI::cast(FFI::ctypes("VipsImage"), $pointer); parent::__construct($pointer); @@ -646,7 +646,7 @@ private static function runCmplx(\Closure $func, Image $image): Image /** * Handy for things like self::more. Call a 2-ary vips operator like - * 'more', but if the arg is not an image (ie. it's a constant), call + * 'more', but if the arg is not an image (i.e. it's a constant), call * 'more_const' instead. * * @param mixed $other The right-hand argument. @@ -689,15 +689,13 @@ private function callEnum( */ public static function findLoad(string $filename): ?string { - $result = FFI::vips()->vips_foreign_find_load($filename); - - return $result; + return FFI::vips()->vips_foreign_find_load($filename); } /** * Create a new Image from a file on disc. * - * @param string $filename The file to open. + * @param string $name The file to open. * @param array $options Any options to pass on to the load operation. * * @throws Exception @@ -722,9 +720,7 @@ public static function newFromFile( ], $options); } - $result = VipsOperation::call($loader, null, [$filename], $options); - - return $result; + return VipsOperation::call($loader, null, [$filename], $options); } /** @@ -738,10 +734,8 @@ public static function newFromFile( */ public static function findLoadBuffer(string $buffer): ?string { - $result = FFI::vips()-> + return FFI::vips()-> vips_foreign_find_load_buffer($buffer, strlen($buffer)); - - return $result; } /** @@ -772,9 +766,7 @@ public static function newFromBuffer( ], $options); } - $result = VipsOperation::call($loader, null, [$buffer], $options); - - return $result; + return VipsOperation::call($loader, null, [$buffer], $options); } /** @@ -862,9 +854,7 @@ public static function newFromMemory( throw new Exception(); } - $result = new Image($pointer); - - return $result; + return new Image($pointer); } /** @@ -872,7 +862,7 @@ public static function newFromMemory( * * See Interpolator::newFromName() for the new thing. */ - public static function newInterpolator(string $name) + public static function newInterpolator(string $name): Interpolate { return Interpolate::newFromName($name); } @@ -903,21 +893,19 @@ public function newFromImage($value): Image $this->height, ['extend' => Extend::COPY] ); - $image = $image->copy([ + return $image->copy([ 'interpretation' => $this->interpretation, 'xres' => $this->xres, 'yres' => $this->yres, 'xoffset' => $this->xoffset, 'yoffset' => $this->yoffset ]); - - return $image; } /** * Write an image to a file. * - * @param string $filename The file to write the image to. + * @param string $name The file to write the image to. * @param array $options Any options to pass on to the selected save * operation. * @@ -975,9 +963,7 @@ public function writeToBuffer(string $suffix, array $options = []): string ], $options); } - $result = VipsOperation::call($saver, $this, [], $options); - - return $result; + return VipsOperation::call($saver, $this, [], $options); } /** @@ -1078,9 +1064,7 @@ public function copyMemory(): Image if ($pointer == null) { throw new Exception(); } - $result = new Image($pointer); - - return $result; + return new Image($pointer); } /** @@ -1104,6 +1088,7 @@ public function __get(string $name) * @param mixed $value The value to set for this property. * * @return void + * @throws Exception */ public function __set(string $name, $value): void { diff --git a/src/Interpolate.php b/src/Interpolate.php index 19872bbc..cb5eee5a 100644 --- a/src/Interpolate.php +++ b/src/Interpolate.php @@ -60,7 +60,7 @@ class Interpolate extends VipsObject */ public \FFI\CData $pointer; - public function __construct($pointer) + public function __construct(\FFI\CData $pointer) { $this->pointer = \FFI::cast(FFI::ctypes("VipsInterpolate"), $pointer); @@ -83,7 +83,7 @@ public function __construct($pointer) * @return Interpolate The interpolator. * @throws Exception If unable to make a new interpolator from $name. */ - public static function newFromName(string $name) + public static function newFromName(string $name): Interpolate { $pointer = FFI::vips()->vips_interpolate_new($name); if ($pointer == null) { diff --git a/src/Introspect.php b/src/Introspect.php index 7a1be5d8..0db87b87 100644 --- a/src/Introspect.php +++ b/src/Introspect.php @@ -57,12 +57,12 @@ class Introspect public string $name; /** - * The operation description (eg. "add two images"). + * The operation description (e.g. "add two images"). */ public string $description; /** - * The operation flags (eg. SEQUENTIAL | DEPRECATED). + * The operation flags (e.g. SEQUENTIAL | DEPRECATED). */ public int $flags; @@ -90,11 +90,14 @@ class Introspect */ public array $method_args; - public function __construct($name) + /** + * @throws Exception + */ + public function __construct($operation_name) { - $this->name = $name; + $this->name = $operation_name; - $operation = VipsOperation::newFromName($name); + $operation = VipsOperation::newFromName($operation_name); $this->description = $operation->getDescription(); @@ -108,7 +111,7 @@ public function __construct($name) $p_n_args ); if ($result != 0) { - error(); + throw new Exception(); } $p_names = $p_names[0]; $p_flags = $p_flags[0]; @@ -194,14 +197,12 @@ public function __construct($name) array_splice($this->method_args, $index); } - Utils::debugLog($name, ['introspect' => strval($this)]); + Utils::debugLog($operation_name, ['introspect' => strval($this)]); } public function __toString() { - $result = ""; - - $result .= "$this->name:\n"; + $result = "$this->name:\n"; foreach ($this->arguments as $name => $details) { $flags = $details["flags"]; @@ -212,9 +213,9 @@ public function __toString() $result .= " $name:\n"; $result .= " flags: $flags\n"; - foreach (ArgumentFlags::NAMES as $name => $flag) { + foreach (ArgumentFlags::NAMES as $flag_name => $flag) { if ($flags & $flag) { - $result .= " $name\n"; + $result .= " $flag_name\n"; } } diff --git a/src/Utils.php b/src/Utils.php index a9e45532..106cff3e 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -69,16 +69,16 @@ public static function debugLog(string $name, array $arguments): void /** * Log an error message. * - * @param string $message The error message. - * @param \Exception $exception The exception. + * @param string $message The error message. + * @param \Exception|null $exception The exception, if any. * * @return void */ - public static function errorLog(string $message, \Exception $exception): void + public static function errorLog(string $message, ?\Exception $exception = null): void { $logger = Config::getLogger(); if ($logger) { - $logger->error($message, ['exception' => $exception]); + $logger->error($message, $exception == null ? [] : ['exception' => $exception]); } } diff --git a/src/VipsObject.php b/src/VipsObject.php index d5db88b6..49a56326 100644 --- a/src/VipsObject.php +++ b/src/VipsObject.php @@ -66,7 +66,7 @@ abstract class VipsObject extends GObject */ private \FFI\CData $gObject; - public function __construct($pointer) + public function __construct(\FFI\CData $pointer) { $this->pointer = \FFI::cast(FFI::ctypes("VipsObject"), $pointer); $this->gObject = \FFI::cast(FFI::ctypes("GObject"), $pointer); @@ -111,7 +111,7 @@ public function getPspec(string $name) // get the type of a property from a VipsObject // 0 if no such property - public function getType(string $name) + public function getType(string $name): int { $pspec = $this->getPspec($name); if (\FFI::isNull($pspec)) { @@ -135,6 +135,9 @@ public function getArgumentDescription(string $name): string return FFI::gobject()->g_param_spec_get_description($pspec); } + /** + * @throws Exception + */ public function get(string $name) { $gvalue = new GValue(); @@ -149,6 +152,9 @@ public function get(string $name) return $value; } + /** + * @throws Exception + */ public function set(string $name, $value) { Utils::debugLog("set", [$name => $value]); @@ -161,7 +167,7 @@ public function set(string $name, $value) g_object_set_property($this->gObject, $name, $gvalue->pointer); } - public function setString(string $string_options) + public function setString(string $string_options): bool { $result = FFI::vips()-> vips_object_set_from_string($this->pointer, $string_options); diff --git a/src/VipsOperation.php b/src/VipsOperation.php index 49ecc109..8a6ddf05 100644 --- a/src/VipsOperation.php +++ b/src/VipsOperation.php @@ -64,7 +64,7 @@ class VipsOperation extends VipsObject */ public Introspect $introspect; - public function __construct($pointer) + public function __construct(\FFI\CData $pointer) { $this->pointer = FFI::vips()-> cast(FFI::ctypes("VipsOperation"), $pointer); @@ -72,7 +72,10 @@ public function __construct($pointer) parent::__construct($pointer); } - public static function newFromName($name) + /** + * @throws Exception + */ + public static function newFromName($name): VipsOperation { $pointer = FFI::vips()->vips_operation_new($name); if ($pointer == null) { @@ -140,27 +143,6 @@ private static function findInside($predicate, $x) return null; } - /** - * Unwrap an array of stuff ready to pass down to the vips_ layer. We - * swap instances of Image for the ffi pointer. - * - * @param array $result Unwrap this. - * - * @return array $result unwrapped, ready for vips. - * - * @internal - */ - private static function unwrap(array $result): array - { - array_walk_recursive($result, function (&$value) { - if ($value instanceof Image) { - $value = $value->image; - } - }); - - return $result; - } - /** * Is $value a VipsImage. * @@ -211,28 +193,6 @@ private static function wrapResult($result) return $result; } - /** - * Check the result of a vips_ call for an error, and throw an exception - * if we see one. - * - * This won't work for things like __get where a non-array return can be - * a valid return. - * - * @param mixed $result Test this. - * - * @throws Exception - * - * @return void - * - * @internal - */ - private static function errorIsArray($result): void - { - if (!is_array($result)) { - throw new Exception(); - } - } - /** * Call any vips operation. The final element of $arguments can be * (but doesn't have to be) an array of options to pass to the operation. @@ -375,7 +335,7 @@ public static function callBase( $result = self::wrapResult($result); - Utils::debugLog($name, ['result' => var_export($result, true)]); + Utils::debugLog($operation_name, ['result' => var_export($result, true)]); return $result; } From d3b38dd6b773427cbc5897b69cf4207ef31017e2 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 28 Jun 2022 11:50:43 +0200 Subject: [PATCH 3/6] Fix `FFI::libraryName` --- src/FFI.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FFI.php b/src/FFI.php index 07e6be34..25686690 100644 --- a/src/FFI.php +++ b/src/FFI.php @@ -181,7 +181,7 @@ public static function shutDown() self::vips()->vips_shutdown(); } - private static function libraryName(string $name, $abi): string + private static function libraryName(string $name, int $abi): string { switch (PHP_OS_FAMILY) { case "Windows": @@ -206,8 +206,8 @@ private static function init() $vips_libname = self::libraryName("libvips", 42); if (PHP_OS_FAMILY === "Windows") { - $glib_libname = self::libraryName("libglib", "2.0-0"); - $gobject_libname = self::libraryName("libgobject", "2.0-0"); + $glib_libname = self::libraryName("libglib-2.0", 0); + $gobject_libname = self::libraryName("libgobject-2.0", 0); } else { $glib_libname = $vips_libname; $gobject_libname = $vips_libname; From bf9b8b303dfcb8ba6a091efafd8ffa7a745b34dc Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 2 Jul 2022 12:58:49 +0200 Subject: [PATCH 4/6] Add missing type declarations --- src/FFI.php | 13 +++++-------- src/GObject.php | 4 ++-- src/GValue.php | 4 ++-- src/Image.php | 2 +- src/Introspect.php | 2 +- src/Utils.php | 4 ++-- src/VipsObject.php | 10 +++++----- src/VipsOperation.php | 2 +- 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/FFI.php b/src/FFI.php index 25686690..1b1dbb0a 100644 --- a/src/FFI.php +++ b/src/FFI.php @@ -118,22 +118,21 @@ public static function vips(): \FFI return self::$vips; } - - public static function ctypes(string $name) + public static function ctypes(string $name): \FFI\CType { self::init(); return self::$ctypes[$name]; } - public static function gtypes(string $name) + public static function gtypes(string $name): int { self::init(); return self::$gtypes[$name]; } - public static function ftypes(string $name) + public static function ftypes(string $name): string { self::init(); @@ -172,11 +171,9 @@ public static function atLeast(int $x, int $y, int $z = 0): bool /** * Shut down libvips. Call this just before process exit. * - * @throws Exception - * * @return void */ - public static function shutDown() + public static function shutDown(): void { self::vips()->vips_shutdown(); } @@ -197,7 +194,7 @@ private static function libraryName(string $name, int $abi): string } } - private static function init() + private static function init(): void { // Already initialized. if (self::$ffi_inited) { diff --git a/src/GObject.php b/src/GObject.php index 43d6f7df..4ebc5001 100644 --- a/src/GObject.php +++ b/src/GObject.php @@ -84,12 +84,12 @@ public function __clone() $this->ref(); } - public function ref() + public function ref(): void { FFI::gobject()->g_object_ref($this->pointer); } - public function unref() + public function unref(): void { FFI::gobject()->g_object_unref($this->pointer); } diff --git a/src/GValue.php b/src/GValue.php index a3b3778c..8560b90c 100644 --- a/src/GValue.php +++ b/src/GValue.php @@ -76,7 +76,7 @@ public static function toEnum(int $gtype, $value): int * Turn an enum into a string, if possible * @throws Exception */ - public static function fromEnum(int $gtype, int $value) + public static function fromEnum(int $gtype, int $value): string { $result = FFI::vips()->vips_enum_nick($gtype, $value); if ($result === null) { @@ -91,7 +91,7 @@ public function __destruct() FFI::gobject()->g_value_unset($this->pointer); } - public function setType(int $gtype) + public function setType(int $gtype): void { FFI::gobject()->g_value_init($this->pointer, $gtype); } diff --git a/src/Image.php b/src/Image.php index bda5198b..5516f156 100644 --- a/src/Image.php +++ b/src/Image.php @@ -1251,7 +1251,7 @@ public function remove(string $name): void * * @return string */ - public function __toString() + public function __toString(): string { $array = [ 'width' => $this->width, diff --git a/src/Introspect.php b/src/Introspect.php index 0db87b87..000b8f06 100644 --- a/src/Introspect.php +++ b/src/Introspect.php @@ -200,7 +200,7 @@ public function __construct($operation_name) Utils::debugLog($operation_name, ['introspect' => strval($this)]); } - public function __toString() + public function __toString(): string { $result = "$this->name:\n"; diff --git a/src/Utils.php b/src/Utils.php index 106cff3e..31e26fc8 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -95,7 +95,7 @@ public static function typeFromName(string $name): int return FFI::gobject()->g_type_from_name($name); } - public static function filenameGetFilename(string $name) + public static function filenameGetFilename(string $name): string { $pointer = FFI::vips()->vips_filename_get_filename($name); $filename = \FFI::string($pointer); @@ -104,7 +104,7 @@ public static function filenameGetFilename(string $name) return $filename; } - public static function filenameGetOptions(string $name) + public static function filenameGetOptions(string $name): string { $pointer = FFI::vips()->vips_filename_get_options($name); $options = \FFI::string($pointer); diff --git a/src/VipsObject.php b/src/VipsObject.php index 49a56326..639c8ea7 100644 --- a/src/VipsObject.php +++ b/src/VipsObject.php @@ -75,12 +75,12 @@ public function __construct(\FFI\CData $pointer) } // print a table of all active vipsobjects ... handy for debugging - public static function printAll() + public static function printAll(): void { FFI::vips()->vips_object_print_all(); } - public function getDescription() + public function getDescription(): string { return FFI::vips()->vips_object_get_description($this->pointer); } @@ -89,7 +89,7 @@ public function getDescription() // NULL for no such name // very slow! avoid if possible // FIXME add a cache for this thing - public function getPspec(string $name) + public function getPspec(string $name): ?\FFI\CData { $pspec = FFI::gobject()->new("GParamSpec*[1]"); $argument_class = FFI::vips()->new("VipsArgumentClass*[1]"); @@ -155,7 +155,7 @@ public function get(string $name) /** * @throws Exception */ - public function set(string $name, $value) + public function set(string $name, $value): void { Utils::debugLog("set", [$name => $value]); @@ -175,7 +175,7 @@ public function setString(string $string_options): bool return $result == 0; } - public function unrefOutputs() + public function unrefOutputs(): void { FFI::vips()->vips_object_unref_outputs($this->pointer); } diff --git a/src/VipsOperation.php b/src/VipsOperation.php index 8a6ddf05..e9b12e9f 100644 --- a/src/VipsOperation.php +++ b/src/VipsOperation.php @@ -85,7 +85,7 @@ public static function newFromName($name): VipsOperation return new VipsOperation($pointer); } - public function setMatch($name, $match_image, $value) + public function setMatch($name, $match_image, $value): void { $flags = $this->introspect->arguments[$name]["flags"]; $gtype = $this->introspect->arguments[$name]["type"]; From f3086e49d2ed1aa893e4284bd4008aa016423fa5 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 2 Jul 2022 12:45:59 +0200 Subject: [PATCH 5/6] Revert "Move FFI functions to a separate class" To make reviewing easier. --- src/Config.php | 692 +++++++++++++++++++++++++++++++++++++- src/Exception.php | 4 +- src/FFI.php | 764 ------------------------------------------ src/GObject.php | 6 +- src/GValue.php | 142 ++++---- src/Image.php | 56 ++-- src/Interpolate.php | 4 +- src/Introspect.php | 14 +- src/Utils.php | 10 +- src/VipsObject.php | 30 +- src/VipsOperation.php | 14 +- 11 files changed, 826 insertions(+), 910 deletions(-) delete mode 100644 src/FFI.php diff --git a/src/Config.php b/src/Config.php index f7824d7e..8e9d4ff3 100644 --- a/src/Config.php +++ b/src/Config.php @@ -58,6 +58,53 @@ class Config */ private static ?LoggerInterface $logger = null; + /** + * The FFI handle we use for the glib binary. + * + * @internal + */ + private static \FFI $glib; + + + /** + * The FFI handle we use for the gobject binary. + * + * @internal + */ + private static \FFI $gobject; + + /** + * The FFI handle we use for the libvips binary. + * + * @internal + */ + private static \FFI $vips; + + /** + * Are the above FFI handles initialized? + * + * @internal + */ + private static bool $ffi_inited = false; + + /** + * The library version number we detect. + * + * @internal + */ + private static int $library_major; + private static int $library_minor; + private static int $library_micro; + + /** + * Look up these once. + * + * @internal + */ + private static array $ctypes; + private static array $gtypes; + private static array $ftypes; + /** * Sets a logger. This can be handy for debugging. For example: * @@ -94,7 +141,7 @@ public static function getLogger(): ?LoggerInterface */ public static function cacheSetMax(int $value): void { - FFI::vips()->vips_cache_set_max($value); + self::vips()->vips_cache_set_max($value); } /** @@ -108,7 +155,7 @@ public static function cacheSetMax(int $value): void */ public static function cacheSetMaxMem(int $value): void { - FFI::vips()->vips_cache_set_max_mem($value); + self::vips()->vips_cache_set_max_mem($value); } /** @@ -121,7 +168,7 @@ public static function cacheSetMaxMem(int $value): void */ public static function cacheSetMaxFiles(int $value): void { - FFI::vips()->vips_cache_set_max_files($value); + self::vips()->vips_cache_set_max_files($value); } /** @@ -135,7 +182,49 @@ public static function cacheSetMaxFiles(int $value): void */ public static function concurrencySet(int $value): void { - FFI::vips()->vips_concurrency_set($value); + self::vips()->vips_concurrency_set($value); + } + + public static function glib(): \FFI + { + self::init(); + + return self::$glib; + } + + public static function gobject(): \FFI + { + self::init(); + + return self::$gobject; + } + + public static function vips(): \FFI + { + self::init(); + + return self::$vips; + } + + public static function ctypes(string $name): \FFI\CType + { + self::init(); + + return self::$ctypes[$name]; + } + + public static function gtypes(string $name): int + { + self::init(); + + return self::$gtypes[$name]; + } + + public static function ftypes(string $name): string + { + self::init(); + + return self::$ftypes[$name]; } /** @@ -146,7 +235,21 @@ public static function concurrencySet(int $value): void */ public static function version(): string { - return FFI::version(); + self::init(); + + return self::$library_major . "." . + self::$library_minor . "." . + self::$library_micro; + } + + /** + * Shut down libvips. Call this just before process exit. + * + * @return void + */ + public static function shutDown(): void + { + self::vips()->vips_shutdown(); } /** @@ -158,7 +261,584 @@ public static function version(): string */ public static function atLeast(int $x, int $y, int $z = 0): bool { - return FFI::atLeast($x, $y, $z); + return self::$library_major > $x || + self::$library_major == $x && self::$library_minor > $y || + self::$library_major == $x && self::$library_minor == $y && self::$library_micro >= $z; + } + + private static function libraryName(string $name, int $abi): string + { + switch (PHP_OS_FAMILY) { + case "Windows": + return "$name-$abi.dll"; + + case "OSX": + case "Darwin": + return "$name.$abi.dylib"; + + default: + // most *nix + return "$name.so.$abi"; + } + } + + private static function init(): void + { + // Already initialized. + if (self::$ffi_inited) { + return; + } + + $vips_libname = self::libraryName("libvips", 42); + if (PHP_OS_FAMILY === "Windows") { + $glib_libname = self::libraryName("libglib-2.0", 0); + $gobject_libname = self::libraryName("libgobject-2.0", 0); + } else { + $glib_libname = $vips_libname; + $gobject_libname = $vips_libname; + } + + Utils::debugLog("init", ["library" => $vips_libname]); + + /* FIXME ... maybe display a helpful message on failure? This will + * probably be the main point of failure. + */ + $vips = \FFI::cdef(<<vips_init(""); + if ($result != 0) { + throw new Exception(); + } + Utils::debugLog("init", ["vips_init" => $result]); + + # get the library version number, then we can build the API + self::$library_major = $vips->vips_version(0); + self::$library_minor = $vips->vips_version(1); + self::$library_micro = $vips->vips_version(2); + Utils::debugLog("init", [ + "libvips version" => [ + self::$library_major, + self::$library_minor, + self::$library_micro + ] + ]); + + if (!self::atLeast(8, 7)) { + throw new Exception("your libvips is too old -- " . + "8.7 or later required"); + } + + $is_64bits = PHP_INT_SIZE === 8; + + // GType is the size of a pointer + $gtype = $is_64bits ? "guint64" : "guint32"; + + // Typedefs shared across the libvips, GLib and GObject declarations + $typedefs = <<vips_blend_mode_get_type(); + self::$vips->vips_interpretation_get_type(); + self::$vips->vips_operation_flags_get_type(); + self::$vips->vips_band_format_get_type(); + self::$vips->vips_token_get_type(); + self::$vips->vips_saveable_get_type(); + self::$vips->vips_image_type_get_type(); + + // look these up in advance + self::$ctypes = [ + "GObject" => self::$gobject->type("GObject*"), + "GParamSpec" => self::$gobject->type("GParamSpec*"), + "VipsObject" => self::$vips->type("VipsObject*"), + "VipsOperation" => self::$vips->type("VipsOperation*"), + "VipsImage" => self::$vips->type("VipsImage*"), + "VipsInterpolate" => self::$vips->type("VipsInterpolate*"), + ]; + + self::$gtypes = [ + "gboolean" => self::$gobject->g_type_from_name("gboolean"), + "gint" => self::$gobject->g_type_from_name("gint"), + "gint64" => self::$gobject->g_type_from_name("gint64"), + "guint64" => self::$gobject->g_type_from_name("guint64"), + "gdouble" => self::$gobject->g_type_from_name("gdouble"), + "gchararray" => self::$gobject->g_type_from_name("gchararray"), + "VipsRefString" => self::$gobject->g_type_from_name("VipsRefString"), + + "GEnum" => self::$gobject->g_type_from_name("GEnum"), + "GFlags" => self::$gobject->g_type_from_name("GFlags"), + "VipsBandFormat" => self::$gobject->g_type_from_name("VipsBandFormat"), + "VipsBlendMode" => self::$gobject->g_type_from_name("VipsBlendMode"), + "VipsArrayInt" => self::$gobject->g_type_from_name("VipsArrayInt"), + "VipsArrayDouble" => + self::$gobject->g_type_from_name("VipsArrayDouble"), + "VipsArrayImage" => self::$gobject->g_type_from_name("VipsArrayImage"), + "VipsBlob" => self::$gobject->g_type_from_name("VipsBlob"), + + "GObject" => self::$gobject->g_type_from_name("GObject"), + "VipsImage" => self::$gobject->g_type_from_name("VipsImage"), + ]; + + // map vips format names to c type names + self::$ftypes = [ + "char" => "char", + "uchar" => "unsigned char", + "short" => "short", + "ushort" => "unsigned short", + "int" => "int", + "uint" => "unsigned int", + "float" => "float", + "double" => "double", + "complex" => "float", + "dpcomplex" => "double", + ]; + + Utils::debugLog("init", ["done"]); + self::$ffi_inited = true; } } diff --git a/src/Exception.php b/src/Exception.php index ce5df1d4..f8279b06 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -54,8 +54,8 @@ class Exception extends \Exception public function __construct($message = "", $code = 0, \Throwable $previous = null) { if ($message == "") { - $message = "libvips error: " . FFI::vips()->vips_error_buffer(); - FFI::vips()->vips_error_clear(); + $message = "libvips error: " . Config::vips()->vips_error_buffer(); + Config::vips()->vips_error_clear(); } Utils::errorLog($message); diff --git a/src/FFI.php b/src/FFI.php deleted file mode 100644 index 1b1dbb0a..00000000 --- a/src/FFI.php +++ /dev/null @@ -1,764 +0,0 @@ - - * @copyright 2016 John Cupitt - * @license https://opensource.org/licenses/MIT MIT - * @link https://github.com/jcupitt/php-vips - */ - -namespace Jcupitt\Vips; - -/** - * This class contains the libvips FFI methods. - * - * @category Images - * @package Jcupitt\Vips - * @author John Cupitt - * @copyright 2016 John Cupitt - * @license https://opensource.org/licenses/MIT MIT - * @link https://github.com/jcupitt/php-vips - */ -class FFI -{ - /** - * The FFI handle we use for the glib binary. - * - * @internal - */ - private static \FFI $glib; - - - /** - * The FFI handle we use for the gobject binary. - * - * @internal - */ - private static \FFI $gobject; - - /** - * The FFI handle we use for the libvips binary. - * - * @internal - */ - private static \FFI $vips; - - /** - * Are the above FFI handles initialized? - * - * @internal - */ - private static bool $ffi_inited = false; - - /** - * Look up these once. - * - * @internal - */ - private static array $ctypes; - private static array $gtypes; - private static array $ftypes; - - /** - * The library version number we detect. - * - * @internal - */ - private static int $library_major; - private static int $library_minor; - private static int $library_micro; - - public static function glib(): \FFI - { - self::init(); - - return self::$glib; - } - - public static function gobject(): \FFI - { - self::init(); - - return self::$gobject; - } - - public static function vips(): \FFI - { - self::init(); - - return self::$vips; - } - - public static function ctypes(string $name): \FFI\CType - { - self::init(); - - return self::$ctypes[$name]; - } - - public static function gtypes(string $name): int - { - self::init(); - - return self::$gtypes[$name]; - } - - public static function ftypes(string $name): string - { - self::init(); - - return self::$ftypes[$name]; - } - - /** - * Gets the libvips version number as a string of the form - * MAJOR.MINOR.MICRO, for example "8.6.1". - * - * @return string - */ - public static function version(): string - { - self::init(); - - return self::$library_major . "." . - self::$library_minor . "." . - self::$library_micro; - } - - /** - * Is this at least libvips major.minor[.patch]? - * @param int $x Major component. - * @param int $y Minor component. - * @param int $z Patch component. - * @return bool `true` if at least libvips major.minor[.patch]; otherwise, `false`. - */ - public static function atLeast(int $x, int $y, int $z = 0): bool - { - return self::$library_major > $x || - self::$library_major == $x && self::$library_minor > $y || - self::$library_major == $x && self::$library_minor == $y && self::$library_micro >= $z; - } - - /** - * Shut down libvips. Call this just before process exit. - * - * @return void - */ - public static function shutDown(): void - { - self::vips()->vips_shutdown(); - } - - private static function libraryName(string $name, int $abi): string - { - switch (PHP_OS_FAMILY) { - case "Windows": - return "$name-$abi.dll"; - - case "OSX": - case "Darwin": - return "$name.$abi.dylib"; - - default: - // most *nix - return "$name.so.$abi"; - } - } - - private static function init(): void - { - // Already initialized. - if (self::$ffi_inited) { - return; - } - - $vips_libname = self::libraryName("libvips", 42); - if (PHP_OS_FAMILY === "Windows") { - $glib_libname = self::libraryName("libglib-2.0", 0); - $gobject_libname = self::libraryName("libgobject-2.0", 0); - } else { - $glib_libname = $vips_libname; - $gobject_libname = $vips_libname; - } - - Utils::debugLog("init", ["library" => $vips_libname]); - - /* FIXME ... maybe display a helpful message on failure? This will - * probably be the main point of failure. - */ - $vips = \FFI::cdef(<<vips_init(""); - if ($result != 0) { - throw new Exception(); - } - Utils::debugLog("init", ["vips_init" => $result]); - - # get the library version number, then we can build the API - self::$library_major = $vips->vips_version(0); - self::$library_minor = $vips->vips_version(1); - self::$library_micro = $vips->vips_version(2); - Utils::debugLog("init", [ - "libvips version" => [ - self::$library_major, - self::$library_minor, - self::$library_micro - ] - ]); - - if (!self::atLeast(8, 7)) { - throw new Exception("your libvips is too old -- " . - "8.7 or later required"); - } - - $is_64bits = PHP_INT_SIZE === 8; - - // GType is the size of a pointer - $gtype = $is_64bits ? "guint64" : "guint32"; - - // Typedefs shared across the libvips, GLib and GObject declarations - $typedefs = <<vips_blend_mode_get_type(); - self::$vips->vips_interpretation_get_type(); - self::$vips->vips_operation_flags_get_type(); - self::$vips->vips_band_format_get_type(); - self::$vips->vips_token_get_type(); - self::$vips->vips_saveable_get_type(); - self::$vips->vips_image_type_get_type(); - - // look these up in advance - self::$ctypes = [ - "GObject" => self::$gobject->type("GObject*"), - "GParamSpec" => self::$gobject->type("GParamSpec*"), - "VipsObject" => self::$vips->type("VipsObject*"), - "VipsOperation" => self::$vips->type("VipsOperation*"), - "VipsImage" => self::$vips->type("VipsImage*"), - "VipsInterpolate" => self::$vips->type("VipsInterpolate*"), - ]; - - self::$gtypes = [ - "gboolean" => self::$gobject->g_type_from_name("gboolean"), - "gint" => self::$gobject->g_type_from_name("gint"), - "gint64" => self::$gobject->g_type_from_name("gint64"), - "guint64" => self::$gobject->g_type_from_name("guint64"), - "gdouble" => self::$gobject->g_type_from_name("gdouble"), - "gchararray" => self::$gobject->g_type_from_name("gchararray"), - "VipsRefString" => self::$gobject->g_type_from_name("VipsRefString"), - - "GEnum" => self::$gobject->g_type_from_name("GEnum"), - "GFlags" => self::$gobject->g_type_from_name("GFlags"), - "VipsBandFormat" => self::$gobject->g_type_from_name("VipsBandFormat"), - "VipsBlendMode" => self::$gobject->g_type_from_name("VipsBlendMode"), - "VipsArrayInt" => self::$gobject->g_type_from_name("VipsArrayInt"), - "VipsArrayDouble" => - self::$gobject->g_type_from_name("VipsArrayDouble"), - "VipsArrayImage" => self::$gobject->g_type_from_name("VipsArrayImage"), - "VipsBlob" => self::$gobject->g_type_from_name("VipsBlob"), - - "GObject" => self::$gobject->g_type_from_name("GObject"), - "VipsImage" => self::$gobject->g_type_from_name("VipsImage"), - ]; - - // map vips format names to c type names - self::$ftypes = [ - "char" => "char", - "uchar" => "unsigned char", - "short" => "short", - "ushort" => "unsigned short", - "int" => "int", - "uint" => "unsigned int", - "float" => "float", - "double" => "double", - "complex" => "float", - "dpcomplex" => "double", - ]; - - Utils::debugLog("init", ["done"]); - self::$ffi_inited = true; - } -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: expandtab sw=4 ts=4 fdm=marker - * vim<600: expandtab sw=4 ts=4 - */ diff --git a/src/GObject.php b/src/GObject.php index 4ebc5001..46620b3e 100644 --- a/src/GObject.php +++ b/src/GObject.php @@ -71,7 +71,7 @@ abstract class GObject */ public function __construct(\FFI\CData $pointer) { - $this->pointer = \FFI::cast(FFI::ctypes("GObject"), $pointer); + $this->pointer = \FFI::cast(Config::ctypes("GObject"), $pointer); } public function __destruct() @@ -86,12 +86,12 @@ public function __clone() public function ref(): void { - FFI::gobject()->g_object_ref($this->pointer); + Config::gobject()->g_object_ref($this->pointer); } public function unref(): void { - FFI::gobject()->g_object_unref($this->pointer); + Config::gobject()->g_object_unref($this->pointer); } // TODO signal marshalling to go in diff --git a/src/GValue.php b/src/GValue.php index 8560b90c..32d28d16 100644 --- a/src/GValue.php +++ b/src/GValue.php @@ -46,7 +46,7 @@ class GValue public function __construct() { # allocate a gvalue on the heap, and make it persistent between requests - $this->struct = FFI::gobject()->new("GValue", true, true); + $this->struct = Config::gobject()->new("GValue", true, true); $this->pointer = \FFI::addr($this->struct); # GValue needs to be inited to all zero @@ -60,7 +60,7 @@ public function __construct() public static function toEnum(int $gtype, $value): int { if (is_string($value)) { - $enum_value = FFI::vips()-> + $enum_value = Config::vips()-> vips_enum_from_nick("php-vips", $gtype, $value); if ($enum_value < 0) { throw new Exception(); @@ -78,7 +78,7 @@ public static function toEnum(int $gtype, $value): int */ public static function fromEnum(int $gtype, int $value): string { - $result = FFI::vips()->vips_enum_nick($gtype, $value); + $result = Config::vips()->vips_enum_nick($gtype, $value); if ($result === null) { throw new Exception("value not in enum"); } @@ -88,12 +88,12 @@ public static function fromEnum(int $gtype, int $value): string public function __destruct() { - FFI::gobject()->g_value_unset($this->pointer); + Config::gobject()->g_value_unset($this->pointer); } public function setType(int $gtype): void { - FFI::gobject()->g_value_init($this->pointer, $gtype); + Config::gobject()->g_value_init($this->pointer, $gtype); } public function getType(): int @@ -113,36 +113,36 @@ public function set($value): void $gtype = $this->getType(); switch ($gtype) { - case FFI::gtypes("gboolean"): - FFI::gobject()->g_value_set_boolean($this->pointer, $value); + case Config::gtypes("gboolean"): + Config::gobject()->g_value_set_boolean($this->pointer, $value); break; - case FFI::gtypes("gint"): - FFI::gobject()->g_value_set_int($this->pointer, $value); + case Config::gtypes("gint"): + Config::gobject()->g_value_set_int($this->pointer, $value); break; - case FFI::gtypes("gint64"): - FFI::gobject()->g_value_set_int64($this->pointer, $value); + case Config::gtypes("gint64"): + Config::gobject()->g_value_set_int64($this->pointer, $value); break; - case FFI::gtypes("guint64"): - FFI::gobject()->g_value_set_uint64($this->pointer, $value); + case Config::gtypes("guint64"): + Config::gobject()->g_value_set_uint64($this->pointer, $value); break; - case FFI::gtypes("gdouble"): - FFI::gobject()->g_value_set_double($this->pointer, $value); + case Config::gtypes("gdouble"): + Config::gobject()->g_value_set_double($this->pointer, $value); break; - case FFI::gtypes("gchararray"): - FFI::gobject()->g_value_set_string($this->pointer, $value); + case Config::gtypes("gchararray"): + Config::gobject()->g_value_set_string($this->pointer, $value); break; - case FFI::gtypes("VipsRefString"): - FFI::vips()-> + case Config::gtypes("VipsRefString"): + Config::vips()-> vips_value_set_ref_string($this->pointer, $value); break; - case FFI::gtypes("VipsArrayInt"): + case Config::gtypes("VipsArrayInt"): if (!is_array($value)) { $value = [$value]; } @@ -152,11 +152,11 @@ public function set($value): void for ($i = 0; $i < $n; $i++) { $array[$i] = $value[$i]; } - FFI::vips()-> + Config::vips()-> vips_value_set_array_int($this->pointer, $array, $n); break; - case FFI::gtypes("VipsArrayDouble"): + case Config::gtypes("VipsArrayDouble"): if (!is_array($value)) { $value = [$value]; } @@ -166,17 +166,17 @@ public function set($value): void for ($i = 0; $i < $n; $i++) { $array[$i] = $value[$i]; } - FFI::vips()-> + Config::vips()-> vips_value_set_array_double($this->pointer, $array, $n); break; - case FFI::gtypes("VipsArrayImage"): + case Config::gtypes("VipsArrayImage"): if (!is_array($value)) { $value = [$value]; } $n = count($value); - FFI::vips()->vips_value_set_array_image($this->pointer, $n); - $array = FFI::vips()-> + Config::vips()->vips_value_set_array_image($this->pointer, $n); + $array = Config::vips()-> vips_value_get_array_image($this->pointer, null); for ($i = 0; $i < $n; $i++) { $image = $value[$i]; @@ -185,7 +185,7 @@ public function set($value): void } break; - case FFI::gtypes("VipsBlob"): + case Config::gtypes("VipsBlob"): # we need to set the blob to a copy of the data that vips_lib # can own and free $n = strlen($value); @@ -194,34 +194,34 @@ public function set($value): void for ($i = 0; $i < $n; $i++) { $memory[$i] = $value[$i]; } - FFI::vips()-> + Config::vips()-> vips_value_set_blob_free($this->pointer, $memory, $n); break; default: - $fundamental = FFI::gobject()->g_type_fundamental($gtype); + $fundamental = Config::gobject()->g_type_fundamental($gtype); switch ($fundamental) { - case FFI::gtypes("GObject"): - FFI::gobject()-> + case Config::gtypes("GObject"): + Config::gobject()-> g_value_set_object($this->pointer, $value->pointer); break; - case FFI::gtypes("GEnum"): - FFI::gobject()->g_value_set_enum( + case Config::gtypes("GEnum"): + Config::gobject()->g_value_set_enum( $this->pointer, self::toEnum($gtype, $value) ); break; - case FFI::gtypes("GFlags"): + case Config::gtypes("GFlags"): /* Just set as int. */ - FFI::gobject()-> + Config::gobject()-> g_value_set_flags($this->pointer, $value); break; default: - $typeName = FFI::gobject()->g_type_name($gtype); + $typeName = Config::gobject()->g_type_name($gtype); throw new \BadMethodCallException( "gtype $typeName ($gtype) not implemented" ); @@ -242,48 +242,48 @@ public function get() $result = null; switch ($gtype) { - case FFI::gtypes("gboolean"): - $result = FFI::gobject()->g_value_get_boolean($this->pointer); + case Config::gtypes("gboolean"): + $result = Config::gobject()->g_value_get_boolean($this->pointer); break; - case FFI::gtypes("gint"): - $result = FFI::gobject()->g_value_get_int($this->pointer); + case Config::gtypes("gint"): + $result = Config::gobject()->g_value_get_int($this->pointer); break; - case FFI::gtypes("gint64"): - $result = FFI::gobject()->g_value_get_int64($this->pointer); + case Config::gtypes("gint64"): + $result = Config::gobject()->g_value_get_int64($this->pointer); break; - case FFI::gtypes("guint64"): - $result = FFI::gobject()->g_value_get_uint64($this->pointer); + case Config::gtypes("guint64"): + $result = Config::gobject()->g_value_get_uint64($this->pointer); break; - case FFI::gtypes("gdouble"): - $result = FFI::gobject()->g_value_get_double($this->pointer); + case Config::gtypes("gdouble"): + $result = Config::gobject()->g_value_get_double($this->pointer); break; - case FFI::gtypes("gchararray"): - $result = FFI::gobject()->g_value_get_string($this->pointer); + case Config::gtypes("gchararray"): + $result = Config::gobject()->g_value_get_string($this->pointer); break; - case FFI::gtypes("VipsRefString"): - $p_size = FFI::vips()->new("size_t[1]"); - $result = FFI::vips()-> + case Config::gtypes("VipsRefString"): + $p_size = Config::vips()->new("size_t[1]"); + $result = Config::vips()-> vips_value_get_ref_string($this->pointer, $p_size); # $p_size[0] will be the string length, but assume it's null # terminated break; - case FFI::gtypes("VipsImage"): - $pointer = FFI::gobject()->g_value_get_object($this->pointer); + case Config::gtypes("VipsImage"): + $pointer = Config::gobject()->g_value_get_object($this->pointer); $result = new Image($pointer); // get_object does not increment the ref count $result->ref(); break; - case FFI::gtypes("VipsArrayInt"): - $p_len = FFI::vips()->new("int[1]"); - $pointer = FFI::vips()-> + case Config::gtypes("VipsArrayInt"): + $p_len = Config::vips()->new("int[1]"); + $pointer = Config::vips()-> vips_value_get_array_int($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -291,9 +291,9 @@ public function get() } break; - case FFI::gtypes("VipsArrayDouble"): - $p_len = FFI::vips()->new("int[1]"); - $pointer = FFI::vips()-> + case Config::gtypes("VipsArrayDouble"): + $p_len = Config::vips()->new("int[1]"); + $pointer = Config::vips()-> vips_value_get_array_double($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -301,9 +301,9 @@ public function get() } break; - case FFI::gtypes("VipsArrayImage"): - $p_len = FFI::vips()->new("int[1]"); - $pointer = FFI::vips()-> + case Config::gtypes("VipsArrayImage"): + $p_len = Config::vips()->new("int[1]"); + $pointer = Config::vips()-> vips_value_get_array_image($this->pointer, $p_len); $result = []; for ($i = 0; $i < $p_len[0]; $i++) { @@ -313,31 +313,31 @@ public function get() } break; - case FFI::gtypes("VipsBlob"): - $p_len = FFI::vips()->new("size_t[1]"); - $pointer = FFI::vips()-> + case Config::gtypes("VipsBlob"): + $p_len = Config::vips()->new("size_t[1]"); + $pointer = Config::vips()-> vips_value_get_blob($this->pointer, $p_len); $result = \FFI::string($pointer, $p_len[0]); break; default: - $fundamental = FFI::gobject()->g_type_fundamental($gtype); + $fundamental = Config::gobject()->g_type_fundamental($gtype); switch ($fundamental) { - case FFI::gtypes("GEnum"): - $result = FFI::gobject()-> + case Config::gtypes("GEnum"): + $result = Config::gobject()-> g_value_get_enum($this->pointer); $result = self::fromEnum($gtype, $result); break; - case FFI::gtypes("GFlags"): + case Config::gtypes("GFlags"): /* Just get as int. */ - $result = FFI::gobject()-> + $result = Config::gobject()-> g_value_get_flags($this->pointer); break; default: - $typeName = FFI::gobject()->g_type_name($gtype); + $typeName = Config::gobject()->g_type_name($gtype); throw new \BadMethodCallException( "gtype $typeName ($gtype) not implemented" ); diff --git a/src/Image.php b/src/Image.php index 5516f156..414198fe 100644 --- a/src/Image.php +++ b/src/Image.php @@ -494,7 +494,7 @@ class Image extends ImageAutodoc implements \ArrayAccess */ public function __construct(\FFI\CData $pointer) { - $this->pointer = \FFI::cast(FFI::ctypes("VipsImage"), $pointer); + $this->pointer = \FFI::cast(Config::ctypes("VipsImage"), $pointer); parent::__construct($pointer); } @@ -689,7 +689,7 @@ private function callEnum( */ public static function findLoad(string $filename): ?string { - return FFI::vips()->vips_foreign_find_load($filename); + return Config::vips()->vips_foreign_find_load($filename); } /** @@ -734,7 +734,7 @@ public static function newFromFile( */ public static function findLoadBuffer(string $buffer): ?string { - return FFI::vips()-> + return Config::vips()-> vips_foreign_find_load_buffer($buffer, strlen($buffer)); } @@ -805,15 +805,15 @@ public static function newFromArray( } } - $pointer = FFI::vips()-> + $pointer = Config::vips()-> vips_image_new_matrix_from_array($width, $height, $a, $n); if ($pointer == null) { throw new Exception(); } $result = new Image($pointer); - $result->setType(FFI::gtypes("gdouble"), 'scale', $scale); - $result->setType(FFI::gtypes("gdouble"), 'offset', $offset); + $result->setType(Config::gtypes("gdouble"), 'scale', $scale); + $result->setType(Config::gtypes("gdouble"), 'offset', $offset); return $result; } @@ -842,7 +842,7 @@ public static function newFromMemory( * * TODO add a references system instead, see pyvips. */ - $pointer = FFI::vips()->vips_image_new_from_memory_copy( + $pointer = Config::vips()->vips_image_new_from_memory_copy( $data, strlen($data), $width, @@ -918,7 +918,7 @@ public function writeToFile(string $name, array $options = []): void $filename = Utils::filenameGetFilename($name); $string_options = Utils::filenameGetOptions($name); - $saver = FFI::vips()->vips_foreign_find_save($filename); + $saver = Config::vips()->vips_foreign_find_save($filename); if ($saver == "") { throw new Exception(); } @@ -952,7 +952,7 @@ public function writeToBuffer(string $suffix, array $options = []): string $filename = Utils::filenameGetFilename($suffix); $string_options = Utils::filenameGetOptions($suffix); - $saver = FFI::vips()->vips_foreign_find_save_buffer($filename); + $saver = Config::vips()->vips_foreign_find_save_buffer($filename); if ($saver == "") { throw new Exception(); } @@ -978,7 +978,7 @@ public function writeToMemory(): string $ctype = \FFI::arrayType(\FFI::type("size_t"), [1]); $p_size = \FFI::new($ctype); - $pointer = FFI::vips()-> + $pointer = Config::vips()-> vips_image_write_to_memory($this->pointer, $p_size); if ($pointer == null) { throw new Exception(); @@ -987,7 +987,7 @@ public function writeToMemory(): string // string() takes a copy $result = \FFI::string($pointer, $p_size[0]); - FFI::glib()->g_free($pointer); + Config::glib()->g_free($pointer); return $result; } @@ -1020,7 +1020,7 @@ public function writeToArray(): array $ctype = \FFI::arrayType(\FFI::type("size_t"), [1]); $p_size = \FFI::new($ctype); - $pointer = FFI::vips()-> + $pointer = Config::vips()-> vips_image_write_to_memory($this->pointer, $p_size); if ($pointer == null) { throw new Exception(); @@ -1028,7 +1028,7 @@ public function writeToArray(): array // wrap pointer up as a C array of the right type $n = $this->width * $this->height * $this->bands; - $type_name = FFI::ftypes($this->format); + $type_name = Config::ftypes($this->format); $ctype = \FFI::arrayType(\FFI::type($type_name), [$n]); $array = \FFI::cast($ctype, $pointer); @@ -1039,7 +1039,7 @@ public function writeToArray(): array } // the vips result is not PHP memory, so we must free it - FFI::glib()->g_free($pointer); + Config::glib()->g_free($pointer); return $result; } @@ -1060,7 +1060,7 @@ public function writeToArray(): array */ public function copyMemory(): Image { - $pointer = FFI::vips()->vips_image_copy_memory($this->pointer); + $pointer = Config::vips()->vips_image_copy_memory($this->pointer); if ($pointer == null) { throw new Exception(); } @@ -1125,7 +1125,7 @@ public function __isset(string $name): bool public function get(string $name) { $gvalue = new GValue(); - if (FFI::vips()-> + if (Config::vips()-> vips_image_get($this->pointer, $name, $gvalue->pointer) != 0) { throw new Exception(); } @@ -1144,7 +1144,7 @@ public function get(string $name) */ public function getType(string $name): int { - return FFI::vips()->vips_image_get_typeof($this->pointer, $name); + return Config::vips()->vips_image_get_typeof($this->pointer, $name); } /** @@ -1182,27 +1182,27 @@ public function set(string $name, $value): void if ($gtype == 0) { if (is_array($value)) { if (is_int($value[0])) { - $gtype = FFI::gtypes("VipsArrayInt"); + $gtype = Config::gtypes("VipsArrayInt"); } elseif (is_float($value[0])) { - $gtype = FFI::gtypes("VipsArrayDouble"); + $gtype = Config::gtypes("VipsArrayDouble"); } else { - $gtype = FFI::gtypes("VipsArrayImage"); + $gtype = Config::gtypes("VipsArrayImage"); } } elseif (is_int($value)) { - $gtype = FFI::gtypes("gint"); + $gtype = Config::gtypes("gint"); } elseif (is_float($value)) { - $gtype = FFI::gtypes("gdouble"); + $gtype = Config::gtypes("gdouble"); } elseif (is_string($value)) { - $gtype = FFI::gtypes("VipsRefString"); + $gtype = Config::gtypes("VipsRefString"); } else { - $gtype = FFI::gtypes("VipsImage"); + $gtype = Config::gtypes("VipsImage"); } } $gvalue->setType($gtype); $gvalue->set($value); - FFI::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); + Config::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); } /** @@ -1227,7 +1227,7 @@ public function setType($type, string $name, $value): void $gvalue = new GValue(); $gvalue->setType($type); $gvalue->set($value); - FFI::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); + Config::vips()->vips_image_set($this->pointer, $name, $gvalue->pointer); } /** @@ -1241,7 +1241,7 @@ public function setType($type, string $name, $value): void */ public function remove(string $name): void { - if (!FFI::vips()->vips_image_remove($this->pointer, $name)) { + if (!Config::vips()->vips_image_remove($this->pointer, $name)) { throw new Exception(); } } @@ -1920,7 +1920,7 @@ public function composite($other, $mode, array $options = []): Image # composite takes an arrayint, but it's really an array of blend modes # gvalue doesn't know this, so we must do name -> enum value mapping $mode = array_map(function ($x) { - return GValue::toEnum(FFI::gtypes("VipsBlendMode"), $x); + return GValue::toEnum(Config::gtypes("VipsBlendMode"), $x); }, $mode); return VipsOperation::call( diff --git a/src/Interpolate.php b/src/Interpolate.php index cb5eee5a..9276b901 100644 --- a/src/Interpolate.php +++ b/src/Interpolate.php @@ -62,7 +62,7 @@ class Interpolate extends VipsObject public function __construct(\FFI\CData $pointer) { - $this->pointer = \FFI::cast(FFI::ctypes("VipsInterpolate"), $pointer); + $this->pointer = \FFI::cast(Config::ctypes("VipsInterpolate"), $pointer); parent::__construct($pointer); } @@ -85,7 +85,7 @@ public function __construct(\FFI\CData $pointer) */ public static function newFromName(string $name): Interpolate { - $pointer = FFI::vips()->vips_interpolate_new($name); + $pointer = Config::vips()->vips_interpolate_new($name); if ($pointer == null) { throw new Exception(); } diff --git a/src/Introspect.php b/src/Introspect.php index 000b8f06..61a711d6 100644 --- a/src/Introspect.php +++ b/src/Introspect.php @@ -101,11 +101,11 @@ public function __construct($operation_name) $this->description = $operation->getDescription(); - $p_names = FFI::vips()->new("char**[1]"); - $p_flags = FFI::vips()->new("int*[1]"); - $p_n_args = FFI::vips()->new("int[1]"); - $result = FFI::vips()->vips_object_get_args( - \FFI::cast(FFI::ctypes("VipsObject"), $operation->pointer), + $p_names = Config::vips()->new("char**[1]"); + $p_flags = Config::vips()->new("int*[1]"); + $p_n_args = Config::vips()->new("int[1]"); + $result = Config::vips()->vips_object_get_args( + \FFI::cast(Config::ctypes("VipsObject"), $operation->pointer), $p_names, $p_flags, $p_n_args @@ -183,7 +183,7 @@ public function __construct($operation_name) $this->member_this = ""; foreach ($this->required_input as $name) { $type = $this->arguments[$name]["type"]; - if ($type == FFI::gtypes("VipsImage")) { + if ($type == Config::gtypes("VipsImage")) { $this->member_this = $name; break; } @@ -208,7 +208,7 @@ public function __toString(): string $flags = $details["flags"]; $blurb = $details["blurb"]; $type = $details["type"]; - $typeName = FFI::gobject()->g_type_name($type); + $typeName = Config::gobject()->g_type_name($type); $result .= " $name:\n"; diff --git a/src/Utils.php b/src/Utils.php index 31e26fc8..808af390 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -92,23 +92,23 @@ public static function errorLog(string $message, ?\Exception $exception = null): */ public static function typeFromName(string $name): int { - return FFI::gobject()->g_type_from_name($name); + return Config::gobject()->g_type_from_name($name); } public static function filenameGetFilename(string $name): string { - $pointer = FFI::vips()->vips_filename_get_filename($name); + $pointer = Config::vips()->vips_filename_get_filename($name); $filename = \FFI::string($pointer); - FFI::glib()->g_free($pointer); + Config::glib()->g_free($pointer); return $filename; } public static function filenameGetOptions(string $name): string { - $pointer = FFI::vips()->vips_filename_get_options($name); + $pointer = Config::vips()->vips_filename_get_options($name); $options = \FFI::string($pointer); - FFI::glib()->g_free($pointer); + Config::glib()->g_free($pointer); return $options; } diff --git a/src/VipsObject.php b/src/VipsObject.php index 639c8ea7..22f5c3b3 100644 --- a/src/VipsObject.php +++ b/src/VipsObject.php @@ -68,8 +68,8 @@ abstract class VipsObject extends GObject public function __construct(\FFI\CData $pointer) { - $this->pointer = \FFI::cast(FFI::ctypes("VipsObject"), $pointer); - $this->gObject = \FFI::cast(FFI::ctypes("GObject"), $pointer); + $this->pointer = \FFI::cast(Config::ctypes("VipsObject"), $pointer); + $this->gObject = \FFI::cast(Config::ctypes("GObject"), $pointer); parent::__construct($pointer); } @@ -77,12 +77,12 @@ public function __construct(\FFI\CData $pointer) // print a table of all active vipsobjects ... handy for debugging public static function printAll(): void { - FFI::vips()->vips_object_print_all(); + Config::vips()->vips_object_print_all(); } public function getDescription(): string { - return FFI::vips()->vips_object_get_description($this->pointer); + return Config::vips()->vips_object_get_description($this->pointer); } // get the pspec for a property @@ -91,10 +91,10 @@ public function getDescription(): string // FIXME add a cache for this thing public function getPspec(string $name): ?\FFI\CData { - $pspec = FFI::gobject()->new("GParamSpec*[1]"); - $argument_class = FFI::vips()->new("VipsArgumentClass*[1]"); - $argument_instance = FFI::vips()->new("VipsArgumentInstance*[1]"); - $result = FFI::vips()->vips_object_get_argument( + $pspec = Config::gobject()->new("GParamSpec*[1]"); + $argument_class = Config::vips()->new("VipsArgumentClass*[1]"); + $argument_instance = Config::vips()->new("VipsArgumentInstance*[1]"); + $result = Config::vips()->vips_object_get_argument( $this->pointer, $name, $pspec, @@ -116,7 +116,7 @@ public function getType(string $name): int $pspec = $this->getPspec($name); if (\FFI::isNull($pspec)) { # need to clear any error, this is horrible - FFI::vips()->vips_error_clear(); + Config::vips()->vips_error_clear(); return 0; } else { return $pspec->value_type; @@ -126,13 +126,13 @@ public function getType(string $name): int public function getBlurb(string $name): string { $pspec = $this->getPspec($name); - return FFI::gobject()->g_param_spec_get_blurb($pspec); + return Config::gobject()->g_param_spec_get_blurb($pspec); } public function getArgumentDescription(string $name): string { $pspec = $this->getPspec($name); - return FFI::gobject()->g_param_spec_get_description($pspec); + return Config::gobject()->g_param_spec_get_description($pspec); } /** @@ -143,7 +143,7 @@ public function get(string $name) $gvalue = new GValue(); $gvalue->setType($this->getType($name)); - FFI::gobject()-> + Config::gobject()-> g_object_get_property($this->gObject, $name, $gvalue->pointer); $value = $gvalue->get(); @@ -163,13 +163,13 @@ public function set(string $name, $value): void $gvalue->setType($this->getType($name)); $gvalue->set($value); - FFI::gobject()-> + Config::gobject()-> g_object_set_property($this->gObject, $name, $gvalue->pointer); } public function setString(string $string_options): bool { - $result = FFI::vips()-> + $result = Config::vips()-> vips_object_set_from_string($this->pointer, $string_options); return $result == 0; @@ -177,7 +177,7 @@ public function setString(string $string_options): bool public function unrefOutputs(): void { - FFI::vips()->vips_object_unref_outputs($this->pointer); + Config::vips()->vips_object_unref_outputs($this->pointer); } } diff --git a/src/VipsOperation.php b/src/VipsOperation.php index e9b12e9f..67266e9c 100644 --- a/src/VipsOperation.php +++ b/src/VipsOperation.php @@ -66,8 +66,8 @@ class VipsOperation extends VipsObject public function __construct(\FFI\CData $pointer) { - $this->pointer = FFI::vips()-> - cast(FFI::ctypes("VipsOperation"), $pointer); + $this->pointer = Config::vips()-> + cast(Config::ctypes("VipsOperation"), $pointer); parent::__construct($pointer); } @@ -77,7 +77,7 @@ public function __construct(\FFI\CData $pointer) */ public static function newFromName($name): VipsOperation { - $pointer = FFI::vips()->vips_operation_new($name); + $pointer = Config::vips()->vips_operation_new($name); if ($pointer == null) { throw new Exception(); } @@ -91,9 +91,9 @@ public function setMatch($name, $match_image, $value): void $gtype = $this->introspect->arguments[$name]["type"]; if ($match_image != null) { - if ($gtype == FFI::gtypes("VipsImage")) { + if ($gtype == Config::gtypes("VipsImage")) { $value = $match_image->imageize($value); - } elseif ($gtype == FFI::gtypes("VipsArrayImage") && + } elseif ($gtype == Config::gtypes("VipsArrayImage") && is_array($value)) { $new_value = []; foreach ($value as $x) { @@ -155,7 +155,7 @@ private static function findInside($predicate, $x) private static function isImagePointer($value): bool { return $value instanceof \FFI\CData && - \FFI::typeof($value) == FFI::ctypes("VipsImage"); + \FFI::typeof($value) == Config::ctypes("VipsImage"); } /** @@ -301,7 +301,7 @@ public static function callBase( /* Build the operation */ - $pointer = FFI::vips()-> + $pointer = Config::vips()-> vips_cache_operation_build($operation->pointer); if ($pointer == null) { $operation->unrefOutputs(); From 2465143e82c832ff08ff63776885523c97b4a2c7 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 2 Jul 2022 13:18:52 +0200 Subject: [PATCH 6/6] Ensure exception is thrown with the error buffer --- src/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Config.php b/src/Config.php index 8e9d4ff3..5a9294fc 100644 --- a/src/Config.php +++ b/src/Config.php @@ -311,7 +311,7 @@ private static function init(): void $result = $vips->vips_init(""); if ($result != 0) { - throw new Exception(); + throw new Exception("libvips error: " . $vips->vips_error_buffer()); } Utils::debugLog("init", ["vips_init" => $result]);