Open SteveHawk opened 11 months ago
Hi @SteveHawk,
pyvips works with any libvips version -- it introspects the libvips binary and exposes the API it finds. pyvips v2.2.1 should work fine with 8.15 and 8.16.
Yes, we've talked about including a binary, and you're right it'd be pretty simple. Someone just needs to do the work :( pyvips still uses the prehistoric setup.py
, so really the whole installer needs redoing and updating.
One slight issue is that pyvips supports ABI (portable but slow and leaky) and API (fast and stable) modes, but with a prebuilt libvips binary we'd be stuck in ABI mode. Maybe the benefits are worth it.
Using pyvips without needing to install many dozens of system dependencies is a lifesaver in deployment.
You should just need the libvips-dev
package (or equivalent), I think. python-dev
as well I guess, and a C compiler.
pyvips works with any libvips version
Oh that's weird. I asked because I tried to use pyvips v2.2.1 with 8.15, but didn't work and throw errors immediately (seems to be related to glib). The master branch works though, that's why I thought v2.2.1 is not compatible with 8.15.
Here's how I did it:
python:3.11-slim-bullseye
docker container, do apt update; apt install pkg-config build-essential
/root/lib/
, insert proper pkgconfig .pc files and run
export LD_LIBRARY_PATH=/root/lib/libvips-8.15.0-linux-x64/lib/
export PKG_CONFIG_PATH=/root/lib/libvips-8.15.0-linux-x64/lib/pkgconfig/
pip install pyvips
, then pip show
reports: Summary: binding for the libvips image processing library, API mode
After setting up the environment, enter python shell and run:
>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> from pyvips import Image
DEBUG:pyvips:Binary module load failed: /usr/local/lib/python3.11/site-packages/_libvips.abi3.so: undefined symbol: vips_path_mode7
DEBUG:pyvips:Falling back to ABI mode
DEBUG:pyvips:Loaded lib <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7fa8935a3550>
DEBUG:pyvips:Loaded lib <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7fa8936f3710>
DEBUG:pyvips:Inited libvips
>>> Image.new_from_file("/root/lib/test.png")
DEBUG:pyvips.voperation:VipsOperation.call: operation_name = VipsForeignLoadPngFile
DEBUG:pyvips.voperation:VipsOperation.call: match_image = None
DEBUG:pyvips.vobject:VipsObject.set: name = filename, value = /root/lib/test.png
(process:875): GLib-CRITICAL **: 09:49:38.370: g_datalist_id_set_data_full: assertion 'key_id > 0' failed
(process:875): GLib-GObject-CRITICAL **: 09:49:38.370: g_param_spec_pool_lookup: assertion 'pool != NULL' failed
(process:875): GLib-GObject-WARNING **: 09:49:38.370: g_object_set_is_valid_property: object class '(null)' has no property named 'filename'
Segmentation fault (core dumped)
That crashed. I also tried thumbnail_buffer
, with no luck:
>>> Image.thumbnail_buffer(b"test", 128)
DEBUG:pyvips.voperation:VipsOperation.call: operation_name = thumbnail_buffer
DEBUG:pyvips.voperation:VipsOperation.call: match_image = None
DEBUG:pyvips.vobject:VipsObject.set: name = buffer, value = b'test'
DEBUG:pyvips.error:Error unsupported gtype for set NULL, fundamental GBoxed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.11/site-packages/pyvips/vimage.py", line 256, in call_function
return pyvips.Operation.call(name, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyvips/voperation.py", line 282, in call
op.set(name, intro.details[name]['flags'], match_image, value)
File "/usr/local/lib/python3.11/site-packages/pyvips/voperation.py", line 216, in set
super(Operation, self).set(name, value)
File "/usr/local/lib/python3.11/site-packages/pyvips/vobject.py", line 122, in set
gv.set(value)
File "/usr/local/lib/python3.11/site-packages/pyvips/gvalue.py", line 242, in set
raise Error('unsupported gtype for set {0}, fundamental {1}'.
pyvips.error.Error: unsupported gtype for set NULL, fundamental GBoxed
When I uninstall the pypi version and install the master branch, pip show still reports API mode, and everything works as expected:
>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> from pyvips import Image
DEBUG:pyvips:Loaded binary module _libvips
DEBUG:pyvips:Module generated for libvips 8.15
DEBUG:pyvips:Linked to libvips 8.15
DEBUG:pyvips:Inited libvips
>>> Image.new_from_file("/root/lib/test.png")
DEBUG:pyvips.voperation:VipsOperation.call: operation_name = VipsForeignLoadPngFile
DEBUG:pyvips.voperation:VipsOperation.call: match_image = None
DEBUG:pyvips.vobject:VipsObject.set: name = filename, value = /root/lib/test.png
DEBUG:pyvips.vobject:VipsObject.get: name = out
DEBUG:pyvips.vobject:VipsObject.get: name = interpretation
DEBUG:pyvips.vobject:VipsObject.get: name = width
DEBUG:pyvips.vobject:VipsObject.get: name = height
DEBUG:pyvips.vobject:VipsObject.get: name = format
DEBUG:pyvips.vobject:VipsObject.get: name = bands
DEBUG:pyvips.vobject:VipsObject.get: name = interpretation
DEBUG:pyvips.voperation:VipsOperation.call: result = <pyvips.Image 1240x1754 uchar, 1 bands, b-w>
DEBUG:pyvips.vobject:VipsObject.get: name = interpretation
DEBUG:pyvips.vobject:VipsObject.get: name = width
DEBUG:pyvips.vobject:VipsObject.get: name = height
DEBUG:pyvips.vobject:VipsObject.get: name = format
DEBUG:pyvips.vobject:VipsObject.get: name = bands
DEBUG:pyvips.vobject:VipsObject.get: name = interpretation
<pyvips.Image 1240x1754 uchar, 1 bands, b-w>
>>> Image.thumbnail_buffer(b"test", 128)
DEBUG:pyvips.voperation:VipsOperation.call: operation_name = thumbnail_buffer
DEBUG:pyvips.voperation:VipsOperation.call: match_image = None
DEBUG:pyvips.vobject:VipsObject.set: name = buffer, value = b'test'
DEBUG:pyvips.vobject:VipsObject.set: name = width, value = 128
INFO:pyvips:VIPS: thumbnailing 4 bytes of data
DEBUG:pyvips.error:Error unable to call thumbnail_buffer VipsForeignLoad: buffer is not in a known format
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.11/site-packages/pyvips/vimage.py", line 256, in call_function
return pyvips.Operation.call(name, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyvips/voperation.py", line 305, in call
raise Error('unable to call {0}'.format(operation_name))
pyvips.error.Error: unable to call thumbnail_buffer
VipsForeignLoad: buffer is not in a known format
but with a prebuilt libvips binary we'd be stuck in ABI mode
I installed pyvips with the prebuilt libvips-dev from kleisauke/libvips-packaging (with proper LD_LIBRARY_PATH and PKG_CONFIG_PATH set) and pip show
reports the installation is using API mode. So I guess this might not be true?
You should just need the libvips-dev package
Actually the package manager will download a LOT of dependencies (over 100 using conda, over 200! using apt, including libjpg, libpng etc.), taking up more disk spaces than statically linked libvips-dev package, and also taking more time to download and install. More importantly, package managers like apt usually don't come with newer versions of these libraries, so that would be another down side.
Huh strange, it ought to work. I'll try to make a dockerfile for this.
Actually the package manager will download a LOT of dependencies (over 100 using conda, over 200! using apt, including libjpg, libpng etc.),
Did you use --no-install-recommends
? The deb package recommends the libvips GUI, and that in turn pulls in most of X11 and gtk2 (!!).
I installed pyvips with the prebuilt libvips-dev from kleisauke/libvips-packaging (with proper LD_LIBRARY_PATH and PKG_CONFIG_PATH set) and pip show reports the installation is using API mode. So I guess this might not be true?
Ah if you use the libvips-dev precompiled binary it'd work, yes. But that's probably no smaller than just installing libvips-dev
from your package manager, and will be annoying to maintain.
I updated this dockerfile:
https://github.com/jcupitt/docker-builds/blob/master/pyvips-alpine/Dockerfile
And it seems to work fine. That's libvips 8.15.1 and pyvips 2.2.1 on alpine.
I've not tried with those precompiled libvips binaries. If you need a newer libvips than is in your package manager, I'd expect building from source yourself to be much more likely to work, should be smaller (it can use the platform libjpeg etc.) and can be deployed pretty easily with docker or whatever.
Did you use
--no-install-recommends
Yes i did, in a python:3.11-slim-bullseye
docker, run apt install --no-install-recommends libvips-dev
resulted in:
1 upgraded, 260 newly installed, 0 to remove and 15 not upgraded.
Need to get 117 MB of archives.
After this operation, 475 MB of additional disk space will be used.
Without the --no-install-recommends
flag that would be even more madness:
1 upgraded, 419 newly installed, 0 to remove and 15 not upgraded.
Need to get 260 MB of archives.
After this operation, 1002 MB of additional disk space will be used.
But that's probably no smaller than just installing libvips-dev from your package manager
The precompiled libvips-dev package is a 8MB tarball and only 26MB uncompressed on disk. I believe it only includes necessary .so files, so it's actually much smaller in size ;)
The prebuilt binaries available at https://github.com/kleisauke/libvips-packaging would only work with pyvips' API mode since GLib is statically-linked.
Here's a Dockerfile to reproduce this issue:
The salient part of the error log is:
DEBUG:pyvips:Binary module load failed: /root/.local/lib/python3.12/site-packages/_libvips.abi3.so: undefined symbol: vips_path_mode7
DEBUG:pyvips:Falling back to ABI mode
OSError: cannot load library 'libgobject-2.0.so.0': libgobject-2.0.so.0: cannot open shared object file: No such file or directory. Additionally, ctypes.util.find_library() did not manage to locate a library called 'libgobject-2.0.so.0'
So, it tries to fallback to ABI mode since the deprecated vips_path_mode7
symbol is not available, this was fixed with commit https://github.com/libvips/pyvips/commit/350a4597ee06d846446fe9b847dde1952112e2ce.
Ah that had popped out of my brain, thanks Kleis.
Then I agree, a pyvips 2.2.2 would be useful. I'll do it now.
We might have v2.2.2, any testing very welcome.
Great! I just opened PR https://github.com/libvips/pyvips/pull/444 to support this in ABI mode.
FWIW, looks like v2.2.2 was miss-tagged as v2.2.0: https://github.com/libvips/pyvips/releases/tag/v2.2.0
pyvips still uses the prehistoric
setup.py
, so really the whole installer needs redoing and updating.
I'll have a look at this somewhere tomorrow.
FWIW, looks like v2.2.2 was miss-tagged as v2.2.0:
:facepalm: fixed.
We might have v2.2.2, any testing very welcome.
Nice! It works well on my codes so far, will do more tests next week. Thanks!
pyvips still uses the prehistoric
setup.py
, so really the whole installer needs redoing and updating.
PR #445 should fix this.
Hi, I'm just wondering, is there going to be a new release of pyvips soon?
libvips 8.15 introduces highway for simd which is exciting, however current pyvips v2.2.1 on PyPI only supports libvips up to 8.13. Master branch of pyvips does work with 8.15 in my setup, but it would be really nice to have a stable version to lock in.
Oh and, will it be possible for pyvips to ship with prebuilt libvips in the future? As my understanding, net-vips and sharp has been doing this for years, I tried the prebuilt package from kleisauke/libvips-packaging with pyvips and it works like a charm. Using pyvips without needing to install many dozens of system dependencies is a lifesaver in deployment.
Thanks!