<div dir="ltr">Hi Phil,<br><br>You are correct, PyQt bindings do provide us with the functionality we need; we're hoping to have the other signatures enabled (assuming it's not a high effort task).<br><br>Majority of our data is already in continuous numpy arrays, so we have a strong interest in being able to pass those arrays to the draw methods in a more direct fashion. We are hoping to be able to do call the QPainter draw methods by putting the array in the correct shape and with the correct data type, without having to convert the it to a list, and without having instantiate or cast each element to QLineF (or QPointF, QPainter.PixmapFragment, QPolygonF objects).<br><br>With our QLineF instance, we hope to be able to pass the pointer of a n_lines x 4 numpy array (of type double/float64) and. be able to call the drawLines method in something like the following fashion.<br><div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>import numpy as np<br>from PyQt6 import QtCore, QtGui, QtWidgets, sip<br>import itertools<br>import sys<br><br>app = QtWidgets.QApplication([])<br><br># array makeup [[x1, y1, x2, y2]]<br>lines = np.array([<br> [0, 0, 0, 10],<br> [0, 10, 10, 0],<br> [10, 0, 20, 10]], dtype=np.float64<br>)<br><br>qimg = QtGui.QImage(20, 20, QtGui.QImage.Format.Format_RGB32)<br>qimg.fill(0)<br>painter = QtGui.QPainter(qimg)<br>painter.setPen(QtCore.Qt.GlobalColor.cyan)<br><br># desired implementation <a href="https://doc-snapshots.qt.io/qt6-dev/qpainter.html#drawLines-4">https://doc-snapshots.qt.io/qt6-dev/qpainter.html#drawLines-4</a><br># ptr = sip.wrapinstance(lines, lines.ctypes.data, QtCore.QLineF)<br># painter.drawLines(ptr, lines.shape[0])<br><br># current implementation <a href="https://doc-snapshots.qt.io/qt6-dev/qpainter.html#drawLines-5">https://doc-snapshots.qt.io/qt6-dev/qpainter.html#drawLines-5</a><br>ptr = list(map(sip.wrapinstance,<br> itertools.count(lines.ctypes.data, lines.strides[0]),<br> itertools.repeat(QtCore.QLineF, lines.shape[0])))<br>painter.drawLines(ptr)<br><br>painter.end()<br>qimg.save('drawLines.png')<br></div><div><br></div></blockquote>For QPainter.drawPixmapFragments (the pyside equivalent of this works actually, not sure if that was intentional on their part or not)<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>import numpy as np<br>from PyQt6 import QtCore, QtGui, QtWidgets, sip<br>import itertools<br><br>app = QtWidgets.QApplication([])<br><br># make the pixmap<br>pix = QtGui.QPixmap(51, 51)<br>pix.fill(0)<br>painter = QtGui.QPainter(pix)<br>painter.setPen(QtCore.Qt.GlobalColor.cyan)<br>painter.drawEllipse(0, 0, 50, 50)<br>painter.end()<br><br># create numpy array representing fragments<br>fieldnames = ['x', 'y', 'sourceLeft', 'sourceTop', 'width', 'height', 'scaleX', 'scaleY', 'rotation', 'opacity']<br>frags_array = np.zeros(3, dtype=[(name, 'f8') for name in fieldnames])<br>frags_array['sourceLeft'] = 0<br>frags_array['sourceTop'] = 0<br>frags_array['width'] = 51<br>frags_array['height'] = 51<br>frags_array['scaleX'] = 1.0<br>frags_array['scaleY'] = 1.0<br>frags_array['rotation'] = 0.0<br>frags_array['opacity'] = 1.0<br><br>frags_array['x'] = [50, 100, 150]<br>frags_array['y'] = [50, 100, 150]<br><br><br>qimg = QtGui.QImage(200, 200, QtGui.QImage.Format.Format_RGB32)<br>qimg.fill(0)<br>painter = QtGui.QPainter(qimg)<br><br># desired implementation<br># frag_ptr = sip.wrapinstance(frags_array.ctypes.data, QtGui.QPainter.PixmapFragment)<br># painter.drawPixmapFragments(frag_ptr, frags_array.size, pix)<br><br># current implementation<br>frag_ptr = list(map(sip.wrapinstance,<br> itertools.count(frags_array.ctypes.data, frags_array.strides[0]),<br> itertools.repeat(QtGui.QPainter.PixmapFragment, frags_array.shape[0])))<br>painter.drawPixmapFragments(frag_ptr[:frags_array.shape[0]], pix)<br>painter.end()<br>qimg.save('drawPixmapFragments.png')</div></blockquote><br><div>Hopefully that clears things up some. Thanks!</div><div>Ogi</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, May 7, 2022 at 1:48 AM Phil Thompson <<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">On 07/05/2022 03:56, Ognyan Moore wrote:<br>
> Hi Phil,<br>
> <br>
> I am one of the maintainers of pyqtgraph, I'd like to request that you<br>
> enable some of the function signatures for QPainter methods that accept<br>
> pointers. The following two would be more beneficial for us:<br>
> <br>
> QPainter::drawLines(const QLineF *lines, int lineCount)<br>
> QPainter::drawPixmapFragments(const QPainter::PixmapFragment <br>
> *fragments,<br>
> int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints<br>
> hints = PixmapFragmentHints())<br>
> <br>
> If it would not be too much trouble, enabling some of the other <br>
> QPainter<br>
> methods that enabled referencing pointers could also be beneficial, but<br>
> these won't have the same impact as the ones above<br>
> <br>
> QPainter::drawConvexPolygon(const QPointF *points, int pointCount)<br>
> QPainter::drawPoints(const QPointF *points, int pointCount)<br>
> QPainter::drawPolygon(const QPointF *points, int pointCount, <br>
> Qt::FillRule<br>
> fillRule = Qt::OddEvenFill)<br>
> QPainter::drawRects(const QRectF *rectangles, int rectCount)<br>
> QPainter::drawPolyline(const QPointF *points, int pointCount)<br>
> <br>
> To demonstrate our usage, I'll highlight what we do with the PySide<br>
> bindings. For the QPainter::drawPixmapFragments we're able to do <br>
> something<br>
> resembling the following<br>
> <br>
> import numpy as np<br>
> size = 1_000<br>
> arr = np.empty((size, 10), dtype=np.float64)<br>
> ptrs = shiboken6.wrapInstance(arr.ctypes.data,<br>
> QtGui.QPainter.PixmapFragment)<br>
> ...<br>
> QPainter.drawPixmapFragments(ptrs, size, pixmap)<br>
> <br>
> For the equivalent functionality with PyQt bindings<br>
> <br>
> ptrs = list(map(sip.wrapInstance,<br>
> itertools.count(arr.ctypes.data, arr.strides[0]),<br>
> itertools.repeat(QtGui.QPainter.PixmapFragment, arr.shape[0])))<br>
> QPainter.drawPixmapFragments(ptrs[:size], pixmap)<br>
> <br>
> <br>
> We do this right now with QImage, and in a round-about way with <br>
> QPolygonF<br>
> construction.<br>
<br>
All of those methods are supported, but maybe not in the way that you <br>
want.<br>
<br>
drawPixmapFragments() takes a list of PixmapFragment. The others takes a <br>
variable number of arguments of the appropriate type, so if you had a <br>
list of QLineF objects (called lines) you would call drawLines(*lines).<br>
<br>
Can you clarify?<br>
<br>
Phil<br>
</blockquote></div>