diff --git a/CHANGELOG.md b/CHANGELOG.md index 950805b2..f2d86ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to `:vips` will be documented in this file. ## master - improve FFI startup [West14] +- revise example use of composer [jcupitt] ## 2.1.1 - 2022-11-13 diff --git a/examples/addconst.php b/examples/addconst.php index 971d757b..e9d330ef 100755 --- a/examples/addconst.php +++ b/examples/addconst.php @@ -1,7 +1,7 @@ #!/usr/bin/env php Vips\Access::SEQUENTIAL]); $im = $im->crop(100, 100, $im->width - 200, $im->height - 200); diff --git a/examples/class.php b/examples/class.php index c98b72ae..47c5b3b1 100755 --- a/examples/class.php +++ b/examples/class.php @@ -1,7 +1,7 @@ #!/usr/bin/env php setProgress(true); + +$image->signalConnect("preeval", function($image, $progress) { + echo "preeval:\n"; +}); +$image->signalConnect("eval", function($image, $progress) { + echo "eval: $progress->percent % complete\r"; +}); + +$image->signalConnect("posteval", function($image, $progress) { + echo "\nposteval:\n"; +}); + +// trigger evaluation +$image->avg(); + +$image = null; + +Vips\FFI::shutDown(); diff --git a/examples/sig.php b/examples/sig.php index 26608675..8b295c7a 100755 --- a/examples/sig.php +++ b/examples/sig.php @@ -1,7 +1,7 @@ #!/usr/bin/env php Vips\Access::SEQUENTIAL]); /** diff --git a/examples/streaming-bench.php b/examples/streaming-bench.php old mode 100644 new mode 100755 diff --git a/examples/streaming-custom.php b/examples/streaming-custom.php new file mode 100755 index 00000000..4a372c32 --- /dev/null +++ b/examples/streaming-custom.php @@ -0,0 +1,55 @@ +#!/usr/bin/env php +onRead(function ($bufferLength) use (&$in_file) { + // return 0 for EOF, -ve for read error + return fread($in_file, $bufferLength); +}); +// seek is optional +$source->onSeek(function ($offset, $whence) use (&$in_file) { + if (fseek($in_file, $offset, $whence)) { + return -1; + } + + return ftell($in_file); +}); + +// open for write and read ... formats like tiff need to be able to seek back +// in the output and update bytes later +$out_file = fopen($argv[2], 'w+'); +$target = new Vips\VipsTargetCustom(); +$target->onWrite(function ($buffer) use (&$out_file) { + $result = fwrite($out_file, $buffer); + if ($result === false) { + // IO error + return -1; + } + else + return $result; +}); +// read and seek are optional +$target->onSeek(function ($offset, $whence) use (&$out_file) { + if (fseek($out_file, $offset, $whence)) { + return -1; + } + + return ftell($out_file); +}); +$target->onRead(function ($bufferLength) use (&$out_file) { + return fread($out_file, $bufferLength); +}); + +$image = Vips\Image::newFromSource($source); +$image->writeToTarget($target, $argv[3]); diff --git a/examples/streaming.php b/examples/streaming.php old mode 100644 new mode 100755 diff --git a/examples/vips-magick.php b/examples/vips-magick.php index 5d355c6a..42e66917 100755 --- a/examples/vips-magick.php +++ b/examples/vips-magick.php @@ -1,10 +1,15 @@ #!/usr/bin/env php "library load failed", "exception" => $e]); + Utils::debugLog("init", [ + "msg" => "library load failed", + "exception" => $e->getMessage() + ]); } } @@ -805,6 +808,7 @@ private static function init(): void "GClosure" => self::$gobject->type("GClosure"), "GParamSpec" => self::$gobject->type("GParamSpec*"), "VipsObject" => self::$vips->type("VipsObject*"), + "VipsProgress" => self::$vips->type("VipsProgress*"), "VipsOperation" => self::$vips->type("VipsOperation*"), "VipsImage" => self::$vips->type("VipsImage*"), "VipsInterpolate" => self::$vips->type("VipsInterpolate*"), diff --git a/src/GObject.php b/src/GObject.php index 8a747fc1..f2bbaab5 100644 --- a/src/GObject.php +++ b/src/GObject.php @@ -99,7 +99,10 @@ public function unref(): void /** * Connect to a signal on this object. - * The callback will be triggered every time this signal is issued on this instance. + * + * The callback will be triggered every time this signal is issued on this + * instance. + * * @throws Exception */ public function signalConnect(string $name, Closure $callback): void @@ -109,12 +112,14 @@ public function signalConnect(string $name, Closure $callback): void throw new Exception("unsupported signal $name"); } - $gc = FFI::gobject()->g_closure_new_simple(\FFI::sizeof(FFI::ctypes('GClosure')), null); + $sizeof = \FFI::sizeof(FFI::ctypes('GClosure')); + $gc = FFI::gobject()->g_closure_new_simple($sizeof, null); $gc->marshal = $marshaler; FFI::gobject()->g_signal_connect_closure($this->pointer, $name, $gc, 0); } - private static function getMarshaler(string $name, Closure $callback): ?Closure + private static function getMarshaler(string $name, + Closure $callback): ?Closure { switch ($name) { case 'preeval': @@ -130,20 +135,20 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ) use (&$callback) { assert($numberOfParams === 3); /** - * Signature: void(VipsImage* image, void* progress, void* handle) + * void(VipsImage*, VipsProgress*, void*) */ - $vi = \FFI::cast( - FFI::ctypes('GObject'), - FFI::gobject()->g_value_get_pointer(\FFI::addr($params[0])) - ); - FFI::gobject()->g_object_ref($vi); - $image = new Image($vi); - $pr = \FFI::cast( - FFI::ctypes('VipsProgress'), - FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1])) - ); - $callback($image, $pr); + $pointer = FFI::gobject()-> + g_value_get_object(\FFI::addr($params[0])); + FFI::gobject()->g_object_ref($pointer); + $image = new Image($pointer); + + $pointer = FFI::gobject()-> + g_value_get_pointer(\FFI::addr($params[1])); + $progress = \FFI::cast(FFI::ctypes('VipsProgress'), $pointer); + + $callback($image, $progress); }; + case 'read': if (FFI::atLeast(8, 9)) { return static function ( @@ -155,23 +160,31 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ?CData $data ) use (&$callback): void { assert($numberOfParams === 4); - /* - * Signature: gint64(VipsSourceCustom* source, void* buffer, gint64 length, void* handle) + /** + * gint64(VipsSourceCustom*, + * void* buffer, gint64 length, void* handle) */ - $bufferLength = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[2])); + $bufferLength = (int)FFI::gobject()-> + g_value_get_int64(\FFI::addr($params[2])); $returnBuffer = $callback($bufferLength); - $returnBufferLength = 0; + $returnBufferLength = + $returnBuffer !== null ? strlen($returnBuffer) : 0; + $returnBufferLength = min($returnBufferLength, + $bufferLength); + $bufferPointer = FFI::gobject()-> + g_value_get_pointer(\FFI::addr($params[1])); + \FFI::memcpy($bufferPointer, + $returnBuffer, + $returnBufferLength); - if ($returnBuffer !== null) { - $returnBufferLength = strlen($returnBuffer); - $bufferPointer = FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1])); - \FFI::memcpy($bufferPointer, $returnBuffer, $returnBufferLength); - } - FFI::gobject()->g_value_set_int64($returnValue, $returnBufferLength); + FFI::gobject()-> + g_value_set_int64($returnValue, + $returnBufferLength); }; } return null; + case 'seek': if (FFI::atLeast(8, 9)) { return static function ( @@ -183,16 +196,22 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ?CData $data ) use (&$callback): void { assert($numberOfParams === 4); - /* - * Signature: gint64(VipsSourceCustom* source, gint64 offset, int whence, void* handle) + /** + * gint64(VipsSourceCustom*, + * gint64 offset, int whence, void* handle) */ - $offset = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[1])); - $whence = (int)FFI::gobject()->g_value_get_int(\FFI::addr($params[2])); - FFI::gobject()->g_value_set_int64($returnValue, $callback($offset, $whence)); + $offset = (int)FFI::gobject()-> + g_value_get_int64(\FFI::addr($params[1])); + $whence = (int)FFI::gobject()-> + g_value_get_int(\FFI::addr($params[2])); + $newOffset = $callback($offset, $whence); + FFI::gobject()-> + g_value_set_int64($returnValue, $newOffset); }; } return null; + case 'write': if (FFI::atLeast(8, 9)) { return static function ( @@ -204,18 +223,24 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ?CData $data ) use (&$callback): void { assert($numberOfParams === 4); - /* - * Signature: gint64(VipsTargetCustom* target, void* buffer, gint64 length, void* handle) + /** + * gint64(VipsTargetCustom*, + * void* buffer, gint64 length, void* handle) */ - $bufferPointer = FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1])); - $bufferLength = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[2])); + $bufferPointer = FFI::gobject()-> + g_value_get_pointer(\FFI::addr($params[1])); + $bufferLength = (int)FFI::gobject()-> + g_value_get_int64(\FFI::addr($params[2])); $buffer = \FFI::string($bufferPointer, $bufferLength); $returnBufferLength = $callback($buffer); - FFI::gobject()->g_value_set_int64($returnValue, $returnBufferLength); + FFI::gobject()-> + g_value_set_int64($returnValue, + $returnBufferLength); }; } return null; + case 'finish': if (FFI::atLeast(8, 9)) { return static function ( @@ -228,13 +253,14 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ) use (&$callback): void { assert($numberOfParams === 2); /** - * Signature: void(VipsTargetCustom* target, void* handle) + * void(VipsTargetCustom*, void* handle) */ $callback(); }; } return null; + case 'end': if (FFI::atLeast(8, 13)) { return static function ( @@ -247,13 +273,15 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure ) use (&$callback): void { assert($numberOfParams === 2); /** - * Signature: int(VipsTargetCustom* target, void* handle) + * int(VipsTargetCustom*, void* handle) */ - FFI::gobject()->g_value_set_int($returnValue, $callback()); + $result = $callback(); + FFI::gobject()->g_value_set_int($returnValue, $result); }; } return null; + default: return null; } diff --git a/src/Image.php b/src/Image.php index a7b53e19..b037a57b 100644 --- a/src/Image.php +++ b/src/Image.php @@ -1296,6 +1296,20 @@ public function remove(string $name): void } } + /** + * Enable progress reporting on an image. + * + * When progress reporting is enabled, evaluation of the most downstream + * image from this image will report progress using the ::preeval, ::eval, + * and ::posteval signals. + * + * @param bool $progress True to enable progress reporting. + */ + public function setProgress($progress): void + { + FFI::vips()->vips_image_set_progress($this->pointer, $progress); + } + /** * Makes a string-ified version of the Image. * diff --git a/tests/images/target.jpg b/tests/images/target.jpg new file mode 100644 index 00000000..b77ec8eb Binary files /dev/null and b/tests/images/target.jpg differ