hhatto / pgmagick

pgmagick is a yet another boost.python based wrapper for GraphicsMagick/ImageMagick.
MIT License
147 stars 33 forks source link

Image from raw data broken in Python3 #39

Closed komackaj closed 6 years ago

komackaj commented 6 years ago

Hi,

I've noticed that constructing an Image from array of raw pixels is broken in Python3 due to str/bytes differences between. This code works fine with python2 (due to autoconversion from str to char), but fails with python3 (unable to convert bytes to char)

from pgmagick import Image, Geometry, StorageType

data = b''.join(val * 3 for val in (b'\x00', b'\x88', b'\xff'))
img = Image(3, 1, "RGB", StorageType.CharPixel, data)

ends with

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Image.__init__(Image, int, int, str, StorageType, bytes)
did not match C++ signature:
    __init__(_object*, Magick::Image)
    __init__(_object*, unsigned int, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MagickLib::StorageType, char const*)
    ...

There is a simple Py2/3 compatible workaround using Blob

from pgmagick import Image, Blob, Geometry
data = b''.join(val * 3 for val in (b'\x00', b'\x88', b'\xff'))
blob = Blob(data)
size = Geometry(3, 1)
depth = 8
img = Image(blob, size, depth, "RGB")

@hhatto For discussion - as a future improvement: How should be used aforementioned constructor with StorageType.IntegerPixel? What data (char*) should be passed from Python? Will we support e.g. a tuple/list of integer / float and Boost's extract method according to StorageType? If not, should we make this constructor deprecated?

komackaj commented 6 years ago

The workaround doesn't work if raw data start with magick header for any format - original constructor calls ConstituteImage with a special path for RGB, RGBA, BGR and so on, while constructing from blob calls BlobToImage that tries to autodetect format

img = Image(Blob(b"\0\0\0\0\4\0\0\0" + 92 * b"\0"), Geometry(5, 5), 8, "RGBA")
img.size().height() * img.size().width()
25

img = Image(Blob(b"\0\0\0\0\7\0\0\0" + 92 * b"\0"), Geometry(5, 5), 8, "RGBA")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Magick: invalid file format version () reported by coders/xwd.c:284 (ReadXWDImage)
>>> 

Relates to https://sourceforge.net/p/graphicsmagick/bugs/75/