Commit 34f013c1be56abac1104812938eb0af568df99e1
1 parent
20a13482
Allow --file and --range with --pages
Accept --file and --range as named parameters in additional to allowing positional arguments. This is in preparation for adding additional flags.
Showing
20 changed files
with
259 additions
and
148 deletions
examples/qpdf-job.cc
| @@ -40,7 +40,9 @@ main(int argc, char* argv[]) | @@ -40,7 +40,9 @@ main(int argc, char* argv[]) | ||
| 40 | ->inputFile("in.pdf") | 40 | ->inputFile("in.pdf") |
| 41 | ->outputFile("out1.pdf") | 41 | ->outputFile("out1.pdf") |
| 42 | ->pages() | 42 | ->pages() |
| 43 | - ->pageSpec(".", "1") | 43 | + // Prior to qpdf 11.9.0, call ->pageSpec(file, range, password) |
| 44 | + ->file(".") | ||
| 45 | + ->range("1") | ||
| 44 | ->endPages() | 46 | ->endPages() |
| 45 | ->linearize() | 47 | ->linearize() |
| 46 | ->staticId() // for testing only | 48 | ->staticId() // for testing only |
include/qpdf/QPDFJob.hh
| @@ -243,6 +243,8 @@ class QPDFJob | @@ -243,6 +243,8 @@ class QPDFJob | ||
| 243 | public: | 243 | public: |
| 244 | QPDF_DLL | 244 | QPDF_DLL |
| 245 | Config* endPages(); | 245 | Config* endPages(); |
| 246 | + // From qpdf 11.9.0, you can call file(), range(), and password(). Each call to file() | ||
| 247 | + // starts a new page spec. | ||
| 246 | QPDF_DLL | 248 | QPDF_DLL |
| 247 | PagesConfig* pageSpec( | 249 | PagesConfig* pageSpec( |
| 248 | std::string const& filename, std::string const& range, char const* password = nullptr); | 250 | std::string const& filename, std::string const& range, char const* password = nullptr); |
include/qpdf/auto_job_c_pages.hh
job.sums
| @@ -5,16 +5,16 @@ include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf2 | @@ -5,16 +5,16 @@ include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf2 | ||
| 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 | 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
| 6 | include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 | 6 | include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 |
| 7 | include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6 | 7 | include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6 |
| 8 | -include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec | 8 | +include/qpdf/auto_job_c_pages.hh 09ca15649cc94fdaf6d9bdae28a20723f2a66616bf15aa86d83df31051d82506 |
| 9 | include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 | 9 | include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 |
| 10 | -job.yml 8ad309ac41520b34692bcf22fd5c2ef4810ff69562aed606bd57df7bf589bc43 | ||
| 11 | -libqpdf/qpdf/auto_job_decl.hh 1e8d73891bd1f0b5df5a5ca7405fb76d2d0fd024941b8c1b86489f1b5f9c5772 | ||
| 12 | -libqpdf/qpdf/auto_job_help.hh 8c172913920a5273e04dc4d2059f2d78fc475960ac1738271357056beb02dd27 | ||
| 13 | -libqpdf/qpdf/auto_job_init.hh ea272fd6a6a5e4d23cabd70a7b7d5ecc543b6304008c656dcba2d353d378efc2 | ||
| 14 | -libqpdf/qpdf/auto_job_json_decl.hh 10ffb0d0e5ca09809a5d5d78f66dee393dfd2653a23441436465fd5ace151880 | ||
| 15 | -libqpdf/qpdf/auto_job_json_init.hh 9c3839877ab3b15a47e92086f0b5616da33fd4970538cc423d3b0a7ff33ce66a | ||
| 16 | -libqpdf/qpdf/auto_job_schema.hh a882939b202d48ad1c0751c094f671ad7aad0fc04c3a4446ad83675db365c8a2 | 10 | +job.yml 45761edeca048c7aa3e99340fcda1b6cd8efe4cc4c8b8a6628580243a4f49b57 |
| 11 | +libqpdf/qpdf/auto_job_decl.hh 20d6affe1e260f5a1af4f1d82a820b933835440ff03020e877382da2e8dac6c6 | ||
| 12 | +libqpdf/qpdf/auto_job_help.hh b19f8a7433c70df70b42f893a8964c801aa2bb78eecaa13cffab7add2ff81e0a | ||
| 13 | +libqpdf/qpdf/auto_job_init.hh d74759d4999201a89dafddf6f0c855e9151bbf77ea91a92d6806510292950123 | ||
| 14 | +libqpdf/qpdf/auto_job_json_decl.hh 485540cde820987cfbed0aa7642a6416f2bd37164c8d4f2322f1381e73edf903 | ||
| 15 | +libqpdf/qpdf/auto_job_json_init.hh c8de8658daa82115b49bf084cebe1be0b8aea73f864a219d7349acc0982b56fe | ||
| 16 | +libqpdf/qpdf/auto_job_schema.hh 3e000b87255bee62ba29b794d67b2ae97cbbdfdb78be3878c51786913564901e | ||
| 17 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 | 17 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 |
| 18 | -manual/cli.rst 43923fab0def5f76e537f03ba2f650270a1ae858a15747e355db2a6ea396f1a0 | ||
| 19 | -manual/qpdf.1 cd335812d450ca83be3c7fe165299d3454b26b4999295f671d57e6b24f6ea7a1 | 18 | +manual/cli.rst 408e17dc13d37befe34badc400dd34d3c283952d17ee3bf9a9d44898af3dabc7 |
| 19 | +manual/qpdf.1 c99d66833aee7a2294176875ca2e9ddf2531d4ab8fb282ea5c45cb82a5d028ea | ||
| 20 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b | 20 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b |
job.yml
| @@ -195,9 +195,9 @@ options: | @@ -195,9 +195,9 @@ options: | ||
| 195 | config: c_pages | 195 | config: c_pages |
| 196 | prefix: Pages | 196 | prefix: Pages |
| 197 | positional: true | 197 | positional: true |
| 198 | - manual: | ||
| 199 | - - password | ||
| 200 | required_parameter: | 198 | required_parameter: |
| 199 | + file: file | ||
| 200 | + range: page-range | ||
| 201 | password: password | 201 | password: password |
| 202 | - table: encryption | 202 | - table: encryption |
| 203 | config: c_main | 203 | config: c_main |
| @@ -436,9 +436,9 @@ json: | @@ -436,9 +436,9 @@ json: | ||
| 436 | oi-min-width: | 436 | oi-min-width: |
| 437 | optimize-images: | 437 | optimize-images: |
| 438 | pages: | 438 | pages: |
| 439 | - - _file: "source for for pages" | 439 | + - file: |
| 440 | Pages.password: | 440 | Pages.password: |
| 441 | - _range: "page range" | 441 | + range: |
| 442 | remove-page-labels: | 442 | remove-page-labels: |
| 443 | report-memory-usage: | 443 | report-memory-usage: |
| 444 | rotate: | 444 | rotate: |
libqpdf/QPDFJob.cc
| @@ -2342,6 +2342,9 @@ QPDFJob::handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_hea | @@ -2342,6 +2342,9 @@ QPDFJob::handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_hea | ||
| 2342 | if (page_spec.filename == ".") { | 2342 | if (page_spec.filename == ".") { |
| 2343 | page_spec.filename = m->infilename.get(); | 2343 | page_spec.filename = m->infilename.get(); |
| 2344 | } | 2344 | } |
| 2345 | + if (page_spec.range.empty()) { | ||
| 2346 | + page_spec.range = "1-z"; | ||
| 2347 | + } | ||
| 2345 | } | 2348 | } |
| 2346 | 2349 | ||
| 2347 | if (!m->keep_files_open_set) { | 2350 | if (!m->keep_files_open_set) { |
libqpdf/QPDFJob_argv.cc
| @@ -34,9 +34,10 @@ namespace | @@ -34,9 +34,10 @@ namespace | ||
| 34 | std::shared_ptr<QPDFJob::UOConfig> c_uo; | 34 | std::shared_ptr<QPDFJob::UOConfig> c_uo; |
| 35 | std::shared_ptr<QPDFJob::EncConfig> c_enc; | 35 | std::shared_ptr<QPDFJob::EncConfig> c_enc; |
| 36 | std::vector<std::string> accumulated_args; | 36 | std::vector<std::string> accumulated_args; |
| 37 | - std::shared_ptr<char> pages_password{nullptr}; | ||
| 38 | std::string user_password; | 37 | std::string user_password; |
| 39 | std::string owner_password; | 38 | std::string owner_password; |
| 39 | + bool called_pages_file{false}; | ||
| 40 | + bool called_pages_range{false}; | ||
| 40 | bool used_enc_password_args{false}; | 41 | bool used_enc_password_args{false}; |
| 41 | bool gave_input{false}; | 42 | bool gave_input{false}; |
| 42 | bool gave_output{false}; | 43 | bool gave_output{false}; |
| @@ -237,81 +238,43 @@ ArgParser::argPages() | @@ -237,81 +238,43 @@ ArgParser::argPages() | ||
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | void | 240 | void |
| 240 | -ArgParser::argPagesPassword(std::string const& parameter) | ||
| 241 | -{ | ||
| 242 | - if (this->pages_password) { | ||
| 243 | - QTC::TC("qpdf", "QPDFJob duplicated pages password"); | ||
| 244 | - usage("--password already specified for this file"); | ||
| 245 | - } | ||
| 246 | - if (this->accumulated_args.size() != 1) { | ||
| 247 | - QTC::TC("qpdf", "QPDFJob misplaced pages password"); | ||
| 248 | - usage("in --pages, --password must immediately follow a file name"); | ||
| 249 | - } | ||
| 250 | - this->pages_password = QUtil::make_shared_cstr(parameter); | ||
| 251 | -} | ||
| 252 | - | ||
| 253 | -void | ||
| 254 | ArgParser::argPagesPositional(std::string const& arg) | 241 | ArgParser::argPagesPositional(std::string const& arg) |
| 255 | { | 242 | { |
| 256 | - if (arg.empty()) { | ||
| 257 | - if (this->accumulated_args.empty()) { | ||
| 258 | - return; | ||
| 259 | - } | ||
| 260 | - } else { | ||
| 261 | - this->accumulated_args.push_back(arg); | 243 | + if (!called_pages_file) { |
| 244 | + c_pages->file(arg); | ||
| 245 | + called_pages_file = true; | ||
| 246 | + return; | ||
| 262 | } | 247 | } |
| 263 | - | ||
| 264 | - std::string file = this->accumulated_args.at(0); | ||
| 265 | - char const* range_p = nullptr; | ||
| 266 | - | ||
| 267 | - size_t n_args = this->accumulated_args.size(); | ||
| 268 | - if (n_args >= 2) { | ||
| 269 | - // will be copied before accumulated_args is cleared | ||
| 270 | - range_p = this->accumulated_args.at(1).c_str(); | 248 | + if (called_pages_range) { |
| 249 | + c_pages->file(arg); | ||
| 250 | + called_pages_range = false; | ||
| 251 | + return; | ||
| 271 | } | 252 | } |
| 272 | - | ||
| 273 | - // See if the user omitted the range entirely, in which case we assume "1-z". | ||
| 274 | - std::string next_file; | ||
| 275 | - if (range_p == nullptr) { | ||
| 276 | - if (arg.empty()) { | ||
| 277 | - // The filename or password was the last argument | ||
| 278 | - QTC::TC("qpdf", "QPDFJob pages range omitted at end", this->pages_password ? 0 : 1); | 253 | + // This could be a range or a file. Try parsing. |
| 254 | + try { | ||
| 255 | + QUtil::parse_numrange(arg.c_str(), 0); | ||
| 256 | + c_pages->range(arg); | ||
| 257 | + called_pages_range = true; | ||
| 258 | + } catch (std::runtime_error& e1) { | ||
| 259 | + // The range is invalid. Let's see if it's a file. | ||
| 260 | + if (arg == ".") { | ||
| 261 | + // "." means the input file. | ||
| 262 | + QTC::TC("qpdf", "QPDFJob pages range omitted with ."); | ||
| 263 | + } else if (QUtil::file_can_be_opened(arg.c_str())) { | ||
| 264 | + QTC::TC("qpdf", "QPDFJob pages range omitted in middle"); | ||
| 265 | + // Yup, it's a file. | ||
| 279 | } else { | 266 | } else { |
| 280 | - // We need to accumulate some more arguments | ||
| 281 | - return; | 267 | + // Give the range error |
| 268 | + usage(e1.what()); | ||
| 282 | } | 269 | } |
| 283 | - } else { | ||
| 284 | - try { | ||
| 285 | - QUtil::parse_numrange(range_p, 0); | ||
| 286 | - } catch (std::runtime_error& e1) { | ||
| 287 | - // The range is invalid. Let's see if it's a file. | ||
| 288 | - if (strcmp(range_p, ".") == 0) { | ||
| 289 | - // "." means the input file. | ||
| 290 | - QTC::TC("qpdf", "QPDFJob pages range omitted with ."); | ||
| 291 | - } else if (QUtil::file_can_be_opened(range_p)) { | ||
| 292 | - QTC::TC("qpdf", "QPDFJob pages range omitted in middle"); | ||
| 293 | - // Yup, it's a file. | ||
| 294 | - } else { | ||
| 295 | - // Give the range error | ||
| 296 | - usage(e1.what()); | ||
| 297 | - } | ||
| 298 | - next_file = range_p; | ||
| 299 | - range_p = nullptr; | ||
| 300 | - } | ||
| 301 | - } | ||
| 302 | - std::string range(range_p ? range_p : "1-z"); | ||
| 303 | - this->c_pages->pageSpec(file, range, this->pages_password.get()); | ||
| 304 | - this->accumulated_args.clear(); | ||
| 305 | - this->pages_password = nullptr; | ||
| 306 | - if (!next_file.empty()) { | ||
| 307 | - this->accumulated_args.push_back(next_file); | 270 | + c_pages->file(arg); |
| 271 | + called_pages_range = false; | ||
| 308 | } | 272 | } |
| 309 | } | 273 | } |
| 310 | 274 | ||
| 311 | void | 275 | void |
| 312 | ArgParser::argEndPages() | 276 | ArgParser::argEndPages() |
| 313 | { | 277 | { |
| 314 | - argPagesPositional(""); | ||
| 315 | c_pages->endPages(); | 278 | c_pages->endPages(); |
| 316 | c_pages = nullptr; | 279 | c_pages = nullptr; |
| 317 | } | 280 | } |
libqpdf/QPDFJob_config.cc
| @@ -968,6 +968,45 @@ QPDFJob::PagesConfig::pageSpec( | @@ -968,6 +968,45 @@ QPDFJob::PagesConfig::pageSpec( | ||
| 968 | return this; | 968 | return this; |
| 969 | } | 969 | } |
| 970 | 970 | ||
| 971 | +QPDFJob::PagesConfig* | ||
| 972 | +QPDFJob::PagesConfig::file(std::string const& arg) | ||
| 973 | +{ | ||
| 974 | + this->config->o.m->page_specs.emplace_back(arg, nullptr, ""); | ||
| 975 | + return this; | ||
| 976 | +} | ||
| 977 | + | ||
| 978 | +QPDFJob::PagesConfig* | ||
| 979 | +QPDFJob::PagesConfig::range(std::string const& arg) | ||
| 980 | +{ | ||
| 981 | + if (config->o.m->page_specs.empty()) { | ||
| 982 | + QTC::TC("qpdf", "QPDFJob misplaced page range"); | ||
| 983 | + usage("in --range must follow a file name"); | ||
| 984 | + } | ||
| 985 | + auto& last = config->o.m->page_specs.back(); | ||
| 986 | + if (!last.range.empty()) { | ||
| 987 | + QTC::TC("qpdf", "QPDFJob duplicated range"); | ||
| 988 | + usage("--range already specified for this file"); | ||
| 989 | + } | ||
| 990 | + last.range = arg; | ||
| 991 | + return this; | ||
| 992 | +} | ||
| 993 | + | ||
| 994 | +QPDFJob::PagesConfig* | ||
| 995 | +QPDFJob::PagesConfig::password(std::string const& arg) | ||
| 996 | +{ | ||
| 997 | + if (config->o.m->page_specs.empty()) { | ||
| 998 | + QTC::TC("qpdf", "QPDFJob misplaced pages password"); | ||
| 999 | + usage("in --pages, --password must follow a file name"); | ||
| 1000 | + } | ||
| 1001 | + auto& last = config->o.m->page_specs.back(); | ||
| 1002 | + if (last.password) { | ||
| 1003 | + QTC::TC("qpdf", "QPDFJob duplicated pages password"); | ||
| 1004 | + usage("--password already specified for this file"); | ||
| 1005 | + } | ||
| 1006 | + last.password = QUtil::make_shared_cstr(arg); | ||
| 1007 | + return this; | ||
| 1008 | +} | ||
| 1009 | + | ||
| 971 | std::shared_ptr<QPDFJob::UOConfig> | 1010 | std::shared_ptr<QPDFJob::UOConfig> |
| 972 | QPDFJob::Config::overlay() | 1011 | QPDFJob::Config::overlay() |
| 973 | { | 1012 | { |
libqpdf/QPDFJob_json.cc
| @@ -467,25 +467,17 @@ Handlers::endPagesArray() | @@ -467,25 +467,17 @@ Handlers::endPagesArray() | ||
| 467 | void | 467 | void |
| 468 | Handlers::beginPages(JSON j) | 468 | Handlers::beginPages(JSON j) |
| 469 | { | 469 | { |
| 470 | - std::string file; | ||
| 471 | - std::string range("1-z"); | ||
| 472 | - std::string password; | ||
| 473 | bool file_seen = false; | 470 | bool file_seen = false; |
| 474 | - bool password_seen = false; | ||
| 475 | - j.forEachDictItem([&](std::string const& key, JSON value) { | 471 | + j.forEachDictItem([&](std::string const& key, JSON const& value) { |
| 476 | if (key == "file") { | 472 | if (key == "file") { |
| 477 | - file_seen = value.getString(file); | ||
| 478 | - } else if (key == "range") { | ||
| 479 | - value.getString(range); | ||
| 480 | - } else if (key == "password") { | ||
| 481 | - password_seen = value.getString(password); | 473 | + std::string v; |
| 474 | + file_seen = value.getString(v); | ||
| 482 | } | 475 | } |
| 483 | }); | 476 | }); |
| 484 | if (!file_seen) { | 477 | if (!file_seen) { |
| 485 | QTC::TC("qpdf", "QPDFJob json pages no file"); | 478 | QTC::TC("qpdf", "QPDFJob json pages no file"); |
| 486 | usage("file is required in page specification"); | 479 | usage("file is required in page specification"); |
| 487 | } | 480 | } |
| 488 | - this->c_pages->pageSpec(file, range, password_seen ? password.c_str() : nullptr); | ||
| 489 | } | 481 | } |
| 490 | 482 | ||
| 491 | void | 483 | void |
| @@ -495,24 +487,9 @@ Handlers::endPages() | @@ -495,24 +487,9 @@ Handlers::endPages() | ||
| 495 | } | 487 | } |
| 496 | 488 | ||
| 497 | void | 489 | void |
| 498 | -Handlers::setupPagesFile() | ||
| 499 | -{ | ||
| 500 | - // handled in beginPages | ||
| 501 | - ignoreItem(); | ||
| 502 | -} | ||
| 503 | - | ||
| 504 | -void | ||
| 505 | Handlers::setupPagesPassword() | 490 | Handlers::setupPagesPassword() |
| 506 | { | 491 | { |
| 507 | - // handled in beginPages | ||
| 508 | - ignoreItem(); | ||
| 509 | -} | ||
| 510 | - | ||
| 511 | -void | ||
| 512 | -Handlers::setupPagesRange() | ||
| 513 | -{ | ||
| 514 | - // handled in beginPages | ||
| 515 | - ignoreItem(); | 492 | + addParameter([this](char const* p) { c_pages->password(p); }); |
| 516 | } | 493 | } |
| 517 | 494 | ||
| 518 | void | 495 | void |
libqpdf/qpdf/auto_job_decl.hh
| @@ -31,7 +31,6 @@ void argReplaceInput(); | @@ -31,7 +31,6 @@ void argReplaceInput(); | ||
| 31 | void argSetPageLabels(); | 31 | void argSetPageLabels(); |
| 32 | void argUnderlay(); | 32 | void argUnderlay(); |
| 33 | void argPagesPositional(std::string const&); | 33 | void argPagesPositional(std::string const&); |
| 34 | -void argPagesPassword(std::string const&); | ||
| 35 | void argEndPages(); | 34 | void argEndPages(); |
| 36 | void argEncPositional(std::string const&); | 35 | void argEncPositional(std::string const&); |
| 37 | void argEncUserPassword(std::string const&); | 36 | void argEncUserPassword(std::string const&); |
libqpdf/qpdf/auto_job_help.hh
| @@ -311,10 +311,24 @@ static void add_help_4(QPDFArgParser& ap) | @@ -311,10 +311,24 @@ static void add_help_4(QPDFArgParser& ap) | ||
| 311 | ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of | 311 | ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of |
| 312 | the PDF, causing the PDF to render differently from the original. | 312 | the PDF, causing the PDF to render differently from the original. |
| 313 | )"); | 313 | )"); |
| 314 | -ap.addOptionHelp("--pages", "modification", "begin page selection", R"(--pages file [--password=password] [page-range] [...] -- | 314 | +ap.addOptionHelp("--pages", "modification", "begin page selection", R"(--pages [--file=]file [options] [...] -- |
| 315 | 315 | ||
| 316 | Run qpdf --help=page-selection for details. | 316 | Run qpdf --help=page-selection for details. |
| 317 | )"); | 317 | )"); |
| 318 | +ap.addOptionHelp("--file", "modification", "source for pages", R"(--file=file | ||
| 319 | + | ||
| 320 | +Specify the file for the current page operation. This is used | ||
| 321 | +with --pages, --overlay, and --underlay and appears between the | ||
| 322 | +option and the terminating --. Run qpdf --help=page-selection | ||
| 323 | +for details. | ||
| 324 | +)"); | ||
| 325 | +ap.addOptionHelp("--range", "modification", "page range", R"(--range=numeric-range | ||
| 326 | + | ||
| 327 | +Specify the page range for the current page operation with | ||
| 328 | +--pages. If omitted, all pages are selected. This is used | ||
| 329 | +with --pages and appears between --pages and --. Run | ||
| 330 | +qpdf --help=page-selection for details. | ||
| 331 | +)"); | ||
| 318 | ap.addOptionHelp("--collate", "modification", "collate with --pages", R"(--collate[=n[,m,...]] | 332 | ap.addOptionHelp("--collate", "modification", "collate with --pages", R"(--collate[=n[,m,...]] |
| 319 | 333 | ||
| 320 | Collate rather than concatenate pages specified with --pages. | 334 | Collate rather than concatenate pages specified with --pages. |
| @@ -437,6 +451,9 @@ iv, then the remaining pages with Arabic numerals starting with | @@ -437,6 +451,9 @@ iv, then the remaining pages with Arabic numerals starting with | ||
| 437 | 1 and continuing sequentially until the end of the document. For | 451 | 1 and continuing sequentially until the end of the document. For |
| 438 | additional examples, please consult the manual. | 452 | additional examples, please consult the manual. |
| 439 | )"); | 453 | )"); |
| 454 | +} | ||
| 455 | +static void add_help_5(QPDFArgParser& ap) | ||
| 456 | +{ | ||
| 440 | ap.addHelpTopic("encryption", "create encrypted files", R"(Create encrypted files. Usage: | 457 | ap.addHelpTopic("encryption", "create encrypted files", R"(Create encrypted files. Usage: |
| 441 | 458 | ||
| 442 | --encrypt \ | 459 | --encrypt \ |
| @@ -520,9 +537,6 @@ ap.addOptionHelp("--user-password", "encryption", "specify user password", R"(-- | @@ -520,9 +537,6 @@ ap.addOptionHelp("--user-password", "encryption", "specify user password", R"(-- | ||
| 520 | 537 | ||
| 521 | Set the user password of the encrypted file. | 538 | Set the user password of the encrypted file. |
| 522 | )"); | 539 | )"); |
| 523 | -} | ||
| 524 | -static void add_help_5(QPDFArgParser& ap) | ||
| 525 | -{ | ||
| 526 | ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password | 540 | ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password |
| 527 | 541 | ||
| 528 | Set the owner password of the encrypted file. | 542 | Set the owner password of the encrypted file. |
| @@ -620,12 +634,24 @@ should not be used except for compatibility testing. | @@ -620,12 +634,24 @@ should not be used except for compatibility testing. | ||
| 620 | )"); | 634 | )"); |
| 621 | ap.addHelpTopic("page-selection", "select pages from one or more files", R"(Use the --pages option to select pages from multiple files. Usage: | 635 | ap.addHelpTopic("page-selection", "select pages from one or more files", R"(Use the --pages option to select pages from multiple files. Usage: |
| 622 | 636 | ||
| 637 | +qpdf in.pdf --pages --file=input-file \ | ||
| 638 | + [--range=page-range] [--password=password] [...] -- out.pdf | ||
| 639 | + | ||
| 640 | +OR | ||
| 641 | + | ||
| 623 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ | 642 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ |
| 624 | [...] -- out.pdf | 643 | [...] -- out.pdf |
| 625 | 644 | ||
| 626 | Between --pages and the -- that terminates pages option, repeat | 645 | Between --pages and the -- that terminates pages option, repeat |
| 627 | the following: | 646 | the following: |
| 628 | 647 | ||
| 648 | +--file=filename [--range=page-range] [--password=password] [options] | ||
| 649 | + | ||
| 650 | +For compatibility, the file and range can be specified | ||
| 651 | +positionally. qpdf versions prior to 11.9.0 | ||
| 652 | +require --password=password to immediately follow the filename. In | ||
| 653 | +the older syntax, repeat the following: | ||
| 654 | + | ||
| 629 | filename [--password=password] [page-range] | 655 | filename [--password=password] [page-range] |
| 630 | 656 | ||
| 631 | Document-level information, such as outlines, tags, etc., is taken | 657 | Document-level information, such as outlines, tags, etc., is taken |
| @@ -654,7 +680,7 @@ Examples: | @@ -654,7 +680,7 @@ Examples: | ||
| 654 | information from in.pdf is retained. Note the use of "." to refer | 680 | information from in.pdf is retained. Note the use of "." to refer |
| 655 | to in.pdf. | 681 | to in.pdf. |
| 656 | 682 | ||
| 657 | - qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf | 683 | + qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf |
| 658 | 684 | ||
| 659 | - Take all the pages from a.pdf, all the pages from b.pdf in | 685 | - Take all the pages from a.pdf, all the pages from b.pdf in |
| 660 | reverse, and only pages 3 and 6 from c.pdf and write the result | 686 | reverse, and only pages 3 and 6 from c.pdf and write the result |
| @@ -687,6 +713,9 @@ those pages to be repeated after the original pages are exhausted. | @@ -687,6 +713,9 @@ those pages to be repeated after the original pages are exhausted. | ||
| 687 | 713 | ||
| 688 | Run qpdf --help=page-ranges for help with page ranges. | 714 | Run qpdf --help=page-ranges for help with page ranges. |
| 689 | )"); | 715 | )"); |
| 716 | +} | ||
| 717 | +static void add_help_6(QPDFArgParser& ap) | ||
| 718 | +{ | ||
| 690 | ap.addOptionHelp("--to", "overlay-underlay", "destination pages for underlay/overlay", R"(--to=page-range | 719 | ap.addOptionHelp("--to", "overlay-underlay", "destination pages for underlay/overlay", R"(--to=page-range |
| 691 | 720 | ||
| 692 | Specify the range of pages in the primary output to apply | 721 | Specify the range of pages in the primary output to apply |
| @@ -700,9 +729,6 @@ the destination pages. See qpdf --help=page-ranges for help | @@ -700,9 +729,6 @@ the destination pages. See qpdf --help=page-ranges for help | ||
| 700 | with the page range syntax. The page range may be omitted | 729 | with the page range syntax. The page range may be omitted |
| 701 | if --repeat is used. | 730 | if --repeat is used. |
| 702 | )"); | 731 | )"); |
| 703 | -} | ||
| 704 | -static void add_help_6(QPDFArgParser& ap) | ||
| 705 | -{ | ||
| 706 | ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range | 732 | ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range |
| 707 | 733 | ||
| 708 | Specify pages from the overlay/underlay that are repeated after | 734 | Specify pages from the overlay/underlay that are repeated after |
| @@ -801,6 +827,9 @@ ap.addHelpTopic("inspection", "inspect PDF files", R"(These options provide tool | @@ -801,6 +827,9 @@ ap.addHelpTopic("inspection", "inspect PDF files", R"(These options provide tool | ||
| 801 | the options in this section are specified, no output file may be | 827 | the options in this section are specified, no output file may be |
| 802 | given. | 828 | given. |
| 803 | )"); | 829 | )"); |
| 830 | +} | ||
| 831 | +static void add_help_7(QPDFArgParser& ap) | ||
| 832 | +{ | ||
| 804 | ap.addOptionHelp("--is-encrypted", "inspection", "silently test whether a file is encrypted", R"(Silently exit with a code indicating the file's encryption status: | 833 | ap.addOptionHelp("--is-encrypted", "inspection", "silently test whether a file is encrypted", R"(Silently exit with a code indicating the file's encryption status: |
| 805 | 834 | ||
| 806 | 0: the file is encrypted | 835 | 0: the file is encrypted |
| @@ -817,9 +846,6 @@ ap.addOptionHelp("--requires-password", "inspection", "silently test a file's pa | @@ -817,9 +846,6 @@ ap.addOptionHelp("--requires-password", "inspection", "silently test a file's pa | ||
| 817 | 2: the file is not encrypted | 846 | 2: the file is not encrypted |
| 818 | 3: the file is encrypted, and correct password (if any) has been supplied | 847 | 3: the file is encrypted, and correct password (if any) has been supplied |
| 819 | )"); | 848 | )"); |
| 820 | -} | ||
| 821 | -static void add_help_7(QPDFArgParser& ap) | ||
| 822 | -{ | ||
| 823 | ap.addOptionHelp("--check", "inspection", "partially check whether PDF is valid", R"(Check the structure of the PDF file as well as a number of other | 849 | ap.addOptionHelp("--check", "inspection", "partially check whether PDF is valid", R"(Check the structure of the PDF file as well as a number of other |
| 824 | aspects of the file, and write information about the file to | 850 | aspects of the file, and write information about the file to |
| 825 | standard output. Note that qpdf does not perform any validation | 851 | standard output. Note that qpdf does not perform any validation |
| @@ -894,6 +920,9 @@ Describe the format of the JSON output by writing to standard | @@ -894,6 +920,9 @@ Describe the format of the JSON output by writing to standard | ||
| 894 | output a JSON object with the same keys and with values | 920 | output a JSON object with the same keys and with values |
| 895 | containing descriptive text. | 921 | containing descriptive text. |
| 896 | )"); | 922 | )"); |
| 923 | +} | ||
| 924 | +static void add_help_8(QPDFArgParser& ap) | ||
| 925 | +{ | ||
| 897 | ap.addOptionHelp("--json-key", "json", "limit which keys are in JSON output", R"(--json-key=key | 926 | ap.addOptionHelp("--json-key", "json", "limit which keys are in JSON output", R"(--json-key=key |
| 898 | 927 | ||
| 899 | This option is repeatable. If given, only the specified | 928 | This option is repeatable. If given, only the specified |
| @@ -907,9 +936,6 @@ This option is repeatable. If given, only specified objects will | @@ -907,9 +936,6 @@ This option is repeatable. If given, only specified objects will | ||
| 907 | be shown in the "objects" key of the JSON output. Otherwise, all | 936 | be shown in the "objects" key of the JSON output. Otherwise, all |
| 908 | objects will be shown. | 937 | objects will be shown. |
| 909 | )"); | 938 | )"); |
| 910 | -} | ||
| 911 | -static void add_help_8(QPDFArgParser& ap) | ||
| 912 | -{ | ||
| 913 | ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file} | 939 | ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file} |
| 914 | 940 | ||
| 915 | When used with --json, this option controls whether streams in | 941 | When used with --json, this option controls whether streams in |
libqpdf/qpdf/auto_job_init.hh
| @@ -127,7 +127,9 @@ this->ap.addChoices("json", [this](std::string const& x){c_main->json(x);}, fals | @@ -127,7 +127,9 @@ this->ap.addChoices("json", [this](std::string const& x){c_main->json(x);}, fals | ||
| 127 | this->ap.addChoices("json-output", [this](std::string const& x){c_main->jsonOutput(x);}, false, json_output_choices); | 127 | this->ap.addChoices("json-output", [this](std::string const& x){c_main->jsonOutput(x);}, false, json_output_choices); |
| 128 | this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages)); | 128 | this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages)); |
| 129 | this->ap.addPositional(p(&ArgParser::argPagesPositional)); | 129 | this->ap.addPositional(p(&ArgParser::argPagesPositional)); |
| 130 | -this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password"); | 130 | +this->ap.addRequiredParameter("file", [this](std::string const& x){c_pages->file(x);}, "file"); |
| 131 | +this->ap.addRequiredParameter("range", [this](std::string const& x){c_pages->range(x);}, "page-range"); | ||
| 132 | +this->ap.addRequiredParameter("password", [this](std::string const& x){c_pages->password(x);}, "password"); | ||
| 131 | this->ap.registerOptionTable("encryption", b(&ArgParser::argEndEncryption)); | 133 | this->ap.registerOptionTable("encryption", b(&ArgParser::argEndEncryption)); |
| 132 | this->ap.addPositional(p(&ArgParser::argEncPositional)); | 134 | this->ap.addPositional(p(&ArgParser::argEncPositional)); |
| 133 | this->ap.addRequiredParameter("user-password", p(&ArgParser::argEncUserPassword), "user_password"); | 135 | this->ap.addRequiredParameter("user-password", p(&ArgParser::argEncUserPassword), "user_password"); |
libqpdf/qpdf/auto_job_json_decl.hh
| @@ -41,9 +41,7 @@ void beginPagesArray(JSON); | @@ -41,9 +41,7 @@ void beginPagesArray(JSON); | ||
| 41 | void endPagesArray(); | 41 | void endPagesArray(); |
| 42 | void beginPages(JSON); | 42 | void beginPages(JSON); |
| 43 | void endPages(); | 43 | void endPages(); |
| 44 | -void setupPagesFile(); | ||
| 45 | void setupPagesPassword(); | 44 | void setupPagesPassword(); |
| 46 | -void setupPagesRange(); | ||
| 47 | void beginSetPageLabelsArray(JSON); | 45 | void beginSetPageLabelsArray(JSON); |
| 48 | void endSetPageLabelsArray(); | 46 | void endSetPageLabelsArray(); |
| 49 | void setupSetPageLabels(); | 47 | void setupSetPageLabels(); |
libqpdf/qpdf/auto_job_json_init.hh
| @@ -402,13 +402,13 @@ pushKey("pages"); | @@ -402,13 +402,13 @@ pushKey("pages"); | ||
| 402 | beginArray(bindJSON(&Handlers::beginPagesArray), bindBare(&Handlers::endPagesArray)); // .pages[] | 402 | beginArray(bindJSON(&Handlers::beginPagesArray), bindBare(&Handlers::endPagesArray)); // .pages[] |
| 403 | beginDict(bindJSON(&Handlers::beginPages), bindBare(&Handlers::endPages)); // .pages | 403 | beginDict(bindJSON(&Handlers::beginPages), bindBare(&Handlers::endPages)); // .pages |
| 404 | pushKey("file"); | 404 | pushKey("file"); |
| 405 | -setupPagesFile(); | 405 | +addParameter([this](std::string const& p) { c_pages->file(p); }); |
| 406 | popHandler(); // key: file | 406 | popHandler(); // key: file |
| 407 | pushKey("password"); | 407 | pushKey("password"); |
| 408 | setupPagesPassword(); | 408 | setupPagesPassword(); |
| 409 | popHandler(); // key: password | 409 | popHandler(); // key: password |
| 410 | pushKey("range"); | 410 | pushKey("range"); |
| 411 | -setupPagesRange(); | 411 | +addParameter([this](std::string const& p) { c_pages->range(p); }); |
| 412 | popHandler(); // key: range | 412 | popHandler(); // key: range |
| 413 | popHandler(); // array: .pages[] | 413 | popHandler(); // array: .pages[] |
| 414 | popHandler(); // key: pages | 414 | popHandler(); // key: pages |
libqpdf/qpdf/auto_job_schema.hh
| @@ -140,7 +140,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ | @@ -140,7 +140,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ | ||
| 140 | "optimizeImages": "use efficient compression for images", | 140 | "optimizeImages": "use efficient compression for images", |
| 141 | "pages": [ | 141 | "pages": [ |
| 142 | { | 142 | { |
| 143 | - "file": "source for for pages", | 143 | + "file": "source for pages", |
| 144 | "password": "password for encrypted file", | 144 | "password": "password for encrypted file", |
| 145 | "range": "page range" | 145 | "range": "page range" |
| 146 | } | 146 | } |
manual/cli.rst
| @@ -1388,7 +1388,7 @@ PDF, causing the PDF to render differently from the original. See also | @@ -1388,7 +1388,7 @@ PDF, causing the PDF to render differently from the original. See also | ||
| 1388 | Related Options | 1388 | Related Options |
| 1389 | ~~~~~~~~~~~~~~~ | 1389 | ~~~~~~~~~~~~~~~ |
| 1390 | 1390 | ||
| 1391 | -.. qpdf:option:: --pages file [--password=password] [page-range] [...] -- | 1391 | +.. qpdf:option:: --pages [--file=]file [options] [...] -- |
| 1392 | 1392 | ||
| 1393 | .. help: begin page selection | 1393 | .. help: begin page selection |
| 1394 | 1394 | ||
| @@ -1403,6 +1403,38 @@ Related Options | @@ -1403,6 +1403,38 @@ Related Options | ||
| 1403 | See also :qpdf:ref:`--split-pages`, :qpdf:ref:`--collate`, | 1403 | See also :qpdf:ref:`--split-pages`, :qpdf:ref:`--collate`, |
| 1404 | :ref:`page-ranges`. | 1404 | :ref:`page-ranges`. |
| 1405 | 1405 | ||
| 1406 | +.. qpdf:option:: --file=file | ||
| 1407 | + | ||
| 1408 | + .. help: source for pages | ||
| 1409 | + | ||
| 1410 | + Specify the file for the current page operation. This is used | ||
| 1411 | + with --pages, --overlay, and --underlay and appears between the | ||
| 1412 | + option and the terminating --. Run qpdf --help=page-selection | ||
| 1413 | + for details. | ||
| 1414 | + | ||
| 1415 | + Specify the file for the current page operation. This option is | ||
| 1416 | + used with :qpdf:ref:`--pages`, :qpdf:ref:`--overlay` and | ||
| 1417 | + :qpdf:ref:`--underlay` and appears between the option and the | ||
| 1418 | + terminating ``--``. | ||
| 1419 | + | ||
| 1420 | + Please see :ref:`page-selection` for additional details. | ||
| 1421 | + | ||
| 1422 | +.. qpdf:option:: --range=numeric-range | ||
| 1423 | + | ||
| 1424 | + .. help: page range | ||
| 1425 | + | ||
| 1426 | + Specify the page range for the current page operation with | ||
| 1427 | + --pages. If omitted, all pages are selected. This is used | ||
| 1428 | + with --pages and appears between --pages and --. Run | ||
| 1429 | + qpdf --help=page-selection for details. | ||
| 1430 | + | ||
| 1431 | + Specify the page range for the current page operation with | ||
| 1432 | + :qpdf:ref:`--pages`. If omitted, all pages are selected. This | ||
| 1433 | + option is used with :qpdf:ref:`--pages` and appears between | ||
| 1434 | + :qpdf:ref:`--pages` and ``--``. | ||
| 1435 | + | ||
| 1436 | + Please see :ref:`page-selection` for additional details. | ||
| 1437 | + | ||
| 1406 | .. qpdf:option:: --collate[=n[,m,...]] | 1438 | .. qpdf:option:: --collate[=n[,m,...]] |
| 1407 | 1439 | ||
| 1408 | .. help: collate with --pages | 1440 | .. help: collate with --pages |
| @@ -2424,12 +2456,24 @@ Page Selection | @@ -2424,12 +2456,24 @@ Page Selection | ||
| 2424 | 2456 | ||
| 2425 | Use the --pages option to select pages from multiple files. Usage: | 2457 | Use the --pages option to select pages from multiple files. Usage: |
| 2426 | 2458 | ||
| 2459 | + qpdf in.pdf --pages --file=input-file \ | ||
| 2460 | + [--range=page-range] [--password=password] [...] -- out.pdf | ||
| 2461 | + | ||
| 2462 | + OR | ||
| 2463 | + | ||
| 2427 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ | 2464 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ |
| 2428 | [...] -- out.pdf | 2465 | [...] -- out.pdf |
| 2429 | 2466 | ||
| 2430 | Between --pages and the -- that terminates pages option, repeat | 2467 | Between --pages and the -- that terminates pages option, repeat |
| 2431 | the following: | 2468 | the following: |
| 2432 | 2469 | ||
| 2470 | + --file=filename [--range=page-range] [--password=password] [options] | ||
| 2471 | + | ||
| 2472 | + For compatibility, the file and range can be specified | ||
| 2473 | + positionally. qpdf versions prior to 11.9.0 | ||
| 2474 | + require --password=password to immediately follow the filename. In | ||
| 2475 | + the older syntax, repeat the following: | ||
| 2476 | + | ||
| 2433 | filename [--password=password] [page-range] | 2477 | filename [--password=password] [page-range] |
| 2434 | 2478 | ||
| 2435 | Document-level information, such as outlines, tags, etc., is taken | 2479 | Document-level information, such as outlines, tags, etc., is taken |
| @@ -2458,7 +2502,7 @@ Page Selection | @@ -2458,7 +2502,7 @@ Page Selection | ||
| 2458 | information from in.pdf is retained. Note the use of "." to refer | 2502 | information from in.pdf is retained. Note the use of "." to refer |
| 2459 | to in.pdf. | 2503 | to in.pdf. |
| 2460 | 2504 | ||
| 2461 | - qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf | 2505 | + qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf |
| 2462 | 2506 | ||
| 2463 | - Take all the pages from a.pdf, all the pages from b.pdf in | 2507 | - Take all the pages from a.pdf, all the pages from b.pdf in |
| 2464 | reverse, and only pages 3 and 6 from c.pdf and write the result | 2508 | reverse, and only pages 3 and 6 from c.pdf and write the result |
| @@ -2472,14 +2516,29 @@ Page Selection | @@ -2472,14 +2516,29 @@ Page Selection | ||
| 2472 | split and merge PDF files by selecting pages from one or more input | 2516 | split and merge PDF files by selecting pages from one or more input |
| 2473 | files. | 2517 | files. |
| 2474 | 2518 | ||
| 2475 | -Usage: :samp:`qpdf {in.pdf} --pages input-file [--password={password}] [{page-range}] [...] -- {out.pdf}` | 2519 | +:: |
| 2476 | 2520 | ||
| 2477 | -Between ``--pages`` and the ``--`` that terminates pages option, | ||
| 2478 | -repeat the following: | 2521 | + qpdf primary-input.pdf \ |
| 2522 | + --file=input.pdf \ | ||
| 2523 | + [--range=page-range] \ | ||
| 2524 | + [--password=password] \ | ||
| 2525 | + [...] \ | ||
| 2526 | + -- output.pdf | ||
| 2479 | 2527 | ||
| 2480 | -:samp:`{filename} [--password={password}] [{page-range}]` | 2528 | +OR |
| 2529 | + | ||
| 2530 | +:: | ||
| 2531 | + | ||
| 2532 | + qpdf primary-input.pdf \ | ||
| 2533 | + input.pdf [--password=password] [page-range] \ | ||
| 2534 | + [...] -- output.pdf | ||
| 2481 | 2535 | ||
| 2482 | Notes: | 2536 | Notes: |
| 2537 | + - The first form, with :qpdf:ref:`--file` and :qpdf:ref:`--range`, | ||
| 2538 | + was introduced in qpdf 11.9.0. In this form, the | ||
| 2539 | + :qpdf:ref:`--range` and :qpdf:ref:`--password` options apply to | ||
| 2540 | + the most recently specified :qpdf:ref:`--file` option. | ||
| 2541 | + | ||
| 2483 | - The password option is needed only for password-protected files. | 2542 | - The password option is needed only for password-protected files. |
| 2484 | If you specify the same file more than once, you only need to supply | 2543 | If you specify the same file more than once, you only need to supply |
| 2485 | the password the first time. | 2544 | the password the first time. |
| @@ -2518,8 +2577,7 @@ Examples | @@ -2518,8 +2577,7 @@ Examples | ||
| 2518 | 2577 | ||
| 2519 | :: | 2578 | :: |
| 2520 | 2579 | ||
| 2521 | - qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf | ||
| 2522 | - | 2580 | + qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf |
| 2523 | 2581 | ||
| 2524 | - Take all the pages from :file:`a.pdf`, all the pages from | 2582 | - Take all the pages from :file:`a.pdf`, all the pages from |
| 2525 | :file:`b.pdf` in reverse, and only pages 3 and 6 from :file:`c.pdf` | 2583 | :file:`b.pdf` in reverse, and only pages 3 and 6 from :file:`c.pdf` |
| @@ -2529,7 +2587,9 @@ Examples | @@ -2529,7 +2587,9 @@ Examples | ||
| 2529 | 2587 | ||
| 2530 | :: | 2588 | :: |
| 2531 | 2589 | ||
| 2532 | - qpdf --empty --pages a.pdf b.pdf --password=x z-1 c.pdf 3,6 | 2590 | + qpdf --empty --pages --file=a.pdf \ |
| 2591 | + --file=b.pdf --password=x --range=z-1 \ | ||
| 2592 | + --file=c.pdf --range=3,6 -- out.pdf | ||
| 2533 | 2593 | ||
| 2534 | - Scan a document with double-sided printing by scanning the fronts | 2594 | - Scan a document with double-sided printing by scanning the fronts |
| 2535 | into :file:`odd.pdf` and the backs into :file:`even.pdf`. Collate | 2595 | into :file:`odd.pdf` and the backs into :file:`even.pdf`. Collate |
| @@ -2542,6 +2602,8 @@ Examples | @@ -2542,6 +2602,8 @@ Examples | ||
| 2542 | qpdf --collate odd.pdf --pages . even.pdf -- all.pdf | 2602 | qpdf --collate odd.pdf --pages . even.pdf -- all.pdf |
| 2543 | OR | 2603 | OR |
| 2544 | qpdf --collate --empty --pages odd.pdf even.pdf -- all.pdf | 2604 | qpdf --collate --empty --pages odd.pdf even.pdf -- all.pdf |
| 2605 | + OR | ||
| 2606 | + qpdf --collate --empty --pages --file=odd.pdf --file=even.pdf -- all.pdf | ||
| 2545 | 2607 | ||
| 2546 | - When collating, any number of files and page ranges can be | 2608 | - When collating, any number of files and page ranges can be |
| 2547 | specified. If any file has fewer pages, that file is just skipped | 2609 | specified. If any file has fewer pages, that file is just skipped |
manual/qpdf.1
| @@ -409,10 +409,26 @@ the PDF, causing the PDF to render differently from the original. | @@ -409,10 +409,26 @@ the PDF, causing the PDF to render differently from the original. | ||
| 409 | Related Options: | 409 | Related Options: |
| 410 | .TP | 410 | .TP |
| 411 | .B --pages \-\- begin page selection | 411 | .B --pages \-\- begin page selection |
| 412 | ---pages file [--password=password] [page-range] [...] -- | 412 | +--pages [--file=]file [options] [...] -- |
| 413 | 413 | ||
| 414 | Run qpdf --help=page-selection for details. | 414 | Run qpdf --help=page-selection for details. |
| 415 | .TP | 415 | .TP |
| 416 | +.B --file \-\- source for pages | ||
| 417 | +--file=file | ||
| 418 | + | ||
| 419 | +Specify the file for the current page operation. This is used | ||
| 420 | +with --pages, --overlay, and --underlay and appears between the | ||
| 421 | +option and the terminating --. Run qpdf --help=page-selection | ||
| 422 | +for details. | ||
| 423 | +.TP | ||
| 424 | +.B --range \-\- page range | ||
| 425 | +--range=numeric-range | ||
| 426 | + | ||
| 427 | +Specify the page range for the current page operation with | ||
| 428 | +--pages. If omitted, all pages are selected. This is used | ||
| 429 | +with --pages and appears between --pages and --. Run | ||
| 430 | +qpdf --help=page-selection for details. | ||
| 431 | +.TP | ||
| 416 | .B --collate \-\- collate with --pages | 432 | .B --collate \-\- collate with --pages |
| 417 | --collate[=n[,m,...]] | 433 | --collate[=n[,m,...]] |
| 418 | 434 | ||
| @@ -754,12 +770,24 @@ should not be used except for compatibility testing. | @@ -754,12 +770,24 @@ should not be used except for compatibility testing. | ||
| 754 | .SH PAGE-SELECTION (select pages from one or more files) | 770 | .SH PAGE-SELECTION (select pages from one or more files) |
| 755 | Use the --pages option to select pages from multiple files. Usage: | 771 | Use the --pages option to select pages from multiple files. Usage: |
| 756 | 772 | ||
| 773 | +qpdf in.pdf --pages --file=input-file \ | ||
| 774 | + [--range=page-range] [--password=password] [...] -- out.pdf | ||
| 775 | + | ||
| 776 | +OR | ||
| 777 | + | ||
| 757 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ | 778 | qpdf in.pdf --pages input-file [--password=password] [page-range] \ |
| 758 | [...] -- out.pdf | 779 | [...] -- out.pdf |
| 759 | 780 | ||
| 760 | Between --pages and the -- that terminates pages option, repeat | 781 | Between --pages and the -- that terminates pages option, repeat |
| 761 | the following: | 782 | the following: |
| 762 | 783 | ||
| 784 | +--file=filename [--range=page-range] [--password=password] [options] | ||
| 785 | + | ||
| 786 | +For compatibility, the file and range can be specified | ||
| 787 | +positionally. qpdf versions prior to 11.9.0 | ||
| 788 | +require --password=password to immediately follow the filename. In | ||
| 789 | +the older syntax, repeat the following: | ||
| 790 | + | ||
| 763 | filename [--password=password] [page-range] | 791 | filename [--password=password] [page-range] |
| 764 | 792 | ||
| 765 | Document-level information, such as outlines, tags, etc., is taken | 793 | Document-level information, such as outlines, tags, etc., is taken |
| @@ -789,7 +817,7 @@ pages from b.pdf, and write the output to out.pdf. Document-level | @@ -789,7 +817,7 @@ pages from b.pdf, and write the output to out.pdf. Document-level | ||
| 789 | information from in.pdf is retained. Note the use of "." to refer | 817 | information from in.pdf is retained. Note the use of "." to refer |
| 790 | to in.pdf. | 818 | to in.pdf. |
| 791 | 819 | ||
| 792 | - qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf | 820 | + qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf |
| 793 | 821 | ||
| 794 | .IP \[bu] | 822 | .IP \[bu] |
| 795 | Take all the pages from a.pdf, all the pages from b.pdf in | 823 | Take all the pages from a.pdf, all the pages from b.pdf in |
qpdf/qpdf.testcov
| @@ -249,7 +249,6 @@ QPDF not caching overridden objstm object 0 | @@ -249,7 +249,6 @@ QPDF not caching overridden objstm object 0 | ||
| 249 | QPDFWriter original obj non-zero gen 0 | 249 | QPDFWriter original obj non-zero gen 0 |
| 250 | QPDF_optimization indirect outlines 0 | 250 | QPDF_optimization indirect outlines 0 |
| 251 | QPDF xref space 2 | 251 | QPDF xref space 2 |
| 252 | -QPDFJob pages range omitted at end 1 | ||
| 253 | QPDFJob pages range omitted in middle 0 | 252 | QPDFJob pages range omitted in middle 0 |
| 254 | QPDFJob npages 0 | 253 | QPDFJob npages 0 |
| 255 | QPDF already reserved object 0 | 254 | QPDF already reserved object 0 |
| @@ -690,3 +689,5 @@ QPDF skipping cache for known unchecked object 0 | @@ -690,3 +689,5 @@ QPDF skipping cache for known unchecked object 0 | ||
| 690 | QPDF fix dangling triggered xref reconstruction 0 | 689 | QPDF fix dangling triggered xref reconstruction 0 |
| 691 | QPDFPageDocumentHelper flatten resources missing or invalid 0 | 690 | QPDFPageDocumentHelper flatten resources missing or invalid 0 |
| 692 | QPDF recover xref stream 0 | 691 | QPDF recover xref stream 0 |
| 692 | +QPDFJob misplaced page range 0 | ||
| 693 | +QPDFJob duplicated range 0 |
qpdf/qtest/arg-parsing.test
| @@ -15,7 +15,7 @@ cleanup(); | @@ -15,7 +15,7 @@ cleanup(); | ||
| 15 | 15 | ||
| 16 | my $td = new TestDriver('arg-parsing'); | 16 | my $td = new TestDriver('arg-parsing'); |
| 17 | 17 | ||
| 18 | -my $n_tests = 24; | 18 | +my $n_tests = 25; |
| 19 | 19 | ||
| 20 | $td->runtest("required argument", | 20 | $td->runtest("required argument", |
| 21 | {$td->COMMAND => "qpdf --password minimal.pdf"}, | 21 | {$td->COMMAND => "qpdf --password minimal.pdf"}, |
| @@ -62,14 +62,20 @@ $td->runtest("bad file detected as unclosed --pages", | @@ -62,14 +62,20 @@ $td->runtest("bad file detected as unclosed --pages", | ||
| 62 | {$td->REGEXP => ".*pages options must be terminated with --.*", | 62 | {$td->REGEXP => ".*pages options must be terminated with --.*", |
| 63 | $td->EXIT_STATUS => 2}, | 63 | $td->EXIT_STATUS => 2}, |
| 64 | $td->NORMALIZE_NEWLINES); | 64 | $td->NORMALIZE_NEWLINES); |
| 65 | -$td->runtest("misplaced pages password 1", | ||
| 66 | - {$td->COMMAND => "qpdf --pages . 1 --password=z --"}, | ||
| 67 | - {$td->REGEXP => ".*password must immediately follow a file name.*", | 65 | +$td->runtest("misplaced pages range", |
| 66 | + {$td->COMMAND => "qpdf --pages --range=1 . --password=z --"}, | ||
| 67 | + {$td->REGEXP => ".*range must follow a file name.*", | ||
| 68 | $td->EXIT_STATUS => 2}, | 68 | $td->EXIT_STATUS => 2}, |
| 69 | $td->NORMALIZE_NEWLINES); | 69 | $td->NORMALIZE_NEWLINES); |
| 70 | -$td->runtest("misplaced pages password 2", | 70 | +$td->runtest("duplicate pages range", |
| 71 | + {$td->COMMAND => "qpdf --pages --file=." . | ||
| 72 | + " --range=1 --range=2 . --password=z --"}, | ||
| 73 | + {$td->REGEXP => ".*range already specified.*", | ||
| 74 | + $td->EXIT_STATUS => 2}, | ||
| 75 | + $td->NORMALIZE_NEWLINES); | ||
| 76 | +$td->runtest("misplaced pages password", | ||
| 71 | {$td->COMMAND => "qpdf --pages --password=z . 1 --"}, | 77 | {$td->COMMAND => "qpdf --pages --password=z . 1 --"}, |
| 72 | - {$td->REGEXP => ".*password must immediately follow a file name.*", | 78 | + {$td->REGEXP => ".*password must follow a file name.*", |
| 73 | $td->EXIT_STATUS => 2}, | 79 | $td->EXIT_STATUS => 2}, |
| 74 | $td->NORMALIZE_NEWLINES); | 80 | $td->NORMALIZE_NEWLINES); |
| 75 | $td->runtest("duplicated pages password", | 81 | $td->runtest("duplicated pages password", |
qpdf/qtest/merge-and-split.test
| @@ -21,9 +21,9 @@ my $n_tests = 28; | @@ -21,9 +21,9 @@ my $n_tests = 28; | ||
| 21 | # first time. The file 20-pages.pdf is specified with two different | 21 | # first time. The file 20-pages.pdf is specified with two different |
| 22 | # paths to duplicate a page. | 22 | # paths to duplicate a page. |
| 23 | my $pages_options = "--pages page-labels-and-outlines.pdf 1,3,5-7,z" . | 23 | my $pages_options = "--pages page-labels-and-outlines.pdf 1,3,5-7,z" . |
| 24 | - " 20-pages.pdf --password=user z-15" . | ||
| 25 | - " page-labels-and-outlines.pdf 12" . | ||
| 26 | - " 20-pages.pdf 10" . | 24 | + " --file=20-pages.pdf --range=z-15 --password=user" . |
| 25 | + " page-labels-and-outlines.pdf --range=12" . | ||
| 26 | + " --file=20-pages.pdf 10" . | ||
| 27 | " ./20-pages.pdf --password=owner 10" . | 27 | " ./20-pages.pdf --password=owner 10" . |
| 28 | " minimal.pdf 1 --"; | 28 | " minimal.pdf 1 --"; |
| 29 | 29 |