emcconville / wand

The ctypes-based simple ImageMagick binding for Python

Home Page:http://docs.wand-py.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

export_pixels(storage='long') crashes on Windows

roelandschoukens opened this issue · comments

Calling export_pixels(storage='long') on a wand Image will crash the Python interpreter.

It seems MagickExportImagePixels expects a buffer with 8-bit integers if you use the corresponding enum value. In the list of storage types, you can use explicitly sized integer types ctypes.c_uint32 and ctypes.c_uint64 instead of c_uint and ctypes.c_ulong:

        c_storage_types = [
            None,
            ctypes.c_uint8,
            ctypes.c_double,
            ctypes.c_float,
            ctypes.c_uint32,
            ctypes.c_uint64,
            ctypes.c_double,  # FIXME: Might be c_longdouble?
            ctypes.c_uint16
        ]

(n.b. long is only 4 bytes on Windows)

Thanks for opening this issue & good find. For the most part, both ImageMagick & Python are standardized to the same C types. That is to say (python)ctypes.sizeof(ctypes.c_ushort) must match (c)sizeof(unsigned short). However, as you pointed out, this is not true for the "long" storage type. Looking into the source code, and I see "long" maps to LongLongPixel type that alias MagickSizeType. Where MagickSizeType is defined as:

#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
  #if (MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG == 8)
    typedef long long MagickOffsetType;
    typedef unsigned long long MagickSizeType;
    #define MagickOffsetFormat  "lld"
    #define MagickSizeFormat  "llu"
  #else
    typedef ssize_t MagickOffsetType;
    typedef size_t MagickSizeType;
    #define MagickOffsetFormat  "ld"
    #define MagickSizeFormat  "lu"
  #endif
#else
  typedef __int64 MagickOffsetType;
  typedef unsigned __int64 MagickSizeType;
  #define MagickOffsetFormat  "I64i"
  #define MagickSizeFormat  "I64u"
#endif

.... which is a fancy way of saying "always uint64 for long". I'll need to dig into this a little bit more, but yes, this is a bug.

Incidentally, the Quantum type (second from the bottom) is an alias for one of the other ones, depending on your build setting. MAGICKCORE_QUANTUM_DEPTH determines the size, and MAGICKCORE_HDRI_SUPPORT determines if it is int or float (in the latter case, float32 is also used for depth 8 and 16). See MagickCore/magick-type.h in the ImageMagick library.

Correct. A bit tricky to identify as Python's ctypes doesn't have access to the preprocessor values and/or configure settings. However I believe this was addressed elsewhere in Wand by IBM folks.

Feel free to test out adfa655 commit. Pending some CI / regression testing on different architectures, this should be fixed.