2016-06-08 61 views
2

我正在嘗試打印QGraphicsScene的內容。目標打印機可以是任何東西 - 從普通打印機到定製尺寸特殊打印機。它必須以實際尺寸(英寸,毫米......)打印東西。
QGraphicsScene我使用72ppi的假設。我需要將QGraphicsScene打印爲實際(英寸/毫米)的刻度

我假設:
1)將場景渲染到打印機將基於打印機分辨率來實現,這樣我就可以獲得與它們在屏幕上顯示的實際尺寸(英寸/毫米)相似的項目。
2)我可以將打印機的紙張大小設置爲所需的畫布大小(這是一個非常大的場景中的矩形),除此之外沒有任何內容可以打印
3)我可以設置頁邊距以及「實際畫布「將不會被打印,包括邊距上的內容。 1)對於不同的打印機,如果我建議自定義尺寸接近其默認紙張尺寸(或者如果I不要設置紙張大小);
如果我設置的紙張尺寸不是很接近(例如在打印機上使用默認「LETTER」尺寸的4x4英寸),它只是打印一張空白頁。 2-3)如果存在打印,並且打印機只是將畫布拉伸至其整頁,則任何位於繪圖區域之外的項目仍將被打印。
我試圖剪輯,無論是在畫家上,或通過在渲染上設置目標矩形,結果是一小部分場景的非常奇怪的剪輯。

我嘗試過使用HP LaserJet,Adobe PDF和一些特定尺寸(如4x6英寸)的自定義打印機。他們都根據我是否指定縱向或橫向將場景縮放到最大尺寸,並完全忽略紙張尺寸請求或實際尺寸。

這是一個小樣本程序來重現我正在嘗試做的事情。
代碼中的註釋顯示了我嘗試過的一些選項。

#include <QApplication> 
#include <QGraphicsView> 
#include <QGraphicsScene> 
#include <QGraphicsRectItem> 
#include <QGraphicsEllipseItem> 
#include <QPrinter> 
#include <QPrintDialog> 


int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 
    QGraphicsScene* s = new QGraphicsScene(); 
    s->setSceneRect(-500, -500, 1500, 1500); 
    QGraphicsView* view = new QGraphicsView(); 
    view->setScene(s); 
    view->show(); 

    int canvasSize = 288; // 4 in 
    QRectF canvasRect(0, 0, canvasSize, canvasSize); 
    // this is to show actual scene 
    QGraphicsRectItem* sss = new QGraphicsRectItem(canvasRect); 
    sss->setBrush(Qt::blue); 
    s->addItem(sss); 
    // this item is partially outside top left 
    QGraphicsEllipseItem* e1 = new QGraphicsEllipseItem(-50, -75, 100, 150); 
    e1->setBrush(Qt::yellow); 
    s->addItem(e1); 
    // this item is partially outside center 
    QGraphicsEllipseItem* e2 = new QGraphicsEllipseItem(100, 150, 250, 50); 
    e2->setBrush(Qt::yellow); 
    s->addItem(e2); 
    // this item is partially outside right 
    QGraphicsEllipseItem* e3 = new QGraphicsEllipseItem(200, 200, 75, 125); 
    e3->setBrush(Qt::yellow); 
    s->addItem(e3); 

    QPrinter printer; 
    // QPrinter printer(QPrinter::HighResolution); // this makes no difference except it rotates the output, strange 

    // without this just to use default printer, if you like 
    QPrintDialog printDialog(&printer); 
    if (printDialog.exec() != QDialog::Accepted) 
     return 1; 

    printer.setFullPage(false); // I see no diference between true and false 

    // this results in empty page (or is ignored if my rect is 8 in) 
    //printer.setPaperSize(canvasRect, QPrinter::Point); 

    printer.setOrientation(QPrinter::Landscape); 
    printer.setPageMargins(0, 0, 0, 0, QPrinter::Point); 

    QPainter painter; 

    if (painter.begin(&printer)) 
    { 
//  painter.setClipRect(canvasRect); // this creates a small clipping, only a tiny corner 
     s->render(&painter, QRectF(), canvasRect, Qt::KeepAspectRatio); 
     // doing this instead clips to a tiny rectangle also 
//  s->render(&painter, canvasRect, canvasRect, Qt::KeepAspectRatio); 
     painter.end(); 
    } 

    return app.exec(); 
} 

這樣做:

QPrinter printer(QPrinter::HighResolution); 
qreal resolutionFactor = printer.resolution()/1200.; 
... 
painter.scale(resolutionFactor, resolutionFactor); 

修復的激光打印(縮放 - 而不是實際的頁面外畫) - 但結果與300 dpi的分辨率的打印機上一個微小的幾乎看不見的打印。

我怎樣才能得到打印輸出是實際的規模(以便我可以測量英寸/毫米在紙上,讓他們是正確的)?

另外我怎樣才能得到輸出剪切到實際的畫布矩形?

+1

'dpi'是一個換算係數。這不是一種物理測量。就像問「開車到紐約有多遠」,而你回答「60英里/小時」。 –

+0

@MarcB我的意思是PPI(像素每英寸 - 或每英寸點數?) - 我正在繪製尺寸爲72 *英寸大小的場景項目。 'QPrinter'似乎同意,如果我'printer.setPaperSize(canvasRect,QPrinter :: Point);'和'qDebug()<< printer.paperSize(QPrinter :: Inch);'它給我預期的大小。 – Thalia

+0

場景中的單位不是像素,所以說PPI是沒有意義的。你可以簡單地說你的場景單位是1/72英寸。 –

回答

3

這一切都很簡單。該方法render做兩件事情

  1. 它從源矩形映射,在場景單元,向目標矩形,在設備單元。
  2. 它僅在目標矩形內繪製。

你的錯誤是傳遞一個空的目標矩形:然後沒有有效的剪輯(它剪輯到設備大小),並且你打印的尺寸錯誤,除非你的場景的尺寸與大小完全一樣設備大小。

設備單位與英寸之間的DPI映射由QPrinter::resolution以DPI(每英寸設備單位數)表示。

要打印canvasRect在正確的比例,內夾在選擇頁的矩形,做到以下幾點,其中in爲1英寸的場景單位(72.0f你的情況):

auto source = canvasRect; 
auto scale = printer.resolution()/in; 
auto page = printer.pageRect(QPrinter::DevicePixel); 
auto target = QRectF(page.topLeft(), source.size()*scale); 
target &= page; // clip target rect to page 
qDebug() << page << scale << source << target; 
scene.render(&painter, target, source); 

打印機設備單位在Qt中看起來是矩形的,但也許這是因爲我沒有嘗試過足夠多的設備。如果他們不是矩形,你可以從pageRect輸出推斷他們:

qreal resolution(QPrinter & printer, Qt::Orientation orientation) { 
    auto in = printer.pageRect(QPrinter::Inch); 
    auto dev = printer.pageRect(QPrinter::DevicePixel); 
    return (orientation == Qt::Horizontal) ? dev.width()/in.width() 
     : dev.height()/in.height(); 
} 
... 
auto scaleX = resolution(printer, Qt::Horizontal); 
auto scaleY = resolution(printer, Qt::Vertical); 
auto target = QRectF(page.left(), page.top(), 
        source.width()*scaleX, source.height()*scaleY); 
... 

完整的示例如下。無論in的值如何,輸出都是相同的,因爲我們使用明確的非化妝筆來繪製輪廓的輪廓。沒有理由將in設置爲任何特定值,如果您的自然單位是英寸然後簡單地設置in=1.0f

// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-print-37708423 
#include <QtWidgets> 
#include <QtPrintSupport> 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 
    QGraphicsScene scene; 
    QGraphicsView view(&scene); 

    auto in = 72.0f; 
    auto pen = QPen(Qt::black, 0.01*in); 
    QRectF canvasRect(0, 0, 4*in, 4*in); 
    // this is to show actual scene 
    QGraphicsRectItem sss(canvasRect); 
    sss.setPen(pen); 
    sss.setBrush(Qt::blue); 
    scene.addItem(&sss); 
    // this item is partially outside top left 
    QGraphicsEllipseItem e1(-0.5*in, -0.5*in, 1*in, 1*in); 
    e1.setPen(pen); 
    e1.setBrush(Qt::yellow); 
    scene.addItem(&e1); 
    // this item is partially outside center 
    QGraphicsEllipseItem e2(2*in, 2*in, 2.5*in, 1*in); 
    e2.setPen(pen); 
    e2.setBrush(Qt::yellow); 
    scene.addItem(&e2); 
    // this item is partially outside right 
    QGraphicsEllipseItem e3(3.5*in, 3.5*in, 1*in, 1*in); 
    e3.setPen(pen); 
    e3.setBrush(Qt::yellow); 
    scene.addItem(&e3); 

    view.fitInView(scene.sceneRect(), Qt::KeepAspectRatio); 
    view.show(); 

    QPrinter printer; 
    QPrintDialog printDialog(&printer); 
    QObject::connect(&printDialog, &QDialog::accepted, [&]{ 
     printer.setOrientation(QPrinter::Landscape); 
     QPainter painter(&printer); 

     auto source = canvasRect; 
     auto scale = printer.resolution()/in; 
     auto page = printer.pageRect(QPrinter::DevicePixel); 
     auto target = QRectF(page.topLeft(), source.size()*scale); 
     target &= page; // clip target rect to page 
     qDebug() << page << scale << source << target; 
     scene.render(&painter, target, source); 
    }); 
    printDialog.show(); // modal on OS X thus must follow `connect` above 
    return app.exec(); 
} 
+0

這很棒,包括不同的水平和垂直分辨率!是否有辦法告訴打印機要使用哪種紙張尺寸,而不冒冒險認可並打印空白頁的風險? – Thalia

+0

@Thalia當'printer.setPageSize(QPageSize :: A4))'(例如)返回true時,你知道它成功了。您可以設置默認頁面大小,然後顯示打印對話框,但預計可能會更改,因爲用戶應該可以更改它,並且不應該忽略更改。您不關心頁面大小,它是用戶設置的任何內容,「pageRect」反映所選頁面的大小。 –

+0

這假設我可以從枚舉中設置紙張大小 - 但對於定製打印機,情況並非如此......特別是對於連續滾動進紙。我試圖告訴打印機紙張尺寸是什麼(或者至少將其提示給打印對話框)。 – Thalia

相關問題