Better handling composite fonts

This commit is contained in:
Jakub Melka 2019-04-30 18:38:27 +02:00
parent 4d770fdfcf
commit 8667cbbf90
4 changed files with 89 additions and 17 deletions

View File

@ -191,11 +191,11 @@ public:
/// Tries to read array of real values from dictionary. If entry dictionary doesn't exist,
/// or error occurs, empty record is returned.
std::vector<PDFReal> readNumberArrayFromDictionary(const PDFDictionary *dictionary, const char *key);
std::vector<PDFReal> readNumberArrayFromDictionary(const PDFDictionary* dictionary, const char* key);
/// Tries to read array of integer values from dictionary. If entry dictionary doesn't exist,
/// or error occurs, empty record is returned.
std::vector<PDFInteger> readIntegerArrayFromDictionary(const PDFDictionary *dictionary, const char *key);
std::vector<PDFInteger> readIntegerArrayFromDictionary(const PDFDictionary* dictionary, const char* key);
/// Reads number from dictionary. If dictionary entry doesn't exist, or error occurs, default value is returned.
/// \param dictionary Dictionary containing desired data

View File

@ -436,7 +436,7 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
}
}
const PDFReal glyphWidth = font->getGlyphWidth(static_cast<uint8_t>(byteArray[i]));
const PDFReal glyphWidth = font->getGlyphAdvance(static_cast<uint8_t>(byteArray[i]));
if (glyphIndex)
{
@ -467,16 +467,23 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
textSequence.items.reserve(textSequence.items.size() + cids.size());
for (CID cid : cids)
{
GID glyphIndex = CIDtoGIDmapper->map(cid);
const GID glyphIndex = CIDtoGIDmapper->map(cid);
const PDFReal glyphWidth = font->getGlyphAdvance(cid);
if (!glyphIndex)
if (glyphIndex)
{
throw PDFParserException(PDFTranslationContext::tr("Glyph for composite font character not found."));
// TODO: Dodelat mapovani na unicode
const Glyph& glyph = getGlyph(glyphIndex);
textSequence.items.emplace_back(&glyph.glyph, QChar(), glyph.advance);
}
else
{
reporter->reportRenderError(RenderErrorType::Warning, PDFTranslationContext::tr("Glyph for composite font character with cid '%1' not found.").arg(cid));
if (glyphWidth > 0)
{
textSequence.items.emplace_back(nullptr, QChar(), glyphWidth * m_pixelSize * FONT_WIDTH_MULTIPLIER);
}
}
// TODO: Dodelat mapovani na unicode
const Glyph& glyph = getGlyph(glyphIndex);
textSequence.items.emplace_back(&glyph.glyph, QChar(), glyph.advance);
}
break;
@ -1060,7 +1067,51 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
baseFont = fontLoader.readNameFromDictionary(descendantFontDictionary, "BaseFont");
return PDFFontPointer(new PDFType0Font(qMove(fontDescriptor), qMove(cmap), qMove(cidToGidMapper)));
// Read default advance
PDFReal dw = fontLoader.readNumberFromDictionary(descendantFontDictionary, "DW", 1000.0);
std::array<PDFReal, 2> dw2 = { };
fontLoader.readNumberArrayFromDictionary(descendantFontDictionary, "DW2", dw2.begin(), dw2.end());
PDFReal defaultWidth = descendantFontDictionary->hasKey("DW") ? dw : dw2.back();
// Read horizontal advances
std::unordered_map<CID, PDFReal> advances;
if (descendantFontDictionary->hasKey("W"))
{
const PDFObject& wArrayObject = document->getObject(descendantFontDictionary->get("W"));
if (wArrayObject.isArray())
{
const PDFArray* wArray = wArrayObject.getArray();
const size_t size = wArray->getCount();
for (size_t i = 0; i < size;)
{
CID startCID = fontLoader.readInteger(wArray->getItem(i++), 0);
const PDFObject& arrayOrCID = document->getObject(wArray->getItem(i++));
if (arrayOrCID.isInt())
{
CID endCID = arrayOrCID.getInteger();
PDFReal width = fontLoader.readInteger(wArray->getItem(i++), 0);
for (CID currentCID = startCID; currentCID <= endCID; ++currentCID)
{
advances[currentCID] = width;
}
}
else if (arrayOrCID.isArray())
{
const PDFArray* widthArray = arrayOrCID.getArray();
const size_t widthArraySize = widthArray->getCount();
for (size_t widthArrayIndex = 0; widthArrayIndex < widthArraySize; ++widthArrayIndex)
{
PDFReal width = fontLoader.readNumber(widthArray->getItem(widthArrayIndex), 0);
advances[startCID + static_cast<CID>(widthArrayIndex)] = width;
}
}
}
}
}
return PDFFontPointer(new PDFType0Font(qMove(fontDescriptor), qMove(cmap), qMove(cidToGidMapper), defaultWidth, qMove(advances)));
}
default:
@ -1113,7 +1164,7 @@ PDFSimpleFont::PDFSimpleFont(FontDescriptor fontDescriptor,
}
PDFInteger PDFSimpleFont::getGlyphWidth(size_t index) const
PDFInteger PDFSimpleFont::getGlyphAdvance(size_t index) const
{
const size_t min = m_firstChar;
const size_t max = m_lastChar;
@ -1560,4 +1611,15 @@ PDFFontCMapRepository::PDFFontCMapRepository()
}
PDFReal PDFType0Font::getGlyphAdvance(CID cid) const
{
auto it = m_advances.find(cid);
if (it != m_advances.cend())
{
return it->second;
}
return m_defaultAdvance;
}
} // namespace pdf

View File

@ -25,6 +25,8 @@
#include <QFont>
#include <QSharedPointer>
#include <unordered_map>
class QPainterPath;
namespace pdf
@ -282,8 +284,8 @@ public:
const encoding::EncodingTable* getEncoding() const { return &m_encoding; }
const GlyphIndices* getGlyphIndices() const { return &m_glyphIndices; }
/// Returns the glyph width (or zero, if glyph width is invalid)
PDFInteger getGlyphWidth(size_t index) const;
/// Returns the glyph advance (or zero, if glyph advance is invalid)
PDFInteger getGlyphAdvance(size_t index) const;
protected:
QByteArray m_name;
@ -466,10 +468,12 @@ private:
class PDFType0Font : public PDFFont
{
public:
explicit inline PDFType0Font(FontDescriptor fontDescriptor, PDFFontCMap cmap, PDFCIDtoGIDMapper mapper) :
explicit inline PDFType0Font(FontDescriptor fontDescriptor, PDFFontCMap cmap, PDFCIDtoGIDMapper mapper, PDFReal defaultAdvance, std::unordered_map<CID, PDFReal> advances) :
PDFFont(qMove(fontDescriptor)),
m_cmap(qMove(cmap)),
m_mapper(qMove(mapper))
m_mapper(qMove(mapper)),
m_defaultAdvance(defaultAdvance),
m_advances(qMove(advances))
{
}
@ -481,9 +485,16 @@ public:
const PDFFontCMap* getCMap() const { return &m_cmap; }
const PDFCIDtoGIDMapper* getCIDtoGIDMapper() const { return &m_mapper; }
/// Returns the glyph advance, if it can be obtained, or zero, if it cannot
/// be obtained or error occurs.
/// \param cid CID of the glyph
PDFReal getGlyphAdvance(CID cid) const;
private:
PDFFontCMap m_cmap;
PDFCIDtoGIDMapper m_mapper;
PDFReal m_defaultAdvance;
std::unordered_map<CID, PDFReal> m_advances;
};
/// Repository with predefined CMaps

View File

@ -1772,7 +1772,6 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
const bool fill = isTextRenderingModeFilled(textRenderingMode);
const bool stroke = isTextRenderingModeStroked(textRenderingMode);
const bool clipped = isTextRenderingModeClipped(textRenderingMode);
// TODO: Pouzit pravdepodobne sirky z widths array?
// Detect horizontal writing system
const bool isHorizontalWritingSystem = font->isHorizontalWritingSystem();