Ability to draw on a page trough page content stream builder

This commit is contained in:
Jakub Melka 2020-11-16 13:20:14 +01:00
parent cb3a36f891
commit 018c8fae3e
5 changed files with 141 additions and 1 deletions

View File

@ -25,4 +25,5 @@ int main(int argc, char *argv[])
PDFExamplesGenerator::generateAnnotationsExample();
PDFExamplesGenerator::generatePageBoxesExample();
PDFExamplesGenerator::generateOutlineExample();
PDFExamplesGenerator::generatePageDrawExample();
}

View File

@ -358,3 +358,31 @@ void PDFExamplesGenerator::generateOutlineExample()
pdf::PDFDocumentWriter writer(nullptr);
writer.write("Ex_Outline.pdf", &document, false);
}
void PDFExamplesGenerator::generatePageDrawExample()
{
pdf::PDFDocumentBuilder builder;
builder.setDocumentTitle("Test document - Page draw");
builder.setDocumentAuthor("Jakub Melka");
builder.setDocumentCreator(QCoreApplication::applicationName());
builder.setDocumentSubject("Testing page draw");
builder.setLanguage(QLocale::system());
QPainter* painter = nullptr;
pdf::PDFPageContentStreamBuilder pageContentStreamBuilder(&builder);
painter = pageContentStreamBuilder.beginNewPage(QRectF(0, 0, 300, 480));
painter->drawEllipse(QPointF(150, 240), 65, 25);
painter->fillRect(QRectF(0, 0, 50, 50), Qt::green);
pageContentStreamBuilder.end(painter);
painter = pageContentStreamBuilder.beginNewPage(QRectF(0, 0, 300, 480));
painter->drawText(QPointF(50, 50), "This is testing text!");
pageContentStreamBuilder.end(painter);
// Write result to a file
pdf::PDFDocument document = builder.build();
pdf::PDFDocumentWriter writer(nullptr);
writer.write("Ex_PageDraw.pdf", &document, false);
}

View File

@ -26,6 +26,7 @@ public:
static void generateAnnotationsExample();
static void generatePageBoxesExample();
static void generateOutlineExample();
static void generatePageDrawExample();
};
#endif // PDFEXAMPLESGENERATOR_H

View File

@ -666,6 +666,82 @@ std::array<PDFReal, 4> PDFDocumentBuilder::getAnnotationReductionRectangle(const
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
}
PDFPageContentStreamBuilder::PDFPageContentStreamBuilder(PDFDocumentBuilder* builder) :
m_documentBuilder(builder),
m_contentStreamBuilder(nullptr)
{
}
QPainter* PDFPageContentStreamBuilder::begin(PDFObjectReference page)
{
if (m_contentStreamBuilder)
{
// Invalid call to begin function
return nullptr;
}
const PDFObjectStorage* storage = m_documentBuilder->getStorage();
const PDFDictionary* pageDictionary = storage->getDictionaryFromObject(storage->getObject(page));
if (!pageDictionary)
{
return nullptr;
}
PDFDocumentDataLoaderDecorator loader(storage);
QRectF mediaBox = loader.readRectangle(pageDictionary->get("MediaBox"), QRectF());
if (!mediaBox.isValid())
{
return nullptr;
}
m_pageReference = page;
m_contentStreamBuilder = new PDFContentStreamBuilder(mediaBox.size(), PDFContentStreamBuilder::CoordinateSystem::Qt);
return m_contentStreamBuilder->begin();
}
QPainter* PDFPageContentStreamBuilder::beginNewPage(QRectF mediaBox)
{
return begin(m_documentBuilder->appendPage(mediaBox));
}
void PDFPageContentStreamBuilder::end(QPainter* painter)
{
if (!m_contentStreamBuilder)
{
return;
}
PDFContentStreamBuilder::ContentStream contentStream = m_contentStreamBuilder->end(painter);
delete m_contentStreamBuilder;
m_contentStreamBuilder = nullptr;
// Update page's content stream
std::vector<PDFObject> copiedObjects = m_documentBuilder->copyFrom({ contentStream.resources, contentStream.contents }, contentStream.document.getStorage(), true);
Q_ASSERT(copiedObjects.size() == 2);
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
PDFObjectReference contentsReference = copiedObjects[1].getReference();
PDFObjectFactory pageUpdateFactory;
pageUpdateFactory.beginDictionary();
pageUpdateFactory.beginDictionaryItem("Contents");
pageUpdateFactory << contentsReference;
pageUpdateFactory.endDictionaryItem();
pageUpdateFactory.beginDictionaryItem("Resources");
pageUpdateFactory << resourcesReference;
pageUpdateFactory.endDictionaryItem();
pageUpdateFactory.endDictionary();
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
}
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
{
PDFAnnotationPtr annotation = PDFAnnotation::parse(&m_storage, annotationReference);
@ -4436,7 +4512,6 @@ void PDFDocumentBuilder::updateTrailerDictionary(PDFInteger objectCount)
updateDocumentInfo(qMove(updatedInfoDictionary));
}
/* END GENERATED CODE */
} // namespace pdf

View File

@ -246,6 +246,41 @@ private:
QPainter* m_painter;
};
/// This class can create page content streams, using the Qt's QPainter
/// to draw graphics elements on it. Content stream can have various
/// resources, which can, if selected be dereferenced, so content
/// stream is encapsulated and doesn't contain references.
class PDFFORQTLIBSHARED_EXPORT PDFPageContentStreamBuilder
{
public:
PDFPageContentStreamBuilder(PDFDocumentBuilder* builder);
/// Starts painting onto the page. Old page content is erased. This
/// function returns painter, onto which can be graphics drawn. Painter
/// uses Qt's coordinate system. Calling begin multiple times, without
/// subsequent calls to end function, is invalid and can result
/// in undefined behaviour. This function can return nullptr,
/// if error occurs.
/// \param page Page, onto which we want to draw
QPainter* begin(PDFObjectReference page);
/// This function is similar to function \p begin(), but it appends
/// a new page to the end of the document.
/// \param mediaBox Page's media box
QPainter* beginNewPage(QRectF mediaBox);
/// Finishes painting on a page content stream. This function updates
/// page content stream, which is associated with this page. This function
/// must be called with painter, which has been returned with call to begin function.
/// \param painter Painter, which was returned with function begin()
void end(QPainter* painter);
private:
PDFDocumentBuilder* m_documentBuilder;
PDFContentStreamBuilder* m_contentStreamBuilder;
PDFObjectReference m_pageReference;
};
class PDFFORQTLIBSHARED_EXPORT PDFDocumentBuilder
{
public: