2019-01-26 22:33:06 +00:00
|
|
|
#include <qpdf/QPDF.hh>
|
|
|
|
#include <qpdf/QPDFPageDocumentHelper.hh>
|
|
|
|
#include <qpdf/QPDFPageObjectHelper.hh>
|
|
|
|
#include <qpdf/QPDFWriter.hh>
|
|
|
|
#include <qpdf/QUtil.hh>
|
2023-05-20 11:22:32 +00:00
|
|
|
#include <cstdlib>
|
2019-01-26 22:33:06 +00:00
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
// This program demonstrates use of form XObjects to overlay a page from one file onto all pages of
|
|
|
|
// another file. The qpdf program's --overlay and --underlay options provide a more general version
|
|
|
|
// of this capability.
|
|
|
|
|
2022-07-26 11:37:50 +00:00
|
|
|
static char const* whoami = nullptr;
|
2019-01-26 22:33:06 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
usage()
|
|
|
|
{
|
|
|
|
std::cerr << "Usage: " << whoami << " infile pagefile outfile" << std::endl
|
2023-12-23 02:45:10 +00:00
|
|
|
<< "Stamp page 1 of pagefile on every page of infile, writing to outfile"
|
|
|
|
<< std::endl;
|
2019-01-26 22:33:06 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stamp_page(char const* infile, char const* stampfile, char const* outfile)
|
|
|
|
{
|
|
|
|
QPDF inpdf;
|
|
|
|
inpdf.processFile(infile);
|
|
|
|
QPDF stamppdf;
|
|
|
|
stamppdf.processFile(stampfile);
|
|
|
|
|
|
|
|
// Get first page from other file
|
|
|
|
QPDFPageObjectHelper stamp_page_1 = QPDFPageDocumentHelper(stamppdf).getAllPages().at(0);
|
|
|
|
// Convert page to a form XObject
|
|
|
|
QPDFObjectHandle foreign_fo = stamp_page_1.getFormXObjectForPage();
|
|
|
|
// Copy form XObject to the input file
|
|
|
|
QPDFObjectHandle stamp_fo = inpdf.copyForeignObject(foreign_fo);
|
|
|
|
|
|
|
|
// For each page...
|
2022-05-21 14:18:15 +00:00
|
|
|
for (auto& ph: QPDFPageDocumentHelper(inpdf).getAllPages()) {
|
2019-01-26 22:33:06 +00:00
|
|
|
// Find a unique resource name for the new form XObject
|
|
|
|
QPDFObjectHandle resources = ph.getAttribute("/Resources", true);
|
|
|
|
int min_suffix = 1;
|
|
|
|
std::string name = resources.getUniqueResourceName("/Fx", min_suffix);
|
|
|
|
|
|
|
|
// Generate content to place the form XObject centered within destination page's trim box.
|
2021-02-22 21:09:02 +00:00
|
|
|
QPDFMatrix m;
|
2019-01-26 22:33:06 +00:00
|
|
|
std::string content =
|
2021-02-22 21:09:02 +00:00
|
|
|
ph.placeFormXObject(stamp_fo, name, ph.getTrimBox().getArrayAsRectangle(), m);
|
2019-01-26 22:33:06 +00:00
|
|
|
if (!content.empty()) {
|
|
|
|
// Append the content to the page's content. Surround the original content with q...Q to
|
|
|
|
// the new content from the page's original content.
|
2022-02-05 14:18:58 +00:00
|
|
|
resources.mergeResources("<< /XObject << >> >>"_qpdf);
|
2019-01-26 22:33:06 +00:00
|
|
|
resources.getKey("/XObject").replaceKey(name, stamp_fo);
|
2022-09-26 18:29:26 +00:00
|
|
|
ph.addPageContents(inpdf.newStream("q\n"), true);
|
|
|
|
ph.addPageContents(inpdf.newStream("\nQ\n" + content), false);
|
2019-01-26 22:33:06 +00:00
|
|
|
}
|
2021-02-22 21:09:02 +00:00
|
|
|
// Copy the annotations and form fields from the original page to the new page. For more
|
|
|
|
// efficiency when copying multiple pages, we can create a QPDFAcroFormDocumentHelper and
|
|
|
|
// pass it in. See comments in QPDFPageObjectHelper.hh for details.
|
|
|
|
ph.copyAnnotations(stamp_page_1, m);
|
2019-01-26 22:33:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QPDFWriter w(inpdf, outfile);
|
|
|
|
w.setStaticID(true); // for testing only
|
|
|
|
w.write();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
whoami = QUtil::getWhoami(argv[0]);
|
|
|
|
|
|
|
|
if (argc != 4) {
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
char const* infile = argv[1];
|
|
|
|
char const* stampfile = argv[2];
|
|
|
|
char const* outfile = argv[3];
|
|
|
|
|
|
|
|
try {
|
|
|
|
stamp_page(infile, stampfile, outfile);
|
|
|
|
} catch (std::exception& e) {
|
2022-02-08 14:18:08 +00:00
|
|
|
std::cerr << whoami << ": " << e.what() << std::endl;
|
|
|
|
exit(2);
|
2019-01-26 22:33:06 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|