mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-03-18 04:10:23 +01:00
Create outline for a document
This commit is contained in:
parent
e06148fa8c
commit
cb3a36f891
@ -24,4 +24,5 @@ int main(int argc, char *argv[])
|
||||
QApplication a(argc, argv);
|
||||
PDFExamplesGenerator::generateAnnotationsExample();
|
||||
PDFExamplesGenerator::generatePageBoxesExample();
|
||||
PDFExamplesGenerator::generateOutlineExample();
|
||||
}
|
||||
|
@ -322,3 +322,39 @@ void PDFExamplesGenerator::generatePageBoxesExample()
|
||||
pdf::PDFDocumentWriter writer(nullptr);
|
||||
writer.write("Ex_PageBoxes.pdf", &document, false);
|
||||
}
|
||||
|
||||
void PDFExamplesGenerator::generateOutlineExample()
|
||||
{
|
||||
pdf::PDFDocumentBuilder builder;
|
||||
builder.setDocumentTitle("Test document - Outline");
|
||||
builder.setDocumentAuthor("Jakub Melka");
|
||||
builder.setDocumentCreator(QCoreApplication::applicationName());
|
||||
builder.setDocumentSubject("Testing outline");
|
||||
builder.setLanguage(QLocale::system());
|
||||
|
||||
pdf::PDFObjectReference pageReference = builder.appendPage(QRectF(0, 0, 200, 200));
|
||||
pdf::PDFOutlineItem root;
|
||||
|
||||
pdf::PDFOutlineItem* child = new pdf::PDFOutlineItem();
|
||||
child->setTitle("Toto je kořen");
|
||||
child->setAction(pdf::PDFActionPtr(new pdf::PDFActionGoTo(pdf::PDFDestination::createFit(pageReference), pdf::PDFDestination())));
|
||||
root.addChild(QSharedPointer<pdf::PDFOutlineItem>(child));
|
||||
child = new pdf::PDFOutlineItem();
|
||||
child->setTitle("Toto je druhý kořen");
|
||||
child->setAction(pdf::PDFActionPtr(new pdf::PDFActionGoTo(pdf::PDFDestination::createFit(pageReference), pdf::PDFDestination())));
|
||||
child->setFontBold(true);
|
||||
child->setTextColor(Qt::green);
|
||||
root.addChild(QSharedPointer<pdf::PDFOutlineItem>(child));
|
||||
|
||||
pdf::PDFOutlineItem* subchild = new pdf::PDFOutlineItem();
|
||||
subchild->setTitle("Toto je dítě");
|
||||
subchild->setAction(pdf::PDFActionPtr(new pdf::PDFActionGoTo(pdf::PDFDestination::createFit(pageReference), pdf::PDFDestination())));
|
||||
child->addChild(QSharedPointer<pdf::PDFOutlineItem>(subchild));
|
||||
|
||||
builder.setOutline(&root);
|
||||
|
||||
// Write result to a file
|
||||
pdf::PDFDocument document = builder.build();
|
||||
pdf::PDFDocumentWriter writer(nullptr);
|
||||
writer.write("Ex_Outline.pdf", &document, false);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
|
||||
static void generateAnnotationsExample();
|
||||
static void generatePageBoxesExample();
|
||||
static void generateOutlineExample();
|
||||
};
|
||||
|
||||
#endif // PDFEXAMPLESGENERATOR_H
|
||||
|
@ -1059,6 +1059,115 @@ QRectF PDFDocumentBuilder::getPolygonsBoundingRect(const Polygons& polygons) con
|
||||
return rect;
|
||||
}
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createOutlineItem(const PDFOutlineItem* root, bool writeOutlineData)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
|
||||
if (writeOutlineData)
|
||||
{
|
||||
// Title
|
||||
objectBuilder.beginDictionaryItem("Title");
|
||||
objectBuilder << root->getTitle();
|
||||
objectBuilder.endDictionaryItem();
|
||||
|
||||
// Destination
|
||||
const PDFActionGoTo* action = dynamic_cast<const PDFActionGoTo*>(root->getAction());
|
||||
if (action)
|
||||
{
|
||||
objectBuilder.beginDictionaryItem("Dest");
|
||||
objectBuilder << action->getDestination();
|
||||
objectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
// Color
|
||||
if (root->getTextColor().isValid() && root->getTextColor() != Qt::black)
|
||||
{
|
||||
objectBuilder.beginDictionaryItem("C");
|
||||
objectBuilder << root->getTextColor();
|
||||
objectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
// Flags
|
||||
PDFInteger flags = 0;
|
||||
if (root->isFontItalics())
|
||||
{
|
||||
flags += 1;
|
||||
}
|
||||
if (root->isFontBold())
|
||||
{
|
||||
flags += 2;
|
||||
}
|
||||
|
||||
if (flags > 0)
|
||||
{
|
||||
objectBuilder.beginDictionaryItem("F");
|
||||
objectBuilder << flags;
|
||||
objectBuilder.endDictionaryItem();
|
||||
}
|
||||
}
|
||||
|
||||
// Create descendands
|
||||
std::vector<PDFObjectReference> children;
|
||||
children.reserve(root->getChildCount());
|
||||
for (size_t i = 0; i < root->getChildCount(); ++i)
|
||||
{
|
||||
children.push_back(createOutlineItem(root->getChild(i), true));
|
||||
}
|
||||
|
||||
if (!children.empty())
|
||||
{
|
||||
// First/Last pointers
|
||||
objectBuilder.beginDictionaryItem("First");
|
||||
objectBuilder << children.front();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Last");
|
||||
objectBuilder << children.back();
|
||||
objectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
size_t totalCount = root->getTotalCount();
|
||||
if (totalCount > 0)
|
||||
{
|
||||
objectBuilder.beginDictionaryItem("Count");
|
||||
objectBuilder << PDFInteger(totalCount);
|
||||
objectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
objectBuilder.endDictionary();
|
||||
PDFObjectReference parentReference = addObject(objectBuilder.takeObject());
|
||||
|
||||
for (size_t i = 0; i < children.size(); ++i)
|
||||
{
|
||||
PDFObjectFactory fixPointersObjectBuilder;
|
||||
fixPointersObjectBuilder.beginDictionary();
|
||||
|
||||
fixPointersObjectBuilder.beginDictionaryItem("Parent");
|
||||
fixPointersObjectBuilder << parentReference;
|
||||
fixPointersObjectBuilder.endDictionaryItem();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
fixPointersObjectBuilder.beginDictionaryItem("Prev");
|
||||
fixPointersObjectBuilder << children[i - 1];
|
||||
fixPointersObjectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
if (i + 1 < children.size())
|
||||
{
|
||||
fixPointersObjectBuilder.beginDictionaryItem("Next");
|
||||
fixPointersObjectBuilder << children[i + 1];
|
||||
fixPointersObjectBuilder.endDictionaryItem();
|
||||
}
|
||||
|
||||
fixPointersObjectBuilder.endDictionary();
|
||||
mergeTo(children[i], fixPointersObjectBuilder.takeObject());
|
||||
}
|
||||
|
||||
return parentReference;
|
||||
}
|
||||
|
||||
void PDFDocumentBuilder::flattenPageTree()
|
||||
{
|
||||
PDFObjectReference pageTreeRoot = getPageTreeRoot();
|
||||
@ -1166,6 +1275,11 @@ std::vector<PDFObjectReference> PDFDocumentBuilder::getPages() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFDocumentBuilder::setOutline(const PDFOutlineItem* root)
|
||||
{
|
||||
setOutline(createOutlineItem(root, false));
|
||||
}
|
||||
|
||||
std::vector<PDFObject> PDFDocumentBuilder::copyFrom(const std::vector<PDFObject>& objects, const PDFObjectStorage& storage, bool createReferences)
|
||||
{
|
||||
// 1) Collect all references, which we must copy. If object is referenced, then
|
||||
@ -4180,6 +4294,20 @@ void PDFDocumentBuilder::setLanguage(QLocale locale)
|
||||
}
|
||||
|
||||
|
||||
void PDFDocumentBuilder::setOutline(PDFObjectReference outline)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Outlines");
|
||||
objectBuilder << outline;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject updatedCatalog = objectBuilder.takeObject();
|
||||
mergeTo(getCatalogReference(), updatedCatalog);
|
||||
}
|
||||
|
||||
|
||||
void PDFDocumentBuilder::setPageArtBox(PDFObjectReference page,
|
||||
QRectF box)
|
||||
{
|
||||
@ -4270,6 +4398,21 @@ void PDFDocumentBuilder::setPageTrimBox(PDFObjectReference page,
|
||||
}
|
||||
|
||||
|
||||
void PDFDocumentBuilder::setPageUserUnit(PDFObjectReference page,
|
||||
PDFReal unit)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("UserUnit");
|
||||
objectBuilder << unit;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject updatedPageObject = objectBuilder.takeObject();
|
||||
mergeTo(page, updatedPageObject);
|
||||
}
|
||||
|
||||
|
||||
void PDFDocumentBuilder::updateTrailerDictionary(PDFInteger objectCount)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
@ -305,6 +305,11 @@ public:
|
||||
/// be flattened to use this function. \sa flattenPageTree
|
||||
std::vector<PDFObjectReference> getPages() const;
|
||||
|
||||
/// Sets document outline root item corresponds to invisible root.
|
||||
/// Top-level items are children of the root.
|
||||
/// \param root Root item
|
||||
void setOutline(const PDFOutlineItem* root);
|
||||
|
||||
/// Adds a new objet to the object storage
|
||||
/// \param object Object
|
||||
PDFObjectReference addObject(PDFObject object);
|
||||
@ -1250,6 +1255,11 @@ public:
|
||||
void setLanguage(QLocale locale);
|
||||
|
||||
|
||||
/// Set document outline.
|
||||
/// \param outline Document outline root
|
||||
void setOutline(PDFObjectReference outline);
|
||||
|
||||
|
||||
/// Sets art box to the page. Art box defines page's meaningful content.
|
||||
/// \param page Page
|
||||
/// \param box Box
|
||||
@ -1296,6 +1306,13 @@ public:
|
||||
QRectF box);
|
||||
|
||||
|
||||
/// Sets page's user unit. It specifies user space unit, in multiples of 1 / 72 inch.
|
||||
/// \param page Page
|
||||
/// \param unit Unit (multiple of 1pt = 1 / 72 inch)
|
||||
void setPageUserUnit(PDFObjectReference page,
|
||||
PDFReal unit);
|
||||
|
||||
|
||||
/// This function is used to update trailer dictionary. Must be called each time the final document is
|
||||
/// being built.
|
||||
/// \param objectCount Number of objects (including empty ones)
|
||||
@ -1312,6 +1329,7 @@ private:
|
||||
PDFObjectReference getDocumentInfo() const;
|
||||
void updateDocumentInfo(PDFObject info);
|
||||
QRectF getPolygonsBoundingRect(const Polygons& Polygons) const;
|
||||
PDFObjectReference createOutlineItem(const PDFOutlineItem* root, bool writeOutlineData);
|
||||
|
||||
PDFObjectStorage m_storage;
|
||||
PDFVersion m_version;
|
||||
|
@ -23,6 +23,18 @@
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
size_t PDFOutlineItem::getTotalCount() const
|
||||
{
|
||||
size_t count = m_children.size();
|
||||
|
||||
for (size_t i = 0; i < m_children.size(); ++i)
|
||||
{
|
||||
count += getChild(i)->getTotalCount();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
QSharedPointer<PDFOutlineItem> PDFOutlineItem::parse(const PDFDocument* document, const PDFObject& root)
|
||||
{
|
||||
const PDFObject& rootDereferenced = document->getObject(root);
|
||||
|
@ -31,7 +31,7 @@ namespace pdf
|
||||
class PDFDocument;
|
||||
|
||||
/// Outline item
|
||||
class PDFOutlineItem
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFOutlineItem
|
||||
{
|
||||
public:
|
||||
explicit PDFOutlineItem() = default;
|
||||
@ -40,6 +40,7 @@ public:
|
||||
void setTitle(const QString& title) { m_title = title; }
|
||||
|
||||
size_t getChildCount() const { return m_children.size(); }
|
||||
size_t getTotalCount() const;
|
||||
const PDFOutlineItem* getChild(size_t index) const { return m_children[index].get(); }
|
||||
void addChild(QSharedPointer<PDFOutlineItem> child) { m_children.emplace_back(qMove(child)); }
|
||||
QSharedPointer<PDFOutlineItem> getChildPtr(size_t index) const { return m_children[index]; }
|
||||
|
@ -9815,6 +9815,63 @@ return rootNodeReference;</property>
|
||||
<property name="functionDescription">Set document language.</property>
|
||||
<property name="returnType">_void</property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedFunction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedParameter">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="parameterName">outline</property>
|
||||
<property name="parameterType">_PDFObjectReference</property>
|
||||
<property name="parameterDescription">Document outline root</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="actionType">Parameters</property>
|
||||
<property name="variableName"></property>
|
||||
<property name="variableType">_void</property>
|
||||
<property name="code"></property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedPDFObject">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedPDFObject">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="dictionaryItemName">Outlines</property>
|
||||
<property name="objectType">DictionaryItemSimple</property>
|
||||
<property name="value">outline</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="dictionaryItemName"></property>
|
||||
<property name="objectType">Dictionary</property>
|
||||
<property name="value"></property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="actionType">CreateObject</property>
|
||||
<property name="variableName">updatedCatalog</property>
|
||||
<property name="variableType">_PDFObject</property>
|
||||
<property name="code"></property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="actionType">Code</property>
|
||||
<property name="variableName"></property>
|
||||
<property name="variableType">_void</property>
|
||||
<property name="code">mergeTo(getCatalogReference(), updatedCatalog);</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="functionType">Structure</property>
|
||||
<property name="functionName">setOutline</property>
|
||||
<property name="functionDescription">Set document outline.</property>
|
||||
<property name="returnType">_void</property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedFunction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
@ -10199,6 +10256,70 @@ return rootNodeReference;</property>
|
||||
<property name="functionDescription">Sets trim box to the page. Trim box is physical region, of the printed page after trimming.</property>
|
||||
<property name="returnType">_void</property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedFunction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedParameter">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="parameterName">page</property>
|
||||
<property name="parameterType">_PDFObjectReference</property>
|
||||
<property name="parameterDescription">Page</property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedParameter">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="parameterName">unit</property>
|
||||
<property name="parameterType">_PDFReal</property>
|
||||
<property name="parameterDescription">Unit (multiple of 1pt = 1 / 72 inch)</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="actionType">Parameters</property>
|
||||
<property name="variableName"></property>
|
||||
<property name="variableType">_void</property>
|
||||
<property name="code"></property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedPDFObject">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
<QObject class="codegen::GeneratedPDFObject">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="dictionaryItemName">UserUnit</property>
|
||||
<property name="objectType">DictionaryItemSimple</property>
|
||||
<property name="value">unit</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="dictionaryItemName"></property>
|
||||
<property name="objectType">Dictionary</property>
|
||||
<property name="value"></property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="actionType">CreateObject</property>
|
||||
<property name="variableName">updatedPageObject</property>
|
||||
<property name="variableType">_PDFObject</property>
|
||||
<property name="code"></property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedAction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items"/>
|
||||
<property name="actionType">Code</property>
|
||||
<property name="variableName"></property>
|
||||
<property name="variableType">_void</property>
|
||||
<property name="code">mergeTo(page, updatedPageObject);</property>
|
||||
</QObject>
|
||||
</property>
|
||||
<property name="functionType">Structure</property>
|
||||
<property name="functionName">setPageUserUnit</property>
|
||||
<property name="functionDescription">Sets page's user unit. It specifies user space unit, in multiples of 1 / 72 inch.</property>
|
||||
<property name="returnType">_void</property>
|
||||
</QObject>
|
||||
<QObject class="codegen::GeneratedFunction">
|
||||
<property name="objectName"></property>
|
||||
<property name="items">
|
||||
|
Loading…
x
Reference in New Issue
Block a user