Commit 4fe2e06b4787ffb639f965ac840b51018308ec07
1 parent
ed613003
Add --create-from-json and --update-from-json arguments
Also add stubs for top-level QPDF methods (createFromJSON, updateFromJSON)
Showing
20 changed files
with
186 additions
and
19 deletions
README-maintainer
| ... | ... | @@ -215,6 +215,14 @@ CODING RULES |
| 215 | 215 | |
| 216 | 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 | 226 | QPDFJob is documented in three places: |
| 219 | 227 | |
| 220 | 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 | 110 | void |
| 111 | 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 | 135 | // Close or otherwise release the input source. Once this has been |
| 114 | 136 | // called, no other methods of qpdf can be called safely except |
| 115 | 137 | // for getWarnings and anyWarnings(). After this has been called, | ... | ... |
include/qpdf/QPDFJob.hh
| ... | ... | @@ -323,6 +323,8 @@ class QPDFJob |
| 323 | 323 | Config* outputFile(std::string const& filename); |
| 324 | 324 | QPDF_DLL |
| 325 | 325 | Config* replaceInput(); |
| 326 | + QPDF_DLL | |
| 327 | + Config* createFromJson(std::string const& filename); | |
| 326 | 328 | |
| 327 | 329 | QPDF_DLL |
| 328 | 330 | std::shared_ptr<CopyAttConfig> copyAttachmentsFrom(); |
| ... | ... | @@ -674,6 +676,8 @@ class QPDFJob |
| 674 | 676 | bool check_requires_password; |
| 675 | 677 | std::shared_ptr<char> infilename; |
| 676 | 678 | std::shared_ptr<char> outfilename; |
| 679 | + std::string create_from_json; | |
| 680 | + std::string update_from_json; | |
| 677 | 681 | }; |
| 678 | 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& parameter); |
| 68 | 68 | QPDF_DLL Config* showAttachment(std::string const& parameter); |
| 69 | 69 | QPDF_DLL Config* showObject(std::string const& parameter); |
| 70 | 70 | QPDF_DLL Config* jsonStreamPrefix(std::string const& parameter); |
| 71 | +QPDF_DLL Config* updateFromJson(std::string const& parameter); | |
| 71 | 72 | QPDF_DLL Config* collate(std::string const& parameter); |
| 72 | 73 | QPDF_DLL Config* collate(); |
| 73 | 74 | QPDF_DLL Config* splitPages(std::string const& parameter); | ... | ... |
job.sums
| ... | ... | @@ -3,15 +3,15 @@ generate_auto_job 0514289f2deb3bf7c1a6e85ef7d99ad120321ef5a6fe49d76c5274c6a658d3 |
| 3 | 3 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 |
| 4 | 4 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
| 5 | 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 | 7 | include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec |
| 8 | 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 | 16 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 |
| 17 | -manual/cli.rst f1bbf59ce4fdb5a6d29fc2470788eee321423dd946984fc2e6f3a904fe5137c1 | |
| 17 | +manual/cli.rst 4550dd1b459721d8ef9affa7c9c07f351a06379498ec1291f702f1a5994b6d84 | ... | ... |
job.yml
| ... | ... | @@ -86,6 +86,7 @@ options: |
| 86 | 86 | - underlay |
| 87 | 87 | - empty |
| 88 | 88 | - replace-input |
| 89 | + - create-from-json | |
| 89 | 90 | positional: true |
| 90 | 91 | bare: |
| 91 | 92 | - add-attachment |
| ... | ... | @@ -163,6 +164,8 @@ options: |
| 163 | 164 | show-attachment: attachment |
| 164 | 165 | show-object: trailer |
| 165 | 166 | json-stream-prefix: stream-file-prefix |
| 167 | + create-from-json: qpdf-json file | |
| 168 | + update-from-json: qpdf-json file | |
| 166 | 169 | required_choices: |
| 167 | 170 | compress-streams: yn |
| 168 | 171 | decode-level: decode_level |
| ... | ... | @@ -278,6 +281,7 @@ json: |
| 278 | 281 | main.password: |
| 279 | 282 | password-file: |
| 280 | 283 | empty: |
| 284 | + create-from-json: | |
| 281 | 285 | # output |
| 282 | 286 | _outputFile: "output filename" |
| 283 | 287 | replace-input: |
| ... | ... | @@ -360,6 +364,7 @@ json: |
| 360 | 364 | json-stream-prefix: |
| 361 | 365 | to-json: |
| 362 | 366 | # other options |
| 367 | + update-from-json: | |
| 363 | 368 | allow-weak-crypto: |
| 364 | 369 | keep-files-open: |
| 365 | 370 | keep-files-open-threshold: | ... | ... |
libqpdf/CMakeLists.txt
libqpdf/QPDFJob.cc
| ... | ... | @@ -553,6 +553,13 @@ QPDFJob::run() |
| 553 | 553 | if (m->check_is_encrypted || m->check_requires_password) { |
| 554 | 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 | 563 | bool other_warnings = false; |
| 557 | 564 | std::vector<std::shared_ptr<QPDF>> page_heap; |
| 558 | 565 | if (!m->page_specs.empty()) { |
| ... | ... | @@ -1937,7 +1944,11 @@ QPDFJob::doProcessOnce( |
| 1937 | 1944 | auto pdf = std::make_shared<QPDF>(); |
| 1938 | 1945 | setQPDFOptions(*pdf); |
| 1939 | 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 | 1952 | } else { |
| 1942 | 1953 | fn(pdf.get(), password); |
| 1943 | 1954 | } | ... | ... |
libqpdf/QPDFJob_argv.cc
| ... | ... | @@ -101,6 +101,13 @@ ArgParser::argReplaceInput() |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 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 | 111 | ArgParser::argVersion() |
| 105 | 112 | { |
| 106 | 113 | auto whoami = this->ap.getProgname(); | ... | ... |
libqpdf/QPDFJob_config.cc
| ... | ... | @@ -25,12 +25,14 @@ QPDFJob::Config::emptyInput() |
| 25 | 25 | { |
| 26 | 26 | if (o.m->infilename == 0) { |
| 27 | 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 | 36 | o.m->infilename = QUtil::make_shared_cstr(""); |
| 35 | 37 | } else { |
| 36 | 38 | usage("empty input can't be used" |
| ... | ... | @@ -294,6 +296,23 @@ QPDFJob::Config::toJson() |
| 294 | 296 | } |
| 295 | 297 | |
| 296 | 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 | 316 | QPDFJob::Config::testJsonSchema() |
| 298 | 317 | { |
| 299 | 318 | o.m->test_json_schema = true; | ... | ... |
libqpdf/QPDFJob_json.cc
| ... | ... | @@ -251,6 +251,12 @@ Handlers::setupEmpty() |
| 251 | 251 | } |
| 252 | 252 | |
| 253 | 253 | void |
| 254 | +Handlers::setupCreateFromJson() | |
| 255 | +{ | |
| 256 | + addParameter([this](char const* p) { c_main->createFromJson(p); }); | |
| 257 | +} | |
| 258 | + | |
| 259 | +void | |
| 254 | 260 | Handlers::setupOutputFile() |
| 255 | 261 | { |
| 256 | 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 | 28 | void argPages(); |
| 29 | 29 | void argReplaceInput(); |
| 30 | 30 | void argUnderlay(); |
| 31 | +void argCreateFromJson(std::string const&); | |
| 31 | 32 | void argPagesPositional(std::string const&); |
| 32 | 33 | void argPagesPassword(std::string const&); |
| 33 | 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 | 836 | will be appended with -nnn to create the name of the file that |
| 837 | 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 | 854 | ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that |
| 840 | 855 | includes files created by qpdf or when testing qpdf itself. |
| 841 | 856 | )"); |
| ... | ... | @@ -843,9 +858,6 @@ ap.addOptionHelp("--static-id", "testing", "use a fixed document ID", R"(Use a f |
| 843 | 858 | testing only. Never use it for production files. See also |
| 844 | 859 | qpdf --help=--deterministic-id. |
| 845 | 860 | )"); |
| 846 | -} | |
| 847 | -static void add_help_8(QPDFArgParser& ap) | |
| 848 | -{ | |
| 849 | 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 | 862 | for testing only so that output files can be reproducible. Never |
| 851 | 863 | use it for production files. This option is not secure since it | ... | ... |
libqpdf/qpdf/auto_job_init.hh
| ... | ... | @@ -104,6 +104,8 @@ this->ap.addRequiredParameter("rotate", [this](std::string const& x){c_main->rot |
| 104 | 104 | this->ap.addRequiredParameter("show-attachment", [this](std::string const& x){c_main->showAttachment(x);}, "attachment"); |
| 105 | 105 | this->ap.addRequiredParameter("show-object", [this](std::string const& x){c_main->showObject(x);}, "trailer"); |
| 106 | 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 | 109 | this->ap.addOptionalParameter("collate", [this](std::string const& x){c_main->collate(x);}); |
| 108 | 110 | this->ap.addOptionalParameter("split-pages", [this](std::string const& x){c_main->splitPages(x);}); |
| 109 | 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
libqpdf/qpdf/auto_job_json_init.hh
| ... | ... | @@ -30,6 +30,9 @@ popHandler(); // key: passwordFile |
| 30 | 30 | pushKey("empty"); |
| 31 | 31 | setupEmpty(); |
| 32 | 32 | popHandler(); // key: empty |
| 33 | +pushKey("createFromJson"); | |
| 34 | +setupCreateFromJson(); | |
| 35 | +popHandler(); // key: createFromJson | |
| 33 | 36 | pushKey("outputFile"); |
| 34 | 37 | setupOutputFile(); |
| 35 | 38 | popHandler(); // key: outputFile |
| ... | ... | @@ -262,6 +265,9 @@ popHandler(); // key: jsonStreamPrefix |
| 262 | 265 | pushKey("toJson"); |
| 263 | 266 | addBare([this]() { c_main->toJson(); }); |
| 264 | 267 | popHandler(); // key: toJson |
| 268 | +pushKey("updateFromJson"); | |
| 269 | +addParameter([this](std::string const& p) { c_main->updateFromJson(p); }); | |
| 270 | +popHandler(); // key: updateFromJson | |
| 265 | 271 | pushKey("allowWeakCrypto"); |
| 266 | 272 | addBare([this]() { c_main->allowWeakCrypto(); }); |
| 267 | 273 | popHandler(); // key: allowWeakCrypto | ... | ... |
libqpdf/qpdf/auto_job_schema.hh
| ... | ... | @@ -3,6 +3,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ |
| 3 | 3 | "password": "password for encrypted file", |
| 4 | 4 | "passwordFile": "read password from a file", |
| 5 | 5 | "empty": "use empty file as input", |
| 6 | + "createFromJson": "create PDF from qpdf JSON", | |
| 6 | 7 | "outputFile": "output filename", |
| 7 | 8 | "replaceInput": "overwrite input with output", |
| 8 | 9 | "qdf": "enable viewing PDF code in a text editor", |
| ... | ... | @@ -87,6 +88,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ |
| 87 | 88 | "jsonStreamData": "how to handle streams in json output", |
| 88 | 89 | "jsonStreamPrefix": "prefix for json stream data files", |
| 89 | 90 | "toJson": "serialize to JSON", |
| 91 | + "updateFromJson": "update a PDF from qpdf JSON", | |
| 90 | 92 | "allowWeakCrypto": "allow insecure cryptographic algorithms", |
| 91 | 93 | "keepFilesOpen": "manage keeping multiple files open", |
| 92 | 94 | "keepFilesOpenThreshold": "set threshold for keepFilesOpen", | ... | ... |
manual/cli.rst
| ... | ... | @@ -3270,6 +3270,31 @@ Related Options |
| 3270 | 3270 | :samp:`-{nnn}` to create the name of the file that will contain the |
| 3271 | 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 | 3298 | .. _test-options: |
| 3274 | 3299 | |
| 3275 | 3300 | Options for Testing or Debugging | ... | ... |
manual/json.rst
| ... | ... | @@ -18,6 +18,13 @@ files programmatically from the command-line in languages that can't |
| 18 | 18 | call or link with the qpdf library directly. Note that stream data can |
| 19 | 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 | 28 | .. _json-guarantees: |
| 22 | 29 | |
| 23 | 30 | JSON Guarantees | ... | ... |