<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Mar 12, 2015 at 2:58 PM, Martin Altmayer <span dir="ltr"><<a href="mailto:martin.altmayer@web.de" target="_blank">martin.altmayer@web.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">As far as I understand the docs at<br>
<a href="http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html#releasing-the-gil" target="_blank">http://pyqt.sourceforge.net/<u></u>Docs/PyQt5/pyqt4_differences.<u></u>html#releasing-the-gil</a><br>
the GIL needs to be released before I call a Qt function from Python. And as far as I understand qimage.sip the GIL is not released for QImage methods.<br>
<br>
Am 12.03.2015 20:52 schrieb Jason H:<div class=""><div class="h5"><br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The GIL is not in effect when you are in C++ code. If you are in<br>
QImage::scale, then you aren't experiencing GIL.<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Sent: Thursday, March 12, 2015 at 1:24 PM<br>
From: "Martin Altmayer" <<a href="mailto:martin.altmayer@web.de" target="_blank">martin.altmayer@web.de</a>><br>
To: <a href="mailto:pyqt@riverbankcomputing.com" target="_blank">pyqt@riverbankcomputing.com</a><br>
Subject: [PyQt] QImage and the GIL<br>
<br>
Hello,<br>
<br>
I use a separate thread to open and scale a large set of images.<br>
Unfortunately, with PyQt5 the main thread blocks while an image is<br>
loaded (it did work in PyQt4). I believe that the reason is that the<br>
QImage-constructor and QImage.scale do not release the GIL. Wouldn't it<br>
be better if they did?<br>
<br>
Thanks,<br>
Martin<a href="http://www.riverbankcomputing.com/mailman/listinfo/pyqt" target="_blank"></a></blockquote></blockquote></div></div></blockquote><div><br></div><div>Hi Martin,<br><br></div><div>It looks like you are correct: <a href="https://github.com/baoboa/pyqt5/blob/dcfb8fa0f23e4f962e753bb1b336c5783c0c7cd9/sip/QtGui/qimage.sip">https://github.com/baoboa/pyqt5/blob/dcfb8fa0f23e4f962e753bb1b336c5783c0c7cd9/sip/QtGui/qimage.sip</a> (this is not my repo - just linking to it for convenience). The only two functions in there that do ReleaseGIL are stream operators (overloaded bitshift operators) for serializing and deserializing to/from a QDataStream. This might potentially be useful if you resort to using the Python multiprocessing module for decoding and scaling images that then need to be streamed back to the main process, perhaps.<br><br></div><div>If you need more speed just for your own purposes, then, in that sip file, replacing<br><br>
<div style="color:rgb(0,0,0);background-color:rgb(245,245,245);font-style:normal;font-weight:normal;text-decoration:none">
<pre><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">load</span><span>(</span><span>QIODevice</span><span> </span><span>*</span><span>device</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span>)</span><span>;</span>
<span></span><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">load</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QString</span><span> </span><span>&</span><span>fileName</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>)</span><span>;</span>
<span></span><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">loadFromData</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>uchar</span><span> </span><span>*</span><span>data</span><span> </span><span>/</span><span>Array</span><span>/</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>len</span><span> </span><span>/</span><span>ArraySize</span><span>/</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>)</span><span>;</span>
<span></span><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">loadFromData</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QByteArray</span><span> </span><span>&</span><span>data</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>)</span><span>;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">save</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QString</span><span> </span><span>&</span><span>fileName</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>quality</span><span> </span><span>=</span><span> </span><span>-</span><span style="color:rgb(0,78,130)">1</span><span>) </span><span style="color:rgb(128,0,128)">const</span><span>;</span>
<span></span><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">save</span><span>(</span><span>QIODevice</span><span> </span><span>*</span><span>device</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>quality</span><span> </span><span>=</span><span> </span><span>-</span><span style="color:rgb(0,78,130)">1</span><span>) </span><span style="color:rgb(128,0,128)">const</span><span>;</span></pre>
</div>
with<br>
<div style="color:rgb(0,0,0);background-color:rgb(245,245,245);font-style:normal;font-weight:normal;text-decoration:none">
<pre><span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">load</span><span>(</span><span>QIODevice</span><span> </span><span>*</span><span>device</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span>) </span><span>/</span><span>ReleaseGIL</span><span>/;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">load</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QString</span><span> </span><span>&</span><span>fileName</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>) </span><span>/</span><span>ReleaseGIL</span><span>/;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">loadFromData</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>uchar</span><span> </span><span>*</span><span>data</span><span> </span><span>/</span><span>Array</span><span>/</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>len</span><span> </span><span>/</span><span>ArraySize</span><span>/</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>) </span><span>/</span><span>ReleaseGIL</span><span>/;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">loadFromData</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QByteArray</span><span> </span><span>&</span><span>data</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>) </span><span>/</span><span>ReleaseGIL</span><span>/;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">save</span><span>(</span><span style="color:rgb(128,0,128)">const</span><span> </span><span>QString</span><span> </span><span>&</span><span>fileName</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>quality</span><span> </span><span>=</span><span> </span><span>-</span><span style="color:rgb(0,78,130)">1</span><span>) </span><span style="color:rgb(128,0,128)">const</span><span> </span><span>/</span><span>ReleaseGIL</span><span>/;</span>
<span style="color:rgb(128,0,128)">bool</span><span> </span><span style="color:rgb(0,0,176)">save</span><span>(</span><span>QIODevice</span><span> </span><span>*</span><span>device</span><span>, </span><span style="color:rgb(128,0,128)">const</span><span> </span><span style="color:rgb(128,0,128)">char</span><span> </span><span>*</span><span>format</span><span> </span><span>=</span><span> </span><span style="color:rgb(0,78,130)">0</span><span>, </span><span style="color:rgb(128,0,128)">int</span><span> </span><span>quality</span><span> </span><span>=</span><span> </span><span>-</span><span style="color:rgb(0,78,130)">1</span><span>) </span><span style="color:rgb(128,0,128)">const</span><span> </span><span>/</span><span>ReleaseGIL</span><span>/;</span></pre></div>
</div><div>and then rebuilding PyQt5 should make the GIL be released. You might also want to give the same treatment to QImage's constructors. I expect that these functions can safely drop the GIL; if this is not the case, it would be interesting to know why :)<br><br></div><div>In my own code, I work around this by using a ctypes freeimage wrapper: <a href="https://github.com/erikhvatum/zplab/blob/master/freeimage.py">https://github.com/erikhvatum/zplab/blob/master/freeimage.py</a> (this is my repo, but credit goes to Dr. Zach Pincus for this file). It drops the GIL in C functions such as image reading and writing, courtesy of ctypes doing that by default. Going to/from the numpy arrays that the wrapper uses to QImage is straightforward. For 24-bit RGB images: Qt.QImage(sip.voidptr(array_from_freeimage.ctypes.data), array_from_freeimage.shape[1], array_from_freeimage.shape[0], Qt.QImage.Format_RGB888). Keep a reference to array_from_freeimage as long as you may need the resulting QImage.<br></div><div><br></div><div>Cheers,<br></div><div>Erik<br>
</div></div>
</div></div>