PDA

View Full Version : Printing and Aspect ratio



cpt4
28th September 2011, 15:18
Hello,

I could not maintain an aspect ratio of 1 during printing (Linux, Qt 4.6.2, Qwt 6.0.1).

I have modified spectrogram/plot.cpp as following :

Plot::Plot (QWidget* parent) : QwtPlot (parent)
{
d_spectrogram = new QwtPlotSpectrogram ( );
QwtPlotRescaler* rescaler = new QwtPlotRescaler (canvas ( ), QwtPlot::xBottom, QwtPlotRescaler::fixed);
rescaler->setAspectRatio (1.);
rescaler->setEnabled (true);
...
}

This works fine in spectrogram window : when I resize it the aspect ratio is kept. But when I print a stretched spectrogram it takes all space and aspect ratio is significantly different from 1.

Does anyone know whats wrong ?

Thanks

Charles

Uwe
28th September 2011, 16:12
QwtPlotRescaler has no effect beside for the widget on screen.

Uwe

cpt4
28th September 2011, 20:15
So what could I do in order to maintain aspect ratio during printing ? Is there any class, any tip, any workaround, ... ? I need it !

Thanks again

Charles

Uwe
29th September 2011, 06:49
Well you want to have a fixed ratio between the scale ranges and the rectangle on the target device. So you need to adjust one of them.

What you can do easily is to set the rectangle for the plot on the target device. When you know the rectangle for your canvas you could use a QwtPlotLayout to find out how many pixels title, scales and legend need and add them to your canvas rectangle.

The other option is to adjust the scales. For this you also have to calculate the layout for the canvas with a QwtPlotLayout first. But be aware of the problem, that changing the scales might change the size of the canvas ( f.e. tick labels need more space ).

Uwe

cpt4
29th September 2011, 10:27
Thanks again Uwe.

I have rewrote the code in the renderer as following :

void QwtPlotRenderer::renderTo (QwtPlot* plot, QPrinter& printer)
{
int w = printer.width ( ), h = printer.height ( );
int cw = plot->canvas ( )->width ( ), ch = plot->canvas ( )->height ( );
QRectF rect (0, 0, w, h);
double caspect = cw / ch;
if (caspect >= 1.) rect.setHeight (rect.width ( ) / caspect);
else rect.setWidth (rect.height ( ) * caspect);

QPainter p (&printer);
render (plot, &p, rect);
}

It works, but not perfectly, the aspect ratio on the sheet is about 0.95, and I have to multiply height with a coef in order to kept my ratio to 1.

Charles


Well you want to have a fixed ratio between the scale ranges and the rectangle on the target device. So you need to adjust one of them.

What you can do easily is to set the rectangle for the plot on the target device. When you know the rectangle for your canvas you could use a QwtPlotLayout to find out how many pixels title, scales and legend need and add them to your canvas rectangle.

The other option is to adjust the scales. For this you also have to calculate the layout for the canvas with a QwtPlotLayout first. But be aware of the problem, that changing the scales might change the size of the canvas ( f.e. tick labels need more space ).

Uwe

Uwe
29th September 2011, 10:52
Ok, you decided to adjust the target rectangle. 2 notes:


There is absolutely no reason for patching QwtPlotRenderer. Your code is application code only and uses the public API of the renderer only.
You want to have the an aspect ratio for the plot canvas only - what is not the same as the bounding rectangle of the complete plot. I recommend to use a QwtPlotLayout and let it calculate the layout for an initial bounding rectangle - like the one in your code. Then check the calculated rectangle for the canvas and add ( or subtract ) the pixels, that are needed to make the ratio perfect and add/subtract it to the initial rectangle. Then render the plot to this rectangle.



Uwe

cpt4
30th September 2011, 12:36
Thank again for your advices Uwe.

I agree with you, but not completly. I should not have to patch the renderer, thats true. But I think that the renderer has to render the plot with the same manear on any device (screen, printer, image). If I explicitly request an aspect ratio of 1, pluging a QwtPlotRescaler, I would like to take benefit of it on any device.

Of course I prefere to respect the public API. I just have tried your last advice, but I have failed again. The code in spectrogram::print is now as following :

QwtPlotRenderer renderer;
int w = printer.width ( ), h = printer.height ( );
int cw = canvas ( )->width ( ), ch = canvas ( )->height ( );
QRectF rect (0, 0, w, h);

double caspect = cw / (double)ch;
if (caspect >= 1.)
rect.setHeight (rect.width ( ) / caspect);
else
rect.setWidth (rect.height ( ) * caspect);

layout.activate (this, rect);
QPainter painter ((QPaintDevice*)&printer);
renderer.render (this, &painter, layout.canvasRect ( ));

My aspect ratio of 1 is still not kept. Maybe the used rectangle is not the good one, I don't know.

Do you have any suggestion ?

Thanks a lot

Charles

Uwe
30th September 2011, 13:28
Start with any reasonable initial rectangle and calculate a layout for it using a QwtPlotLayout.
Check the calculated sub-rectangle for the canvas and find out how many pixels are missing for having the desired aspect ratio.
Then add/subtract these pixels to the initial rectangle and render into this one.

The strategy of QwtPlotLayout is to find out what title and scales need and distribute the rest to canvas and legend. So when you expand your initial rectangle you can expect that all extra pixels go to canvas + legend. When you don't have a legend with several rows/columns the region for it should be fix too.

Of course you have to take care, that there no stuff like word wrapping happens, when adjusting your initial rectangle,

Uwe

cpt4
30th September 2011, 13:51
I have applied my test with a pretty plot (a reasonable rectangle), but my aspect ratio (w/h on the paper) is about 0.8. I don't have wrapped words.

I am not sure to understand exactly what you mean with "add/subtract these pixels to the initial rectangle". Where is the "initial rectangle", how could I get it and how modify it ? How should I render into this rectangle ?

What is not correct in my code ?

Thanks

Charles

Uwe
30th September 2011, 14:28
Where is the "initial rectangle ..."
This could be any rectangle - big enough to expect to have no word wraps. It is only a starting point and doesn't need to have any aspect ratio. It could be the rectangle from your code, if you want to.

The only purpose for calculating a layout for this rectangle is to get the size for the canvas ( for the print - not for the widget on screen ) to find out how you could adjust it to have the aspect ratio you need. Because the sizes for scales, title and legend shouldn't depend on the bounding rectangle for your print you can expect that you get a correct ratio for the canvas rectangle, when you add your adjustment to the initial rectangle and render into this adjusted bounding rectangle.

But isn't this more or less the same I have written before ?


What is not correct in my code ?

Almost everything,

Uwe