Passing uchar pointer with PySide in Maya

Hi,

I’m working on tools to manage textures in Maya.
I’ve started with Maya 2011 and PyQt4, but with the integration of PySide in Maya 2014, I’ve change my mind and convert my code.
Now, I’m stuck with one problem, when I try to pass a pointer of a MImage to a QImage.

This code works well with PyQt, but not with PySide… and I don’t know how to convert my SwigPyObject to PySide.QtCore.uchar



import maya.OpenMaya as om
from PySide.QtGui import *
from PySide.QtCore import *

texturePath = 'c:/image.png'

# create pointers
wUtil = om.MScriptUtil()
wUtil.createFromInt(0)
wPtr = wUtil.asUintPtr()

hUtil = om.MScriptUtil()
hUtil.createFromInt(0)
hPtr = hUtil.asUintPtr()

# create Maya MImage
mTexture = om.MImage()
mTexture.readFromFile(texturePath)
mTexture.verticalFlip()
mTexture.getSize(wPtr, hPtr)

# get texture size
width = wUtil.getUint(wPtr)
height = hUtil.getUint(hPtr)

# convert to Qt format
mQTexture = None
try:
	mQTexture = QImage(mTexture.pixels(), width, height, QImage.Format_RGB32).rgbSwapped()
except Exception as e:
	print e

And the error message :



Error: 'PySide.QtGui.QImage' called with wrong argument types:
  PySide.QtGui.QImage(SwigPyObject, int, int, PySide.QtGui.QImage.Format)
Supported signatures:
  PySide.QtGui.QImage()
  PySide.QtGui.QImage(PySide.QtCore.QString, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.QString, int, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtGui.QImage)
  PySide.QtGui.QImage(PySide.QtCore.QSize, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(unicode, str = None)
  PySide.QtGui.QImage(PySide.QtCore.char)
  PySide.QtGui.QImage(int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.uchar, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.uchar, int, int, int, PySide.QtGui.QImage.Format)

Any suggestions ?
Thanks in advance

SOLUTION HERE

David

Maybe Nathan can help once again?

http://nathanhorne.com/?p=500

I’m going to guess you need to use a shiboken type converter? My practical knowledge around this is nill.

thank for the link btribble but I found it here earlier and it’s really helpful, thank’s Nathan :):,
but the wrapinstance seems to be useful with Q###, not with the primitive type like “uchar”, I try different things with no luck :curses:

What happens if you try changing mTexture.pixels() to mTexture.pixels().this ?

I have an error :
‘SwigPyObject’ object has no attribute ‘this’

I’m not comfortable with SwigPyObject, I don’t know how to access his internal pointer.
I think the only way is to use shiboken wrapinstance, but how ?

What properties and methods does it have with dir(SwigPyObject) ?

this is the result of a pprint(dir(mTexture.pixels()))

[‘class’,
cmp’,
delattr’,
doc’,
eq’,
format’,
ge’,
getattribute’,
gt’,
hash’,
hex’,
init’,
int’,
le’,
long’,
lt’,
ne’,
new’,
oct’,
reduce’,
reduce_ex’,
repr’,
setattr’,
sizeof’,
str’,
subclasshook’,
‘acquire’,
‘append’,
‘disown’,
‘next’,
‘own’]

thanks for the help :slight_smile:

can you just str(mTexture.pixels()) it?

I get the same error when using PyQt. Did you change anything else besides the import?

just from the logic of it, shouldn’t using int(mTexture.pixels()) retrieve the address, where the pixels pointer actually points to? I mean, that would be what is needed guessing from the constructor of QImage in C++, but i don’t know if the python equivalent, expecting a QtCore.uchar will understand that correctly. Havent tested it, but that would be the first thing i would try :wink:

I have to admit that i’m a little confused here. A uchar is 8 bits which isn’t long enough to be a real pointer. Is this really *uchar data, and is that why the QImage class also takes “string” arguments? It sounds silly, but can you try str(mTexture.pixels()) as TheMaxx suggests? Seems like the conversion would add a bit of overhead versus passing a pointer, though the SwigPyObject does have a native str method, so maybe there is no extra copy step going on.

Also, in regards to other difference that my be causing issues, did you switch from 32 bit to 64 bit Maya at the same time as the PyQt to PySide switch?

[QUOTE=TheMaxx;23814]can you just str(mTexture.pixels()) it?[/QUOTE]
str(mTexture.pixels()) give me a string look like this : _80c0dd3300000000_p_unsigned_char
The QImage constructor accept it, but I read the wrong adress and my image is a beautiful mosaic ^^

[QUOTE=capper;23815]I get the same error when using PyQt. Did you change anything else besides the import?[/QUOTE]
I have only change import, but the Maya version is not the same :S
FYI :

import PyQt4.QtCore as QtCore
help(QtCore)
DATA
PYQT_VERSION = 263680
PYQT_VERSION_STR = '4.6-snapshot-20090810'
QT_VERSION = 263426
QT_VERSION_STR = '4.5.2'

[QUOTE=alfalfasprossen;23817]just from the logic of it, shouldn’t using int(mTexture.pixels()) retrieve the address, where the pixels pointer actually points to? I mean, that would be what is needed guessing from the constructor of QImage in C++, but i don’t know if the python equivalent, expecting a QtCore.uchar will understand that correctly. Havent tested it, but that would be the first thing i would try ;)[/QUOTE]
with int() or long(), it give me this signature :

PySide.QtGui.QImage(long, int, int, PySide.QtGui.QImage.Format)

but there is no supported signature with long for data in QImage constructor

[QUOTE=btribble;23819]Also, in regards to other difference that my be causing issues, did you switch from 32 bit to 64 bit Maya at the same time as the PyQt to PySide switch?[/QUOTE]
Maya2011 x64 with PyQt4 → Maya2014 x64 with embedded PySide

For information :
Maya API documentation :

unsigned char * MImage::pixels 	( )  	const

Returns a pointer to the first pixel of the uncompressed pixels array. This array is tightly packed, of size (width * height * depth) bytes. For the moment, pixels are always stored in a RGBA (depth=4 bytes) pixel format.

Returns:

        Pointer to the first pixel of the array.
        NULL if no image is currently opened, or the current image has a pixel type other than kByte

Qt documentation :

QImage::QImage ( const uchar * data, int width, int height, Format format )

Silly question, what happens if you use version 2 of the OpenMaya API via:

import maya.api.OpenMaya as om

Same thing with the API V2, but V2 is not completed yet, maybe with Maya2015 ^^

PySide.QtGui.QImage' called with wrong argument types:
  PySide.QtGui.QImage(SwigPyObject, int, int, PySide.QtGui.QImage.Format)
Supported signatures:
  PySide.QtGui.QImage()
  PySide.QtGui.QImage(PySide.QtCore.QString, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.QString, int, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtGui.QImage)
  PySide.QtGui.QImage(PySide.QtCore.QSize, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(unicode, str = None)
  PySide.QtGui.QImage(PySide.QtCore.char)
  PySide.QtGui.QImage(int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.uchar, int, int, PySide.QtGui.QImage.Format)
  PySide.QtGui.QImage(PySide.QtCore.uchar, int, int, int, PySide.QtGui.QImage.Format)

Capper mentioned that he saw the same problem with PyQt. Does your code work with PyQT still? I see examples that tell you to do:

mQTexture = QImage(sip.voidptr(long(mTexture.pixels())), width, height, QImage.Format_RGB32).rgbSwapped(

Unfortunately, shiboken doesn’t appear to have a .voidptr implementation. :stuck_out_tongue:

Yes, my code work with my Maya 2011 with PyQt4, no problem

Indeed, sip is really different than shiboken, however both have wrapinstance. The sip module found the best match whereas shiboken return the “exact” type as far as I know.

I’ve found this documentation for shiboken :
http://shiboken.readthedocs.org/en/latest/shibokenmodule.html

Yes, but does it work in 2014 with PyQt? Do you have a version compiled for 2014 x64? Capper says it does not work for him, but he doesn’t indicate what version he’s running. We’re in 2012 x64/PyQt, so I don’t want to throw further confusion into the mix or I would try it here.

I think I found the beginning of an answer. There is a QChar in PyQt but nothing in PySide even in the documentation QChar is quoted here for example.

from PyQt4 import QtCore
help(QtCore)
[...]
CLASSES
    __builtin__.int(__builtin__.object)
        QtMsgType
    __builtin__.object
        pyqtSignal
    __builtin__.property(__builtin__.object)
        pyqtProperty
    sip.simplewrapper(__builtin__.object)
        MSG
        POINT
        QAbstractFileEngineHandler
        QAbstractFileEngineIterator
        QBasicTimer
        QBitArray
        QByteArray
        QByteArrayMatcher
        [B]QChar[/B]
from PySide import QtCore
help(QtCore)
[...]
CLASSES
    Shiboken.Object(__builtin__.object)
        MSG
        POINT
        QAbstractFileEngine
            QFSFileEngine
        QAbstractFileEngineHandler
        QAbstractFileEngineIterator
        QBasicTimer
        QBitArray
        QByteArray
        QByteArrayMatcher
        QCryptographicHash
        QDataStream

[QUOTE=btribble;23830]Yes, but does it work in 2014 with PyQt? Do you have a version compiled for 2014 x64? Capper says it does not work for him, but he doesn’t indicate what version he’s running. We’re in 2012 x64/PyQt, so I don’t want to throw further confusion into the mix or I would try it here.[/QUOTE]

You’re right, I’ll try PyQt in Maya 2014