mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-03-19 21:00:21 +01:00
Font information
This commit is contained in:
parent
f2f398e82b
commit
f48709c8c5
@ -31,6 +31,7 @@
|
|||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "Windows.h"
|
#include "Windows.h"
|
||||||
@ -350,6 +351,9 @@ public:
|
|||||||
|
|
||||||
/// Returns true, if font has horizontal writing system
|
/// Returns true, if font has horizontal writing system
|
||||||
virtual bool isHorizontalWritingSystem() const = 0;
|
virtual bool isHorizontalWritingSystem() const = 0;
|
||||||
|
|
||||||
|
/// Dumps information about the font
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem* item) const { Q_UNUSED(item); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implementation of the PDFRealizedFont class using PIMPL pattern for Type 3 fonts
|
/// Implementation of the PDFRealizedFont class using PIMPL pattern for Type 3 fonts
|
||||||
@ -379,6 +383,7 @@ public:
|
|||||||
|
|
||||||
virtual void fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence, PDFRenderErrorReporter* reporter) override;
|
virtual void fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence, PDFRenderErrorReporter* reporter) override;
|
||||||
virtual bool isHorizontalWritingSystem() const override { return !m_isVertical; }
|
virtual bool isHorizontalWritingSystem() const override { return !m_isVertical; }
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem* item) const override;
|
||||||
|
|
||||||
static constexpr const PDFReal PIXEL_SIZE_MULTIPLIER = 100.0;
|
static constexpr const PDFReal PIXEL_SIZE_MULTIPLIER = 100.0;
|
||||||
|
|
||||||
@ -553,6 +558,107 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFRealizedFontImpl::dumpFontToTreeItem(QTreeWidgetItem* item) const
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* root = new QTreeWidgetItem(item, { PDFTranslationContext::tr("Details") });
|
||||||
|
|
||||||
|
if (m_face->family_name)
|
||||||
|
{
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Font"), QString::fromLatin1(m_face->family_name) });
|
||||||
|
}
|
||||||
|
if (m_face->style_name)
|
||||||
|
{
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Style"), QString::fromLatin1(m_face->style_name) });
|
||||||
|
}
|
||||||
|
|
||||||
|
QString yesString = PDFTranslationContext::tr("Yes");
|
||||||
|
QString noString = PDFTranslationContext::tr("No");
|
||||||
|
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Glyph count"), QString::number(m_face->num_glyphs) });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Is CID keyed"), (m_face->face_flags & FT_FACE_FLAG_CID_KEYED) ? yesString : noString });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Is bold"), (m_face->style_flags & FT_STYLE_FLAG_BOLD) ? yesString : noString });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Is italics"), (m_face->style_flags & FT_STYLE_FLAG_ITALIC) ? yesString : noString });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Has vertical writing system"), (m_face->face_flags & FT_FACE_FLAG_VERTICAL) ? yesString : noString });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Has SFNT storage scheme"), (m_face->face_flags & FT_FACE_FLAG_SFNT) ? yesString : noString });
|
||||||
|
new QTreeWidgetItem(root, { PDFTranslationContext::tr("Has glyph names"), (m_face->face_flags & FT_FACE_FLAG_GLYPH_NAMES) ? yesString : noString });
|
||||||
|
|
||||||
|
if (m_face->num_charmaps > 0)
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* encodingRoot = new QTreeWidgetItem(item, { PDFTranslationContext::tr("Encoding") });
|
||||||
|
for (FT_Int i = 0; i < m_face->num_charmaps; ++i)
|
||||||
|
{
|
||||||
|
FT_CharMap charMap = m_face->charmaps[i];
|
||||||
|
|
||||||
|
const FT_Encoding encoding = charMap->encoding;
|
||||||
|
QString encodingName;
|
||||||
|
switch (encoding)
|
||||||
|
{
|
||||||
|
case FT_ENCODING_NONE:
|
||||||
|
encodingName = PDFTranslationContext::tr("None");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_UNICODE:
|
||||||
|
encodingName = PDFTranslationContext::tr("Unicode");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_MS_SYMBOL:
|
||||||
|
encodingName = PDFTranslationContext::tr("MS Symbol");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_SJIS:
|
||||||
|
encodingName = PDFTranslationContext::tr("Japanese Shift JIS");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_PRC:
|
||||||
|
encodingName = PDFTranslationContext::tr("PRC - Simplified Chinese");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_BIG5:
|
||||||
|
encodingName = PDFTranslationContext::tr("Traditional Chinese");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_WANSUNG:
|
||||||
|
encodingName = PDFTranslationContext::tr("Korean Extended Wansung");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_JOHAB:
|
||||||
|
encodingName = PDFTranslationContext::tr("Korean Standard");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_ADOBE_STANDARD:
|
||||||
|
encodingName = PDFTranslationContext::tr("Adobe Standard");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_ADOBE_EXPERT:
|
||||||
|
encodingName = PDFTranslationContext::tr("Adobe Expert");
|
||||||
|
break;
|
||||||
|
case FT_ENCODING_ADOBE_CUSTOM:
|
||||||
|
encodingName = PDFTranslationContext::tr("Adobe Custom");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_ADOBE_LATIN_1:
|
||||||
|
encodingName = PDFTranslationContext::tr("Adobe Latin 1");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_OLD_LATIN_2:
|
||||||
|
encodingName = PDFTranslationContext::tr("Old Latin 1");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FT_ENCODING_APPLE_ROMAN:
|
||||||
|
encodingName = PDFTranslationContext::tr("Apple Roman");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
encodingName = PDFTranslationContext::tr("Unknown");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString encodingString = PDFTranslationContext::tr("Platform/Encoding = %1 %2").arg(charMap->platform_id).arg(charMap->encoding_id);
|
||||||
|
new QTreeWidgetItem(encodingRoot, { encodingName, encodingString });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int PDFRealizedFontImpl::outlineMoveTo(const FT_Vector* to, void* user)
|
int PDFRealizedFontImpl::outlineMoveTo(const FT_Vector* to, void* user)
|
||||||
{
|
{
|
||||||
Glyph* glyph = reinterpret_cast<Glyph*>(user);
|
Glyph* glyph = reinterpret_cast<Glyph*>(user);
|
||||||
@ -647,6 +753,11 @@ bool PDFRealizedFont::isHorizontalWritingSystem() const
|
|||||||
return m_impl->isHorizontalWritingSystem();
|
return m_impl->isHorizontalWritingSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFRealizedFont::dumpFontToTreeItem(QTreeWidgetItem* item) const
|
||||||
|
{
|
||||||
|
m_impl->dumpFontToTreeItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(PDFFontPointer font, PDFReal pixelSize, PDFRenderErrorReporter* reporter)
|
PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(PDFFontPointer font, PDFReal pixelSize, PDFRenderErrorReporter* reporter)
|
||||||
{
|
{
|
||||||
PDFRealizedFontPointer result;
|
PDFRealizedFontPointer result;
|
||||||
@ -1347,6 +1458,59 @@ PDFInteger PDFSimpleFont::getGlyphAdvance(size_t index) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFSimpleFont::dumpFontToTreeItem(QTreeWidgetItem* item) const
|
||||||
|
{
|
||||||
|
BaseClass::dumpFontToTreeItem(item);
|
||||||
|
|
||||||
|
QString encodingTypeString;
|
||||||
|
switch (m_encodingType)
|
||||||
|
{
|
||||||
|
case PDFEncoding::Encoding::Standard:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Standard");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::MacRoman:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Mac Roman");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::WinAnsi:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Win Ansi");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::PDFDoc:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("PDF Doc");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::MacExpert:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Mac Expert");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::Symbol:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Symbol");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::ZapfDingbats:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Zapf Dingbats");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::MacOsRoman:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Mac OS Roman");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFEncoding::Encoding::Custom:
|
||||||
|
encodingTypeString = PDFTranslationContext::tr("Custom");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new QTreeWidgetItem(item, { PDFTranslationContext::tr("Encoding"), encodingTypeString });
|
||||||
|
}
|
||||||
|
|
||||||
PDFType1Font::PDFType1Font(FontDescriptor fontDescriptor,
|
PDFType1Font::PDFType1Font(FontDescriptor fontDescriptor,
|
||||||
QByteArray name,
|
QByteArray name,
|
||||||
QByteArray baseFont,
|
QByteArray baseFont,
|
||||||
@ -1368,6 +1532,53 @@ FontType PDFType1Font::getFontType() const
|
|||||||
return FontType::Type1;
|
return FontType::Type1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFType1Font::dumpFontToTreeItem(QTreeWidgetItem* item) const
|
||||||
|
{
|
||||||
|
BaseClass::dumpFontToTreeItem(item);
|
||||||
|
|
||||||
|
if (m_standardFontType != StandardFontType::Invalid)
|
||||||
|
{
|
||||||
|
QString standardFontTypeString;
|
||||||
|
switch (m_standardFontType)
|
||||||
|
{
|
||||||
|
case StandardFontType::TimesRoman:
|
||||||
|
case StandardFontType::TimesRomanBold:
|
||||||
|
case StandardFontType::TimesRomanItalics:
|
||||||
|
case StandardFontType::TimesRomanBoldItalics:
|
||||||
|
standardFontTypeString = PDFTranslationContext::tr("Times Roman");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StandardFontType::Helvetica:
|
||||||
|
case StandardFontType::HelveticaBold:
|
||||||
|
case StandardFontType::HelveticaOblique:
|
||||||
|
case StandardFontType::HelveticaBoldOblique:
|
||||||
|
standardFontTypeString = PDFTranslationContext::tr("Helvetica");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StandardFontType::Courier:
|
||||||
|
case StandardFontType::CourierBold:
|
||||||
|
case StandardFontType::CourierOblique:
|
||||||
|
case StandardFontType::CourierBoldOblique:
|
||||||
|
standardFontTypeString = PDFTranslationContext::tr("Courier");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StandardFontType::Symbol:
|
||||||
|
standardFontTypeString = PDFTranslationContext::tr("Symbol");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StandardFontType::ZapfDingbats:
|
||||||
|
standardFontTypeString = PDFTranslationContext::tr("Zapf Dingbats");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
new QTreeWidgetItem(item, { PDFTranslationContext::tr("Standard font"), standardFontTypeString });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FontType PDFTrueTypeFont::getFontType() const
|
FontType PDFTrueTypeFont::getFontType() const
|
||||||
{
|
{
|
||||||
return FontType::TrueType;
|
return FontType::TrueType;
|
||||||
@ -1920,6 +2131,11 @@ FontType PDFType3Font::getFontType() const
|
|||||||
return FontType::Type3;
|
return FontType::Type3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFType3Font::dumpFontToTreeItem(QTreeWidgetItem* item) const
|
||||||
|
{
|
||||||
|
new QTreeWidgetItem(item, { PDFTranslationContext::tr("Character count"), QString::number(m_characterContentStreams.size()) });
|
||||||
|
}
|
||||||
|
|
||||||
double PDFType3Font::getWidth(int characterIndex) const
|
double PDFType3Font::getWidth(int characterIndex) const
|
||||||
{
|
{
|
||||||
if (characterIndex >= m_firstCharacterIndex && characterIndex <= m_lastCharacterIndex)
|
if (characterIndex >= m_firstCharacterIndex && characterIndex <= m_lastCharacterIndex)
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QMatrix>
|
#include <QMatrix>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ static constexpr PDFEncoding::Encoding getEncodingForStandardFont(StandardFontTy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FontDescriptor
|
struct PDFFORQTLIBSHARED_EXPORT FontDescriptor
|
||||||
{
|
{
|
||||||
bool isEmbedded() const { return !fontFile.isEmpty() || !fontFile2.isEmpty() || !fontFile3.isEmpty(); }
|
bool isEmbedded() const { return !fontFile.isEmpty() || !fontFile2.isEmpty() || !fontFile3.isEmpty(); }
|
||||||
|
|
||||||
@ -216,7 +217,7 @@ using PDFRealizedFontPointer = QSharedPointer<PDFRealizedFont>;
|
|||||||
|
|
||||||
/// Font, which has fixed pixel size. It is programmed as PIMPL, because we need
|
/// Font, which has fixed pixel size. It is programmed as PIMPL, because we need
|
||||||
/// to remove FreeType types from the interface (so we do not include FreeType in the interface).
|
/// to remove FreeType types from the interface (so we do not include FreeType in the interface).
|
||||||
class PDFRealizedFont
|
class PDFFORQTLIBSHARED_EXPORT PDFRealizedFont
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~PDFRealizedFont();
|
~PDFRealizedFont();
|
||||||
@ -231,6 +232,9 @@ public:
|
|||||||
/// Return true, if we have horizontal writing system
|
/// Return true, if we have horizontal writing system
|
||||||
bool isHorizontalWritingSystem() const;
|
bool isHorizontalWritingSystem() const;
|
||||||
|
|
||||||
|
/// Adds information about the font into tree item
|
||||||
|
void dumpFontToTreeItem(QTreeWidgetItem* item) const;
|
||||||
|
|
||||||
/// Creates new realized font from the standard font. If font can't be created,
|
/// Creates new realized font from the standard font. If font can't be created,
|
||||||
/// then exception is thrown.
|
/// then exception is thrown.
|
||||||
static PDFRealizedFontPointer createRealizedFont(PDFFontPointer font, PDFReal pixelSize, PDFRenderErrorReporter* reporter);
|
static PDFRealizedFontPointer createRealizedFont(PDFFontPointer font, PDFReal pixelSize, PDFRenderErrorReporter* reporter);
|
||||||
@ -243,7 +247,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Base class representing font in the PDF file
|
/// Base class representing font in the PDF file
|
||||||
class PDFFont
|
class PDFFORQTLIBSHARED_EXPORT PDFFont
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit PDFFont(FontDescriptor fontDescriptor);
|
explicit PDFFont(FontDescriptor fontDescriptor);
|
||||||
@ -255,6 +259,9 @@ public:
|
|||||||
/// Returns font descriptor
|
/// Returns font descriptor
|
||||||
const FontDescriptor* getFontDescriptor() const { return &m_fontDescriptor; }
|
const FontDescriptor* getFontDescriptor() const { return &m_fontDescriptor; }
|
||||||
|
|
||||||
|
/// Adds information about the font into tree item
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem* item) const { Q_UNUSED(item); }
|
||||||
|
|
||||||
/// Creates font from the object. If font can't be created, exception is thrown.
|
/// Creates font from the object. If font can't be created, exception is thrown.
|
||||||
/// \param object Font dictionary
|
/// \param object Font dictionary
|
||||||
/// \param document Document
|
/// \param document Document
|
||||||
@ -274,6 +281,8 @@ private:
|
|||||||
/// which maps single-byte character to the glyph in the font.
|
/// which maps single-byte character to the glyph in the font.
|
||||||
class PDFSimpleFont : public PDFFont
|
class PDFSimpleFont : public PDFFont
|
||||||
{
|
{
|
||||||
|
using BaseClass = PDFFont;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PDFSimpleFont(FontDescriptor fontDescriptor,
|
explicit PDFSimpleFont(FontDescriptor fontDescriptor,
|
||||||
QByteArray name,
|
QByteArray name,
|
||||||
@ -292,6 +301,8 @@ public:
|
|||||||
/// Returns the glyph advance (or zero, if glyph advance is invalid)
|
/// Returns the glyph advance (or zero, if glyph advance is invalid)
|
||||||
PDFInteger getGlyphAdvance(size_t index) const;
|
PDFInteger getGlyphAdvance(size_t index) const;
|
||||||
|
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem* item) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QByteArray m_name;
|
QByteArray m_name;
|
||||||
QByteArray m_baseFont;
|
QByteArray m_baseFont;
|
||||||
@ -305,6 +316,8 @@ protected:
|
|||||||
|
|
||||||
class PDFType1Font : public PDFSimpleFont
|
class PDFType1Font : public PDFSimpleFont
|
||||||
{
|
{
|
||||||
|
using BaseClass = PDFSimpleFont;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PDFType1Font(FontDescriptor fontDescriptor,
|
explicit PDFType1Font(FontDescriptor fontDescriptor,
|
||||||
QByteArray name,
|
QByteArray name,
|
||||||
@ -319,6 +332,7 @@ public:
|
|||||||
virtual ~PDFType1Font() override = default;
|
virtual ~PDFType1Font() override = default;
|
||||||
|
|
||||||
virtual FontType getFontType() const override;
|
virtual FontType getFontType() const override;
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem*item) const override;
|
||||||
|
|
||||||
/// Returns the assigned standard font (or invalid, if font is not standard)
|
/// Returns the assigned standard font (or invalid, if font is not standard)
|
||||||
StandardFontType getStandardFontType() const { return m_standardFontType; }
|
StandardFontType getStandardFontType() const { return m_standardFontType; }
|
||||||
@ -347,6 +361,7 @@ public:
|
|||||||
const PDFObject& resources);
|
const PDFObject& resources);
|
||||||
|
|
||||||
virtual FontType getFontType() const override;
|
virtual FontType getFontType() const override;
|
||||||
|
virtual void dumpFontToTreeItem(QTreeWidgetItem*item) const override;
|
||||||
|
|
||||||
/// Returns width of the character. If character doesn't exist, then zero is returned.
|
/// Returns width of the character. If character doesn't exist, then zero is returned.
|
||||||
double getWidth(int characterIndex) const;
|
double getWidth(int characterIndex) const;
|
||||||
|
@ -226,7 +226,7 @@ private:
|
|||||||
/// an array of pairs key-value, where key is name object and value is any
|
/// an array of pairs key-value, where key is name object and value is any
|
||||||
/// PDF object. For this reason, we use QByteArray for key. We do not use
|
/// PDF object. For this reason, we use QByteArray for key. We do not use
|
||||||
/// map, because dictionaries are usually small.
|
/// map, because dictionaries are usually small.
|
||||||
class PDFDictionary : public PDFObjectContent
|
class PDFFORQTLIBSHARED_EXPORT PDFDictionary : public PDFObjectContent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using DictionaryEntry = std::pair<QByteArray, PDFObject>;
|
using DictionaryEntry = std::pair<QByteArray, PDFObject>;
|
||||||
|
@ -20,9 +20,15 @@
|
|||||||
|
|
||||||
#include "pdfdocument.h"
|
#include "pdfdocument.h"
|
||||||
#include "pdfwidgetutils.h"
|
#include "pdfwidgetutils.h"
|
||||||
|
#include "pdffont.h"
|
||||||
|
#include "pdfutils.h"
|
||||||
|
#include "pdfexception.h"
|
||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QPageSize>
|
#include <QPageSize>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
|
#include <execution>
|
||||||
|
|
||||||
namespace pdfviewer
|
namespace pdfviewer
|
||||||
{
|
{
|
||||||
@ -38,6 +44,7 @@ PDFDocumentPropertiesDialog::PDFDocumentPropertiesDialog(const pdf::PDFDocument*
|
|||||||
initializeProperties(document);
|
initializeProperties(document);
|
||||||
initializeFileInfoProperties(fileInfo);
|
initializeFileInfoProperties(fileInfo);
|
||||||
initializeSecurity(document);
|
initializeSecurity(document);
|
||||||
|
initializeFonts(document);
|
||||||
|
|
||||||
const int defaultWidth = PDFWidgetUtils::getPixelSize(this, 240.0);
|
const int defaultWidth = PDFWidgetUtils::getPixelSize(this, 240.0);
|
||||||
const int defaultHeight = PDFWidgetUtils::getPixelSize(this, 200.0);
|
const int defaultHeight = PDFWidgetUtils::getPixelSize(this, 200.0);
|
||||||
@ -46,6 +53,7 @@ PDFDocumentPropertiesDialog::PDFDocumentPropertiesDialog(const pdf::PDFDocument*
|
|||||||
|
|
||||||
PDFDocumentPropertiesDialog::~PDFDocumentPropertiesDialog()
|
PDFDocumentPropertiesDialog::~PDFDocumentPropertiesDialog()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_fontTreeWidgetItems.empty());
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,4 +236,164 @@ void PDFDocumentPropertiesDialog::initializeSecurity(const pdf::PDFDocument* doc
|
|||||||
ui->securityTreeWidget->resizeColumnToContents(0);
|
ui->securityTreeWidget->resizeColumnToContents(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFDocumentPropertiesDialog::initializeFonts(const pdf::PDFDocument* document)
|
||||||
|
{
|
||||||
|
auto createFontInfo = [this, document]()
|
||||||
|
{
|
||||||
|
pdf::PDFInteger pageCount = document->getCatalog()->getPageCount();
|
||||||
|
|
||||||
|
QMutex fontTreeItemMutex;
|
||||||
|
QMutex usedFontReferencesMutex;
|
||||||
|
std::set<pdf::PDFObjectReference> usedFontReferences;
|
||||||
|
|
||||||
|
auto processPage = [&](pdf::PDFInteger pageIndex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const pdf::PDFPage* page = document->getCatalog()->getPage(pageIndex);
|
||||||
|
if (const pdf::PDFDictionary* resourcesDictionary = document->getDictionaryFromObject(page->getResources()))
|
||||||
|
{
|
||||||
|
if (const pdf::PDFDictionary* fontsDictionary = document->getDictionaryFromObject(resourcesDictionary->get("Font")))
|
||||||
|
{
|
||||||
|
// Iterate trough each font
|
||||||
|
const size_t fontsCount = fontsDictionary->getCount();
|
||||||
|
for (size_t i = 0; i < fontsCount; ++i)
|
||||||
|
{
|
||||||
|
pdf::PDFObject object = fontsDictionary->getValue(i);
|
||||||
|
if (object.isReference())
|
||||||
|
{
|
||||||
|
// Check, if we have not processed the object. If we have it processed,
|
||||||
|
// then do nothing, otherwise insert it into the processed objects.
|
||||||
|
// We must also use mutex, because we use multithreading.
|
||||||
|
QMutexLocker lock(&usedFontReferencesMutex);
|
||||||
|
if (usedFontReferences.count(object.getReference()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usedFontReferences.insert(object.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (pdf::PDFFontPointer font = pdf::PDFFont::createFont(object, document))
|
||||||
|
{
|
||||||
|
pdf::PDFRealizedFontPointer realizedFont = pdf::PDFRealizedFont::createRealizedFont(font, 8.0, nullptr);
|
||||||
|
if (realizedFont)
|
||||||
|
{
|
||||||
|
const pdf::FontType fontType = font->getFontType();
|
||||||
|
const pdf::FontDescriptor* fontDescriptor = font->getFontDescriptor();
|
||||||
|
QString fontName = fontDescriptor->fontName;
|
||||||
|
|
||||||
|
// Try to remove characters from +, if we have font name 'SDFDSF+ValidFontName'
|
||||||
|
int plusPos = fontName.lastIndexOf('+');
|
||||||
|
if (plusPos != -1 && plusPos < fontName.size() - 1)
|
||||||
|
{
|
||||||
|
fontName = fontName.mid(plusPos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontName.isEmpty())
|
||||||
|
{
|
||||||
|
fontName = QString::fromLatin1(fontsDictionary->getKey(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<QTreeWidgetItem> fontRootItemPtr = std::make_unique<QTreeWidgetItem>(QStringList({ fontName }));
|
||||||
|
QTreeWidgetItem* fontRootItem = fontRootItemPtr.get();
|
||||||
|
|
||||||
|
QString fontTypeString;
|
||||||
|
switch (fontType)
|
||||||
|
{
|
||||||
|
case pdf::FontType::TrueType:
|
||||||
|
fontTypeString = tr("TrueType");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pdf::FontType::Type0:
|
||||||
|
fontTypeString = tr("Type0 (CID keyed)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pdf::FontType::Type1:
|
||||||
|
fontTypeString = tr("Type1 (8 bit keyed)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pdf::FontType::Type3:
|
||||||
|
fontTypeString = tr("Type3 (content streams for font glyphs)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
new QTreeWidgetItem(fontRootItem, { tr("Type"), fontTypeString });
|
||||||
|
if (!fontDescriptor->fontFamily.isEmpty())
|
||||||
|
{
|
||||||
|
new QTreeWidgetItem(fontRootItem, { tr("Font family"), fontDescriptor->fontFamily });
|
||||||
|
}
|
||||||
|
new QTreeWidgetItem(fontRootItem, { tr("Embedded subset"), fontDescriptor->getEmbeddedFontData() ? tr("Yes") : tr("No") });
|
||||||
|
font->dumpFontToTreeItem(fontRootItem);
|
||||||
|
realizedFont->dumpFontToTreeItem(fontRootItem);
|
||||||
|
|
||||||
|
// Separator item
|
||||||
|
new QTreeWidgetItem(fontRootItem, QStringList());
|
||||||
|
|
||||||
|
// Finally add the tree item
|
||||||
|
QMutexLocker lock(&fontTreeItemMutex);
|
||||||
|
m_fontTreeWidgetItems.push_back(fontRootItemPtr.release());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (pdf::PDFException)
|
||||||
|
{
|
||||||
|
// Do nothing, some error occured, continue with next font
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (pdf::PDFException)
|
||||||
|
{
|
||||||
|
// Do nothing, some error occured
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pdf::PDFIntegerRange<pdf::PDFInteger> indices(pdf::PDFInteger(0), pageCount);
|
||||||
|
std::for_each(std::execution::parallel_policy(), indices.begin(), indices.end(), processPage);
|
||||||
|
};
|
||||||
|
m_future = QtConcurrent::run(createFontInfo);
|
||||||
|
connect(&m_futureWatcher, &QFutureWatcher<void>::finished, this, &PDFDocumentPropertiesDialog::onFontsFinished);
|
||||||
|
m_futureWatcher.setFuture(m_future);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFDocumentPropertiesDialog::onFontsFinished()
|
||||||
|
{
|
||||||
|
if (!m_fontTreeWidgetItems.empty())
|
||||||
|
{
|
||||||
|
std::sort(m_fontTreeWidgetItems.begin(), m_fontTreeWidgetItems.end(), [](QTreeWidgetItem* left, QTreeWidgetItem* right) { return left->data(0, Qt::DisplayRole) < right->data(0, Qt::DisplayRole); });
|
||||||
|
for (QTreeWidgetItem* item : m_fontTreeWidgetItems)
|
||||||
|
{
|
||||||
|
ui->fontsTreeWidget->addTopLevelItem(item);
|
||||||
|
}
|
||||||
|
m_fontTreeWidgetItems.clear();
|
||||||
|
|
||||||
|
ui->fontsTreeWidget->collapseAll();
|
||||||
|
ui->fontsTreeWidget->expandToDepth(0);
|
||||||
|
ui->fontsTreeWidget->resizeColumnToContents(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFDocumentPropertiesDialog::closeEvent(QCloseEvent* event)
|
||||||
|
{
|
||||||
|
// We must wait for finishing of font loading;
|
||||||
|
m_futureWatcher.waitForFinished();
|
||||||
|
|
||||||
|
// We must delete all font tree items, because of asynchronous signal sent
|
||||||
|
qDeleteAll(m_fontTreeWidgetItems);
|
||||||
|
m_fontTreeWidgetItems.clear();
|
||||||
|
|
||||||
|
BaseClass::closeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
|
||||||
|
class QTreeWidgetItem;
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
{
|
{
|
||||||
@ -50,18 +54,31 @@ class PDFDocumentPropertiesDialog : public QDialog
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = QDialog;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PDFDocumentPropertiesDialog(const pdf::PDFDocument* document,
|
explicit PDFDocumentPropertiesDialog(const pdf::PDFDocument* document,
|
||||||
const PDFFileInfo* fileInfo,
|
const PDFFileInfo* fileInfo,
|
||||||
QWidget* parent);
|
QWidget* parent);
|
||||||
virtual ~PDFDocumentPropertiesDialog() override;
|
virtual ~PDFDocumentPropertiesDialog() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::PDFDocumentPropertiesDialog* ui;
|
Ui::PDFDocumentPropertiesDialog* ui;
|
||||||
|
|
||||||
void initializeProperties(const pdf::PDFDocument* document);
|
void initializeProperties(const pdf::PDFDocument* document);
|
||||||
void initializeFileInfoProperties(const PDFFileInfo* fileInfo);
|
void initializeFileInfoProperties(const PDFFileInfo* fileInfo);
|
||||||
void initializeSecurity(const pdf::PDFDocument* document);
|
void initializeSecurity(const pdf::PDFDocument* document);
|
||||||
|
void initializeFonts(const pdf::PDFDocument* document);
|
||||||
|
|
||||||
|
void onFontsFinished();
|
||||||
|
|
||||||
|
std::vector<QTreeWidgetItem*> m_fontTreeWidgetItems;
|
||||||
|
QFuture<void> m_future;
|
||||||
|
QFutureWatcher<void> m_futureWatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
@ -25,11 +25,11 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="propertiesLayout" stretch="3,2">
|
<layout class="QVBoxLayout" name="propertiesLayout" stretch="3,2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="documentPropertiesGroupBox">
|
<widget class="QGroupBox" name="propertiesGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Properties</string>
|
<string>Properties</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="propertiesGroupBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeWidget" name="propertiesTreeWidget">
|
<widget class="QTreeWidget" name="propertiesTreeWidget">
|
||||||
<property name="columnCount">
|
<property name="columnCount">
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File Information</string>
|
<string>File Information</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="fileInfoGroupBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeWidget" name="fileInfoTreeWidget">
|
<widget class="QTreeWidget" name="fileInfoTreeWidget">
|
||||||
<property name="columnCount">
|
<property name="columnCount">
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Security</string>
|
<string>Security</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="securityTabLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="securityGroupBox">
|
<widget class="QGroupBox" name="securityGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -120,6 +120,42 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="fontsTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Fonts</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="fontsTabLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="fontsGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Fonts</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="fontsGroupBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="fontsTreeWidget">
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">1</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">2</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user