Commit 2d1db060422eabb82aaa1764926a3f9e881116e2

Authored by Jay Berkenbilt
1 parent 623f5b66

Example of form XObject, page overlay

ChangeLog
1 1 2019-01-26 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Create examples/pdf-overlay-page.cc to demonstrate use of
  4 + page/form XObject interaction
  5 +
3 6 * Add new methods QPDFPageObjectHelper::getFormXObjectForPage,
4 7 which creates a form XObject equivalent to a page, and
5 8 QPDFObjectHandle::placeFormXObject, which generates content stream
... ...
examples/build.mk
... ... @@ -9,7 +9,8 @@ BINS_examples = \
9 9 pdf-split-pages \
10 10 pdf-filter-tokens \
11 11 pdf-count-strings \
12   - pdf-set-form-values
  12 + pdf-set-form-values \
  13 + pdf-overlay-page
13 14 CBINS_examples = pdf-linearize
14 15  
15 16 TARGETS_examples = $(foreach B,$(BINS_examples) $(CBINS_examples),examples/$(OUTPUT_DIR)/$(call binname,$(B)))
... ...
examples/pdf-overlay-page.cc 0 → 100644
  1 +#include <iostream>
  2 +#include <string.h>
  3 +#include <stdlib.h>
  4 +#include <qpdf/QPDF.hh>
  5 +#include <qpdf/QPDFPageDocumentHelper.hh>
  6 +#include <qpdf/QPDFPageObjectHelper.hh>
  7 +#include <qpdf/QPDFWriter.hh>
  8 +#include <qpdf/QUtil.hh>
  9 +
  10 +// This program demonstrates use of form XObjects to overlay a page
  11 +// from one file onto all pages of another file. The qpdf program's
  12 +// --overlay and --underlay options provide a more general version of
  13 +// this capability.
  14 +
  15 +static char const* whoami = 0;
  16 +
  17 +void usage()
  18 +{
  19 + std::cerr << "Usage: " << whoami << " infile pagefile outfile"
  20 + << std::endl
  21 + << "Stamp page 1 of pagefile on every page of infile,"
  22 + << " writing to outfile"
  23 + << std::endl;
  24 + exit(2);
  25 +}
  26 +
  27 +static void stamp_page(char const* infile,
  28 + char const* stampfile,
  29 + char const* outfile)
  30 +{
  31 + QPDF inpdf;
  32 + inpdf.processFile(infile);
  33 + QPDF stamppdf;
  34 + stamppdf.processFile(stampfile);
  35 +
  36 + // Get first page from other file
  37 + QPDFPageObjectHelper stamp_page_1 =
  38 + QPDFPageDocumentHelper(stamppdf).getAllPages().at(0);
  39 + // Convert page to a form XObject
  40 + QPDFObjectHandle foreign_fo = stamp_page_1.getFormXObjectForPage();
  41 + // Copy form XObject to the input file
  42 + QPDFObjectHandle stamp_fo = inpdf.copyForeignObject(foreign_fo);
  43 +
  44 + // For each page...
  45 + std::vector<QPDFPageObjectHelper> pages =
  46 + QPDFPageDocumentHelper(inpdf).getAllPages();
  47 + for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
  48 + iter != pages.end(); ++iter)
  49 + {
  50 + QPDFPageObjectHelper& ph = *iter;
  51 +
  52 + // Find a unique resource name for the new form XObject
  53 + QPDFObjectHandle resources = ph.getAttribute("/Resources", true);
  54 + int min_suffix = 1;
  55 + std::string name = resources.getUniqueResourceName("/Fx", min_suffix);
  56 +
  57 + // Generate content to place the form XObject centered within
  58 + // destination page's trim box.
  59 + std::string content =
  60 + ph.placeFormXObject(
  61 + stamp_fo, name, ph.getTrimBox().getArrayAsRectangle());
  62 + if (! content.empty())
  63 + {
  64 + // Append the content to the page's content. Surround the
  65 + // original content with q...Q to the new content from the
  66 + // page's original content.
  67 + resources.mergeResources(
  68 + QPDFObjectHandle::parse("<< /XObject << >> >>"));
  69 + resources.getKey("/XObject").replaceKey(name, stamp_fo);
  70 + ph.addPageContents(
  71 + QPDFObjectHandle::newStream(&inpdf, "q\n"), true);
  72 + ph.addPageContents(
  73 + QPDFObjectHandle::newStream(&inpdf, "\nQ\n" + content), false);
  74 + }
  75 + }
  76 +
  77 + QPDFWriter w(inpdf, outfile);
  78 + w.setStaticID(true); // for testing only
  79 + w.write();
  80 +}
  81 +
  82 +int main(int argc, char* argv[])
  83 +{
  84 + whoami = QUtil::getWhoami(argv[0]);
  85 +
  86 + // For libtool's sake....
  87 + if (strncmp(whoami, "lt-", 3) == 0)
  88 + {
  89 + whoami += 3;
  90 + }
  91 +
  92 + if (argc != 4)
  93 + {
  94 + usage();
  95 + }
  96 + char const* infile = argv[1];
  97 + char const* stampfile = argv[2];
  98 + char const* outfile = argv[3];
  99 +
  100 + try
  101 + {
  102 + stamp_page(infile, stampfile, outfile);
  103 + }
  104 + catch (std::exception &e)
  105 + {
  106 + std::cerr << whoami << ": " << e.what() << std::endl;
  107 + exit(2);
  108 + }
  109 + return 0;
  110 +}
... ...
examples/qtest/overlay-page.test 0 → 100644
  1 +#!/usr/bin/env perl
  2 +require 5.008;
  3 +use warnings;
  4 +use strict;
  5 +
  6 +chdir("overlay-page");
  7 +
  8 +require TestDriver;
  9 +
  10 +my $td = new TestDriver('overlay-page');
  11 +
  12 +cleanup();
  13 +
  14 +$td->runtest("overlay-page",
  15 + {$td->COMMAND => "pdf-overlay-page in.pdf stamp.pdf a.pdf"},
  16 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  17 +$td->runtest("compare files",
  18 + {$td->FILE => "a.pdf"},
  19 + {$td->FILE => "out.pdf"});
  20 +
  21 +cleanup();
  22 +
  23 +$td->report(2);
  24 +
  25 +sub cleanup
  26 +{
  27 + unlink("a.pdf");
  28 +}
... ...
examples/qtest/overlay-page/in.pdf 0 → 100644
No preview for this file type
examples/qtest/overlay-page/out.pdf 0 → 100644
No preview for this file type
examples/qtest/overlay-page/stamp.pdf 0 → 100644
No preview for this file type