diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/build.mk | 3 | ||||
-rw-r--r-- | examples/pdf-bookmarks.cc | 193 | ||||
-rw-r--r-- | examples/pdf-overlay-page.cc | 110 | ||||
-rw-r--r-- | examples/pdf-split-pages.cc | 2 | ||||
-rw-r--r-- | examples/qtest/create.test | 1 | ||||
-rw-r--r-- | examples/qtest/overlay-page.test | 28 | ||||
-rw-r--r-- | examples/qtest/overlay-page/in.pdf | bin | 0 -> 1840 bytes | |||
-rw-r--r-- | examples/qtest/overlay-page/out.pdf | bin | 0 -> 3361 bytes | |||
-rw-r--r-- | examples/qtest/overlay-page/stamp.pdf | bin | 0 -> 799 bytes |
9 files changed, 235 insertions, 102 deletions
diff --git a/examples/build.mk b/examples/build.mk index 031601ff..8033d7d2 100644 --- a/examples/build.mk +++ b/examples/build.mk @@ -9,7 +9,8 @@ BINS_examples = \ pdf-split-pages \ pdf-filter-tokens \ pdf-count-strings \ - pdf-set-form-values + pdf-set-form-values \ + pdf-overlay-page CBINS_examples = pdf-linearize TARGETS_examples = $(foreach B,$(BINS_examples) $(CBINS_examples),examples/$(OUTPUT_DIR)/$(call binname,$(B))) diff --git a/examples/pdf-bookmarks.cc b/examples/pdf-bookmarks.cc index ed5b8029..807fc02f 100644 --- a/examples/pdf-bookmarks.cc +++ b/examples/pdf-bookmarks.cc @@ -3,9 +3,14 @@ #include <stdlib.h> #include <qpdf/QPDF.hh> #include <qpdf/QPDFPageDocumentHelper.hh> +#include <qpdf/QPDFOutlineDocumentHelper.hh> #include <qpdf/QUtil.hh> #include <qpdf/QTC.hh> +// This program demonstrates extraction of bookmarks using the qpdf +// outlines API. Note that all the information shown by this program +// can also be obtained from a PDF file using qpdf's --json option. + static char const* whoami = 0; static enum { st_none, st_numbers, st_lines } style = st_none; static bool show_open = false; @@ -56,111 +61,99 @@ void generate_page_map(QPDF& qpdf) } } -void extract_bookmarks(QPDFObjectHandle outlines, std::vector<int>& numbers) +void show_bookmark_details(QPDFOutlineObjectHelper outline, + std::vector<int> numbers) { - if (outlines.hasKey("/Title")) + // No default so gcc will warn on missing tag + switch (style) { - // No default so gcc will warn on missing tag - switch (style) - { - case st_none: - QTC::TC("examples", "pdf-bookmarks none"); - break; - - case st_numbers: - QTC::TC("examples", "pdf-bookmarks numbers"); - for (std::vector<int>::iterator iter = numbers.begin(); - iter != numbers.end(); ++iter) - { - std::cout << *iter << "."; - } - std::cout << " "; - break; - - case st_lines: - QTC::TC("examples", "pdf-bookmarks lines"); - print_lines(numbers); - std::cout << "|" << std::endl; - print_lines(numbers); - std::cout << "+-+ "; - break; - } - - if (show_open) - { - if (outlines.hasKey("/Count")) - { - QTC::TC("examples", "pdf-bookmarks has count"); - int count = outlines.getKey("/Count").getIntValue(); - if (count > 0) - { - // hierarchy is open at this point - QTC::TC("examples", "pdf-bookmarks open"); - std::cout << "(v) "; - } - else - { - QTC::TC("examples", "pdf-bookmarks closed"); - std::cout << "(>) "; - } - } - else - { - QTC::TC("examples", "pdf-bookmarks no count"); - std::cout << "( ) "; - } - } - - if (show_targets) - { - QTC::TC("examples", "pdf-bookmarks targets"); - std::string target = "unknown"; - // Only explicit destinations supported for now - if (outlines.hasKey("/Dest")) - { - QTC::TC("examples", "pdf-bookmarks dest"); - QPDFObjectHandle dest = outlines.getKey("/Dest"); - if ((dest.isArray()) && (dest.getArrayNItems() > 0)) - { - QPDFObjectHandle first = dest.getArrayItem(0); - QPDFObjGen og = first.getObjGen(); - if (page_map.count(og)) - { - target = QUtil::int_to_string(page_map[og]); - } - } + case st_none: + QTC::TC("examples", "pdf-bookmarks none"); + break; + + case st_numbers: + QTC::TC("examples", "pdf-bookmarks numbers"); + for (std::vector<int>::iterator iter = numbers.begin(); + iter != numbers.end(); ++iter) + { + std::cout << *iter << "."; + } + std::cout << " "; + break; + + case st_lines: + QTC::TC("examples", "pdf-bookmarks lines"); + print_lines(numbers); + std::cout << "|" << std::endl; + print_lines(numbers); + std::cout << "+-+ "; + break; + } - std::cout << "[ -> " << target << " ] "; - } - } + if (show_open) + { + int count = outline.getCount(); + if (count) + { + QTC::TC("examples", "pdf-bookmarks has count"); + if (count > 0) + { + // hierarchy is open at this point + QTC::TC("examples", "pdf-bookmarks open"); + std::cout << "(v) "; + } + else + { + QTC::TC("examples", "pdf-bookmarks closed"); + std::cout << "(>) "; + } + } + else + { + QTC::TC("examples", "pdf-bookmarks no count"); + std::cout << "( ) "; + } + } - std::cout << outlines.getKey("/Title").getUTF8Value() << std::endl; + if (show_targets) + { + QTC::TC("examples", "pdf-bookmarks targets"); + std::string target = "unknown"; + QPDFObjectHandle dest_page = outline.getDestPage(); + if (! dest_page.isNull()) + { + QTC::TC("examples", "pdf-bookmarks dest"); + QPDFObjGen og = dest_page.getObjGen(); + if (page_map.count(og)) + { + target = QUtil::int_to_string(page_map[og]); + } + } + std::cout << "[ -> " << target << " ] "; } - if (outlines.hasKey("/First")) + std::cout << outline.getTitle() << std::endl; +} + +void extract_bookmarks(std::list<QPDFOutlineObjectHelper> outlines, + std::vector<int>& numbers) +{ + numbers.push_back(0); + for (std::list<QPDFOutlineObjectHelper>::iterator iter = outlines.begin(); + iter != outlines.end(); ++iter) { - numbers.push_back(0); - QPDFObjectHandle child = outlines.getKey("/First"); - while (1) - { - ++(numbers.back()); - bool has_next = child.hasKey("/Next"); - if ((style == st_lines) && (! has_next)) - { - numbers.back() = 0; - } - extract_bookmarks(child, numbers); - if (has_next) - { - child = child.getKey("/Next"); - } - else - { - break; - } - } - numbers.pop_back(); + ++(numbers.back()); + show_bookmark_details(*iter, numbers); + std::list<QPDFOutlineObjectHelper>::iterator next = iter; + ++next; + bool has_next = (next != outlines.end()); + if ((style == st_lines) && (! has_next)) + { + numbers.back() = 0; + } + extract_bookmarks((*iter).getKids(), numbers); } + numbers.pop_back(); } int main(int argc, char* argv[]) @@ -233,15 +226,15 @@ int main(int argc, char* argv[]) QPDF qpdf; qpdf.processFile(filename, password); - QPDFObjectHandle root = qpdf.getRoot(); - if (root.hasKey("/Outlines")) + QPDFOutlineDocumentHelper odh(qpdf); + if (odh.hasOutlines()) { std::vector<int> numbers; if (show_targets) { generate_page_map(qpdf); } - extract_bookmarks(root.getKey("/Outlines"), numbers); + extract_bookmarks(odh.getTopLevelOutlines(), numbers); } else { diff --git a/examples/pdf-overlay-page.cc b/examples/pdf-overlay-page.cc new file mode 100644 index 00000000..88722352 --- /dev/null +++ b/examples/pdf-overlay-page.cc @@ -0,0 +1,110 @@ +#include <iostream> +#include <string.h> +#include <stdlib.h> +#include <qpdf/QPDF.hh> +#include <qpdf/QPDFPageDocumentHelper.hh> +#include <qpdf/QPDFPageObjectHelper.hh> +#include <qpdf/QPDFWriter.hh> +#include <qpdf/QUtil.hh> + +// 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. + +static char const* whoami = 0; + +void usage() +{ + std::cerr << "Usage: " << whoami << " infile pagefile outfile" + << std::endl + << "Stamp page 1 of pagefile on every page of infile," + << " writing to outfile" + << std::endl; + 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... + std::vector<QPDFPageObjectHelper> pages = + QPDFPageDocumentHelper(inpdf).getAllPages(); + for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); + iter != pages.end(); ++iter) + { + QPDFPageObjectHelper& ph = *iter; + + // 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. + std::string content = + ph.placeFormXObject( + stamp_fo, name, ph.getTrimBox().getArrayAsRectangle()); + 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. + resources.mergeResources( + QPDFObjectHandle::parse("<< /XObject << >> >>")); + resources.getKey("/XObject").replaceKey(name, stamp_fo); + ph.addPageContents( + QPDFObjectHandle::newStream(&inpdf, "q\n"), true); + ph.addPageContents( + QPDFObjectHandle::newStream(&inpdf, "\nQ\n" + content), false); + } + } + + QPDFWriter w(inpdf, outfile); + w.setStaticID(true); // for testing only + w.write(); +} + +int main(int argc, char* argv[]) +{ + whoami = QUtil::getWhoami(argv[0]); + + // For libtool's sake.... + if (strncmp(whoami, "lt-", 3) == 0) + { + whoami += 3; + } + + 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) + { + std::cerr << whoami << ": " << e.what() << std::endl; + exit(2); + } + return 0; +} diff --git a/examples/pdf-split-pages.cc b/examples/pdf-split-pages.cc index b65f96ee..aa089e5a 100644 --- a/examples/pdf-split-pages.cc +++ b/examples/pdf-split-pages.cc @@ -77,7 +77,7 @@ int main(int argc, char* argv[]) { process(whoami, argv[1], argv[2]); } - catch (std::exception e) + catch (std::exception const& e) { std::cerr << whoami << ": exception: " << e.what() << std::endl; return 2; diff --git a/examples/qtest/create.test b/examples/qtest/create.test index f83509e2..f18c5fd6 100644 --- a/examples/qtest/create.test +++ b/examples/qtest/create.test @@ -23,4 +23,5 @@ $td->report(1); sub cleanup { unlink "a.pdf"; + unlink "tmp.out"; } diff --git a/examples/qtest/overlay-page.test b/examples/qtest/overlay-page.test new file mode 100644 index 00000000..68e695d3 --- /dev/null +++ b/examples/qtest/overlay-page.test @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +require 5.008; +use warnings; +use strict; + +chdir("overlay-page"); + +require TestDriver; + +my $td = new TestDriver('overlay-page'); + +cleanup(); + +$td->runtest("overlay-page", + {$td->COMMAND => "pdf-overlay-page in.pdf stamp.pdf a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); +$td->runtest("compare files", + {$td->FILE => "a.pdf"}, + {$td->FILE => "out.pdf"}); + +cleanup(); + +$td->report(2); + +sub cleanup +{ + unlink("a.pdf"); +} diff --git a/examples/qtest/overlay-page/in.pdf b/examples/qtest/overlay-page/in.pdf Binary files differnew file mode 100644 index 00000000..f94c739a --- /dev/null +++ b/examples/qtest/overlay-page/in.pdf diff --git a/examples/qtest/overlay-page/out.pdf b/examples/qtest/overlay-page/out.pdf Binary files differnew file mode 100644 index 00000000..b589d2c4 --- /dev/null +++ b/examples/qtest/overlay-page/out.pdf diff --git a/examples/qtest/overlay-page/stamp.pdf b/examples/qtest/overlay-page/stamp.pdf Binary files differnew file mode 100644 index 00000000..a86f4344 --- /dev/null +++ b/examples/qtest/overlay-page/stamp.pdf |