aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2024-01-05 18:16:13 +0100
committerJay Berkenbilt <ejb@ql.org>2024-01-05 23:10:32 +0100
commita0e70b370afcb628caabb3e8610d600fea6966f3 (patch)
tree1a86fd7d0a654a5db10ba351a824640dbe4d0ad0
parent1921e44ca7ba50b48b1baa78d147b52fe1aae19a (diff)
downloadqpdf-a0e70b370afcb628caabb3e8610d600fea6966f3.tar.zst
Wiring for --set-page-labels: manual (non-bisectable commit)
This commit contains only the manual changes. It is separated for clarity. This commit would not pass CI because it lacks the automated changes, which appear in the next commit.
-rw-r--r--include/qpdf/QPDFJob.hh20
-rw-r--r--job.yml7
-rw-r--r--libqpdf/QPDFJob_argv.cc20
-rw-r--r--libqpdf/QPDFJob_config.cc22
-rw-r--r--libqpdf/QPDFJob_json.cc21
-rw-r--r--manual/cli.rst110
-rw-r--r--qpdf/sizes.cc1
7 files changed, 201 insertions, 0 deletions
diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh
index 01fe35ae..9a7afb0f 100644
--- a/include/qpdf/QPDFJob.hh
+++ b/include/qpdf/QPDFJob.hh
@@ -296,6 +296,23 @@ class QPDFJob
Config* config;
};
+ class PageLabelsConfig {
+ friend class QPDFJob;
+ friend class Config;
+
+ public:
+ QPDF_DLL
+ Config* endSetPageLabels();
+
+#include <qpdf/auto_job_c_set_page_labels.hh>
+
+ private:
+ PageLabelsConfig(Config*);
+ PageLabelsConfig(PagesConfig const&) = delete;
+
+ Config* config;
+ };
+
class Config
{
friend class QPDFJob;
@@ -313,6 +330,8 @@ class QPDFJob
Config* outputFile(std::string const& filename);
QPDF_DLL
Config* replaceInput();
+ QPDF_DLL
+ Config* setPageLabels(std::vector<std::string> const& specs);
QPDF_DLL
std::shared_ptr<CopyAttConfig> copyAttachmentsFrom();
@@ -675,6 +694,7 @@ class QPDFJob
bool json_output{false};
std::string update_from_json;
bool report_mem_usage{false};
+ std::vector<std::string> page_label_specs;
};
std::shared_ptr<Members> m;
};
diff --git a/job.yml b/job.yml
index d342e7a2..3d918385 100644
--- a/job.yml
+++ b/job.yml
@@ -94,6 +94,7 @@ options:
- underlay
- empty
- replace-input
+ - set-page-labels
positional: true
bare:
- add-attachment
@@ -134,6 +135,7 @@ options:
- report-memory-usage
- requires-password
- remove-restrictions
+ - set-page-labels
- show-encryption
- show-encryption-key
- show-linearization
@@ -282,6 +284,9 @@ options:
required_parameter:
prefix: prefix
password: password
+ - table: set page labels
+ prefix: PageLabels
+ positional: true
json:
# The structure of this section defines what the json input to
# QPDFJob looks like. If a key starts with underscore, it does not
@@ -437,6 +442,8 @@ json:
remove-page-labels:
report-memory-usage:
rotate:
+ set-page-labels:
+ - null
overlay:
_file: "source file for overlay"
UO.password:
diff --git a/libqpdf/QPDFJob_argv.cc b/libqpdf/QPDFJob_argv.cc
index eadf9a33..737059f0 100644
--- a/libqpdf/QPDFJob_argv.cc
+++ b/libqpdf/QPDFJob_argv.cc
@@ -409,6 +409,26 @@ ArgParser::argEndCopyAttachment()
}
void
+ArgParser::argSetPageLabels()
+{
+ this->ap.selectOptionTable(O_SET_PAGE_LABELS);
+ accumulated_args.clear();
+}
+
+void
+ArgParser::argPageLabelsPositional(std::string const& arg)
+{
+ accumulated_args.push_back(arg);
+}
+
+void
+ArgParser::argEndSetPageLabels()
+{
+ c_main->setPageLabels(accumulated_args);
+ accumulated_args.clear();
+}
+
+void
ArgParser::argJobJsonHelp()
{
*QPDFLogger::defaultLogger()->getInfo()
diff --git a/libqpdf/QPDFJob_config.cc b/libqpdf/QPDFJob_config.cc
index a0dc10f6..9651c3b9 100644
--- a/libqpdf/QPDFJob_config.cc
+++ b/libqpdf/QPDFJob_config.cc
@@ -1059,6 +1059,17 @@ QPDFJob::Config::encrypt(
return std::shared_ptr<EncConfig>(new EncConfig(this));
}
+QPDFJob::Config*
+QPDFJob::Config::setPageLabels(const std::vector<std::string>& specs)
+{
+ // XXX validate
+ for (auto const& xxx: specs) {
+ std::cout << "XXX config: spec: " << xxx << std::endl;
+ }
+ o.m->page_label_specs = specs;
+ return this;
+}
+
QPDFJob::EncConfig::EncConfig(Config* c) :
config(c)
{
@@ -1213,3 +1224,14 @@ QPDFJob::EncConfig::forceR5()
config->o.m->force_R5 = true;
return this;
}
+
+QPDFJob::PageLabelsConfig::PageLabelsConfig(Config* c) :
+ config(c)
+{
+}
+
+QPDFJob::Config*
+QPDFJob::PageLabelsConfig::endSetPageLabels()
+{
+ return this->config;
+}
diff --git a/libqpdf/QPDFJob_json.cc b/libqpdf/QPDFJob_json.cc
index d44652f4..754cb81b 100644
--- a/libqpdf/QPDFJob_json.cc
+++ b/libqpdf/QPDFJob_json.cc
@@ -66,6 +66,7 @@ namespace
std::shared_ptr<QPDFJob::PagesConfig> c_pages;
std::shared_ptr<QPDFJob::UOConfig> c_uo;
std::shared_ptr<QPDFJob::EncConfig> c_enc;
+ std::vector<std::string> accumulated_args;
};
} // namespace
@@ -565,6 +566,26 @@ Handlers::setupUnderlayPassword()
}
void
+Handlers::setupSetPageLabels()
+{
+ accumulated_args.clear();
+ addParameter([this](char const* p) { accumulated_args.push_back(p); });
+}
+
+void
+Handlers::endSetPageLabelsArray()
+{
+ c_main->setPageLabels(accumulated_args);
+ accumulated_args.clear();
+}
+
+void
+Handlers::beginSetPageLabelsArray(JSON)
+{
+ // nothing needed
+}
+
+void
QPDFJob::initializeFromJson(std::string const& json, bool partial)
{
std::list<std::string> errors;
diff --git a/manual/cli.rst b/manual/cli.rst
index 1d530641..6495829f 100644
--- a/manual/cli.rst
+++ b/manual/cli.rst
@@ -1748,6 +1748,116 @@ Related Options
Exclude page labels (explicit page numbers) from the output file.
Exclude page labels (explicit page numbers) from the output file.
+ See also :qpdf:ref:`--set-page-labels`.
+
+.. qpdf:option:: --set-page-labels label-spec ... --
+
+ .. help: number pages for the entire document
+
+ Set page labels (explicit page numbers) for the entire file.
+ Each label-spec has the form
+
+ first-page:[type][/start[/prefix]]
+
+ where
+
+ - "first-page" represents a sequential page number using the
+ same format as page ranges: a number, a number preceded by "r"
+ to indicate counting from the end, or "z" indicating the last
+ page
+ - "type" is one of
+ - D: Arabic numerals (digits)
+ - A: Upper-case alphabetic characters
+ - a: Lower-case alphabetic characters
+ - R: Upper-case Roman numerals
+ - r: Lower-case Roman numerals
+ - omitted: the page number does not appear, though the prefix,
+ if specified will still appear
+ - "prefix"` may be any string and is prepended to each page
+ label
+
+ A given page label spec causes pages to be numbered according to
+ that scheme starting with first-page and continuing until the
+ next label spec or the end of the document. If you want to omit
+ numbering starting at a certain page, you can use first-page: as
+ the spec.
+
+ Example: "1:r 5:D" would number the first four pages i through
+ 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.
+
+ Set page labels (explicit page numbers) for the entire file. A PDF
+ file's pages can be explicitly numbered using page labels. Page
+ labels in a PDF file have an optional type (Arabic numerals,
+ upper/lower-case alphabetic characters, upper/lower-case Roman
+ numerals), an optional prefix, and an optional starting value,
+ which defaults to 1. A qpdf page label spec has the form
+
+ :samp:`{first-page}:[{type}][/{start}[/{prefix}]]`
+
+ where
+
+ - :samp:`{first-page}` represents a sequential page number using
+ the same format as page ranges (see :ref:`page-ranges`): a
+ number, a number preceded by ``r`` to indicate counting from the
+ end, or ``z`` indicating the last page
+
+ - :samp:`{type}` may be one of
+
+ - ``D``: Arabic numerals (digits)
+
+ - ``A``: Upper-case alphabetic characters
+
+ - ``a``: Lower-case alphabetic characters
+
+ - ``R``: Upper-case Roman numerals
+
+ - ``r``: Lower-case Roman numerals
+
+ - omitted: the page number does not appear, though the prefix, if
+ specified will still appear
+
+ - :samp:`{prefix}` may be any string and is prepended to each page
+ label
+
+ A given page label spec causes pages to be numbered according to
+ that scheme starting with :samp:`{first-page}` and continuing until
+ the next label spec or the end of the document. If you want to omit
+ numbering starting at a certain page, you can use
+ :samp:`{first-page}:` as the spec.
+
+ Here are some example page labeling schemes. First these examples,
+ assume a 50-page document.
+
+ - ``1:a 5:D``
+
+ - The first four pages will be numbered ``a`` through ``d``, then
+ the remaining pages will numbered ``1`` through ``46``.
+
+ - ``1:r 5:D 12: 14:D/10 r5:D//A- z://"end note"``:
+
+ - The first four pages are numbered ``i`` through ``iv``
+
+ - The 5th page is numbered ``1``, and pages are numbered
+ sequentially through the 11th page, which will be numbered
+ ``7``
+
+ - The 12th and 13th pages will not have labels
+
+ - The 14th page is numbered ``10``. Pages will be numered
+ sequentially up through the 45th page, which will be numbered
+ ``41``
+
+ - Starting with the 46th page (the fifth to last page) and going
+ to the 49th page, pages will be labeled ``A-1`` through ``A-4``
+
+ - The 50th page (the last page) will be labeled ``end note``.
+
+ The limitations on the range of formats for page labels are as
+ specified in Section 12.4.2 of the PDF spec, ISO 32000.
+
+ See also :qpdf:ref:`--remove-page-labels`.
.. _encryption-options:
diff --git a/qpdf/sizes.cc b/qpdf/sizes.cc
index cbec5cd5..65121872 100644
--- a/qpdf/sizes.cc
+++ b/qpdf/sizes.cc
@@ -101,6 +101,7 @@ main()
print_size(QPDFJob::EncConfig);
print_size(QPDFJob::PagesConfig);
print_size(QPDFJob::UOConfig);
+ print_size(QPDFJob::PageLabelsConfig);
print_size(QPDFLogger);
print_size(QPDFMatrix);
print_size(QPDFNameTreeObjectHelper);