I'm using PoDoFo to extract character displacement to update a text matrix correctly. This is a code fragment of mine:
PdfString str, ucode_str;
std::stack<PdfVariant> *stack;
const PdfFontMetrics *f_metrics;
...
/* Convert string to UTF8 */
str = stack->top().GetString();
ucode_str = ts->font->GetEncoding()->ConvertToUnicode(str, ts->font);
stack->pop();
c_str = (char *) ucode_str.GetStringUtf8().c_str();
/* Font metrics to obtain a character displacement */
f_metrics = ts->font->GetFontMetrics();
for (j = 0; j < strlen(c_str); j++) {
str_w = f_metrics->CharWidth(c_str[j]);
/* Adjust text matrix using str_w */
...
}
It works well for some PDF files (str_w
contains a useful width), but doesn't work for others. In these cases str_w
contains 0.0
. I took a look at the PoDoFo 0.9.5
sources and found CharWidth()
implemented for all sub-classes of PdfFontMetrics
.
Am I missing something important during this string conversion?
Update from 04.08.2017
@mkl did a really good job reviewing PoDoFo's code. However, I realized that I had to obtain a bit different parameter. To be precise, I needed a glyph width expressed in text space units (see PDF Reference 1.7, 5.1.3 Glyph Positioning and Metrics), but CharWidth()
is implemented in PdfFontMetricsObject.cpp
like:
double PdfFontMetricsObject::CharWidth(unsigned char c) const
{
if (c >= m_nFirst && c <= m_nLast &&
c - m_nFirst < static_cast<int>(m_width.GetSize())) {
double dWidth = m_width[c - m_nFirst].GetReal();
return (dWidth * m_matrix.front().GetReal() * this->GetFontSize() + this->GetFontCharSpace()) * this->GetFontScale() / 100.0;
}
if (m_missingWidth != NULL)
return m_missingWidth->GetReal();
else
return m_dDefWidth;
}
Width is calculated using additional multipliers (like font size, character space, etc.). What I really needed was dWidth * m_matrix.front().GetReal()
only. Thus, I decided to implement GetGlyphWidth(int c)
from the same file like:
double PdfFontMetricsObject::GetGlyphWidth(int c) const
{
if (c >= m_nFirst && c <= m_nLast &&
c - m_nFirst < static_cast<int>(m_width.GetSize())) {
double dWidth = m_width[c - m_nFirst].GetReal();
return dWidth * m_matrix.front().GetReal();
}
return 0.0;
}
and call this one instead of CharWidth()
from the first listing.