2016-06-08 8 views
2

QGraphicsScene의 내용을 인쇄하려고합니다. 대상 프린터는 일반 프린터에서 사용자 정의 크기의 특수 프린터에 이르기까지 모든 것이 될 수 있습니다. 실제 크기 (인치, mm ....)로 물건을 인쇄해야합니다.
QGraphicsScene에서 나는 72ppi라는 가정을 사용하고 있습니다.실제 (인치/mm) 눈금에 QGraphicsScene를 인쇄해야합니다.

가정 :
1) 장면을 프린터로 렌더링하면 프린터 해상도에 따라 렌더링되므로 화면에 표시되는 것과 비슷한 실제 크기 (인치/mm)의 항목을 얻을 수 있습니다.
2) 프린터의 용지 크기를 원하는 캔버스 크기 (매우 큰 장면의 사각형)로 설정할 수 있습니다. 아무 것도 인쇄 할 수 없습니다.
3) 여백을 설정할 수 있으며 " 실제 캔버스 "는 여백에있는 것을 포함하여 인쇄되지 않습니다.

내 모든 가정은 지금까지 잘못되었습니다.
1) 다른 프린터의 경우, 기본 용지 크기에 가까운 사용자 지정 크기를 제안하는 경우 렌더링이 최대 적합 (가로 세로 비율 사용) 인 것처럼 보입니다. 용지 크기를 설정하지 마십시오.);
기본적으로 "LETTER"크기의 프린터에서 4x4 인치와 같이 닫히지 않은 용지 크기를 설정하면 빈 페이지 만 인쇄됩니다.
2-3) 인쇄가 있고 프린터가 캔버스를 전체 페이지로 늘리면 도면 영역 밖에있는 항목은 계속 인쇄됩니다.
화가에서 렌더링하거나 렌더링시 대상 사각형을 설정하여 클립을 만들려고했는데 그 결과 장면의 작은 부분이 매우 이상하게 클리핑되었습니다.

HP LaserJet, Adobe PDF 및 특정 크기 (예 : 4x6 인치)의 맞춤 프린터를 사용해 보았습니다. 세로 또는 가로를 지정했는지 여부에 따라 장면을 최대 크기로 조절하고 내 용지 크기 요청 또는 실제 크기를 완전히 무시합니다.

다음은 내가하려는 것을 재현하는 작은 샘플 프로그램입니다.
코드의 주석은 내가 시도한 몇 가지 옵션을 보여줍니다.

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

수정 레이저젯 프린트 (-하지 실제 페이지 외부 그림 크기 조정)를 -하지만 300 dpi의 해상도의 프린터에 작은 거의 보이지 인쇄에 결과 :

#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(); 
} 

수행.

출력물을 실제 크기로 가져와 (용지에서 인치/mm를 측정하여 정확하게 만들 수 있도록하려면 어떻게해야합니까?)?

또한 출력을 실제 캔버스 사각형으로 잘릴 수 있습니까?

+1

dpi는 변환 인수입니다. 그것은 육체적 인 측정이 아닙니다. 그것은 "뉴욕까지 얼마나 멀리 운전해야하는지"묻는 것과 같고 당신은 "60mph"라고 대답합니다. –

+0

@MarcB는 PPI (인치당 픽셀 수 또는 인치당 포인트 수)를 의미합니다. - 72 * 인치 크기의 장면 항목을 그리는 중입니다. 'printer.setPaperSize (canvasRect, QPrinter :: Point);와'qDebug() << printer.paperSize (QPrinter :: Inch);를 실행하면'QPrinter'가 동의하는 것으로 보입니다. – Thalia

+0

장면의 단위가 픽셀이 아니므로 PPI는 의미가 없습니다. 장면 단위가 1/72 인치라고 간단하게 말할 수 있습니다. –

답변

3

정말 간단합니다. 장치 단위로 대상 사각형,

  1. 그것은 장면 단위로, 소스 사각형에서지도 다음 render 방법은 두 가지 않습니다.
  2. 대상 사각형 내에서만 그립니다.

실수로 null 대상 사각형이 전달되었습니다. 유효 크기가 클리핑되지 않고 (장치 크기에 맞춰 짐) 장면이 완전히 동일한 크기가 아닌 한 잘못된 배율로 인쇄됩니다. 장치 크기

장치 단위와 인치 사이의 DPI 매핑은 QPrinter::resolution에 의해 DPI (장치 단위/인치)로 표시됩니다.

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); 

프린터 장치 :

는 (귀하의 경우 72.0f를) in 장면 단위로 1 인치이고, 다음을 수행 내에서 올바른 규모에 canvasRect를 인쇄 선택한 페이지 사각형 클리핑하려면 단위는 Qt에서 직사각형처럼 보일지 모르지만, 그 이유는 충분히 이상한 장치를 사용하지 않았기 때문일 것입니다.

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); 
... 

완전한 예는 다음과 같습니다 경우 그들은 당신이 pageRect의 출력에서 ​​그들을 추론 할 수있는, 직사각형하지 않았다. 출력은 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