PDA

View Full Version : Pixelated QwtPlotTextLabel and QwtPlotRenderer



Seamus
11th June 2013, 13:35
Hello Everybody

When using classes derived from QwtPlotTextLabel with QwtPlotRenderer I'm getting pixelated text, I think the cached copy is being used. The screenshot is of a print preview at 200%, the watermark and two bright labels are the objects that inherit QwtPlotTextLabel, no painter or draw functions have been overloaded.
9139

Saving to PDF works as expected, all text is vector. I would like to get raster formats and print preview to display vector text (setting PDF output on the QPrinter/QPrintPreviewDialog doesn't help).

Is there a flag I can set to disable caching prior to calling QwtPlotRenderer?

Uwe
11th June 2013, 20:03
Have a look at the implementation of QwtPlotTextLabel::draw(). In case of a painter, that is scaling, doAlign should be set to false - not using the pixmap cache.

Please check the implementation in the debugger and tell me if I'm true.

Uwe

PS: to be honest I didn't get what you mean as "pixelated" in the screenshot - maybe it can be seen easier with 800% ?

Seamus
11th June 2013, 23:29
Okay, I implemented QwtPlotTextLabel::draw(), just added a test for QPaintEngine::Picture and now text renders nice and crisp.

I think a case for QPaintEngine::Picture may be a nice addition to QwtPainter::isAligning(), or even just in draw functions for plot items that cache text.

Uwe
12th June 2013, 06:51
Okay, I implemented QwtPlotTextLabel::draw() ...
From looking at the code the cache is not used as soon as you have a painter that is scaling. So even when rendering to a QImage the cache should have not been used !
When you work around it in your code and don't tell me what went wrong I can't fix it in the lib.


I think a case for QPaintEngine::Picture may be a nice addition to QwtPainter::isAligning(), or even just in draw functions for plot items that cache text.
The same with QwtGraphic (http://qwt.sourceforge.net/class_qwt_graphic.html), that has been implemented because of the limitations of QPicture and QSvgRenderer.

Note that there is a global setting, where you can en/disable all rounding for integer based paint devices: http://qwt.sourceforge.net/class_qwt_painter.html#a49581f980f2c761852cda08502 c96abb, what disables all pixmap caches as a side effect. But be careful with using it as this is about avoiding rounding errors: f.e. the raster paint engine rounds the right/bottom coordinates of rectangles in a different way than it is needed for a plot.

Uwe

Seamus
12th June 2013, 08:01
When you work around it in your code and don't tell me what went wrong I can't fix it in the lib.
The printer sent with QPrintPreviewDialog::paintRequested(), returns QPaintEngine::Picture for paintEngine()->type().

This was the workaround I used:


void PlotTextLabel::draw( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect ) const
{
if (painter->paintEngine()->type() == QPaintEngine::Picture) {
const int m = margin();

const QRectF rect = textRect( canvasRect.adjusted( m, m, -m, -m ),
text().textSize( painter->font() ) );

text().draw(painter, rect);
} else {
QwtPlotTextLabel::draw(painter, xMap, yMap, canvasRect);
}
}


This would have worked, but may have some side-effects.


bool QwtPainter::isAligning( QPainter *painter )
{
if ( painter && painter->isActive() )
{
switch ( painter->paintEngine()->type() )
{
case QPaintEngine::Pdf:
case QPaintEngine::SVG:
case QPaintEngine::Picture: // <- Here
return false;

default:;
}

const QTransform tr = painter->transform();
if ( tr.isRotating() || tr.isScaling() )
{
return false;
}
}

return true;
}

Uwe
12th June 2013, 08:50
Come on: drawing to a QImage should also be done without using the cache for a painter with scaling ( see the code you have posted ! ) and all your code should be obsolete.
As you wrote that this is not working I'm more interested in fixing the bug instead of finding workarounds.

About your proposal adding QPaintEngine::Picture as not aligning: this is as wrong as returning that it is aligning. The correct answer would be 'don't know' as it depends on the paint device where the picture is replayed.

You might avoid rounding errors when replaying the picture with a scaled painter, but instead you introduce other rounding errors f.e. where gridlines and curve symbols are not aligned anymore. What type of errors are less annoying depends on the application and can only be decided there ( use QwtPainter::setRoundingAlignment() ) - but as it is not possible to avoid having rounding issues with record/replay paint devices ( QPicture/QwtGraphic/QSvgRenderer ) I would try to avoid them.

Uwe

Seamus
12th June 2013, 22:35
Come on: drawing to a QImage should also be done without using the cache for a painter with scaling ( see the code you have posted ! ) and all your code should be obsolete.
How can you tell if the QPainter is scaling when QPainter::transform().isScaling() always return false.



void PlotTextLabel::draw( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect ) const
{
qDebug() << __FUNCTION__ << painter->paintEngine()->type() << painter->transform().isScaling();
QwtPlotTextLabel::draw(painter, xMap, yMap, canvasRect);
}

Uwe
13th June 2013, 06:50
How can you tell if the QPainter is scaling when QPainter::transform().isScaling() always return false.
Then the painter is not scaling - but when you don't have a painter transformation, what is the reason of the "pixelation". Could you make a small compilable demo showing the issue ?

Uwe

PS: One thing I can see is that the pixmap cache should be created by QwtPainter::backingStore() for the Retina displays on the Mac. But this shouldn't be of importance for your situation.

Seamus
14th June 2013, 01:31
9154
To see the jagged edges just zoom in on the label (the text in the centre).

Uwe
14th June 2013, 08:18
O.k. now I see: QPrinter/QPrintPreviewDialog redirects to a QPicture - then the picture is replayed/scaled according to the size of the preview window.

But what is the correct solution for record/replay paint devices:



not rounding while recording means that you run into issues when replaying ( Qt doesn't know how to round ).
When rounding while recording you run into problems when replaying with a scaling factor


As there is no general solution to this problem it is something that should at least be decidable by the application, that knows more about the plot and the use case. With the current implementation this is possible with QwtPainter::setRoundingAlignment(), where you can disable rounding done by Qwt. When adding QPaintEngine::Picture to QwtPainter::isAligning() rounding would always be disabled and could not be enabled in application code anymore. That's why I don't like this fix.

But for your problem this all is of no imprtance. Texts are never 100% aligned to plot coordinates and the decision for using a cache in QwtPlotTextLabel is made because of performance considerations only. So I changed the implementation of QwtPlotTextLabel::draw() not using the cache for QPaintEngine::Picture and QPaintEngine::User ( usually QwtGraphic ). Fixed in SVN trunk and 6.1 branch.

When working with Qwt 6.1.0 this should be the workaround for your code ( accepting minor rounding errors when replaying images, rectangles or shapes ):


void PixellationMainWindow::renderPlot(QPrinter *printer)
{
const bool doAlign = QwtPainter::roundingAlignment();
QwtPainter::setRoundingAlignment( false );

...

QwtPainter::setRoundingAlignment( doAlign );
}Uwe