I am trying to print the contents of a QGraphicsScene
. The target printer could be anything - from the normal printers to custom size special printers. It must print things at actual size (inches, mm....).
In the QGraphicsScene
I am using the assumption of 72 ppi.
I assumed that:
1) rendering the scene to a printer would do it based on printer resolution, so that I would get items at actual size (inches/mm) similar to what they show on screen.
2) I can set the paper size for the printer to the desired canvas size (which is a rectangle on a very large scene) and nothing beyond it would print
3) I can set margins, and the contents outside the "actual canvas" will not be printed, including what is on margins.
All my assumptions so far are wrong:
1) for different printers, it seems the rendering is for max fit (using aspect ratio), if I suggest a custom size close to its default paper size (or if I don't set a paper size);
If I set a paper size that is not close (like 4x4 inch on a printer with default "LETTER" size) it just prints a blank page.
2-3) In the case where there is a print, and the printer just stretches the canvas to its full page, any items that are outside the drawing area are still printed.
I tried to clip, either on the painter or by setting the target rectangle on render, and the result was very odd clipping of a small section of the scene.
I have tried on HP LaserJet, Adobe PDF, and some custom printers with specific sizes (like 4x6 inch). They all scale the scene to the max size based on whether I specify Portrait or Landscape, and completely ignore my paper size request or the actual sizes.
Here is a small sample program to reproduce what I am trying to do.
The comments in the code show some options I tried.
#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();
}
Doing:
QPrinter printer(QPrinter::HighResolution);
qreal resolutionFactor = printer.resolution() / 1200.;
...
painter.scale(resolutionFactor, resolutionFactor);
fixes the LaserJet print (the scaling - not the painting outside the actual page) - but results into a tiny almost invisible print on a printer with 300 dpi resolution.
How can I get the printed output to be to actual scale (so that I can measure inches/mm on paper and have them be correct) ?
Also how can I get the output to be clipped to the actual canvas rectangle ?