mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Ability to draw on a page trough page content stream builder
This commit is contained in:
@ -25,4 +25,5 @@ int main(int argc, char *argv[])
|
|||||||
PDFExamplesGenerator::generateAnnotationsExample();
|
PDFExamplesGenerator::generateAnnotationsExample();
|
||||||
PDFExamplesGenerator::generatePageBoxesExample();
|
PDFExamplesGenerator::generatePageBoxesExample();
|
||||||
PDFExamplesGenerator::generateOutlineExample();
|
PDFExamplesGenerator::generateOutlineExample();
|
||||||
|
PDFExamplesGenerator::generatePageDrawExample();
|
||||||
}
|
}
|
||||||
|
@ -358,3 +358,31 @@ void PDFExamplesGenerator::generateOutlineExample()
|
|||||||
pdf::PDFDocumentWriter writer(nullptr);
|
pdf::PDFDocumentWriter writer(nullptr);
|
||||||
writer.write("Ex_Outline.pdf", &document, false);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
static void generateAnnotationsExample();
|
static void generateAnnotationsExample();
|
||||||
static void generatePageBoxesExample();
|
static void generatePageBoxesExample();
|
||||||
static void generateOutlineExample();
|
static void generateOutlineExample();
|
||||||
|
static void generatePageDrawExample();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PDFEXAMPLESGENERATOR_H
|
#endif // PDFEXAMPLESGENERATOR_H
|
||||||
|
@ -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()) };
|
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)
|
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
|
||||||
{
|
{
|
||||||
PDFAnnotationPtr annotation = PDFAnnotation::parse(&m_storage, annotationReference);
|
PDFAnnotationPtr annotation = PDFAnnotation::parse(&m_storage, annotationReference);
|
||||||
@ -4436,7 +4512,6 @@ void PDFDocumentBuilder::updateTrailerDictionary(PDFInteger objectCount)
|
|||||||
updateDocumentInfo(qMove(updatedInfoDictionary));
|
updateDocumentInfo(qMove(updatedInfoDictionary));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* END GENERATED CODE */
|
/* END GENERATED CODE */
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -246,6 +246,41 @@ private:
|
|||||||
QPainter* m_painter;
|
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
|
class PDFFORQTLIBSHARED_EXPORT PDFDocumentBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Reference in New Issue
Block a user