aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Parente Lima <hugo.pl@gmail.com>2011-01-28 16:28:17 -0200
committerHugo Parente Lima <hugo.pl@gmail.com>2012-03-08 16:53:50 -0300
commit279fb0242963caf5a03ea30d6cde5f10d3387f7b (patch)
tree10cd1c6fc4f95e98d6c4e8a17b10606647d91c69
parent9c7d055f3d6f7f93f66ed977ca480979b445fcb8 (diff)
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.
-rw-r--r--PySide/QtGui/typesystem_gui_common.xml92
-rw-r--r--tests/QtGui/qimage_test.py24
2 files changed, 84 insertions, 32 deletions
diff --git a/PySide/QtGui/typesystem_gui_common.xml b/PySide/QtGui/typesystem_gui_common.xml
index f39478154..63fec0478 100644
--- a/PySide/QtGui/typesystem_gui_common.xml
+++ b/PySide/QtGui/typesystem_gui_common.xml
@@ -722,45 +722,85 @@
<modify-function signature="QImage(const char *, const char *)" remove="all" />
<modify-function signature="QImage(const char **)" remove="all" />
- <template name="QImageStringBufferConversionRule">
- const uchar* %out = reinterpret_cast&lt;const uchar*>(PyString_AS_STRING(%PYARG_1));
+ <template name="qimage_buffer_constructor">
+ 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>
-
- <modify-function signature="QImage(uchar *,int,int,int,QImage::Format)" remove="all"/>
- <modify-function signature="QImage(const uchar*,int,int,int,QImage::Format)">
- <modify-argument index="1">
- <replace-type modified-type="const char*"/>
- <conversion-rule class="native">
- <insert-template name="QImageStringBufferConversionRule"/>
- </conversion-rule>
+ <modify-function signature="QImage(uchar *,int,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, %5" />
+ </insert-template>
+ </inject-code>
</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" />
- <modify-function signature="QImage(const uchar *, int, int, QImage::Format)">
- <modify-argument index="1">
- <replace-type modified-type="const char*"/>
- <conversion-rule class="native">
- <insert-template name="QImageStringBufferConversionRule"/>
- </conversion-rule>
- </modify-argument>
+ <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>
+ <!-- The non-const versions are already used -->
+ <modify-function signature="QImage(const uchar*,int,int,int,QImage::Format)" remove="all"/>
+ <modify-function signature="QImage(const uchar *, int, int, QImage::Format)" 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="text(const char*,const char*)const" remove="all" />
- <modify-function signature="serialNumber()const" remove="all"/>
<!--### Obsolete in 4.3-->
+ <modify-function signature="serialNumber()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="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="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-argument index="1">
<rename to="mode"/>
diff --git a/tests/QtGui/qimage_test.py b/tests/QtGui/qimage_test.py
index d8aa545af..e9af2d71d 100644
--- a/tests/QtGui/qimage_test.py
+++ b/tests/QtGui/qimage_test.py
@@ -2,18 +2,30 @@
'''Test cases for QImage'''
import unittest
-
-from PySide.QtGui import QImage
-
-from helper import UsesQApplication
+from PySide.QtGui import *
+from helper import *
class QImageTest(UsesQApplication):
'''Test case for calling setPixel with float as argument'''
def testQImageStringBuffer(self):
'''Test if the QImage signatures receiving string buffers exist.'''
- img0 = QImage('', 100, 100, QImage.Format_ARGB32)
- img1 = QImage('', 100, 100, 0, QImage.Format_ARGB32)
+ img0 = QImage(adjust_filename('sample.png', __file__))
+
+ 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__':
unittest.main()