mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 02:49:00 +00:00
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.
This commit is contained in:
parent
20a134826c
commit
34f013c1be
@ -40,7 +40,9 @@ main(int argc, char* argv[])
|
||||
->inputFile("in.pdf")
|
||||
->outputFile("out1.pdf")
|
||||
->pages()
|
||||
->pageSpec(".", "1")
|
||||
// Prior to qpdf 11.9.0, call ->pageSpec(file, range, password)
|
||||
->file(".")
|
||||
->range("1")
|
||||
->endPages()
|
||||
->linearize()
|
||||
->staticId() // for testing only
|
||||
|
@ -243,6 +243,8 @@ class QPDFJob
|
||||
public:
|
||||
QPDF_DLL
|
||||
Config* endPages();
|
||||
// From qpdf 11.9.0, you can call file(), range(), and password(). Each call to file()
|
||||
// starts a new page spec.
|
||||
QPDF_DLL
|
||||
PagesConfig* pageSpec(
|
||||
std::string const& filename, std::string const& range, char const* password = nullptr);
|
||||
|
@ -5,3 +5,6 @@
|
||||
//
|
||||
// clang-format off
|
||||
//
|
||||
QPDF_DLL PagesConfig* file(std::string const& parameter);
|
||||
QPDF_DLL PagesConfig* range(std::string const& parameter);
|
||||
QPDF_DLL PagesConfig* password(std::string const& parameter);
|
||||
|
20
job.sums
20
job.sums
@ -5,16 +5,16 @@ include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf2
|
||||
include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
|
||||
include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5
|
||||
include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6
|
||||
include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
|
||||
include/qpdf/auto_job_c_pages.hh 09ca15649cc94fdaf6d9bdae28a20723f2a66616bf15aa86d83df31051d82506
|
||||
include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
|
||||
job.yml 8ad309ac41520b34692bcf22fd5c2ef4810ff69562aed606bd57df7bf589bc43
|
||||
libqpdf/qpdf/auto_job_decl.hh 1e8d73891bd1f0b5df5a5ca7405fb76d2d0fd024941b8c1b86489f1b5f9c5772
|
||||
libqpdf/qpdf/auto_job_help.hh 8c172913920a5273e04dc4d2059f2d78fc475960ac1738271357056beb02dd27
|
||||
libqpdf/qpdf/auto_job_init.hh ea272fd6a6a5e4d23cabd70a7b7d5ecc543b6304008c656dcba2d353d378efc2
|
||||
libqpdf/qpdf/auto_job_json_decl.hh 10ffb0d0e5ca09809a5d5d78f66dee393dfd2653a23441436465fd5ace151880
|
||||
libqpdf/qpdf/auto_job_json_init.hh 9c3839877ab3b15a47e92086f0b5616da33fd4970538cc423d3b0a7ff33ce66a
|
||||
libqpdf/qpdf/auto_job_schema.hh a882939b202d48ad1c0751c094f671ad7aad0fc04c3a4446ad83675db365c8a2
|
||||
job.yml 45761edeca048c7aa3e99340fcda1b6cd8efe4cc4c8b8a6628580243a4f49b57
|
||||
libqpdf/qpdf/auto_job_decl.hh 20d6affe1e260f5a1af4f1d82a820b933835440ff03020e877382da2e8dac6c6
|
||||
libqpdf/qpdf/auto_job_help.hh b19f8a7433c70df70b42f893a8964c801aa2bb78eecaa13cffab7add2ff81e0a
|
||||
libqpdf/qpdf/auto_job_init.hh d74759d4999201a89dafddf6f0c855e9151bbf77ea91a92d6806510292950123
|
||||
libqpdf/qpdf/auto_job_json_decl.hh 485540cde820987cfbed0aa7642a6416f2bd37164c8d4f2322f1381e73edf903
|
||||
libqpdf/qpdf/auto_job_json_init.hh c8de8658daa82115b49bf084cebe1be0b8aea73f864a219d7349acc0982b56fe
|
||||
libqpdf/qpdf/auto_job_schema.hh 3e000b87255bee62ba29b794d67b2ae97cbbdfdb78be3878c51786913564901e
|
||||
manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
|
||||
manual/cli.rst 43923fab0def5f76e537f03ba2f650270a1ae858a15747e355db2a6ea396f1a0
|
||||
manual/qpdf.1 cd335812d450ca83be3c7fe165299d3454b26b4999295f671d57e6b24f6ea7a1
|
||||
manual/cli.rst 408e17dc13d37befe34badc400dd34d3c283952d17ee3bf9a9d44898af3dabc7
|
||||
manual/qpdf.1 c99d66833aee7a2294176875ca2e9ddf2531d4ab8fb282ea5c45cb82a5d028ea
|
||||
manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b
|
||||
|
8
job.yml
8
job.yml
@ -195,9 +195,9 @@ options:
|
||||
config: c_pages
|
||||
prefix: Pages
|
||||
positional: true
|
||||
manual:
|
||||
- password
|
||||
required_parameter:
|
||||
file: file
|
||||
range: page-range
|
||||
password: password
|
||||
- table: encryption
|
||||
config: c_main
|
||||
@ -436,9 +436,9 @@ json:
|
||||
oi-min-width:
|
||||
optimize-images:
|
||||
pages:
|
||||
- _file: "source for for pages"
|
||||
- file:
|
||||
Pages.password:
|
||||
_range: "page range"
|
||||
range:
|
||||
remove-page-labels:
|
||||
report-memory-usage:
|
||||
rotate:
|
||||
|
@ -2342,6 +2342,9 @@ QPDFJob::handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_hea
|
||||
if (page_spec.filename == ".") {
|
||||
page_spec.filename = m->infilename.get();
|
||||
}
|
||||
if (page_spec.range.empty()) {
|
||||
page_spec.range = "1-z";
|
||||
}
|
||||
}
|
||||
|
||||
if (!m->keep_files_open_set) {
|
||||
|
@ -34,9 +34,10 @@ namespace
|
||||
std::shared_ptr<QPDFJob::UOConfig> c_uo;
|
||||
std::shared_ptr<QPDFJob::EncConfig> c_enc;
|
||||
std::vector<std::string> accumulated_args;
|
||||
std::shared_ptr<char> pages_password{nullptr};
|
||||
std::string user_password;
|
||||
std::string owner_password;
|
||||
bool called_pages_file{false};
|
||||
bool called_pages_range{false};
|
||||
bool used_enc_password_args{false};
|
||||
bool gave_input{false};
|
||||
bool gave_output{false};
|
||||
@ -236,82 +237,44 @@ ArgParser::argPages()
|
||||
this->ap.selectOptionTable(O_PAGES);
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::argPagesPassword(std::string const& parameter)
|
||||
{
|
||||
if (this->pages_password) {
|
||||
QTC::TC("qpdf", "QPDFJob duplicated pages password");
|
||||
usage("--password already specified for this file");
|
||||
}
|
||||
if (this->accumulated_args.size() != 1) {
|
||||
QTC::TC("qpdf", "QPDFJob misplaced pages password");
|
||||
usage("in --pages, --password must immediately follow a file name");
|
||||
}
|
||||
this->pages_password = QUtil::make_shared_cstr(parameter);
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::argPagesPositional(std::string const& arg)
|
||||
{
|
||||
if (arg.empty()) {
|
||||
if (this->accumulated_args.empty()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this->accumulated_args.push_back(arg);
|
||||
if (!called_pages_file) {
|
||||
c_pages->file(arg);
|
||||
called_pages_file = true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string file = this->accumulated_args.at(0);
|
||||
char const* range_p = nullptr;
|
||||
|
||||
size_t n_args = this->accumulated_args.size();
|
||||
if (n_args >= 2) {
|
||||
// will be copied before accumulated_args is cleared
|
||||
range_p = this->accumulated_args.at(1).c_str();
|
||||
if (called_pages_range) {
|
||||
c_pages->file(arg);
|
||||
called_pages_range = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// See if the user omitted the range entirely, in which case we assume "1-z".
|
||||
std::string next_file;
|
||||
if (range_p == nullptr) {
|
||||
if (arg.empty()) {
|
||||
// The filename or password was the last argument
|
||||
QTC::TC("qpdf", "QPDFJob pages range omitted at end", this->pages_password ? 0 : 1);
|
||||
// This could be a range or a file. Try parsing.
|
||||
try {
|
||||
QUtil::parse_numrange(arg.c_str(), 0);
|
||||
c_pages->range(arg);
|
||||
called_pages_range = true;
|
||||
} catch (std::runtime_error& e1) {
|
||||
// The range is invalid. Let's see if it's a file.
|
||||
if (arg == ".") {
|
||||
// "." means the input file.
|
||||
QTC::TC("qpdf", "QPDFJob pages range omitted with .");
|
||||
} else if (QUtil::file_can_be_opened(arg.c_str())) {
|
||||
QTC::TC("qpdf", "QPDFJob pages range omitted in middle");
|
||||
// Yup, it's a file.
|
||||
} else {
|
||||
// We need to accumulate some more arguments
|
||||
return;
|
||||
// Give the range error
|
||||
usage(e1.what());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
QUtil::parse_numrange(range_p, 0);
|
||||
} catch (std::runtime_error& e1) {
|
||||
// The range is invalid. Let's see if it's a file.
|
||||
if (strcmp(range_p, ".") == 0) {
|
||||
// "." means the input file.
|
||||
QTC::TC("qpdf", "QPDFJob pages range omitted with .");
|
||||
} else if (QUtil::file_can_be_opened(range_p)) {
|
||||
QTC::TC("qpdf", "QPDFJob pages range omitted in middle");
|
||||
// Yup, it's a file.
|
||||
} else {
|
||||
// Give the range error
|
||||
usage(e1.what());
|
||||
}
|
||||
next_file = range_p;
|
||||
range_p = nullptr;
|
||||
}
|
||||
}
|
||||
std::string range(range_p ? range_p : "1-z");
|
||||
this->c_pages->pageSpec(file, range, this->pages_password.get());
|
||||
this->accumulated_args.clear();
|
||||
this->pages_password = nullptr;
|
||||
if (!next_file.empty()) {
|
||||
this->accumulated_args.push_back(next_file);
|
||||
c_pages->file(arg);
|
||||
called_pages_range = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::argEndPages()
|
||||
{
|
||||
argPagesPositional("");
|
||||
c_pages->endPages();
|
||||
c_pages = nullptr;
|
||||
}
|
||||
|
@ -968,6 +968,45 @@ QPDFJob::PagesConfig::pageSpec(
|
||||
return this;
|
||||
}
|
||||
|
||||
QPDFJob::PagesConfig*
|
||||
QPDFJob::PagesConfig::file(std::string const& arg)
|
||||
{
|
||||
this->config->o.m->page_specs.emplace_back(arg, nullptr, "");
|
||||
return this;
|
||||
}
|
||||
|
||||
QPDFJob::PagesConfig*
|
||||
QPDFJob::PagesConfig::range(std::string const& arg)
|
||||
{
|
||||
if (config->o.m->page_specs.empty()) {
|
||||
QTC::TC("qpdf", "QPDFJob misplaced page range");
|
||||
usage("in --range must follow a file name");
|
||||
}
|
||||
auto& last = config->o.m->page_specs.back();
|
||||
if (!last.range.empty()) {
|
||||
QTC::TC("qpdf", "QPDFJob duplicated range");
|
||||
usage("--range already specified for this file");
|
||||
}
|
||||
last.range = arg;
|
||||
return this;
|
||||
}
|
||||
|
||||
QPDFJob::PagesConfig*
|
||||
QPDFJob::PagesConfig::password(std::string const& arg)
|
||||
{
|
||||
if (config->o.m->page_specs.empty()) {
|
||||
QTC::TC("qpdf", "QPDFJob misplaced pages password");
|
||||
usage("in --pages, --password must follow a file name");
|
||||
}
|
||||
auto& last = config->o.m->page_specs.back();
|
||||
if (last.password) {
|
||||
QTC::TC("qpdf", "QPDFJob duplicated pages password");
|
||||
usage("--password already specified for this file");
|
||||
}
|
||||
last.password = QUtil::make_shared_cstr(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
std::shared_ptr<QPDFJob::UOConfig>
|
||||
QPDFJob::Config::overlay()
|
||||
{
|
||||
|
@ -467,25 +467,17 @@ Handlers::endPagesArray()
|
||||
void
|
||||
Handlers::beginPages(JSON j)
|
||||
{
|
||||
std::string file;
|
||||
std::string range("1-z");
|
||||
std::string password;
|
||||
bool file_seen = false;
|
||||
bool password_seen = false;
|
||||
j.forEachDictItem([&](std::string const& key, JSON value) {
|
||||
j.forEachDictItem([&](std::string const& key, JSON const& value) {
|
||||
if (key == "file") {
|
||||
file_seen = value.getString(file);
|
||||
} else if (key == "range") {
|
||||
value.getString(range);
|
||||
} else if (key == "password") {
|
||||
password_seen = value.getString(password);
|
||||
std::string v;
|
||||
file_seen = value.getString(v);
|
||||
}
|
||||
});
|
||||
if (!file_seen) {
|
||||
QTC::TC("qpdf", "QPDFJob json pages no file");
|
||||
usage("file is required in page specification");
|
||||
}
|
||||
this->c_pages->pageSpec(file, range, password_seen ? password.c_str() : nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -494,25 +486,10 @@ Handlers::endPages()
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
void
|
||||
Handlers::setupPagesFile()
|
||||
{
|
||||
// handled in beginPages
|
||||
ignoreItem();
|
||||
}
|
||||
|
||||
void
|
||||
Handlers::setupPagesPassword()
|
||||
{
|
||||
// handled in beginPages
|
||||
ignoreItem();
|
||||
}
|
||||
|
||||
void
|
||||
Handlers::setupPagesRange()
|
||||
{
|
||||
// handled in beginPages
|
||||
ignoreItem();
|
||||
addParameter([this](char const* p) { c_pages->password(p); });
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -31,7 +31,6 @@ void argReplaceInput();
|
||||
void argSetPageLabels();
|
||||
void argUnderlay();
|
||||
void argPagesPositional(std::string const&);
|
||||
void argPagesPassword(std::string const&);
|
||||
void argEndPages();
|
||||
void argEncPositional(std::string const&);
|
||||
void argEncUserPassword(std::string const&);
|
||||
|
@ -311,10 +311,24 @@ static void add_help_4(QPDFArgParser& ap)
|
||||
ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of
|
||||
the PDF, causing the PDF to render differently from the original.
|
||||
)");
|
||||
ap.addOptionHelp("--pages", "modification", "begin page selection", R"(--pages file [--password=password] [page-range] [...] --
|
||||
ap.addOptionHelp("--pages", "modification", "begin page selection", R"(--pages [--file=]file [options] [...] --
|
||||
|
||||
Run qpdf --help=page-selection for details.
|
||||
)");
|
||||
ap.addOptionHelp("--file", "modification", "source for pages", R"(--file=file
|
||||
|
||||
Specify the file for the current page operation. This is used
|
||||
with --pages, --overlay, and --underlay and appears between the
|
||||
option and the terminating --. Run qpdf --help=page-selection
|
||||
for details.
|
||||
)");
|
||||
ap.addOptionHelp("--range", "modification", "page range", R"(--range=numeric-range
|
||||
|
||||
Specify the page range for the current page operation with
|
||||
--pages. If omitted, all pages are selected. This is used
|
||||
with --pages and appears between --pages and --. Run
|
||||
qpdf --help=page-selection for details.
|
||||
)");
|
||||
ap.addOptionHelp("--collate", "modification", "collate with --pages", R"(--collate[=n[,m,...]]
|
||||
|
||||
Collate rather than concatenate pages specified with --pages.
|
||||
@ -437,6 +451,9 @@ iv, then the remaining pages with Arabic numerals starting with
|
||||
1 and continuing sequentially until the end of the document. For
|
||||
additional examples, please consult the manual.
|
||||
)");
|
||||
}
|
||||
static void add_help_5(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addHelpTopic("encryption", "create encrypted files", R"(Create encrypted files. Usage:
|
||||
|
||||
--encrypt \
|
||||
@ -520,9 +537,6 @@ ap.addOptionHelp("--user-password", "encryption", "specify user password", R"(--
|
||||
|
||||
Set the user password of the encrypted file.
|
||||
)");
|
||||
}
|
||||
static void add_help_5(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password
|
||||
|
||||
Set the owner password of the encrypted file.
|
||||
@ -620,12 +634,24 @@ should not be used except for compatibility testing.
|
||||
)");
|
||||
ap.addHelpTopic("page-selection", "select pages from one or more files", R"(Use the --pages option to select pages from multiple files. Usage:
|
||||
|
||||
qpdf in.pdf --pages --file=input-file \
|
||||
[--range=page-range] [--password=password] [...] -- out.pdf
|
||||
|
||||
OR
|
||||
|
||||
qpdf in.pdf --pages input-file [--password=password] [page-range] \
|
||||
[...] -- out.pdf
|
||||
|
||||
Between --pages and the -- that terminates pages option, repeat
|
||||
the following:
|
||||
|
||||
--file=filename [--range=page-range] [--password=password] [options]
|
||||
|
||||
For compatibility, the file and range can be specified
|
||||
positionally. qpdf versions prior to 11.9.0
|
||||
require --password=password to immediately follow the filename. In
|
||||
the older syntax, repeat the following:
|
||||
|
||||
filename [--password=password] [page-range]
|
||||
|
||||
Document-level information, such as outlines, tags, etc., is taken
|
||||
@ -654,7 +680,7 @@ Examples:
|
||||
information from in.pdf is retained. Note the use of "." to refer
|
||||
to in.pdf.
|
||||
|
||||
qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf
|
||||
qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf
|
||||
|
||||
- Take all the pages from a.pdf, all the pages from b.pdf in
|
||||
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.
|
||||
|
||||
Run qpdf --help=page-ranges for help with page ranges.
|
||||
)");
|
||||
}
|
||||
static void add_help_6(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--to", "overlay-underlay", "destination pages for underlay/overlay", R"(--to=page-range
|
||||
|
||||
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
|
||||
with the page range syntax. The page range may be omitted
|
||||
if --repeat is used.
|
||||
)");
|
||||
}
|
||||
static void add_help_6(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range
|
||||
|
||||
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
|
||||
the options in this section are specified, no output file may be
|
||||
given.
|
||||
)");
|
||||
}
|
||||
static void add_help_7(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--is-encrypted", "inspection", "silently test whether a file is encrypted", R"(Silently exit with a code indicating the file's encryption status:
|
||||
|
||||
0: the file is encrypted
|
||||
@ -817,9 +846,6 @@ ap.addOptionHelp("--requires-password", "inspection", "silently test a file's pa
|
||||
2: the file is not encrypted
|
||||
3: the file is encrypted, and correct password (if any) has been supplied
|
||||
)");
|
||||
}
|
||||
static void add_help_7(QPDFArgParser& ap)
|
||||
{
|
||||
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
|
||||
aspects of the file, and write information about the file to
|
||||
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
|
||||
output a JSON object with the same keys and with values
|
||||
containing descriptive text.
|
||||
)");
|
||||
}
|
||||
static void add_help_8(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--json-key", "json", "limit which keys are in JSON output", R"(--json-key=key
|
||||
|
||||
This option is repeatable. If given, only the specified
|
||||
@ -907,9 +936,6 @@ This option is repeatable. If given, only specified objects will
|
||||
be shown in the "objects" key of the JSON output. Otherwise, all
|
||||
objects will be shown.
|
||||
)");
|
||||
}
|
||||
static void add_help_8(QPDFArgParser& ap)
|
||||
{
|
||||
ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file}
|
||||
|
||||
When used with --json, this option controls whether streams in
|
||||
|
@ -127,7 +127,9 @@ this->ap.addChoices("json", [this](std::string const& x){c_main->json(x);}, fals
|
||||
this->ap.addChoices("json-output", [this](std::string const& x){c_main->jsonOutput(x);}, false, json_output_choices);
|
||||
this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages));
|
||||
this->ap.addPositional(p(&ArgParser::argPagesPositional));
|
||||
this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password");
|
||||
this->ap.addRequiredParameter("file", [this](std::string const& x){c_pages->file(x);}, "file");
|
||||
this->ap.addRequiredParameter("range", [this](std::string const& x){c_pages->range(x);}, "page-range");
|
||||
this->ap.addRequiredParameter("password", [this](std::string const& x){c_pages->password(x);}, "password");
|
||||
this->ap.registerOptionTable("encryption", b(&ArgParser::argEndEncryption));
|
||||
this->ap.addPositional(p(&ArgParser::argEncPositional));
|
||||
this->ap.addRequiredParameter("user-password", p(&ArgParser::argEncUserPassword), "user_password");
|
||||
|
@ -41,9 +41,7 @@ void beginPagesArray(JSON);
|
||||
void endPagesArray();
|
||||
void beginPages(JSON);
|
||||
void endPages();
|
||||
void setupPagesFile();
|
||||
void setupPagesPassword();
|
||||
void setupPagesRange();
|
||||
void beginSetPageLabelsArray(JSON);
|
||||
void endSetPageLabelsArray();
|
||||
void setupSetPageLabels();
|
||||
|
@ -402,13 +402,13 @@ pushKey("pages");
|
||||
beginArray(bindJSON(&Handlers::beginPagesArray), bindBare(&Handlers::endPagesArray)); // .pages[]
|
||||
beginDict(bindJSON(&Handlers::beginPages), bindBare(&Handlers::endPages)); // .pages
|
||||
pushKey("file");
|
||||
setupPagesFile();
|
||||
addParameter([this](std::string const& p) { c_pages->file(p); });
|
||||
popHandler(); // key: file
|
||||
pushKey("password");
|
||||
setupPagesPassword();
|
||||
popHandler(); // key: password
|
||||
pushKey("range");
|
||||
setupPagesRange();
|
||||
addParameter([this](std::string const& p) { c_pages->range(p); });
|
||||
popHandler(); // key: range
|
||||
popHandler(); // array: .pages[]
|
||||
popHandler(); // key: pages
|
||||
|
@ -140,7 +140,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({
|
||||
"optimizeImages": "use efficient compression for images",
|
||||
"pages": [
|
||||
{
|
||||
"file": "source for for pages",
|
||||
"file": "source for pages",
|
||||
"password": "password for encrypted file",
|
||||
"range": "page range"
|
||||
}
|
||||
|
@ -1388,7 +1388,7 @@ PDF, causing the PDF to render differently from the original. See also
|
||||
Related Options
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. qpdf:option:: --pages file [--password=password] [page-range] [...] --
|
||||
.. qpdf:option:: --pages [--file=]file [options] [...] --
|
||||
|
||||
.. help: begin page selection
|
||||
|
||||
@ -1403,6 +1403,38 @@ Related Options
|
||||
See also :qpdf:ref:`--split-pages`, :qpdf:ref:`--collate`,
|
||||
:ref:`page-ranges`.
|
||||
|
||||
.. qpdf:option:: --file=file
|
||||
|
||||
.. help: source for pages
|
||||
|
||||
Specify the file for the current page operation. This is used
|
||||
with --pages, --overlay, and --underlay and appears between the
|
||||
option and the terminating --. Run qpdf --help=page-selection
|
||||
for details.
|
||||
|
||||
Specify the file for the current page operation. This option is
|
||||
used with :qpdf:ref:`--pages`, :qpdf:ref:`--overlay` and
|
||||
:qpdf:ref:`--underlay` and appears between the option and the
|
||||
terminating ``--``.
|
||||
|
||||
Please see :ref:`page-selection` for additional details.
|
||||
|
||||
.. qpdf:option:: --range=numeric-range
|
||||
|
||||
.. help: page range
|
||||
|
||||
Specify the page range for the current page operation with
|
||||
--pages. If omitted, all pages are selected. This is used
|
||||
with --pages and appears between --pages and --. Run
|
||||
qpdf --help=page-selection for details.
|
||||
|
||||
Specify the page range for the current page operation with
|
||||
:qpdf:ref:`--pages`. If omitted, all pages are selected. This
|
||||
option is used with :qpdf:ref:`--pages` and appears between
|
||||
:qpdf:ref:`--pages` and ``--``.
|
||||
|
||||
Please see :ref:`page-selection` for additional details.
|
||||
|
||||
.. qpdf:option:: --collate[=n[,m,...]]
|
||||
|
||||
.. help: collate with --pages
|
||||
@ -2424,12 +2456,24 @@ Page Selection
|
||||
|
||||
Use the --pages option to select pages from multiple files. Usage:
|
||||
|
||||
qpdf in.pdf --pages --file=input-file \
|
||||
[--range=page-range] [--password=password] [...] -- out.pdf
|
||||
|
||||
OR
|
||||
|
||||
qpdf in.pdf --pages input-file [--password=password] [page-range] \
|
||||
[...] -- out.pdf
|
||||
|
||||
Between --pages and the -- that terminates pages option, repeat
|
||||
the following:
|
||||
|
||||
--file=filename [--range=page-range] [--password=password] [options]
|
||||
|
||||
For compatibility, the file and range can be specified
|
||||
positionally. qpdf versions prior to 11.9.0
|
||||
require --password=password to immediately follow the filename. In
|
||||
the older syntax, repeat the following:
|
||||
|
||||
filename [--password=password] [page-range]
|
||||
|
||||
Document-level information, such as outlines, tags, etc., is taken
|
||||
@ -2458,7 +2502,7 @@ Page Selection
|
||||
information from in.pdf is retained. Note the use of "." to refer
|
||||
to in.pdf.
|
||||
|
||||
qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf
|
||||
qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf
|
||||
|
||||
- Take all the pages from a.pdf, all the pages from b.pdf in
|
||||
reverse, and only pages 3 and 6 from c.pdf and write the result
|
||||
@ -2472,14 +2516,29 @@ Page Selection
|
||||
split and merge PDF files by selecting pages from one or more input
|
||||
files.
|
||||
|
||||
Usage: :samp:`qpdf {in.pdf} --pages input-file [--password={password}] [{page-range}] [...] -- {out.pdf}`
|
||||
::
|
||||
|
||||
Between ``--pages`` and the ``--`` that terminates pages option,
|
||||
repeat the following:
|
||||
qpdf primary-input.pdf \
|
||||
--file=input.pdf \
|
||||
[--range=page-range] \
|
||||
[--password=password] \
|
||||
[...] \
|
||||
-- output.pdf
|
||||
|
||||
:samp:`{filename} [--password={password}] [{page-range}]`
|
||||
OR
|
||||
|
||||
::
|
||||
|
||||
qpdf primary-input.pdf \
|
||||
input.pdf [--password=password] [page-range] \
|
||||
[...] -- output.pdf
|
||||
|
||||
Notes:
|
||||
- The first form, with :qpdf:ref:`--file` and :qpdf:ref:`--range`,
|
||||
was introduced in qpdf 11.9.0. In this form, the
|
||||
:qpdf:ref:`--range` and :qpdf:ref:`--password` options apply to
|
||||
the most recently specified :qpdf:ref:`--file` option.
|
||||
|
||||
- The password option is needed only for password-protected files.
|
||||
If you specify the same file more than once, you only need to supply
|
||||
the password the first time.
|
||||
@ -2518,8 +2577,7 @@ Examples
|
||||
|
||||
::
|
||||
|
||||
qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf
|
||||
|
||||
qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf
|
||||
|
||||
- Take all the pages from :file:`a.pdf`, all the pages from
|
||||
:file:`b.pdf` in reverse, and only pages 3 and 6 from :file:`c.pdf`
|
||||
@ -2529,7 +2587,9 @@ Examples
|
||||
|
||||
::
|
||||
|
||||
qpdf --empty --pages a.pdf b.pdf --password=x z-1 c.pdf 3,6
|
||||
qpdf --empty --pages --file=a.pdf \
|
||||
--file=b.pdf --password=x --range=z-1 \
|
||||
--file=c.pdf --range=3,6 -- out.pdf
|
||||
|
||||
- Scan a document with double-sided printing by scanning the fronts
|
||||
into :file:`odd.pdf` and the backs into :file:`even.pdf`. Collate
|
||||
@ -2542,6 +2602,8 @@ Examples
|
||||
qpdf --collate odd.pdf --pages . even.pdf -- all.pdf
|
||||
OR
|
||||
qpdf --collate --empty --pages odd.pdf even.pdf -- all.pdf
|
||||
OR
|
||||
qpdf --collate --empty --pages --file=odd.pdf --file=even.pdf -- all.pdf
|
||||
|
||||
- When collating, any number of files and page ranges can be
|
||||
specified. If any file has fewer pages, that file is just skipped
|
||||
|
@ -409,10 +409,26 @@ the PDF, causing the PDF to render differently from the original.
|
||||
Related Options:
|
||||
.TP
|
||||
.B --pages \-\- begin page selection
|
||||
--pages file [--password=password] [page-range] [...] --
|
||||
--pages [--file=]file [options] [...] --
|
||||
|
||||
Run qpdf --help=page-selection for details.
|
||||
.TP
|
||||
.B --file \-\- source for pages
|
||||
--file=file
|
||||
|
||||
Specify the file for the current page operation. This is used
|
||||
with --pages, --overlay, and --underlay and appears between the
|
||||
option and the terminating --. Run qpdf --help=page-selection
|
||||
for details.
|
||||
.TP
|
||||
.B --range \-\- page range
|
||||
--range=numeric-range
|
||||
|
||||
Specify the page range for the current page operation with
|
||||
--pages. If omitted, all pages are selected. This is used
|
||||
with --pages and appears between --pages and --. Run
|
||||
qpdf --help=page-selection for details.
|
||||
.TP
|
||||
.B --collate \-\- collate with --pages
|
||||
--collate[=n[,m,...]]
|
||||
|
||||
@ -754,12 +770,24 @@ should not be used except for compatibility testing.
|
||||
.SH PAGE-SELECTION (select pages from one or more files)
|
||||
Use the --pages option to select pages from multiple files. Usage:
|
||||
|
||||
qpdf in.pdf --pages --file=input-file \
|
||||
[--range=page-range] [--password=password] [...] -- out.pdf
|
||||
|
||||
OR
|
||||
|
||||
qpdf in.pdf --pages input-file [--password=password] [page-range] \
|
||||
[...] -- out.pdf
|
||||
|
||||
Between --pages and the -- that terminates pages option, repeat
|
||||
the following:
|
||||
|
||||
--file=filename [--range=page-range] [--password=password] [options]
|
||||
|
||||
For compatibility, the file and range can be specified
|
||||
positionally. qpdf versions prior to 11.9.0
|
||||
require --password=password to immediately follow the filename. In
|
||||
the older syntax, repeat the following:
|
||||
|
||||
filename [--password=password] [page-range]
|
||||
|
||||
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
|
||||
information from in.pdf is retained. Note the use of "." to refer
|
||||
to in.pdf.
|
||||
|
||||
qpdf in.pdf --pages . a.pdf b.pdf:even -- out.pdf
|
||||
qpdf in.pdf --pages . a.pdf b.pdf 1-z:even -- out.pdf
|
||||
|
||||
.IP \[bu]
|
||||
Take all the pages from a.pdf, all the pages from b.pdf in
|
||||
|
@ -249,7 +249,6 @@ QPDF not caching overridden objstm object 0
|
||||
QPDFWriter original obj non-zero gen 0
|
||||
QPDF_optimization indirect outlines 0
|
||||
QPDF xref space 2
|
||||
QPDFJob pages range omitted at end 1
|
||||
QPDFJob pages range omitted in middle 0
|
||||
QPDFJob npages 0
|
||||
QPDF already reserved object 0
|
||||
@ -690,3 +689,5 @@ QPDF skipping cache for known unchecked object 0
|
||||
QPDF fix dangling triggered xref reconstruction 0
|
||||
QPDFPageDocumentHelper flatten resources missing or invalid 0
|
||||
QPDF recover xref stream 0
|
||||
QPDFJob misplaced page range 0
|
||||
QPDFJob duplicated range 0
|
||||
|
@ -15,7 +15,7 @@ cleanup();
|
||||
|
||||
my $td = new TestDriver('arg-parsing');
|
||||
|
||||
my $n_tests = 24;
|
||||
my $n_tests = 25;
|
||||
|
||||
$td->runtest("required argument",
|
||||
{$td->COMMAND => "qpdf --password minimal.pdf"},
|
||||
@ -62,14 +62,20 @@ $td->runtest("bad file detected as unclosed --pages",
|
||||
{$td->REGEXP => ".*pages options must be terminated with --.*",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("misplaced pages password 1",
|
||||
{$td->COMMAND => "qpdf --pages . 1 --password=z --"},
|
||||
{$td->REGEXP => ".*password must immediately follow a file name.*",
|
||||
$td->runtest("misplaced pages range",
|
||||
{$td->COMMAND => "qpdf --pages --range=1 . --password=z --"},
|
||||
{$td->REGEXP => ".*range must follow a file name.*",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("misplaced pages password 2",
|
||||
$td->runtest("duplicate pages range",
|
||||
{$td->COMMAND => "qpdf --pages --file=." .
|
||||
" --range=1 --range=2 . --password=z --"},
|
||||
{$td->REGEXP => ".*range already specified.*",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("misplaced pages password",
|
||||
{$td->COMMAND => "qpdf --pages --password=z . 1 --"},
|
||||
{$td->REGEXP => ".*password must immediately follow a file name.*",
|
||||
{$td->REGEXP => ".*password must follow a file name.*",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("duplicated pages password",
|
||||
|
@ -21,9 +21,9 @@ my $n_tests = 28;
|
||||
# first time. The file 20-pages.pdf is specified with two different
|
||||
# paths to duplicate a page.
|
||||
my $pages_options = "--pages page-labels-and-outlines.pdf 1,3,5-7,z" .
|
||||
" 20-pages.pdf --password=user z-15" .
|
||||
" page-labels-and-outlines.pdf 12" .
|
||||
" 20-pages.pdf 10" .
|
||||
" --file=20-pages.pdf --range=z-15 --password=user" .
|
||||
" page-labels-and-outlines.pdf --range=12" .
|
||||
" --file=20-pages.pdf 10" .
|
||||
" ./20-pages.pdf --password=owner 10" .
|
||||
" minimal.pdf 1 --";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user