關於用QPainter畫過大的圖片出現問題的原因

起源

CSDN上有網友問到:

在qpixmap(40000,100)上畫圖到x=32768之後就畫不出來了怎麼辦驗證

寫段代碼測試一下:

import sys
from PySide import QtCore, QtGui

app = QtGui.QApplication(sys.argv)
pix = QtGui.QPixmap(40000, 100)
p = QtGui.QPainter(pix)
p.setPen(QtCore.Qt.red)
p.drawLine(0, 50, 40000, 50)
pix.save("abcd.png")
sys.exit(app.exec_())

結果確實如網友所說:一條直線,無故終止了。

原因

原因何在呢?打開google,搜索,再搜索,依然無果。於是,還是看源碼吧:

Qt 的 Paint System 由三部分構成

  • QPainter
  • QPaintEngine
    • QRasterPaintEngine
  • QPaintDevice
    • QPixmap

對我們這個情況來說,QPainter 不用多說,QPixmap 是 QPaintDevice 的派生類,也容易理解。唯獨 QPaintEngine 比較隱蔽, 我們這兒關注的是它的派生類 QRasterPaintEngine

$QTDIR/src/gui/painting/qpaintengine_raster.cpp

函數調用 關係:

  • QPainter::QPainter(QPaintDevice *pd)

    • bool QPainter::begin(QPaintDevice *pd)

      • bool QRasterPaintEngine::begin(QPaintDevice *device)

        • void QRasterPaintEnginePrivate::systemStateChanged()

看看 systemStateChanged() 的代碼:

void QRasterPaintEnginePrivate::systemStateChanged()
{
QRect clipRect(0, 0,
qMin(QT_RASTER_COORD_LIMIT, device->width()),
qMin(QT_RASTER_COORD_LIMIT, device->height()));

if (!systemClip.isEmpty()) {
QRegion clippedDeviceRgn = systemClip & clipRect;
deviceRect = clippedDeviceRgn.boundingRect();
baseClip->setClipRegion(clippedDeviceRgn);
} else {
deviceRect = clipRect;
baseClip->setClipRect(deviceRect);
}
...
}

發現什麼沒?有一個宏出現了 QT_RASTER_COORD_LIMIT,其數值爲 32767

這樣一來,PainterEngine 中的設備大小始終不會超出這個值,而 QPainter 要通過 PainterEngine 實現在 QPainteDevice 中的圖線繪製。於是,結果就是我們一開始所看到的了。


看來出了問題一味的求助於google是不夠的,有時反而會浪費很多時間,查看源碼往往是最直接,最快的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章