我需要将QGraphicsScene打印为实际(英寸/毫米)的刻度
我正在尝试打印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的分辨率的打印机上一个微小的几乎看不见的打印。
我怎样才能得到打印输出是实际的规模(以便我可以测量英寸/毫米在纸上,让他们是正确的)?
另外我怎样才能得到输出剪切到实际的画布矩形?
这一切都很简单。该方法render
做两件事情仅:
- 它从源矩形映射,在场景单元,向目标矩形,在设备单元。
- 它仅在目标矩形内绘制。
你的错误是传递一个空的目标矩形:然后没有有效的剪辑(它剪辑到设备大小),并且你打印的尺寸错误,除非你的场景的尺寸与大小完全一样设备大小。
设备单位与英寸之间的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/*n/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();
}
这很棒,包括不同的水平和垂直分辨率!是否有办法告诉打印机要使用哪种纸张尺寸,而不冒冒险认可并打印空白页的风险? – Thalia
@Thalia当'printer.setPageSize(QPageSize :: A4))'(例如)返回true时,你知道它成功了。您可以设置默认页面大小,然后显示打印对话框,但预计可能会更改,因为用户应该可以更改它,并且不应该忽略更改。您不关心页面大小,它是用户设置的任何内容,“pageRect”反映所选页面的大小。 –
这假设我可以从枚举中设置纸张大小 - 但对于定制打印机,情况并非如此......特别是对于连续滚动进纸。我试图告诉打印机纸张尺寸是什么(或者至少将其提示给打印对话框)。 – Thalia
'dpi'是一个换算系数。这不是一种物理测量。就像问“开车到纽约有多远”,而你回答“60英里/小时”。 –
@MarcB我的意思是PPI(像素每英寸 - 或每英寸点数?) - 我正在绘制尺寸为72 *英寸大小的场景项目。 'QPrinter'似乎同意,如果我'printer.setPaperSize(canvasRect,QPrinter :: Point);'和'qDebug() Thalia
场景中的单位不是像素,所以说PPI是没有意义的。你可以简单地说你的场景单位是1/72英寸。 –