Printing really huge image on plotter using QPrinter - qt

I have to print on plotter world map with a lot of vector data on it from Qt based app. Plotter has 80 GB hard drive, to print high resolution images. All data is loaded in QGraphicsScene.
QGraphicsScene *scene;
.....
QPrinter *printer = new QPrinter(QPrinter::ScreenResolution);
printer->setPaperSize(QPrinter::A4);
QPainter painter(printer);
painter.setRenderHint(QPainter::Antialiasing);
A4 is using for improve speed during tests.
forever
{
if(printedHeight >= sceneHeight)
{
isPrintingRunning = false;
qDebug() << "Printing finished";
break;
}
...loading next tile strip
scene->render(&painter, toPage(sceneRect), tileStripRect);
scene->clearStrip;
printedHeight += stripHeight;
}
After loading vector data, i'm loading tiles(256x256 px) by horizontal strips, render strip to painter, clear tiles from scene, than again. Because i'm rendering by strips scene doesn't exceed available memory, but QPainter doesn't send data to printer until it will be deleted, that's why my app very quickly run out of memory. There is an opportunity to call QPainter::end() each cycle step, but in this way each strip is printed on differrent page on ordinary printer, so I suppose plotter will cut each strip, as soon as i can't control plotter's knife. So this is not a solution. How can I force QPainter to send data and clear its cache, but stay in the same print session?

Related

Is it possible to set a clip path on a QImage or save what a Qpainter paints?

I have a QImage I am able to clip out a QRegion of and successfully clip out the region using the QPainter class setClipRegion() function. However, I want to save what is drawn as a new QImage but am not seeing anything in the docs about saving what is actually displayed.
I've tried directly changing the images alpha channel to match the clipping region but my implementation is very inefficient. The setClipRegion() function was the only thing I learned that could efficiently display what I wanted. My end goal is to use the clipped image as a QOpenGLTexture so I somehow need to save the originally clipped image.
Thanks for any help.
You can simply specify a new file name when saving. so you do not overwrite the old one.
image = QtGui.QImage('orginal.png')
output = QtGui.QImage(image.size(), QtGui.QImage.Format_ARGB32)
output.fill(QtCore.Qt.transparent)
painter = QtGui.QPainter(output)
....
-> your clip path
....
painter.drawImage(QtCore.QPoint(), image)
painter.end()
output.save('new.png')

How to print long widgets consecutively

At QT, I made the ui with QWidget. And I want to print the ui with my printer. But, The ui is too long to print on one page.(height is greater than the A4 size) I want continuous prints without newPage() function.
I use QPrinter and QPainter. But, The result I received was a cropped widget image. I don't want to use newPage() function.
QPrinter printer;
QPainter painter;
QPrintDialog printDialog(&printer);
if (printDialog.exec() == QDialog::Accepted) {
painter.begin(&printer);
ui->scrollArea->widget()->render(&painter);
}
I do not like to apply printer.newPage() manually to every ui.
Is there any option or code that prints automatically on the next page like MS Word?

How to draw QLines at startup?

I'm going to draw a QLine in a QGraphicsScene and display it via a QGraphicsView.
The line is drawn during mainwindow construction, but deleted after leaving the MainWindow constructor shortly after been drawn and before reaching any slot. (I noticed this behaviour during debugging.)
The most relevant code lines are:
MainWindow::MainWindow(QWidget* parent):
ui{new Ui::MainWindow},
scene{new QGraphicsScene(this)},
view{new ClickableMap(scene)}, / ... */
{
ui->setupUi(this);
ui->view->setScene(scene);
for (/* ... */ ) {
QGraphicsItem* edgeDrawing= scene->addLine(x1, y1, x2, y2);
edgeDrawing->setZValue(1);
}
ui->view->show();
}
Why exactly is the drawing hidden? It's no problem to draw by using the signal-slot concept (mouse click on the QGraphicsView), but I would like to display the drawing at program start.
Thanks to #hyde , I found the answer: I executed scene->clear() in a slot called after loading some pictures. Apparently, the execution was delayed by Qt. (Some debug output was output before the scene was deleted in reality despite these output instructions were placed after the call of QGraphicsView::clear() in the source code.)

Convert pixel size to point size for fonts on multiple platforms

I need a way to translate point size and pixel size between multiple platforms.
I have a Qt application that must run on multi-platform, including an embedded Linux on a type of tablet.
It is expected that users can save files created by the application, on a desktop (either windows or linux) and open on the custom device.
The data consists of drawings, and text - QGraphicsItems on a QGraphicsScene. Some text items are "rich text", so we can change font on fragments of text.
For normal text, including all UI text, we used pixel size instead of point size to achieve a similar look. But rich text defies me: the QTextCharFormat doesn't have a pixelSize() option. Only setFontPointSize() and fontPointSize(). I can use font().setPixelSize() then setFont() but the result is that when saving, using the html() method, I lose all font information. (Must be a qt bug ?)
So, what I need is to be able to use pixel size everywhere, and then calculate the point size to set it on paragraphs (and go in reverse when reading sizes).
But - what is the relation between pixel size and point size ? If I determine both, for a given font, on the current platform, can I establish some sort of equation to use ?
Edit - I found an interesting post - it seems to do what I want, but it is specific to only OSX. https://stackoverflow.com/a/25929628/1217150
My target platforms, Windows / Linux / OSX but also, especially, a custom tablet running embedded Linux, and possibly in the future Android devices.
Qt 4.8
Edit - using the conversion in answer below, left text using setPixelSize(20) and right text using setPointSize(20 * screenDpi) where
qreal screenDpi = QApplication::desktop()->physicalDpiX() / 72.;
Note the size is not the same... (running in windows, have not yet tested on other platforms)
I even tried
#ifdef Q_OS_WIN32
qreal screenDpi = QApplication::desktop()->physicalDpiX() / 96.;
#else
qreal screenDpi = QApplication::desktop()->physicalDpiX() / 72.;
#endif
Yes, I think it is possible:
double ptToPx(double pt, double dpi) {
return pt/72*dpi
}
double pxToPt(double px, double dpi) {
return px*72/dpi
}
...
double dpi = QGuiApplication::primaryScreen()->physicalDotsPerInch();
qDebug() << "12 pt is" << ptToPx(12, dpi) << "px";
qDebug() << "26 px is" << pxToPt(26, dpi) << "pt";
But rich text defies me: the QTextCharFormat doesn't have a pixelSize() option. Only setFontPointSize() and fontPointSize().
You can set prepared QFont with QTextCharFormat::FontPropertiesSpecifiedOnly behavior parameter to set only pixelSize:
QFont font;
font.setPixelSize(18);
QTextCharFormat fmt;
fmt.setFont(font, QTextCharFormat::FontPropertiesSpecifiedOnly);

Constructing QImage from unsigned char* data

I encountered a problem with passing Image object (captured with Point Grej FlyCapture2 SDK) to QImage object. I am getting a pointer associated with Image data by function:
virtual unsigned char* FlyCapture2::GetData ( )
and then loading the data by:
QImage::QImage ( uchar * data, int width, int height, int bytesPerLine, Format format )
Formats of data of both Image objects are 8-bit monocolor. BytesPerLine parameter should be equal to width of the Image (I've already checked it by saving FlyCapture2::Image to .bmp and then loading it to QImage).
Do you thing the problem is casting from unsigned char* to uchar*?
Do you have any other ideas? Copying image pixel by pixel is much too slow.
EDIT: I am converting Image captured by FlyCapture into the FlyCapture2::PIXEL_FORMAT_RGB8 , for which: R = G = B = 8 bits, within PGR::SnapShot() function. SnapShot() returns unsigned char* const.
and here is a part of my Qt display function:
unsigned char *const img = PGRSystem->SnapShot();
QImage Img(img, 1024, 768, QImage::Format_RGB888);
QGraphicsScene *Scene = new QGraphicsScene();
Scene->addPixmap(QPixmap::fromImage(Img));
ui.ImageView->setScene(Scene);
ui.ImageView->fitInView(ui.ImageView->itemAt(100,100));
delete [] Scene;
I also tried to save Img to file, but got unhandled exception then. I tried other pixel format pairs (FlyCapture2::PIXEL_FORMAT_RGB - 24 bit RGB with QImage::RGB888 and FlyCapture2::PIXEL_FORMAT_RGBU32 with QImage::RGB32)
It is also worth to mention that QImage constuctor, which I am using, does not set the colorTable (I am getting exception when checking if QImage is in grayScale).
I need a little more help I guess.
First thing - QImage doesn't support a native greyscale image, which is what it sounds as if you're getting as output - so I would be curious what Format argument you're using. Probably the easiest solution, though memory-inefficent, will be to expand your greyscale image to RGB by copying each value three times (into a new QByteArray).
An additional concern is that the particular QImage constructor you're using, does not copy the underlying data, so you need be sure the pointer returned from GetData() outlives the QImage - or force the QImage to make a copy internally, using, say, QImage::copy.
Seeing more code would help, as other respondents noted above.
Thanks a lot for your help, you were right about the Image formats. Unfortunatelly the main problem was associated with passing the pointer between functions. In PGR::SnapShot() I was creating FlyCapture2::Image and then I was getting the pointer to data. FlyCapture2::Image was detructed when exit the function so returned pointer was BadPtr.

Resources