Qt 我需要按实际(英寸/毫米)比例打印QGraphicscene

Qt 我需要按实际(英寸/毫米)比例打印QGraphicscene,qt,printing,qgraphicsscene,qprinter,Qt,Printing,Qgraphicsscene,Qprinter,我正在尝试打印qgraphicscene的内容。目标打印机可以是任何东西-从普通打印机到自定义大小的特殊打印机。它必须以实际尺寸(英寸、毫米……)打印内容。 在qgraphicscene中,我使用72 ppi的假设 我假设: 1) 将场景渲染到打印机将根据打印机分辨率进行,这样我将获得与屏幕上显示的项目类似的实际大小(英寸/毫米)。 2) 我可以将打印机的纸张大小设置为所需的画布大小(在一个非常大的场景中是一个矩形),超出该大小的任何内容都无法打印 3) 我可以设置边距,“实际画布”之外的内容将

我正在尝试打印
qgraphicscene
的内容。目标打印机可以是任何东西-从普通打印机到自定义大小的特殊打印机。它必须以实际尺寸(英寸、毫米……)打印内容。
qgraphicscene
中,我使用72 ppi的假设

我假设:
1) 将场景渲染到打印机将根据打印机分辨率进行,这样我将获得与屏幕上显示的项目类似的实际大小(英寸/毫米)。
2) 我可以将打印机的纸张大小设置为所需的画布大小(在一个非常大的场景中是一个矩形),超出该大小的任何内容都无法打印
3) 我可以设置边距,“实际画布”之外的内容将不会打印,包括边距上的内容

到目前为止,我所有的假设都是错误的:
1) 对于不同的打印机,如果我建议使用接近其默认纸张大小的自定义大小(或者如果我没有设置纸张大小),则渲染似乎是为了最大匹配(使用纵横比)
如果我设置的纸张大小不接近(如打印机上的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();
}
修复了LaserJet打印(缩放-而不是实际页面外的绘画)-但在分辨率为300 dpi的打印机上会产生几乎看不见的微小打印

如何使打印输出达到实际比例(以便在纸上测量英寸/毫米并使其正确)


另外,如何将输出剪裁到实际的画布矩形?

非常简单。
render
方法只做两件事:

  • 它以场景为单位从源矩形映射到以设备为单位的目标矩形
  • 它仅在目标矩形内绘制
  • 您的错误是传递了一个空的目标矩形:当时没有有效的剪辑(剪辑到设备大小),并且您的打印比例也错误,除非您的场景恰好与设备大小完全相同

    设备单位和英寸之间的DPI映射由
    QPrinter::resolution
    以DPI(每英寸设备单位)表示

    要在选定的页面矩形内以正确的比例打印
    canvasRect
    ,请执行以下操作,其中
    中的
    以场景单位表示为1英寸(
    72.0f
    ):

    完整的例子如下。无论
    中的
    值是多少,输出都是相同的,因为我们使用一支明确的、非装饰性的笔来绘制形状的轮廓。没有理由将
    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();
    }
    
    //https://github.com/KubaO/stackoverflown/tree/master/questions/scene-print-37708423
    #包括
    #包括
    int main(int argc,char*argv[])
    {
    QApplication应用程序(argc、argv);
    QsCENE场景;
    QGraphicsView视图(和场景);
    自动输入=72.0华氏度;
    自动笔=QPen(Qt::黑色,0.01*in);
    QRectF canvasRect(0,0,4*in,4*in);
    //这是真实的场景
    QGraphicsRectItem sss(canvasRect);
    sss.设置笔(笔);
    sss.挫折(Qt::蓝色);
    场景。附加项(&sss);
    //此项部分位于左上方
    QGraphicsSellipseitem e1(-0.5*in,-0.5*in,1*in,1*in);
    e1.设置笔(笔);
    e1.退根(Qt::黄色);
    场景。附加项(&e1);
    //此项目部分位于中心外
    QGraphicsSellipseitem e2(2*in,2*in,2.5*in,1*in);
    e2.设置笔(笔);
    e2.挫折感(Qt::黄色);
    场景。附加项(&e2);
    //此项部分位于右侧外侧
    QGraphicsSellipseitem e3(3.5*in,3.5*in,1*in,1*in);
    e3.设置笔(笔);
    e3.挫折感(Qt::黄色);
    场景。附加项(&e3);
    view.fitInView(scene.scen直立(),Qt::KeepAspectRatio);
    view.show();
    打印机;
    QPrintDialog打印对话框(&打印机);
    QObject::connect(&printDialog,&QDialog::accepted,[&]{
    打印机设置方向(QPrinter::横向);
    Q油漆工和打印机;
    自动源=canvasRect;
    自动缩放=打印机。分辨率()/in;
    自动分页=printer.pageRect(QPrinter::DevicePixel);
    自动目标=QRectF(page.topLeft(),source.size()*比例);
    target&=page;//将目标rect剪辑到page
    
    qDebug()
    dpi
    是一个转换系数。它不是一个物理测量。这就像问“到纽约有多远”,然后你回答“60英里每小时”。@MarcB I的意思是PPI(每英寸像素-或每英寸点数?)-我正在绘制72*英寸大小的场景项目。
    QPrinter
    似乎同意,如果我使用
    printer.setPaperSize(canvasRect,QPrinter::Point);
    qDebug()场景中的单位不是像素,所以说PPI毫无意义。你可以简单地说你的场景单位是1/72英寸。我很欣赏你的独立测试用例。非常感谢!这很好,包括不同的水平和垂直分辨率!有没有办法告诉打印机要使用的纸张大小,在不冒它无法识别并打印空白页的风险的情况下?@Thalia When
    printer.setPageSize(QPageSize::A4))
    (例如)返回true,您就知道它成功了。您可以设置默认页大小,然后
    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);
    
    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);
    ...
    
    // 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();
    }