Fix bug 565 - "QImage missing *data constructors"

Fix bug 566 - "'PySide.QtGui.QImage' object has no attribute 'scanLine'"

The constructors now accepts any PyObject which implements the buffer protocol, as the
C++ and PyQt4 version the buffer must be alive during the life time of QImage because QImage
*does not* copy the image data.

scanLine() and bits() now return buffer objects pointing to the memory inside QImage.
This commit is contained in:
Hugo Parente Lima 2011-01-28 16:28:17 -02:00
commit 2a43919024
2 changed files with 84 additions and 32 deletions

View file

@ -722,45 +722,85 @@
<modify-function signature="QImage(const char *, const char *)" remove="all" /> <modify-function signature="QImage(const char *, const char *)" remove="all" />
<modify-function signature="QImage(const char **)" remove="all" /> <modify-function signature="QImage(const char **)" remove="all" />
<template name="QImageStringBufferConversionRule"> <template name="qimage_buffer_constructor">
const uchar* %out = reinterpret_cast&lt;const uchar*>(PyString_AS_STRING(%PYARG_1)); PyTypeObject* pyType = reinterpret_cast&lt;PyTypeObject*>(%PYARG_1->ob_type);
if (pyType->tp_as_buffer
&amp;&amp; pyType->tp_as_buffer->bf_getreadbuffer
&amp;&amp; pyType->tp_as_buffer->bf_getsegcount(%PYARG_1, 0) == 1) {
void* ptr;
pyType->tp_as_buffer->bf_getreadbuffer(%PYARG_1, 0, &amp;ptr);
%0 = new %TYPE((uchar*)ptr, %ARGS);
} else {
PyErr_SetString(PyExc_TypeError, "The object must support buffer protocol with just one segment.");
}
</template> </template>
<modify-function signature="QImage(uchar *,int,int,int,QImage::Format)">
<modify-function signature="QImage(uchar *,int,int,int,QImage::Format)" remove="all"/> <modify-argument index="1">
<modify-function signature="QImage(const uchar*,int,int,int,QImage::Format)"> <replace-type modified-type="PyObject"/>
<modify-argument index="1">
<replace-type modified-type="const char*"/>
<conversion-rule class="native">
<insert-template name="QImageStringBufferConversionRule"/>
</conversion-rule>
</modify-argument> </modify-argument>
<inject-code>
<insert-template name="qimage_buffer_constructor">
<replace from="%ARGS" to="%2, %3, %4, %5" />
</insert-template>
</inject-code>
</modify-function>
<modify-function signature="QImage(uchar*,int,int,QImage::Format)">
<modify-argument index="1">
<replace-type modified-type="PyObject"/>
</modify-argument>
<inject-code>
<insert-template name="qimage_buffer_constructor">
<replace from="%ARGS" to="%2, %3, %4" />
</insert-template>
</inject-code>
</modify-function> </modify-function>
<modify-function signature="bits()const" remove="all" />
<modify-function signature="scanLine(int)const" remove="all" />
<modify-function signature="QImage(uchar*,int,int,QImage::Format)" remove="all" /> <!-- The non-const versions are already used -->
<modify-function signature="QImage(const uchar *, int, int, QImage::Format)"> <modify-function signature="QImage(const uchar*,int,int,int,QImage::Format)" remove="all"/>
<modify-argument index="1"> <modify-function signature="QImage(const uchar *, int, int, QImage::Format)" remove="all" />
<replace-type modified-type="const char*"/>
<conversion-rule class="native">
<insert-template name="QImageStringBufferConversionRule"/>
</conversion-rule>
</modify-argument>
</modify-function>
<modify-function signature="loadFromData(const uchar*,int,const char*)" remove="all" /> <modify-function signature="loadFromData(const uchar*,int,const char*)" remove="all" />
<!-- Functions removed because we already have overloads using QString -->
<modify-function signature="setText(const char*,const char*,QString)" remove="all" /> <modify-function signature="setText(const char*,const char*,QString)" remove="all" />
<modify-function signature="text(const char*,const char*)const" remove="all" /> <modify-function signature="text(const char*,const char*)const" remove="all" />
<!--### Obsolete in 4.3-->
<modify-function signature="serialNumber()const" remove="all"/> <modify-function signature="serialNumber()const" remove="all"/>
<!--### Obsolete in 4.3-->
<modify-function signature="textLanguages()const" remove="all"/> <modify-function signature="textLanguages()const" remove="all"/>
<!--### Obsolete in 4.3-->
<modify-function signature="QImage(const char**)" remove="all"/> <modify-function signature="QImage(const char**)" remove="all"/>
<modify-function signature="setColorTable(const QVector&lt;uint&gt;)" remove="all"/> <!--### end of obsolete section -->
<modify-function signature="loadFromData(const uchar *,int,const char *)" remove="all"/> <modify-function signature="loadFromData(const uchar *,int,const char *)" remove="all"/>
<modify-function signature="fromData(const uchar *,int,const char *)" remove="all"/> <modify-function signature="fromData(const uchar *,int,const char *)" remove="all"/>
<modify-function signature="bits()" remove="all"/>
<modify-function signature="scanLine(int)" remove="all"/> <modify-function signature="constBits()const" since="4.7">
<inject-code>
%PYARG_0 = PyBuffer_FromMemory(const_cast&lt;uchar*>(%CPPSELF.%FUNCTION_NAME()), %CPPSELF.byteCount());
</inject-code>
</modify-function>
<modify-function signature="bits()">
<inject-code>
// byteCount() is only available on Qt4.7, so we use bytesPerLine * height
%PYARG_0 = PyBuffer_FromReadWriteMemory(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.bytesPerLine() * %CPPSELF.height());
</inject-code>
</modify-function>
<modify-function signature="constScanLine(int)const" since="4.7">
<inject-code>
%PYARG_0 = PyBuffer_FromMemory(const_cast&lt;uchar*>(%CPPSELF.%FUNCTION_NAME(%1)), %CPPSELF.bytesPerLine());
</inject-code>
</modify-function>
<modify-function signature="scanLine(int)">
<inject-code>
%PYARG_0 = PyBuffer_FromReadWriteMemory(%CPPSELF.%FUNCTION_NAME(%1), %CPPSELF.bytesPerLine());
</inject-code>
</modify-function>
<!--
Only the non-const version of bits() and scanLine() is exported to Python
If the user don't want to detach the QImage data he must use constBits or constScanLine
as Python doesn't have the concept of constness.
-->
<modify-function signature="bits()const" remove="all"/>
<modify-function signature="scanLine(int)const" remove="all"/>
<modify-function signature="invertPixels(QImage::InvertMode)"> <modify-function signature="invertPixels(QImage::InvertMode)">
<modify-argument index="1"> <modify-argument index="1">
<rename to="mode"/> <rename to="mode"/>

View file

@ -2,18 +2,30 @@
'''Test cases for QImage''' '''Test cases for QImage'''
import unittest import unittest
from PySide.QtGui import *
from PySide.QtGui import QImage from helper import *
from helper import UsesQApplication
class QImageTest(UsesQApplication): class QImageTest(UsesQApplication):
'''Test case for calling setPixel with float as argument''' '''Test case for calling setPixel with float as argument'''
def testQImageStringBuffer(self): def testQImageStringBuffer(self):
'''Test if the QImage signatures receiving string buffers exist.''' '''Test if the QImage signatures receiving string buffers exist.'''
img0 = QImage('', 100, 100, QImage.Format_ARGB32) img0 = QImage(adjust_filename('sample.png', __file__))
img1 = QImage('', 100, 100, 0, QImage.Format_ARGB32)
print type(img0.bits())
# btw let's test the bits() method
img1 = QImage(img0.bits(), img0.width(), img0.height(), img0.format())
self.assertEqual(img0, img1)
img2 = QImage(img0.bits(), img0.width(), img0.height(), img0.bytesPerLine(), img0.format())
self.assertEqual(img0, img2)
## test scanLine method
data1 = img0.scanLine(0)
data2 = img1.scanLine(0)
self.assertEqual(data1, data2)
self.assertEquals(str(data1), img0.bits()[:img0.bytesPerLine()])
self.assertEquals(str(data2), img0.bits()[:img0.bytesPerLine()])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()