If you have tried putting Gujarati captions on a video, you have probably seen one of four things: the tops of letters cut flat, marks from one line touching the line above, joined letters split apart, or empty rectangles where characters should be.
These look like four problems. They are two, and the first one has a single cause that we hit while building Bolo's caption renderer and that took a while to identify because nothing about it looks wrong in the code.
The measurement that causes it
A text renderer has to decide how tall a line is before it can stack lines. There are two ways to ask, and they give different answers.
The first is to measure the glyph bounding box — the rectangle around the ink actually drawn for those specific characters. The second is to ask the font what its line height is, using the metrics the type designer recorded.
For English these agree closely enough that nobody notices. Nothing in the Latin alphabet sits far above the capital height, so the ink and the font's declared ascent are near enough the same. Almost every text-rendering tutorial therefore uses the bounding box, because it is the more obvious call.
Why Gujarati breaks it
Gujarati is an abugida. Vowel marks — matras — attach above and below the consonant rather than sitting beside it, and some consonants join into conjunct forms that occupy more vertical space than either letter alone.
Those marks are frequently outside the glyph bounding box the renderer measured, because the box is drawn around the ink of the characters it was handed rather than around the vertical space the script needs. So the computed line height comes out too short.
Then the lines get stacked at that height. Line one looks fine, because there is nothing above it to collide with. Line two's upper matras run into line one's descenders, and if the frame is cropped at all, the tops get cut flat.
The fix
Measure from the font, not from the ink. In Python's PIL, that is the difference between two calls:
| Call | What it measures | Correct for Gujarati? |
|---|---|---|
| `font.getbbox(text)` | The ink of these specific characters | No — matras fall outside it |
| `font.getmetrics()` | The font's own ascent and descent | Yes |
Broken conjuncts are a different fault
If joined letters are appearing as separate characters — શ્રી rendering as three distinct shapes rather than one — that is not a line-height problem and no spacing change will fix it.
That is the font. Gujarati conjuncts require the font to contain the joined forms and the substitution rules that select them. A font with partial Gujarati coverage will render individual letters correctly and fail on the joins, which reads to a Gujarati speaker as a spelling error rather than a styling choice.
Empty rectangles are the same category, one step worse: the font has no glyph for that character at all.
How to test any tool in thirty seconds
- Generate a caption containing શ્રીજી, દ્વારકા and પ્રશ્ન. Between them these cover conjuncts and marks both above and below the line.
- Force it onto two or three lines with a longer sentence. One line hides the fault entirely.
- Look at the top edge of the letters on lines two and three. Marks should be complete and clear of the line above.
- Check the joins in શ્રી and પ્ર. Two separate shapes means the font lacks the conjunct forms.
- Look for empty rectangles anywhere. That is a missing glyph.
Why so many tools have this
Not carelessness, mostly. The bounding-box approach is what nearly every tutorial teaches, it is correct for the language those tutorials are written in, and it produces no visible symptom until someone renders an Indic script on more than one line.
It also survives review easily, because the code looks right. There is no error, no warning and no failing test — the measurement is simply answering a slightly different question than the one being asked.
The practical consequence for anyone choosing a tool is that this cannot be evaluated from a feature list. A tool either had someone test it in Gujarati specifically, or it did not, and thirty seconds with the three words above will tell you which.
The short version
- Clipped tops and overlapping lines come from measuring line height off the glyph bounding box.
- Gujarati matras sit outside that box, so the height comes out too short.
- Measure from the font metrics instead — `getmetrics()` rather than `getbbox()` in PIL.
- It only shows on lines two and three. A single-line test passes on a broken renderer.
- Split conjuncts are a font problem, not a spacing one, and need a font with the joined forms.
- Always check the exported file on a phone, never the editor preview.