TL;DR:在 4 核系统上,您应该能够在一秒钟内绘制约 1000 万个小矩形,而在 QImage 上只使用 QPainter::drawRect。
绘制一百万个矩形并不是什么大问题,一个典型的 1920x1080 屏幕大约有 200 万个像素,因此绘制“小”矩形就像单独写入每对像素,或者平均每个矩形写入 8 个字节。
在我的特定系统上,运行 Qt 5.6 的 i5 iMac,绘制 100 万个小矩形需要大约 1/3 秒:
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QImage image(1920, 1080, QImage::Format_ARGB32_Premultiplied);
QPainter p(&image);
QElapsedTimer timer;
timer.start();
int n = 0;
for (int y = 0; y < image.height(); ++y)
for (int x = 0; x < image.width(); x+=2) {
++ n;
p.drawRect(x, y, 2, 1);
}
p.end();
qDebug() << n << timer.elapsed();
}
如果您愿意,您可以跨多个线程并行绘制。
// https://github.com/KubaO/stackoverflown/tree/master/questions/qimage-rectangles-37510435
#include <QtWidgets>
#include <QtConcurrent>
QVector<QRect> rects(const QSize & size) {
QVector<QRect> rs;
for (int y = 0; y < size.height(); ++y)
for (int x = 0; x < size.width(); x+=2)
rs.append(QRect(x, y, 2, 1));
return rs;
}
QImage render(const QVector<QRect> & rects, const QSize & size, const QPair<int,int> range)
{
QImage image(size, QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter p(&image);
QElapsedTimer timer;
timer.start();
const int n = range.second-range.first;
for (int i = range.first; i < range.second; ++i)
p.drawRect(rects[i]);
p.end();
qDebug() << n << timer.elapsed();
return image;
}
struct Render {
const QVector<QRect> & rects;
const QSize & size;
typedef QImage result_type;
QImage operator()(const QPair<int,int> range) { return render(rects, size, range); }
Render(QVector<QRect>& rects, const QSize& size) : rects(rects), size(size) {}
};
template <typename Seq>
QVector<QPair<int,int>> partition(const Seq & s, int n)
{
QVector<QPair<int,int>> ps;
ps.reserve(n);
int begin = 0;
for (int i = 0; i < n; ++i) {
int end = (s.count() * (i+1))/n;
ps.append(qMakePair(begin, end));
begin = end;
}
return ps;
}
void combine(QImage & result, const QImage & source)
{
if (result.isNull()) {
result = source;
return;
}
QPainter p(&result);
p.drawImage(0, 0, source);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QSize size{1920, 1080};
auto rs = rects(size);
auto ranges = partition(rs, QThread::idealThreadCount());
QElapsedTimer t;
t.start();
QtConcurrent::blockingMappedReduced(ranges, Render(rs, size), combine);
qDebug() << "parallel time" << t.elapsed() << "ms";
t.restart();
render(rs, size, qMakePair(0, rs.count()));
qDebug() << "serial time" << t.elapsed() << "ms";
}
输出:
259200 94
259200 97
259200 102
259200 102
parallel time 112 ms
1036800 360
serial time 362 ms
如果您可以将矩形分组到具有相同笔/画笔的组中,那么请利用 drawRects 比重复调用 drawRect 更快(在我的机器上快约 20%)这一事实。
您也可以自己实现一个未转换的drawRect 并使其更快。