Source: wand
Version: 0.7.1-1
Severity: normal
Tags: patch upstream
Dear Maintainer,
I discovered an upstream bug[1] which is causing migration issues on
Ubuntu[2].
Essentially, if the OS and Python file cursors ever get desynced, then
wand will pass the incorrect offset to ImageMagick. This was caused by
the move from RawIOBase to IOBase in the fix for upstream issue 675[3].
This problem can be reproduced on Debian by running a Python script
which first performs a buffered read and then seeks back to the
beginning:
```
from wand.image import Image
GIF = (b'GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00!\xf9'
b'\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;')
open("test.gif", "wb").write(GIF)
f = open("test.gif", "rb")
f.read(16)
f.seek(0)
Image(file=f)
```
Running this script on Debian will produce the error:
```
$ python3 test.py
Traceback (most recent call last):
File "/root/wand/test.py", line 10, in <module>
Image(file=f)
~~~~~^^^^^^^^
File "/usr/lib/python3/dist-packages/wand/image.py", line 9632, in
__init__
self.read(file=file)
~~~~~~~~~^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/wand/image.py", line 10488, in read
self.raise_exception()
~~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib/python3/dist-packages/wand/resource.py", line 211, in
raise_exception
raise e
wand.exceptions.MissingDelegateError: no decode delegate for this image
format `/tmp/magick-dnTm7mNPKK3qbsxOo1cdKU1ziBT5zdc8' @
error/constitute.c/ReadImage/755
```
I have added a patch which fixes this issue. I have also forwarded the
fix upstream[4], so this delta will eventually be dropped.
[1]: https://github.com/emcconville/wand/issues/688
[2]: https://bugs.launchpad.net/ubuntu/+source/wand/+bug/2158013
[3]: https://github.com/emcconville/wand/issues/675
[4]: https://github.com/emcconville/wand/pull/689
Description: Sync file offsets before reading
A buffered Python file object can advance both the OS and the Python file
cursor offsets. seek() can rewind the Python cursor without moving the OS
cursor. wand cannot handle this situation and will pass the incorrect offset to
ImageMagick.
.
This patch fixes this situation by forcing the OS cursor to match the object's
logical position.
.
Non-seekable streams return OSError and closed objects return ValueError when
attempting to lseek; in these cases the offset is left alone.
Author: Max Gilmour <[email protected]>
Bug: https://github.com/emcconville/wand/issues/688
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/wand/+bug/2158013
Forwarded: https://github.com/emcconville/wand/pull/689
Last-Update: 2026-06-23
---
--- a/wand/image.py
+++ b/wand/image.py
@@ -13,6 +13,7 @@
import ctypes
import functools
import numbers
+import os
import weakref
from collections import abc
from io import IOBase
@@ -9879,6 +9880,12 @@
callable(getattr(file, 'fileno', None)),
hasattr(file, 'mode'))
if all(is_fd):
+ try:
+ # Resync the fd offset before reading
+ os.lseek(file.fileno(), file.tell(), os.SEEK_SET)
+ except (OSError, ValueError):
+ # Do nothing if stream isn't seekable
+ pass
fd = libc.fdopen(file.fileno(), binary(file.mode))
r = library.MagickPingImageFile(instance.wand, fd)
elif not callable(getattr(file, 'read', None)):
@@ -10465,6 +10472,12 @@
callable(getattr(file, 'fileno', None)),
hasattr(file, 'mode'))
if all(is_fd):
+ try:
+ # Resync the fd offset before reading
+ os.lseek(file.fileno(), file.tell(), os.SEEK_SET)
+ except (OSError, ValueError):
+ # Do nothing if stream isn't seekable
+ pass
fd = libc.fdopen(file.fileno(), binary(file.mode))
r = library.MagickReadImageFile(self.wand, fd)
elif not callable(getattr(file, 'read', None)):