Commit 4fe2e06b4787ffb639f965ac840b51018308ec07

Authored by Jay Berkenbilt
1 parent ed613003

Add --create-from-json and --update-from-json arguments

Also add stubs for top-level QPDF methods (createFromJSON,
updateFromJSON)
README-maintainer
@@ -215,6 +215,14 @@ CODING RULES @@ -215,6 +215,14 @@ CODING RULES
215 215
216 HOW TO ADD A COMMAND-LINE ARGUMENT 216 HOW TO ADD A COMMAND-LINE ARGUMENT
217 217
  218 +Quick reminder:
  219 +
  220 +* Add an entry to the top half of job.yml for the command-line
  221 + argument
  222 +* Add an entry to the bottom half of job.yml for the job JSON field
  223 +* Add documentation for the new option to cli.rst
  224 +* Implement the QPDFJob::Config method in QPDFJob_config.cc.
  225 +
218 QPDFJob is documented in three places: 226 QPDFJob is documented in three places:
219 227
220 * This section provides a quick reminder for how to add a command-line 228 * This section provides a quick reminder for how to add a command-line
include/qpdf/QPDF.hh
@@ -110,6 +110,28 @@ class QPDF @@ -110,6 +110,28 @@ class QPDF
110 void 110 void
111 processInputSource(std::shared_ptr<InputSource>, char const* password = 0); 111 processInputSource(std::shared_ptr<InputSource>, char const* password = 0);
112 112
  113 + // Create a PDF from an input source that contains JSON as written
  114 + // by qpdf --json (version 2 or higher). The JSON must be a
  115 + // complete representation of a PDF. See "QPDF JSON Format" in the
  116 + // manual for details.
  117 + QPDF_DLL
  118 + void
  119 + createFromJSON(std::string const& json_file);
  120 + QPDF_DLL
  121 + void
  122 + createFromJSON(std::shared_ptr<InputSource>);
  123 +
  124 + // Update a PDF from an input source that contains JSON in the
  125 + // same format as is written by qpdf --json (version 2 or higher).
  126 + // Objects in the PDF and not in the JSON are not modified. See
  127 + // "QPDF JSON Format" in the manual for details.
  128 + QPDF_DLL
  129 + void
  130 + updateFromJSON(std::string const& json_file);
  131 + QPDF_DLL
  132 + void
  133 + updateFromJSON(std::shared_ptr<InputSource>);
  134 +
113 // Close or otherwise release the input source. Once this has been 135 // Close or otherwise release the input source. Once this has been
114 // called, no other methods of qpdf can be called safely except 136 // called, no other methods of qpdf can be called safely except
115 // for getWarnings and anyWarnings(). After this has been called, 137 // for getWarnings and anyWarnings(). After this has been called,
include/qpdf/QPDFJob.hh
@@ -323,6 +323,8 @@ class QPDFJob @@ -323,6 +323,8 @@ class QPDFJob
323 Config* outputFile(std::string const& filename); 323 Config* outputFile(std::string const& filename);
324 QPDF_DLL 324 QPDF_DLL
325 Config* replaceInput(); 325 Config* replaceInput();
  326 + QPDF_DLL
  327 + Config* createFromJson(std::string const& filename);
326 328
327 QPDF_DLL 329 QPDF_DLL
328 std::shared_ptr<CopyAttConfig> copyAttachmentsFrom(); 330 std::shared_ptr<CopyAttConfig> copyAttachmentsFrom();
@@ -674,6 +676,8 @@ class QPDFJob @@ -674,6 +676,8 @@ class QPDFJob
674 bool check_requires_password; 676 bool check_requires_password;
675 std::shared_ptr<char> infilename; 677 std::shared_ptr<char> infilename;
676 std::shared_ptr<char> outfilename; 678 std::shared_ptr<char> outfilename;
  679 + std::string create_from_json;
  680 + std::string update_from_json;
677 }; 681 };
678 std::shared_ptr<Members> m; 682 std::shared_ptr<Members> m;
679 }; 683 };
include/qpdf/auto_job_c_main.hh
@@ -68,6 +68,7 @@ QPDF_DLL Config* rotate(std::string const&amp; parameter); @@ -68,6 +68,7 @@ QPDF_DLL Config* rotate(std::string const&amp; parameter);
68 QPDF_DLL Config* showAttachment(std::string const& parameter); 68 QPDF_DLL Config* showAttachment(std::string const& parameter);
69 QPDF_DLL Config* showObject(std::string const& parameter); 69 QPDF_DLL Config* showObject(std::string const& parameter);
70 QPDF_DLL Config* jsonStreamPrefix(std::string const& parameter); 70 QPDF_DLL Config* jsonStreamPrefix(std::string const& parameter);
  71 +QPDF_DLL Config* updateFromJson(std::string const& parameter);
71 QPDF_DLL Config* collate(std::string const& parameter); 72 QPDF_DLL Config* collate(std::string const& parameter);
72 QPDF_DLL Config* collate(); 73 QPDF_DLL Config* collate();
73 QPDF_DLL Config* splitPages(std::string const& parameter); 74 QPDF_DLL Config* splitPages(std::string const& parameter);
job.sums
@@ -3,15 +3,15 @@ generate_auto_job 0514289f2deb3bf7c1a6e85ef7d99ad120321ef5a6fe49d76c5274c6a658d3 @@ -3,15 +3,15 @@ generate_auto_job 0514289f2deb3bf7c1a6e85ef7d99ad120321ef5a6fe49d76c5274c6a658d3
3 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 3 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4
4 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 4 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
5 include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 5 include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5
6 -include/qpdf/auto_job_c_main.hh 50214d1583d0384e70ce7c91d6bb92c58f8cc125490a680681cfffe6455a1dce 6 +include/qpdf/auto_job_c_main.hh 178a0c98c80d53036910ec67165dbc3902aa8da857de8a0df52911f005918c54
7 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec 7 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
8 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 8 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
9 -job.yml c046a750e0cf6889b920484ab937bcb999be55273d77b263cb227b82006fbb36  
10 -libqpdf/qpdf/auto_job_decl.hh 74df4d7fdbdf51ecd0d58ce1e9844bb5525b9adac5a45f7c9a787ecdda2868df  
11 -libqpdf/qpdf/auto_job_help.hh e9b37d33bfcbf165bfba21b6778df3f356b904a961bfae68f9638b85142a87e8  
12 -libqpdf/qpdf/auto_job_init.hh 423157a51fa470fb45d6e341cc3fc8f044b5344f06f86475b37302610c7d8afd  
13 -libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297  
14 -libqpdf/qpdf/auto_job_json_init.hh eaed8624a1a394c75a3e298e1c31015146211e240d710509eb627fc711a387a6  
15 -libqpdf/qpdf/auto_job_schema.hh a9971c82c9821a5ec620ccc003bcb3383c054e45658b50fa559b5855e694ed1a 9 +job.yml a95b2446066293f409b36032a0ee411dbe570a7a94f5fd295048d009215f993f
  10 +libqpdf/qpdf/auto_job_decl.hh 833bde9c1f8fc17b914f16498e26d9d1315361645b4ac5c50c1f830a76618ca7
  11 +libqpdf/qpdf/auto_job_help.hh 38bf89067ca7dc244e4e697c598ba0ba8a827600a78b9195fc69f0ac1663f3a2
  12 +libqpdf/qpdf/auto_job_init.hh f0ffab312430b232a7288b8443382ed859021e6ad6ed2c8c9a4dbbd2b33e2aa7
  13 +libqpdf/qpdf/auto_job_json_decl.hh 81d09d4b82b2e042a64246ed1d7a187bdc83b671b45e7b8ee60ad37c0c11e9a7
  14 +libqpdf/qpdf/auto_job_json_init.hh 2fcdae08365abe351d2dfb6a823e2b3af27a6510632de23cabef6cefa5dfb199
  15 +libqpdf/qpdf/auto_job_schema.hh 1a80be3b8d97e9b5a55b8aa45a4b312668b1687eab6f038c4ee5f4662ab71997
16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
17 -manual/cli.rst f1bbf59ce4fdb5a6d29fc2470788eee321423dd946984fc2e6f3a904fe5137c1 17 +manual/cli.rst 4550dd1b459721d8ef9affa7c9c07f351a06379498ec1291f702f1a5994b6d84
@@ -86,6 +86,7 @@ options: @@ -86,6 +86,7 @@ options:
86 - underlay 86 - underlay
87 - empty 87 - empty
88 - replace-input 88 - replace-input
  89 + - create-from-json
89 positional: true 90 positional: true
90 bare: 91 bare:
91 - add-attachment 92 - add-attachment
@@ -163,6 +164,8 @@ options: @@ -163,6 +164,8 @@ options:
163 show-attachment: attachment 164 show-attachment: attachment
164 show-object: trailer 165 show-object: trailer
165 json-stream-prefix: stream-file-prefix 166 json-stream-prefix: stream-file-prefix
  167 + create-from-json: qpdf-json file
  168 + update-from-json: qpdf-json file
166 required_choices: 169 required_choices:
167 compress-streams: yn 170 compress-streams: yn
168 decode-level: decode_level 171 decode-level: decode_level
@@ -278,6 +281,7 @@ json: @@ -278,6 +281,7 @@ json:
278 main.password: 281 main.password:
279 password-file: 282 password-file:
280 empty: 283 empty:
  284 + create-from-json:
281 # output 285 # output
282 _outputFile: "output filename" 286 _outputFile: "output filename"
283 replace-input: 287 replace-input:
@@ -360,6 +364,7 @@ json: @@ -360,6 +364,7 @@ json:
360 json-stream-prefix: 364 json-stream-prefix:
361 to-json: 365 to-json:
362 # other options 366 # other options
  367 + update-from-json:
363 allow-weak-crypto: 368 allow-weak-crypto:
364 keep-files-open: 369 keep-files-open:
365 keep-files-open-threshold: 370 keep-files-open-threshold:
libqpdf/CMakeLists.txt
@@ -97,6 +97,7 @@ set(libqpdf_SOURCES @@ -97,6 +97,7 @@ set(libqpdf_SOURCES
97 QPDF_Stream.cc 97 QPDF_Stream.cc
98 QPDF_String.cc 98 QPDF_String.cc
99 QPDF_encryption.cc 99 QPDF_encryption.cc
  100 + QPDF_json.cc
100 QPDF_linearization.cc 101 QPDF_linearization.cc
101 QPDF_optimization.cc 102 QPDF_optimization.cc
102 QPDF_pages.cc 103 QPDF_pages.cc
libqpdf/QPDFJob.cc
@@ -553,6 +553,13 @@ QPDFJob::run() @@ -553,6 +553,13 @@ QPDFJob::run()
553 if (m->check_is_encrypted || m->check_requires_password) { 553 if (m->check_is_encrypted || m->check_requires_password) {
554 return; 554 return;
555 } 555 }
  556 +
  557 + // If we are updating from JSON, this has to be done first before
  558 + // other options may cause transformations to the input.
  559 + if (!this->m->update_from_json.empty()) {
  560 + pdf.updateFromJSON(this->m->update_from_json);
  561 + }
  562 +
556 bool other_warnings = false; 563 bool other_warnings = false;
557 std::vector<std::shared_ptr<QPDF>> page_heap; 564 std::vector<std::shared_ptr<QPDF>> page_heap;
558 if (!m->page_specs.empty()) { 565 if (!m->page_specs.empty()) {
@@ -1937,7 +1944,11 @@ QPDFJob::doProcessOnce( @@ -1937,7 +1944,11 @@ QPDFJob::doProcessOnce(
1937 auto pdf = std::make_shared<QPDF>(); 1944 auto pdf = std::make_shared<QPDF>();
1938 setQPDFOptions(*pdf); 1945 setQPDFOptions(*pdf);
1939 if (empty) { 1946 if (empty) {
1940 - pdf->emptyPDF(); 1947 + if (!this->m->create_from_json.empty()) {
  1948 + pdf->createFromJSON(this->m->create_from_json);
  1949 + } else {
  1950 + pdf->emptyPDF();
  1951 + }
1941 } else { 1952 } else {
1942 fn(pdf.get(), password); 1953 fn(pdf.get(), password);
1943 } 1954 }
libqpdf/QPDFJob_argv.cc
@@ -101,6 +101,13 @@ ArgParser::argReplaceInput() @@ -101,6 +101,13 @@ ArgParser::argReplaceInput()
101 } 101 }
102 102
103 void 103 void
  104 +ArgParser::argCreateFromJson(std::string const& arg)
  105 +{
  106 + c_main->createFromJson(arg);
  107 + this->gave_input = true;
  108 +}
  109 +
  110 +void
104 ArgParser::argVersion() 111 ArgParser::argVersion()
105 { 112 {
106 auto whoami = this->ap.getProgname(); 113 auto whoami = this->ap.getProgname();
libqpdf/QPDFJob_config.cc
@@ -25,12 +25,14 @@ QPDFJob::Config::emptyInput() @@ -25,12 +25,14 @@ QPDFJob::Config::emptyInput()
25 { 25 {
26 if (o.m->infilename == 0) { 26 if (o.m->infilename == 0) {
27 // Various places in QPDFJob.cc know that the empty string for 27 // Various places in QPDFJob.cc know that the empty string for
28 - // infile means empty. This means that passing "" as the  
29 - // argument to inputFile, or equivalently using "" as a  
30 - // positional command-line argument would be the same as  
31 - // --empty. This probably isn't worth blocking or coding  
32 - // around, but it would be better if we had a tighter way of  
33 - // knowing that the input file is empty. 28 + // infile means empty. We set it to something other than a
  29 + // null pointer as an indication that some input source has
  30 + // been specified. The --create-from-json option also sets
  31 + // infilename to empty. This approach means that passing "" as
  32 + // the argument to inputFile in job JSON, or equivalently
  33 + // using "" as a positional command-line argument would be the
  34 + // same as --empty. This probably isn't worth blocking or
  35 + // coding around.
34 o.m->infilename = QUtil::make_shared_cstr(""); 36 o.m->infilename = QUtil::make_shared_cstr("");
35 } else { 37 } else {
36 usage("empty input can't be used" 38 usage("empty input can't be used"
@@ -294,6 +296,23 @@ QPDFJob::Config::toJson() @@ -294,6 +296,23 @@ QPDFJob::Config::toJson()
294 } 296 }
295 297
296 QPDFJob::Config* 298 QPDFJob::Config*
  299 +QPDFJob::Config::createFromJson(std::string const& parameter)
  300 +{
  301 + // See comments in emptyInput() about setting infilename to the
  302 + // empty string.
  303 + o.m->infilename = QUtil::make_shared_cstr("");
  304 + o.m->create_from_json = parameter;
  305 + return this;
  306 +}
  307 +
  308 +QPDFJob::Config*
  309 +QPDFJob::Config::updateFromJson(std::string const& parameter)
  310 +{
  311 + o.m->update_from_json = parameter;
  312 + return this;
  313 +}
  314 +
  315 +QPDFJob::Config*
297 QPDFJob::Config::testJsonSchema() 316 QPDFJob::Config::testJsonSchema()
298 { 317 {
299 o.m->test_json_schema = true; 318 o.m->test_json_schema = true;
libqpdf/QPDFJob_json.cc
@@ -251,6 +251,12 @@ Handlers::setupEmpty() @@ -251,6 +251,12 @@ Handlers::setupEmpty()
251 } 251 }
252 252
253 void 253 void
  254 +Handlers::setupCreateFromJson()
  255 +{
  256 + addParameter([this](char const* p) { c_main->createFromJson(p); });
  257 +}
  258 +
  259 +void
254 Handlers::setupOutputFile() 260 Handlers::setupOutputFile()
255 { 261 {
256 addParameter([this](char const* p) { c_main->outputFile(p); }); 262 addParameter([this](char const* p) { c_main->outputFile(p); });
libqpdf/QPDF_json.cc 0 โ†’ 100644
  1 +#include <qpdf/QPDF.hh>
  2 +
  3 +#include <qpdf/FileInputSource.hh>
  4 +
  5 +void
  6 +QPDF::createFromJSON(std::string const& json_file)
  7 +{
  8 + createFromJSON(std::make_shared<FileInputSource>(json_file.c_str()));
  9 +}
  10 +
  11 +void
  12 +QPDF::createFromJSON(std::shared_ptr<InputSource>)
  13 +{
  14 + // QXXXQ
  15 +}
  16 +
  17 +void
  18 +QPDF::updateFromJSON(std::string const& json_file)
  19 +{
  20 + updateFromJSON(std::make_shared<FileInputSource>(json_file.c_str()));
  21 +}
  22 +
  23 +void
  24 +QPDF::updateFromJSON(std::shared_ptr<InputSource>)
  25 +{
  26 + // QXXXQ
  27 +}
libqpdf/qpdf/auto_job_decl.hh
@@ -28,6 +28,7 @@ void argOverlay(); @@ -28,6 +28,7 @@ void argOverlay();
28 void argPages(); 28 void argPages();
29 void argReplaceInput(); 29 void argReplaceInput();
30 void argUnderlay(); 30 void argUnderlay();
  31 +void argCreateFromJson(std::string const&);
31 void argPagesPositional(std::string const&); 32 void argPagesPositional(std::string const&);
32 void argPagesPassword(std::string const&); 33 void argPagesPassword(std::string const&);
33 void argEndPages(); 34 void argEndPages();
libqpdf/qpdf/auto_job_help.hh
@@ -836,6 +836,21 @@ name as the prefix for stream data files. Whatever is given here @@ -836,6 +836,21 @@ name as the prefix for stream data files. Whatever is given here
836 will be appended with -nnn to create the name of the file that 836 will be appended with -nnn to create the name of the file that
837 will contain the data for the stream stream in object nnn. 837 will contain the data for the stream stream in object nnn.
838 )"); 838 )");
  839 +ap.addOptionHelp("--create-from-json", "json", "create PDF from qpdf JSON", R"(--create-from-json=qpdf-json-file
  840 +
  841 +Create a PDF file from the prior output of qpdf --json. See the
  842 +"QPDF JSON Format" section of the manual for information about
  843 +how to use this option.
  844 +)");
  845 +ap.addOptionHelp("--update-from-json", "json", "update a PDF from qpdf JSON", R"(--update-from-json=qpdf-json-file
  846 +
  847 +Update a PDF file from a JSON file. Please see the "QPDF JSON
  848 +Format" section of the manual for information about how to use
  849 +this option.
  850 +)");
  851 +}
  852 +static void add_help_8(QPDFArgParser& ap)
  853 +{
839 ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that 854 ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that
840 includes files created by qpdf or when testing qpdf itself. 855 includes files created by qpdf or when testing qpdf itself.
841 )"); 856 )");
@@ -843,9 +858,6 @@ ap.addOptionHelp(&quot;--static-id&quot;, &quot;testing&quot;, &quot;use a fixed document ID&quot;, R&quot;(Use a f @@ -843,9 +858,6 @@ ap.addOptionHelp(&quot;--static-id&quot;, &quot;testing&quot;, &quot;use a fixed document ID&quot;, R&quot;(Use a f
843 testing only. Never use it for production files. See also 858 testing only. Never use it for production files. See also
844 qpdf --help=--deterministic-id. 859 qpdf --help=--deterministic-id.
845 )"); 860 )");
846 -}  
847 -static void add_help_8(QPDFArgParser& ap)  
848 -{  
849 ap.addOptionHelp("--static-aes-iv", "testing", "use a fixed AES vector", R"(Use a static initialization vector for AES-CBC. This is intended 861 ap.addOptionHelp("--static-aes-iv", "testing", "use a fixed AES vector", R"(Use a static initialization vector for AES-CBC. This is intended
850 for testing only so that output files can be reproducible. Never 862 for testing only so that output files can be reproducible. Never
851 use it for production files. This option is not secure since it 863 use it for production files. This option is not secure since it
libqpdf/qpdf/auto_job_init.hh
@@ -104,6 +104,8 @@ this-&gt;ap.addRequiredParameter(&quot;rotate&quot;, [this](std::string const&amp; x){c_main-&gt;rot @@ -104,6 +104,8 @@ this-&gt;ap.addRequiredParameter(&quot;rotate&quot;, [this](std::string const&amp; x){c_main-&gt;rot
104 this->ap.addRequiredParameter("show-attachment", [this](std::string const& x){c_main->showAttachment(x);}, "attachment"); 104 this->ap.addRequiredParameter("show-attachment", [this](std::string const& x){c_main->showAttachment(x);}, "attachment");
105 this->ap.addRequiredParameter("show-object", [this](std::string const& x){c_main->showObject(x);}, "trailer"); 105 this->ap.addRequiredParameter("show-object", [this](std::string const& x){c_main->showObject(x);}, "trailer");
106 this->ap.addRequiredParameter("json-stream-prefix", [this](std::string const& x){c_main->jsonStreamPrefix(x);}, "stream-file-prefix"); 106 this->ap.addRequiredParameter("json-stream-prefix", [this](std::string const& x){c_main->jsonStreamPrefix(x);}, "stream-file-prefix");
  107 +this->ap.addRequiredParameter("create-from-json", p(&ArgParser::argCreateFromJson), "qpdf-json file");
  108 +this->ap.addRequiredParameter("update-from-json", [this](std::string const& x){c_main->updateFromJson(x);}, "qpdf-json file");
107 this->ap.addOptionalParameter("collate", [this](std::string const& x){c_main->collate(x);}); 109 this->ap.addOptionalParameter("collate", [this](std::string const& x){c_main->collate(x);});
108 this->ap.addOptionalParameter("split-pages", [this](std::string const& x){c_main->splitPages(x);}); 110 this->ap.addOptionalParameter("split-pages", [this](std::string const& x){c_main->splitPages(x);});
109 this->ap.addChoices("compress-streams", [this](std::string const& x){c_main->compressStreams(x);}, true, yn_choices); 111 this->ap.addChoices("compress-streams", [this](std::string const& x){c_main->compressStreams(x);}, true, yn_choices);
libqpdf/qpdf/auto_job_json_decl.hh
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 void setupInputFile(); 8 void setupInputFile();
9 void setupPassword(); 9 void setupPassword();
10 void setupEmpty(); 10 void setupEmpty();
  11 +void setupCreateFromJson();
11 void setupOutputFile(); 12 void setupOutputFile();
12 void setupReplaceInput(); 13 void setupReplaceInput();
13 void beginEncrypt(JSON); 14 void beginEncrypt(JSON);
libqpdf/qpdf/auto_job_json_init.hh
@@ -30,6 +30,9 @@ popHandler(); // key: passwordFile @@ -30,6 +30,9 @@ popHandler(); // key: passwordFile
30 pushKey("empty"); 30 pushKey("empty");
31 setupEmpty(); 31 setupEmpty();
32 popHandler(); // key: empty 32 popHandler(); // key: empty
  33 +pushKey("createFromJson");
  34 +setupCreateFromJson();
  35 +popHandler(); // key: createFromJson
33 pushKey("outputFile"); 36 pushKey("outputFile");
34 setupOutputFile(); 37 setupOutputFile();
35 popHandler(); // key: outputFile 38 popHandler(); // key: outputFile
@@ -262,6 +265,9 @@ popHandler(); // key: jsonStreamPrefix @@ -262,6 +265,9 @@ popHandler(); // key: jsonStreamPrefix
262 pushKey("toJson"); 265 pushKey("toJson");
263 addBare([this]() { c_main->toJson(); }); 266 addBare([this]() { c_main->toJson(); });
264 popHandler(); // key: toJson 267 popHandler(); // key: toJson
  268 +pushKey("updateFromJson");
  269 +addParameter([this](std::string const& p) { c_main->updateFromJson(p); });
  270 +popHandler(); // key: updateFromJson
265 pushKey("allowWeakCrypto"); 271 pushKey("allowWeakCrypto");
266 addBare([this]() { c_main->allowWeakCrypto(); }); 272 addBare([this]() { c_main->allowWeakCrypto(); });
267 popHandler(); // key: allowWeakCrypto 273 popHandler(); // key: allowWeakCrypto
libqpdf/qpdf/auto_job_schema.hh
@@ -3,6 +3,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({ @@ -3,6 +3,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({
3 "password": "password for encrypted file", 3 "password": "password for encrypted file",
4 "passwordFile": "read password from a file", 4 "passwordFile": "read password from a file",
5 "empty": "use empty file as input", 5 "empty": "use empty file as input",
  6 + "createFromJson": "create PDF from qpdf JSON",
6 "outputFile": "output filename", 7 "outputFile": "output filename",
7 "replaceInput": "overwrite input with output", 8 "replaceInput": "overwrite input with output",
8 "qdf": "enable viewing PDF code in a text editor", 9 "qdf": "enable viewing PDF code in a text editor",
@@ -87,6 +88,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({ @@ -87,6 +88,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({
87 "jsonStreamData": "how to handle streams in json output", 88 "jsonStreamData": "how to handle streams in json output",
88 "jsonStreamPrefix": "prefix for json stream data files", 89 "jsonStreamPrefix": "prefix for json stream data files",
89 "toJson": "serialize to JSON", 90 "toJson": "serialize to JSON",
  91 + "updateFromJson": "update a PDF from qpdf JSON",
90 "allowWeakCrypto": "allow insecure cryptographic algorithms", 92 "allowWeakCrypto": "allow insecure cryptographic algorithms",
91 "keepFilesOpen": "manage keeping multiple files open", 93 "keepFilesOpen": "manage keeping multiple files open",
92 "keepFilesOpenThreshold": "set threshold for keepFilesOpen", 94 "keepFilesOpenThreshold": "set threshold for keepFilesOpen",
manual/cli.rst
@@ -3270,6 +3270,31 @@ Related Options @@ -3270,6 +3270,31 @@ Related Options
3270 :samp:`-{nnn}` to create the name of the file that will contain the 3270 :samp:`-{nnn}` to create the name of the file that will contain the
3271 data for the stream stream in object :samp:`{nnn}`. 3271 data for the stream stream in object :samp:`{nnn}`.
3272 3272
  3273 +.. qpdf:option:: --create-from-json=qpdf-json-file
  3274 +
  3275 + .. help: create PDF from qpdf JSON
  3276 +
  3277 + Create a PDF file from the prior output of qpdf --json. See the
  3278 + "QPDF JSON Format" section of the manual for information about
  3279 + how to use this option.
  3280 +
  3281 + This option creates a PDF file from the previous output of ``qpdf
  3282 + --json`` that includes stream data and information about all
  3283 + objects. For information about converting between PDF and JSON,
  3284 + please see :ref:`qpdf-json`.
  3285 +
  3286 +.. qpdf:option:: --update-from-json=qpdf-json-file
  3287 +
  3288 + .. help: update a PDF from qpdf JSON
  3289 +
  3290 + Update a PDF file from a JSON file. Please see the "QPDF JSON
  3291 + Format" section of the manual for information about how to use
  3292 + this option.
  3293 +
  3294 + This option updates a PDF file from a qpdf JSON file. For a
  3295 + information about how to use this option, please see
  3296 + :ref:`qpdf-json`.
  3297 +
3273 .. _test-options: 3298 .. _test-options:
3274 3299
3275 Options for Testing or Debugging 3300 Options for Testing or Debugging
manual/json.rst
@@ -18,6 +18,13 @@ files programmatically from the command-line in languages that can&#39;t @@ -18,6 +18,13 @@ files programmatically from the command-line in languages that can&#39;t
18 call or link with the qpdf library directly. Note that stream data can 18 call or link with the qpdf library directly. Note that stream data can
19 be extracted from PDF files using other qpdf command-line options. 19 be extracted from PDF files using other qpdf command-line options.
20 20
  21 +.. _qpdf-json:
  22 +
  23 +QPDF JSON Format
  24 +----------------
  25 +
  26 +QXXXQ Write this.
  27 +
21 .. _json-guarantees: 28 .. _json-guarantees:
22 29
23 JSON Guarantees 30 JSON Guarantees