Commit 2e8a3e163f50da1bb69d740a8955ce8915e32181

Authored by Jay Berkenbilt
1 parent 2650a4d7

Add interactive form example

ChangeLog
1 1 2018-06-21 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Create examples/pdf-set-form-values.cc to illustrate use of
  4 + interactive form helpers.
  5 +
3 6 * Added methods QPDFAcroFormDocumentHelper::setNeedAppearances and
4 7 added methods to QPDFFormFieldObjectHelper to set a field's value,
5 8 optionally updating the document to indicate that appearance
... ...
examples/build.mk
... ... @@ -8,7 +8,8 @@ BINS_examples = \
8 8 pdf-parse-content \
9 9 pdf-split-pages \
10 10 pdf-filter-tokens \
11   - pdf-count-strings
  11 + pdf-count-strings \
  12 + pdf-set-form-values
12 13 CBINS_examples = pdf-linearize
13 14  
14 15 TARGETS_examples = $(foreach B,$(BINS_examples) $(CBINS_examples),examples/$(OUTPUT_DIR)/$(call binname,$(B)))
... ...
examples/pdf-set-form-values.cc 0 → 100644
  1 +#include <iostream>
  2 +#include <stdlib.h>
  3 +#include <qpdf/QPDF.hh>
  4 +#include <qpdf/QPDFPageDocumentHelper.hh>
  5 +#include <qpdf/QPDFAcroFormDocumentHelper.hh>
  6 +#include <qpdf/QPDFWriter.hh>
  7 +#include <qpdf/QUtil.hh>
  8 +
  9 +static char const* whoami = 0;
  10 +
  11 +void usage()
  12 +{
  13 + std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf value"
  14 + << std::endl
  15 + << "Set the value of all text fields to a specified value"
  16 + << std::endl;
  17 + exit(2);
  18 +}
  19 +
  20 +
  21 +int main(int argc, char* argv[])
  22 +{
  23 + whoami = QUtil::getWhoami(argv[0]);
  24 +
  25 + // For libtool's sake....
  26 + if (strncmp(whoami, "lt-", 3) == 0)
  27 + {
  28 + whoami += 3;
  29 + }
  30 +
  31 + if (argc != 4)
  32 + {
  33 + usage();
  34 + }
  35 +
  36 + char const* infilename = argv[1];
  37 + char const* outfilename = argv[2];
  38 + char const* value = argv[3];
  39 +
  40 + // This is a contrived example that just goes through a file page
  41 + // by page and sets the value of any text fields it finds to a
  42 + // fixed value as given on the command line. The purpose here is
  43 + // to illustrate use of the helper classes around interactive
  44 + // forms.
  45 +
  46 + try
  47 + {
  48 + QPDF qpdf;
  49 + qpdf.processFile(infilename);
  50 +
  51 + // We will iterate through form fields by starting at the page
  52 + // level and looking at each field for each page. We could
  53 + // also called QPDFAcroFormDocumentHelper::getFormFields to
  54 + // iterate at the field level, but doing it as below
  55 + // illustrates how we can map from annotations to fields.
  56 +
  57 + QPDFAcroFormDocumentHelper afdh(qpdf);
  58 + QPDFPageDocumentHelper pdh(qpdf);
  59 + std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages();
  60 + for (std::vector<QPDFPageObjectHelper>::iterator page_iter =
  61 + pages.begin();
  62 + page_iter != pages.end(); ++page_iter)
  63 + {
  64 + // Get all widget annotations for each page. Widget
  65 + // annotations are the ones that contain the details of
  66 + // what's in a form field.
  67 + std::vector<QPDFAnnotationObjectHelper> annotations =
  68 + afdh.getWidgetAnnotationsForPage(*page_iter);
  69 + for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter =
  70 + annotations.begin();
  71 + annot_iter != annotations.end(); ++annot_iter)
  72 + {
  73 + // For each annotation, find its associated field. If
  74 + // it's a text field, set its value. This will
  75 + // automatically update the document to indicate that
  76 + // appearance streams need to be regenerated. At the
  77 + // time of this writing, qpdf doesn't have any helper
  78 + // code to assist with appearance stream generation,
  79 + // though there's nothing that prevents it from being
  80 + // possible.
  81 + QPDFFormFieldObjectHelper ffh =
  82 + afdh.getFieldForAnnotation(*annot_iter);
  83 + if (ffh.getFieldType() == "/Tx")
  84 + {
  85 + // Set the value. This will automatically set
  86 + // /NeedAppearances to true. If you don't want to
  87 + // do that, pass false as the second argument. For
  88 + // details see comments in
  89 + // QPDFFormFieldObjectHelper.hh.
  90 + ffh.setV(value);
  91 + }
  92 + }
  93 + }
  94 +
  95 + // Write out a new file
  96 + QPDFWriter w(qpdf, outfilename);
  97 + w.setStaticID(true); // for testing only
  98 + w.write();
  99 + }
  100 + catch (std::exception &e)
  101 + {
  102 + std::cerr << whoami << " processing file " << infilename << ": "
  103 + << e.what() << std::endl;
  104 + exit(2);
  105 + }
  106 +
  107 + return 0;
  108 +}
... ...
examples/qtest/set-form-values.test 0 → 100644
  1 +#!/usr/bin/env perl
  2 +require 5.008;
  3 +BEGIN { $^W = 1; }
  4 +use strict;
  5 +
  6 +chdir("set-form-values");
  7 +
  8 +require TestDriver;
  9 +
  10 +my $td = new TestDriver('pdf-set-form-values');
  11 +
  12 +cleanup();
  13 +
  14 +$td->runtest("set form values",
  15 + {$td->COMMAND => "pdf-set-form-values form-in.pdf a.pdf soup"},
  16 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  17 +$td->runtest("compare files",
  18 + {$td->FILE => "a.pdf"},
  19 + {$td->FILE => "form-out.pdf"});
  20 +
  21 +cleanup();
  22 +
  23 +$td->report(2);
  24 +
  25 +sub cleanup
  26 +{
  27 + unlink("a.pdf");
  28 +}
... ...
examples/qtest/set-form-values/form-in.pdf 0 → 100644
No preview for this file type
examples/qtest/set-form-values/form-out.pdf 0 → 100644
No preview for this file type