PDA

View Full Version : QPrinter & QPainter Font Differences Between LInux and WIndows



tpf80
13th January 2009, 14:55
I have a Qt 4.4.3 app that uses QPainter to draw to a PDF QPrinter. It works perfectly in linux, and in windows, however the font sizes are enlarged when the code runs on the windows version. How can I get the Windows and Linux PDF's to render fonts exactly the same size?

Heres the code that I used to create the PDF:



void PdfGenerate::generatePdf() {

QString stufftowritetopdf;

QPrinter printer; //create a printer
setupLetterPoints(printer, "filename.pdf"); //set up reference points for our coordinate system
QPainter painter(&printer); //make a painter, which uses this printer,

///////////////////////////////////////////
/// in here draw some text
/////////////////////////////////////////////

stufftowritetopdf = "here we put a lot of text so that its long enough
to force a word wrap. When this text is rendered in linux and windows,
the resulting PDFs will have a different visable font size, even though the
code and text is the same. If You put enough text here to fill up a page
when compiled in linux, it will run off the bottom of the page in the windows
compiled version due to the windows version using a larger font size.";
totaldepth = totaldepth + drawrichtextinrect(&painter, leftmargin, totaldepth, horizmarginwidth, 0, stufftowritetopdf, normalsize);

///////////////////////////////////////////
/// done drawing text
/////////////////////////////////////////////

printlastpage(painter); //end the final page:
}

//set up the point coordinates for a letter sheet of paper:
void PdfGenerate::setupLetterPoints(QPrinter& printer, QString filename) {

printer.setOrientation(QPrinter::Portrait); //set theorientation of the paper
printer.setOutputFormat(QPrinter::PdfFormat); //make that printer as a PDF
printer.setOutputFileName(filename); //set the PDF file name
printer.setPaperSize(QPrinter::Letter); //set paper size
printer.setFullPage(false); //coordinates based on printable area
printer.setPageMargins( 0.5, 0.5, 0.5, 0.5, QPrinter::Inch);
printer.setResolution(72); //72 is standard

//(72 points / inch)
pagewidth = 540; //8.5 inch
pageheight = 720; //11 inch

margin = 0; // 0.5 inch margin

topmargin = margin;
bottommargin = pageheight - margin;
leftmargin = margin;
rightmargin = pagewidth - margin;

vertmarginwidth = pageheight - (margin * 2);
horizmarginwidth = pagewidth - (margin * 2);

noindent = 0;
indent1 = noindent + 15;
indent2 = indent1 + 15;

//font sizes:
fontFamily = "Times New Roman";
headersize = 15;
titlesize = 12;
stitlesize = 10;
normalsize = 8;
contractsize = 6;
pagenumsize = 8;

totaldepth = topmargin;
pagenum = 1;
totalpages = 5;
}

//draw rich text in a rect:
qreal PdfGenerate::drawrichtextinrect(QPainter *painter, qreal ulx, qreal uly, qreal rwidth, int flags, QString &text, int fontsize) {
QRectF rect(ulx, uly - 2, rwidth, 0);
qreal txtHeight = rect.height();

QTextDocument textdocument;
textdocument.setHtml(text);
textdocument.setDefaultFont(QFont(fontFamily, fontsize));

textdocument.setPageSize(QSize(rect.width(), QWIDGETSIZE_MAX));

QAbstractTextDocumentLayout* layout = textdocument.documentLayout();

//if our text takes up more than the rectangle height, then return the actual space taken up:
if (layout->documentSize().height() > txtHeight) {
txtHeight = layout->documentSize().height() - 4;
}

const int height = qRound(layout->documentSize().height());

int y = rect.y();
if (flags & Qt::AlignBottom)
y += (rect.height() - height);
else if (flags & Qt::AlignVCenter)
y += (rect.height() - height)/2;

QAbstractTextDocumentLayout::PaintContext context;
context.palette.setColor(QPalette::Text, painter->pen().color());

painter->save();

painter->translate(rect.x(), rect.y());
layout->draw(painter, context);

painter->restore();

return txtHeight;
}

void PdfGenerate::printlastpage(QPainter& painter) {
painter.end(); //done drawing, so save the PDF
}


Also, the PDF that is generated on the linux machine looks the same on the windows machine as it does on the linux machine. Conversely the PDF generated on the windows machine will have larger fonts when viewed on the linux machine. This leads me to believe the problem lies either in my code, the font, or a difference in the PDF QPrinter from windows to linux.

seneca
14th January 2009, 14:43
I ran into similar issue lately. It turned out that QTextDocument will allways assume (logical) screen resolution when painting, and that is probably different between windows and linux. On windows (where I'm working) the logical screen resolution is 96 DPI.

In my case everything was fine when printing in default QPrinter::ScreenResolution mode, but everything was far too small when printing with QPrinter::HighResolution.

My workaround was to scale the QPainter so QTextDocument could paint believing that the resolution is = screen resolution, and QPainter would "fix" it by its transformation.

Here a snippet of code:


int screenResolution = Bps::screenResolution();
qreal oldWidth = prv_->mDocument.textWidth();
if (prv_->mResolution>0 && prv_->mResolution != screenResolution) {
qreal f = prv_->mResolution / screenResolution;
aPainter->scale(f, f);
prv_->mDocument.setTextWidth(oldWidth / f);
} // if
prv_->mDocument.drawContents(aPainter);
prv_->mDocument.setTextWidth(oldWidth);

tpf80
14th January 2009, 20:29
Thanks, your tip did reveal that the difference in screen resolutions was causing the PDFs to render differently. Since QTextDocument is only used to paint to the PDF and not shown to the user, I would have never figured this out.

tpf80
15th January 2009, 00:07
Using the scaling workaround, I have gotten the PDF's to render very closely to the same on Windows and Linux. Although the characters render exactly the same size, Still the windows one renders blocks of text slightly bigger. What I notice is that there are still some slight differences in the way the font is rendered. For example:

1) There seems to be a difference between the character spacing on windows vs linux. Some phrases rendered in the linux version are maybe a pixel or 2 wider than on windows or vice versa. On average however it seems that windows is rendering blocks of text slightly wider.

2) Underlined text in linux renders different as well. For example if I have letters that hang down such as "y" "q" "g", etc. in linux the underline is below the whole letter, and on windows, the letter actually crosses the line.

On a small form with not much text this isn't much of a problem, but on a document with many pages of dense text, it is much more noticeable, and causes some text to not fit.

I am thinking that the font on windows is not exactly the same as the one on linux, but very close.

Currently I use the "Times New Roman" family and use this function to set the font:


textdocument.setDefaultFont(QFont(fontFamily, fontsize));


is there a way to specify more strictly specify the font to use, for example including a font file with my program and telling it to only use that font to generate PDF's?

seneca
15th January 2009, 00:46
QFontDatabase will do that.

tpf80
15th January 2009, 10:03
Thanks, looking further into QFontDatabase, I found blog entry at http://labs.trolltech.com/blogs/2006/08/04/fun-with-fonts/ which had a good example of this.