PDA

View Full Version : Trying to render two text strings on alternating lines and determining glyph height.



houzi
13th April 2014, 03:20
What I want to do is to make a simple word processor that will handle Tibetan Unicode and allow the user to specify some simple layout and be able to print everything out to paper. Code: https://gist.github.com/ironhouzi/10564915. Output: 10280

One of the problems I have to solve is that Tibetan being both horizontally and vertically oriented, can in rare cases have stacks that extend past the bottom line of the font (font descent). This is demonstrated in the beginning of the first two lines in the attached image. I have had to manually shorten and move the English line below to give room for the tall Tibetan glyph stack. I need to find a way to programatically detect when such a glyph stack is present so I can make the necessary line adjustments.

I've come across this example: http://stackoverflow.com/questions/14792074/how-to-determine-the-rendered-height-of-the-lines-of-a-qt-document

So I need to use QTextDocument, but how do I add my two QTextLayouts to the QTextDocument? I've tried to use QTextDocument.setDocumentLayout(), but this takes a QAbstractTextDocument as argument.

I could really need some guidance here, since there's not that much information on the lower level text rendering parts of Qt.

Am I going down a dead end path?

If anybody knows any books that explains the finer points of text rendering in Qt in great detail, I would love to know about it.

ChrisW67
13th April 2014, 23:14
Once you have determined the number of characters that will be drawn on one line you could possibly use QPainter::boundingRect() or QTextLayout::boundingRect() with the relevant part of the text to determine how high the line will render. If this gives you a sane height for the Tibetan stacks then you can ensure the following English line is rendered below that and not have to try to avoid the descending stacks.

houzi
13th April 2014, 23:25
Thank you for your reply.
Sadly, boundingRect() does not follow the actual printed glyphs, rather it seems as if the base of the rectangle returned from boundingRect() is equal to the value returned from QFontMetrics().descent(). The rendered glyph stack extends far below the rectangle of boundingRect().

ChrisW67
14th April 2014, 00:17
The problem is that the red box should enclose the text in this image:
10282
from the test code:


#include <QApplication>
#include <QPixmap>
#include <QPainter>
#include <QFont>
#include <QDebug>

int main(int argc, char **argv)
{
QApplication app(argc, argv);

const QString text = QString::fromUtf8(
// Your text
"\xE0\xBD\x96\xE0\xBD\xA6\xE0\xBE\x90\xE0\xBE\xB1\x E0\xBD\xBC\xE0\xBD\x84\xE0\xBD\xA6"
// Your complex text
"\xE0\xBD\xA7\xE0\xBE\xB9\xE0\xBE\xA8\xE0\xBE\xB3\x E0\xBE\xBA\xE0\xBE\xBC"
"\xE0\xBE\xBB\xE0\xBE\x83\xE0\xBC\x8B\xE0\xBD\x8A\x E0\xBE\x9B\xE0\xBE\x9C"
"\xE0\xBE\x9D\xE0\xBE\x9E\xE0\xBD\xB1\xE0\xBC\x8B"
);

QFont font("Microsoft Himalaya", 30);

QPixmap pixmap(200, 100);
pixmap.fill(Qt::white);
QPainter p(&pixmap);
p.setFont(font);
QRect br;
p.drawText(pixmap.rect(), Qt::AlignLeft | Qt::AlignTop, text, &br);
p.setPen(Qt::red);
p.drawRect(br);
p.end();
qDebug() << br;
pixmap.save("test.png");

return 0;
}
and it does not (Linux Qt 4.8.5 and 5.2.0). I would call this a bug but perhaps someone with more non-Latin text rendering experience has an insight.

I used to think boustrophedon (http://www.wikipedia.org/wiki/Boustrophedon) was exotic.

houzi
14th April 2014, 04:13
While I'm certainly a beginner with regards to the esoteric arts of font rendering on computers, I might think that this problem stems from the font designer breaking the rule for the descent value http://qt-project.org/doc/qt-4.8/qfontmetricsf.html#descent, but it's hard to know for sure when I don't really know much about this subject matter.

I do suspect that the font designer broke the rule for the right reasons though. These tall glyph stacks are clearly corner cases and the rectangle should enclose most Tibetan words. MS Himalaya is the only font I know that will handle these tall glyph stacks correctly and I suspect it is due to breaking this rule of allowing glyphs to be rendered beyond the descent boundary. But these are mere speculations unfortunately.

ChrisW67
14th April 2014, 04:42
I assume the exceptional glyph stacks are transliterations of things like foreign names.

I have had a bit more of a tinker and all the ways I can see of getting the rendered text size give the same result.

houzi
14th April 2014, 12:36
Your assumptions are correct. The tall glyph stacks are transliterations of Sanskrit words.
Anyways, thank you so much for your replies.
Perhaps I need to utilize some external libraries that can query the font somehow.

houzi
17th April 2014, 14:43
I found something that might work. QFontMatricsF.boundingRect(QFontMatricsF(QFont('hi malaya', 30)), "à½§à¾¹à¾¨à¾³à¾ºà¾¼à¾»à¾ƒà ¼‹à½Šà¾›à¾œà¾à¾žà½±à¼‹") does in fact draw a rectangle with the correct width and height, but the y coordinate is off. This call produced QRectF(0, -22, 44, 66.656). If I draw a rectangle for the coordinates (0, 11, 44, 67), they match up perfectly to the rendered glyph stacks.

Does anybody know why the y coordinate is completely off?

ChrisW67
17th April 2014, 22:02
I had noticed something similar but could not exploit it to get the expected result.

As I understand the Tibetan script the stacks are made of glyphs that can either be subscripted below existing ones, or superscripted above existing ones. Does your example have a superscripted glyph that might be the cause of the negative?

houzi
18th April 2014, 11:08
Tibetan glyph stacks can often have root letters with both superscribed and subscribed letters. Thanks for your input, I will try to remove the superscribed glyph and see how the rectangle changes.