Bugfixes in the font drawing

This commit is contained in:
Jakub Melka 2019-04-16 19:59:10 +02:00
parent 9d982747e2
commit e167e2463d
4 changed files with 99 additions and 94 deletions

View File

@ -27,6 +27,7 @@
#include <freetype/ftoutln.h>
#include <QMutex>
#include <QPainterPath>
#ifdef Q_OS_WIN
#include "Windows.h"
@ -405,7 +406,7 @@ void PDFRealizedFontImpl::checkFreeTypeError(FT_Error error)
message = QString::fromLatin1(errorString);
}
throw PDFParserException(PDFTranslationContext::tr("FreeType error code %1: message").arg(error).arg(message));
throw PDFParserException(PDFTranslationContext::tr("FreeType error code %1: %2").arg(error).arg(message));
}
}
@ -435,21 +436,10 @@ PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(PDFFontPointer font,
const FontDescriptor* descriptor = font->getFontDescriptor();
if (descriptor->isEmbedded())
{
PDFRealizedFontImpl::checkFreeTypeError(FT_Init_FreeType(&impl->m_library));
if (!descriptor->fontFile.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile;
}
else if (!descriptor->fontFile2.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile2;
}
else if (!descriptor->fontFile3.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile3;
}
const QByteArray* embeddedFontData = descriptor->getEmbeddedFontData();
Q_ASSERT(embeddedFontData);
impl->m_embeddedFontData = *embeddedFontData;
// At this time, embedded font data should not be empty!
Q_ASSERT(!impl->m_embeddedFontData.isEmpty());
@ -689,7 +679,8 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
throw PDFParserException(PDFTranslationContext::tr("Invalid encoding entry of the font."));
}
}
else
if (encoding == PDFEncoding::Encoding::Invalid)
{
// We get encoding for the standard font. If we have invalid standard font,
// then we get standard encoding. So we shouldn't test it.
@ -703,6 +694,73 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
simpleFontEncodingTable = *PDFEncoding::getTableForEncoding(encoding);
if (fontDescriptor.isEmbedded())
{
// Return encoding from the embedded font
const QByteArray* embeddedFontData = fontDescriptor.getEmbeddedFontData();
Q_ASSERT(embeddedFontData);
FT_Library library;
if (!FT_Init_FreeType(&library))
{
FT_Face face;
if (!FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(embeddedFontData->constData()), embeddedFontData->size(), 0, &face))
{
if (FT_Has_PS_Glyph_Names(face))
{
for (FT_Int i = 0; i < face->num_charmaps; ++i)
{
FT_CharMap charMap = face->charmaps[i];
switch (charMap->encoding)
{
case FT_ENCODING_ADOBE_STANDARD:
case FT_ENCODING_ADOBE_LATIN_1:
case FT_ENCODING_ADOBE_CUSTOM:
case FT_ENCODING_ADOBE_EXPERT:
{
// Try to load data from the encoding
if (!FT_Set_Charmap(face, charMap))
{
for (size_t i = 0; i < simpleFontEncodingTable.size(); ++i)
{
FT_UInt glyphIndex = FT_Get_Char_Index(face, static_cast<FT_ULong>(i));
if (glyphIndex > 0)
{
char buffer[128] = { };
if (!FT_Get_Glyph_Name(face, glyphIndex, buffer, static_cast<FT_ULong>(std::size(buffer))))
{
QByteArray byteArrayBuffer(buffer);
QChar character = PDFNameToUnicode::getUnicodeForName(byteArrayBuffer);
if (character.isNull())
{
character = PDFNameToUnicode::getUnicodeForNameZapfDingbats(byteArrayBuffer);
}
if (!character.isNull())
{
encoding = PDFEncoding::Encoding::Custom;
simpleFontEncodingTable[i] = character;
}
}
}
}
}
break;
}
default:
break;
}
}
}
FT_Done_Face(face);
}
FT_Done_FreeType(library);
}
}
// Fill in differences
if (hasDifferences)
{
@ -784,45 +842,7 @@ PDFSimpleFont::PDFSimpleFont(FontDescriptor fontDescriptor,
PDFRealizedFontPointer PDFSimpleFont::getRealizedFont(PDFFontPointer font, PDFReal fontSize) const
{
// TODO: Fix font creation to use also embedded fonts, font descriptor, etc.
// TODO: Remove QRawFont
return PDFRealizedFont::createRealizedFont(font, fontSize);
/*
QRawFont rawFont;
if (m_fontDescriptor.isEmbedded())
{
// Type 1 font
if (!m_fontDescriptor.fontFile.isEmpty())
{
rawFont.loadFromData(m_fontDescriptor.fontFile, fontSize, QFont::PreferNoHinting);
}
else if (!m_fontDescriptor.fontFile2.isEmpty())
{
rawFont.loadFromData(m_fontDescriptor.fontFile2, fontSize, QFont::PreferNoHinting);
}
if (!rawFont.isValid())
{
throw PDFParserException(PDFTranslationContext::tr("Can't load embedded font."));
}
}
else
{
// TODO: Zkontrolovat, zda se zde opravdu prebiraji spravne fonty
const int weight = qBound<int>(0, m_fontDescriptor.fontWeight / 10.0, 99);
const int stretch = qBound<int>(1, m_fontDescriptor.fontStretch, 4000);
QFont font(m_baseFont);
font.setHintingPreference(QFont::PreferNoHinting);
font.setStretch(stretch);
font.setWeight(weight);
font.setPixelSize(fontSize);
rawFont = QRawFont::fromFont(font, QFontDatabase::Any);
}
return rawFont;*/
}
QString PDFSimpleFont::getTextUsingEncoding(const QByteArray& byteArray) const
@ -928,4 +948,22 @@ PDFRealizedFontPointer PDFFontCache::getRealizedFont(const PDFFontPointer& font,
return it->second;
}
const QByteArray* FontDescriptor::getEmbeddedFontData() const
{
if (!fontFile.isEmpty())
{
return &fontFile;
}
else if (!fontFile2.isEmpty())
{
return &fontFile2;
}
else if (!fontFile3.isEmpty())
{
return &fontFile3;
}
return nullptr;
}
} // namespace pdf

View File

@ -22,9 +22,11 @@
#include "pdfencoding.h"
#include "pdfobject.h"
#include <QRawFont>
#include <QFont>
#include <QSharedPointer>
class QPainterPath;
namespace pdf
{
class PDFDocument;
@ -154,6 +156,9 @@ struct FontDescriptor
{
bool isEmbedded() const { return !fontFile.isEmpty() || !fontFile2.isEmpty() || !fontFile3.isEmpty(); }
/// Returns embedded font data, or nullptr, if font is not embedded
const QByteArray* getEmbeddedFontData() const;
QByteArray fontName;
QByteArray fontFamily;
QFont::Stretch fontStretch = QFont::AnyStretch;
@ -233,7 +238,7 @@ public:
virtual FontType getFontType() const = 0;
/// Realizes the font (physical materialization of the font using pixel size,
/// if font can't be realized, then empty QRawFont is returned).
/// if font can't be realized, then exception is thrown).
/// \param fontSize Size of the font
virtual PDFRealizedFontPointer getRealizedFont(PDFFontPointer font, PDFReal fontSize) const = 0;

View File

@ -1818,43 +1818,6 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
m_graphicState.setTextMatrix(textMatrix);
updateGraphicState();
/*std::vector<QChar> chars;
chars.reserve(textSequence.items.size());
for (const TextSequenceItem& item : textSequence.items)
{
if (item.isCharacter())
{
chars.push_back(item.character);
}
}
int numGlyphs = static_cast<int>(chars.size());
std::vector<uint32_t> glyphIndices;
glyphIndices.resize(chars.size(), 0);
if (font.glyphIndexesForChars(chars.data(), static_cast<int>(chars.size()), glyphIndices.data(), &numGlyphs))
{
if (chars.size() != static_cast<size_t>(numGlyphs))
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Cant convert unicode to glyph indices, text can't be printed."));
}
std::vector<QPointF> advances;
advances.resize(numGlyphs, QPointF());
if (font.advancesForGlyphIndexes(glyphIndices.data(), advances.data(), numGlyphs, QRawFont::SeparateAdvances | QRawFont::UseDesignMetrics))
{
}
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Cant convert unicode to glyph indices, text can't be printed."));
}
}
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Cant convert unicode to glyph indices, text can't be printed."));
}*/
}
else
{

View File

@ -25,7 +25,6 @@
#include "pdfutils.h"
#include <QMatrix>
#include <QRawFont>
#include <QPainterPath>
#include <QSharedPointer>