mirror of
https://github.com/qpdf/qpdf.git
synced 2024-06-04 03:10:52 +00:00
Incorporate job schema generation into generate_auto_job
This commit is contained in:
parent
b9cd693a5b
commit
1c8d53465f
|
@ -128,7 +128,10 @@ Command-line arguments are closely coupled with QPDFJob. To add a new
|
||||||
command-line argument, add the option to the appropriate table in
|
command-line argument, add the option to the appropriate table in
|
||||||
job.yml. This will automatically declare a method in the private
|
job.yml. This will automatically declare a method in the private
|
||||||
ArgParser class in QPDFJob_argv.cc which you have to implement. The
|
ArgParser class in QPDFJob_argv.cc which you have to implement. The
|
||||||
implementation should make calls to methods in QPDFJob.
|
implementation should make calls to methods in QPDFJob. Then, add the
|
||||||
|
same option to either the no-json section of job.yml if it is to be
|
||||||
|
excluded from the job json structure, or add it under the json
|
||||||
|
structure to the place where it should appear in the json structure.
|
||||||
|
|
||||||
The build will fail until the new option is documented in
|
The build will fail until the new option is documented in
|
||||||
manual/cli.rst. To do that, create documentation for the option by
|
manual/cli.rst. To do that, create documentation for the option by
|
||||||
|
|
|
@ -5,6 +5,7 @@ import argparse
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
import yaml
|
import yaml
|
||||||
|
import json
|
||||||
|
|
||||||
whoami = os.path.basename(sys.argv[0])
|
whoami = os.path.basename(sys.argv[0])
|
||||||
BANNER = f'''//
|
BANNER = f'''//
|
||||||
|
@ -29,6 +30,7 @@ class Main:
|
||||||
'decl': 'libqpdf/qpdf/auto_job_decl.hh',
|
'decl': 'libqpdf/qpdf/auto_job_decl.hh',
|
||||||
'init': 'libqpdf/qpdf/auto_job_init.hh',
|
'init': 'libqpdf/qpdf/auto_job_init.hh',
|
||||||
'help': 'libqpdf/qpdf/auto_job_help.hh',
|
'help': 'libqpdf/qpdf/auto_job_help.hh',
|
||||||
|
'schema': 'libqpdf/qpdf/auto_job_schema.hh',
|
||||||
}
|
}
|
||||||
SUMS = 'job.sums'
|
SUMS = 'job.sums'
|
||||||
|
|
||||||
|
@ -199,6 +201,9 @@ class Main:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f'help for unknown option {option},'
|
f'help for unknown option {option},'
|
||||||
f' lineno={lineno}')
|
f' lineno={lineno}')
|
||||||
|
if option not in self.help_options:
|
||||||
|
# QXXXQ also need to exclude help table
|
||||||
|
self.jdata[option[2:]]['help'] = short_text
|
||||||
print(f'ap.addOptionHelp("{option}", "{topic}",'
|
print(f'ap.addOptionHelp("{option}", "{topic}",'
|
||||||
f' "{short_text}", R"({long_text})");', file=f)
|
f' "{short_text}", R"({long_text})");', file=f)
|
||||||
help_lines += 1
|
help_lines += 1
|
||||||
|
@ -226,9 +231,12 @@ class Main:
|
||||||
with open('job.yml', 'r') as f:
|
with open('job.yml', 'r') as f:
|
||||||
data = yaml.safe_load(f.read())
|
data = yaml.safe_load(f.read())
|
||||||
self.validate(data)
|
self.validate(data)
|
||||||
self.options_without_help = set(
|
# Add the built-in help options to tables that we populate as
|
||||||
|
# we read job.yml since we won't encounter these in job.yml
|
||||||
|
self.help_options = set(
|
||||||
['--completion-bash', '--completion-zsh', '--help']
|
['--completion-bash', '--completion-zsh', '--help']
|
||||||
)
|
)
|
||||||
|
self.options_without_help = set(self.help_options)
|
||||||
self.prepare(data)
|
self.prepare(data)
|
||||||
with open(self.DESTS['decl'], 'w') as f:
|
with open(self.DESTS['decl'], 'w') as f:
|
||||||
print(BANNER, file=f)
|
print(BANNER, file=f)
|
||||||
|
@ -242,6 +250,11 @@ class Main:
|
||||||
with open('manual/cli.rst', 'r') as df:
|
with open('manual/cli.rst', 'r') as df:
|
||||||
print(BANNER, file=f)
|
print(BANNER, file=f)
|
||||||
self.generate_doc(df, f)
|
self.generate_doc(df, f)
|
||||||
|
self.generate_schema(data)
|
||||||
|
with open(self.DESTS['schema'], 'w') as f:
|
||||||
|
print('static constexpr char const* JOB_SCHEMA_DATA = R"(' +
|
||||||
|
json.dumps(self.schema, indent=2, separators=(',', ': ')) +
|
||||||
|
')";', file=f)
|
||||||
|
|
||||||
# Update hashes last to ensure that this will be rerun in the
|
# Update hashes last to ensure that this will be rerun in the
|
||||||
# event of a failure.
|
# event of a failure.
|
||||||
|
@ -251,6 +264,24 @@ class Main:
|
||||||
def prepare(self, data):
|
def prepare(self, data):
|
||||||
self.decls = []
|
self.decls = []
|
||||||
self.init = []
|
self.init = []
|
||||||
|
self.jdata = {
|
||||||
|
# option: {
|
||||||
|
# tables: set(),
|
||||||
|
# help: string,
|
||||||
|
# QXXXQ something for registering handler
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_jdata(flag, table):
|
||||||
|
nonlocal self
|
||||||
|
if table == 'help':
|
||||||
|
self.help_options.add(f'--{flag}')
|
||||||
|
elif flag in self.jdata:
|
||||||
|
self.jdata[flag]['tables'].add(table)
|
||||||
|
else:
|
||||||
|
self.jdata[flag] = {
|
||||||
|
'tables': set([table]),
|
||||||
|
}
|
||||||
|
|
||||||
self.init.append('auto b = [this](void (ArgParser::*f)()) {')
|
self.init.append('auto b = [this](void (ArgParser::*f)()) {')
|
||||||
self.init.append(' return QPDFArgParser::bindBare(f, this);')
|
self.init.append(' return QPDFArgParser::bindBare(f, this);')
|
||||||
|
@ -275,7 +306,7 @@ class Main:
|
||||||
self.decls.append('')
|
self.decls.append('')
|
||||||
for o in data['options']:
|
for o in data['options']:
|
||||||
table = o['table']
|
table = o['table']
|
||||||
|
table_prefix = o.get('prefix', table)
|
||||||
if table == 'main':
|
if table == 'main':
|
||||||
self.init.append('this->ap.selectMainOptionTable();')
|
self.init.append('this->ap.selectMainOptionTable();')
|
||||||
elif table == 'help':
|
elif table == 'help':
|
||||||
|
@ -296,12 +327,14 @@ class Main:
|
||||||
self.decls.append(f'void {identifier}();')
|
self.decls.append(f'void {identifier}();')
|
||||||
self.init.append(f'this->ap.addBare("{i}", '
|
self.init.append(f'this->ap.addBare("{i}", '
|
||||||
f'b(&ArgParser::{identifier}));')
|
f'b(&ArgParser::{identifier}));')
|
||||||
|
add_jdata(i, table_prefix)
|
||||||
for i in o.get('optional_parameter', []):
|
for i in o.get('optional_parameter', []):
|
||||||
self.options_without_help.add(f'--{i}')
|
self.options_without_help.add(f'--{i}')
|
||||||
identifier = self.to_identifier(i, prefix, False)
|
identifier = self.to_identifier(i, prefix, False)
|
||||||
self.decls.append(f'void {identifier}(char *);')
|
self.decls.append(f'void {identifier}(char *);')
|
||||||
self.init.append(f'this->ap.addOptionalParameter("{i}", '
|
self.init.append(f'this->ap.addOptionalParameter("{i}", '
|
||||||
f'p(&ArgParser::{identifier}));')
|
f'p(&ArgParser::{identifier}));')
|
||||||
|
add_jdata(i, table_prefix)
|
||||||
for i, v in o.get('required_parameter', {}).items():
|
for i, v in o.get('required_parameter', {}).items():
|
||||||
self.options_without_help.add(f'--{i}')
|
self.options_without_help.add(f'--{i}')
|
||||||
identifier = self.to_identifier(i, prefix, False)
|
identifier = self.to_identifier(i, prefix, False)
|
||||||
|
@ -309,6 +342,7 @@ class Main:
|
||||||
self.init.append(f'this->ap.addRequiredParameter("{i}", '
|
self.init.append(f'this->ap.addRequiredParameter("{i}", '
|
||||||
f'p(&ArgParser::{identifier})'
|
f'p(&ArgParser::{identifier})'
|
||||||
f', "{v}");')
|
f', "{v}");')
|
||||||
|
add_jdata(i, table_prefix)
|
||||||
for i, v in o.get('required_choices', {}).items():
|
for i, v in o.get('required_choices', {}).items():
|
||||||
self.options_without_help.add(f'--{i}')
|
self.options_without_help.add(f'--{i}')
|
||||||
identifier = self.to_identifier(i, prefix, False)
|
identifier = self.to_identifier(i, prefix, False)
|
||||||
|
@ -316,6 +350,7 @@ class Main:
|
||||||
self.init.append(f'this->ap.addChoices("{i}", '
|
self.init.append(f'this->ap.addChoices("{i}", '
|
||||||
f'p(&ArgParser::{identifier})'
|
f'p(&ArgParser::{identifier})'
|
||||||
f', true, {v}_choices);')
|
f', true, {v}_choices);')
|
||||||
|
add_jdata(i, table_prefix)
|
||||||
for i, v in o.get('optional_choices', {}).items():
|
for i, v in o.get('optional_choices', {}).items():
|
||||||
self.options_without_help.add(f'--{i}')
|
self.options_without_help.add(f'--{i}')
|
||||||
identifier = self.to_identifier(i, prefix, False)
|
identifier = self.to_identifier(i, prefix, False)
|
||||||
|
@ -323,11 +358,13 @@ class Main:
|
||||||
self.init.append(f'this->ap.addChoices("{i}", '
|
self.init.append(f'this->ap.addChoices("{i}", '
|
||||||
f'p(&ArgParser::{identifier})'
|
f'p(&ArgParser::{identifier})'
|
||||||
f', false, {v}_choices);')
|
f', false, {v}_choices);')
|
||||||
|
add_jdata(i, table_prefix)
|
||||||
if table not in ('main', 'help'):
|
if table not in ('main', 'help'):
|
||||||
identifier = self.to_identifier(table, 'argEnd', False)
|
identifier = self.to_identifier(table, 'argEnd', False)
|
||||||
self.decls.append(f'void {identifier}();')
|
self.decls.append(f'void {identifier}();')
|
||||||
for o in data['options']:
|
for o in data['options']:
|
||||||
table = o['table']
|
table = o['table']
|
||||||
|
table_prefix = o.get('prefix', table)
|
||||||
if 'from_table' not in o:
|
if 'from_table' not in o:
|
||||||
continue
|
continue
|
||||||
if table == 'main':
|
if table == 'main':
|
||||||
|
@ -341,6 +378,79 @@ class Main:
|
||||||
for j in ft['options']:
|
for j in ft['options']:
|
||||||
self.init.append('this->ap.copyFromOtherTable'
|
self.init.append('this->ap.copyFromOtherTable'
|
||||||
f'("{j}", "{other_table}");')
|
f'("{j}", "{other_table}");')
|
||||||
|
add_jdata(j, table_prefix)
|
||||||
|
|
||||||
|
def generate_schema(self, data):
|
||||||
|
# XXX check data['json'] against what we know from jdata.
|
||||||
|
# Ultimately be able to generate a schema as well as
|
||||||
|
# JSONHandler and registering stuff.
|
||||||
|
|
||||||
|
# Check to make sure that every command-line option is
|
||||||
|
# represented either in data['json'] or data['no-json'].
|
||||||
|
|
||||||
|
# Build a list of options that we expect. If an option appears
|
||||||
|
# once, we just expect to see it once. If it appears in more
|
||||||
|
# than one options table, we need to see a separate version of
|
||||||
|
# it for each option table. It is represented prepended in
|
||||||
|
# job.yml with the table prefix. The table prefix is removed
|
||||||
|
# in the schema.
|
||||||
|
expected = {}
|
||||||
|
for k, v in self.jdata.items():
|
||||||
|
tables = v['tables']
|
||||||
|
if len(tables) == 1:
|
||||||
|
expected[k] = {**v}
|
||||||
|
else:
|
||||||
|
for t in sorted(tables):
|
||||||
|
expected[f'{t}.{k}'] = {**v}
|
||||||
|
for _, v in expected.items():
|
||||||
|
del v['tables']
|
||||||
|
options_seen = set(data['no-json'])
|
||||||
|
|
||||||
|
self.schema = {}
|
||||||
|
|
||||||
|
def option_to_json_key(s):
|
||||||
|
return self.to_identifier(s, '', False)
|
||||||
|
|
||||||
|
# Walk through the json information building the schema as we
|
||||||
|
# go. This verifies consistency between command-line options
|
||||||
|
# and the json section of the data and builds up a schema by
|
||||||
|
# populating with help information as available.
|
||||||
|
def build_schema(j, s):
|
||||||
|
for k, v in j.items():
|
||||||
|
if not (k in expected or
|
||||||
|
k.startswith('_') or
|
||||||
|
isinstance(v, str)):
|
||||||
|
raise Exception(f'json: unknown key {k}')
|
||||||
|
if k.startswith('_'):
|
||||||
|
schema_key = k[1:]
|
||||||
|
else:
|
||||||
|
schema_key = re.sub(r'[^\.]+\.', '', k)
|
||||||
|
schema_key = option_to_json_key(schema_key)
|
||||||
|
schema_value = v
|
||||||
|
if k in expected:
|
||||||
|
options_seen.add(re.sub('^_', '', k))
|
||||||
|
if v is None:
|
||||||
|
schema_value = re.sub(
|
||||||
|
r'--(\S+)',
|
||||||
|
lambda x: option_to_json_key(x.group(1)),
|
||||||
|
expected[k]['help'])
|
||||||
|
if (isinstance(v, dict)):
|
||||||
|
schema_value = {}
|
||||||
|
build_schema(v, schema_value)
|
||||||
|
elif (isinstance(v, list)):
|
||||||
|
if len(v) != 1:
|
||||||
|
raise Exception('json contains array with length != 1')
|
||||||
|
if isinstance(v[0], dict):
|
||||||
|
schema_value = [{}]
|
||||||
|
build_schema(v[0], schema_value[0])
|
||||||
|
elif schema_value is None:
|
||||||
|
raise Exception(f'unknown schema value for {k}')
|
||||||
|
s[schema_key] = schema_value
|
||||||
|
|
||||||
|
build_schema(data['json'], self.schema)
|
||||||
|
if options_seen != set(expected.keys()):
|
||||||
|
raise Exception('missing from json: ' +
|
||||||
|
str(set(expected.keys()) - options_seen))
|
||||||
|
|
||||||
def check_keys(self, what, d, exp):
|
def check_keys(self, what, d, exp):
|
||||||
if not isinstance(d, dict):
|
if not isinstance(d, dict):
|
||||||
|
@ -351,7 +461,8 @@ class Main:
|
||||||
exit(f'{what}: unknown keys = {extra}')
|
exit(f'{what}: unknown keys = {extra}')
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
self.check_keys('top', data, set(['choices', 'options']))
|
self.check_keys('top', data, set(
|
||||||
|
['choices', 'options', 'no-json', 'json']))
|
||||||
for o in data['options']:
|
for o in data['options']:
|
||||||
self.check_keys('top', o, set(
|
self.check_keys('top', o, set(
|
||||||
['table', 'prefix', 'bare', 'positional',
|
['table', 'prefix', 'bare', 'positional',
|
||||||
|
@ -363,7 +474,10 @@ class Main:
|
||||||
if const:
|
if const:
|
||||||
identifier = f'{prefix}_{identifier.upper()}'
|
identifier = f'{prefix}_{identifier.upper()}'
|
||||||
else:
|
else:
|
||||||
identifier = f'{prefix}_{identifier.lower()}'
|
if prefix:
|
||||||
|
identifier = f'{prefix}_{identifier.lower()}'
|
||||||
|
else:
|
||||||
|
identifier = identifier.lower()
|
||||||
identifier = re.sub(r'_([a-z])',
|
identifier = re.sub(r'_([a-z])',
|
||||||
lambda x: x.group(1).upper(),
|
lambda x: x.group(1).upper(),
|
||||||
identifier).replace('_', '')
|
identifier).replace('_', '')
|
||||||
|
|
5
job.sums
5
job.sums
|
@ -1,8 +1,9 @@
|
||||||
# Generated by generate_auto_job
|
# Generated by generate_auto_job
|
||||||
generate_auto_job b70f64314f1ae1f100fa6a11975dee5f7669038e2a619b6c9da1e5230db1dd1b
|
generate_auto_job 0758b244fc4e2d3e440883072d2740bc4cdb26c5aa8de938f028afd7d83fad79
|
||||||
job.yml 8177cadf41096efdc174f04daadfe5d98c592ad44ad10cb96537521fd79a801a
|
job.yml 2856c2635d42f0a58717d3ffce3125816d8f98ff17245c4b7a0669d70cd68b84
|
||||||
libqpdf/qpdf/auto_job_decl.hh 97395ecbe590b23ae04d6cce2080dbd0e998917ff5eeaa5c6aafa91041d3cd6a
|
libqpdf/qpdf/auto_job_decl.hh 97395ecbe590b23ae04d6cce2080dbd0e998917ff5eeaa5c6aafa91041d3cd6a
|
||||||
libqpdf/qpdf/auto_job_help.hh 2653faaf59415bec81c3a85d426239d52b609ac24faba34ec2d26f00710dd2c6
|
libqpdf/qpdf/auto_job_help.hh 2653faaf59415bec81c3a85d426239d52b609ac24faba34ec2d26f00710dd2c6
|
||||||
libqpdf/qpdf/auto_job_init.hh 465bf46769559ceb77110d1b9d3293ba9b3595850b49848c31aeabd10aadb4ad
|
libqpdf/qpdf/auto_job_init.hh 465bf46769559ceb77110d1b9d3293ba9b3595850b49848c31aeabd10aadb4ad
|
||||||
|
libqpdf/qpdf/auto_job_schema.hh c91a4e182e088797b70dda94af03ca32d360f3564890132da2a8bdc3c4432423
|
||||||
manual/_ext/qpdf.py 855fe12de5af7a10bb24be6ecc4d5dff4c84ac58cf388a13be6bbb394346a67d
|
manual/_ext/qpdf.py 855fe12de5af7a10bb24be6ecc4d5dff4c84ac58cf388a13be6bbb394346a67d
|
||||||
manual/cli.rst b136c7f33a538c580b081a7e802c27635aad2a4229efa0eb0736466116b7aa90
|
manual/cli.rst b136c7f33a538c580b081a7e802c27635aad2a4229efa0eb0736466116b7aa90
|
||||||
|
|
158
job.yml
158
job.yml
|
@ -217,3 +217,161 @@ options:
|
||||||
required_parameter:
|
required_parameter:
|
||||||
prefix: prefix
|
prefix: prefix
|
||||||
password: password
|
password: password
|
||||||
|
no-json:
|
||||||
|
- preserve-unreferenced-resources
|
||||||
|
json:
|
||||||
|
# The structure of this section defines what the json input to
|
||||||
|
# QPDFJob looks like. If a key starts with underscore or has a value
|
||||||
|
# that is a string, it does not map to a command-line argument. If
|
||||||
|
# value is null, its properties and help come from other information
|
||||||
|
# known by generate_auto_job. This information is used to construct
|
||||||
|
# a "schema" (as in JSON.hh) for the json input to QPDFJob. The
|
||||||
|
# leading underscore is removed.
|
||||||
|
_input:
|
||||||
|
_file:
|
||||||
|
_name: "input filename"
|
||||||
|
main.password:
|
||||||
|
password-file:
|
||||||
|
empty:
|
||||||
|
_output:
|
||||||
|
_file:
|
||||||
|
_name: "output filename"
|
||||||
|
replace-input:
|
||||||
|
split-pages:
|
||||||
|
_options:
|
||||||
|
qdf:
|
||||||
|
preserve-unreferenced:
|
||||||
|
newline-before-endstream:
|
||||||
|
normalize-content:
|
||||||
|
stream-data:
|
||||||
|
compress-streams:
|
||||||
|
recompress-flate:
|
||||||
|
decode-level:
|
||||||
|
decrypt:
|
||||||
|
static-aes-iv:
|
||||||
|
static-id:
|
||||||
|
no-original-object-ids:
|
||||||
|
copy-encryption:
|
||||||
|
encryption-file-password:
|
||||||
|
linearize:
|
||||||
|
linearize-pass1:
|
||||||
|
object-streams:
|
||||||
|
min-version:
|
||||||
|
force-version:
|
||||||
|
progress:
|
||||||
|
encrypt:
|
||||||
|
user-password: "user password"
|
||||||
|
owner-password: "owner password"
|
||||||
|
key-length: "key length: 48, 128, 256"
|
||||||
|
_40-bit:
|
||||||
|
Enc40.annotate:
|
||||||
|
Enc40.extract:
|
||||||
|
Enc40.modify:
|
||||||
|
Enc40.print:
|
||||||
|
_128-bit:
|
||||||
|
Enc128.accessibility:
|
||||||
|
Enc128.annotate:
|
||||||
|
Enc128.assemble:
|
||||||
|
Enc128.cleartext-metadata:
|
||||||
|
Enc128.extract:
|
||||||
|
Enc128.form:
|
||||||
|
Enc128.modify-other:
|
||||||
|
Enc128.modify:
|
||||||
|
Enc128.print:
|
||||||
|
force-V4:
|
||||||
|
use-aes:
|
||||||
|
_256-bit:
|
||||||
|
Enc256.accessibility:
|
||||||
|
Enc256.annotate:
|
||||||
|
Enc256.assemble:
|
||||||
|
Enc256.cleartext-metadata:
|
||||||
|
Enc256.extract:
|
||||||
|
Enc256.form:
|
||||||
|
Enc256.modify-other:
|
||||||
|
Enc256.modify:
|
||||||
|
Enc256.print:
|
||||||
|
allow-insecure:
|
||||||
|
force-R5:
|
||||||
|
_options:
|
||||||
|
allow-weak-crypto:
|
||||||
|
deterministic-id:
|
||||||
|
keep-files-open:
|
||||||
|
keep-files-open-threshold:
|
||||||
|
no-warn:
|
||||||
|
verbose:
|
||||||
|
warning-exit-0:
|
||||||
|
ignore-xref-streams:
|
||||||
|
password-is-hex-key:
|
||||||
|
password-mode:
|
||||||
|
suppress-password-recovery:
|
||||||
|
suppress-recovery:
|
||||||
|
_inspect:
|
||||||
|
check:
|
||||||
|
check-linearization:
|
||||||
|
filtered-stream-data:
|
||||||
|
is-encrypted:
|
||||||
|
raw-stream-data:
|
||||||
|
requires-password:
|
||||||
|
show-encryption:
|
||||||
|
show-encryption-key:
|
||||||
|
show-linearization:
|
||||||
|
show-npages:
|
||||||
|
show-object:
|
||||||
|
show-pages:
|
||||||
|
show-xref:
|
||||||
|
with-images:
|
||||||
|
list-attachments:
|
||||||
|
show-attachment:
|
||||||
|
json:
|
||||||
|
json-key:
|
||||||
|
- null
|
||||||
|
json-object:
|
||||||
|
- null
|
||||||
|
_transform:
|
||||||
|
coalesce-contents:
|
||||||
|
compression-level:
|
||||||
|
externalize-inline-images:
|
||||||
|
ii-min-bytes:
|
||||||
|
remove-unreferenced-resources:
|
||||||
|
_modify:
|
||||||
|
add-attachment:
|
||||||
|
- file: "attachment to add"
|
||||||
|
creationdate:
|
||||||
|
description:
|
||||||
|
filename:
|
||||||
|
key:
|
||||||
|
mimetype:
|
||||||
|
moddate:
|
||||||
|
replace:
|
||||||
|
remove-attachment:
|
||||||
|
copy-attachments-from:
|
||||||
|
- file: "attachment source filename"
|
||||||
|
CopyAtt.password:
|
||||||
|
prefix:
|
||||||
|
collate:
|
||||||
|
flatten-annotations:
|
||||||
|
flatten-rotation:
|
||||||
|
generate-appearances:
|
||||||
|
keep-inline-images:
|
||||||
|
oi-min-area:
|
||||||
|
oi-min-height:
|
||||||
|
oi-min-width:
|
||||||
|
optimize-images:
|
||||||
|
pages:
|
||||||
|
- file: "source for for pages"
|
||||||
|
Pages.password:
|
||||||
|
range: "page range"
|
||||||
|
remove-page-labels:
|
||||||
|
rotate:
|
||||||
|
overlay:
|
||||||
|
file: "source file for overlay"
|
||||||
|
UO.password:
|
||||||
|
from:
|
||||||
|
repeat:
|
||||||
|
to:
|
||||||
|
underlay:
|
||||||
|
file: "source file for underlay"
|
||||||
|
UO.password:
|
||||||
|
from:
|
||||||
|
repeat:
|
||||||
|
to:
|
||||||
|
|
176
libqpdf/qpdf/auto_job_schema.hh
Normal file
176
libqpdf/qpdf/auto_job_schema.hh
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
static constexpr char const* JOB_SCHEMA_DATA = R"({
|
||||||
|
"input": {
|
||||||
|
"file": {
|
||||||
|
"name": "input filename",
|
||||||
|
"password": "specify password",
|
||||||
|
"passwordFile": "read password from a file"
|
||||||
|
},
|
||||||
|
"empty": "empty input file"
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"file": {
|
||||||
|
"name": "output filename"
|
||||||
|
},
|
||||||
|
"replaceInput": "replace input with output",
|
||||||
|
"splitPages": "write pages to separate files",
|
||||||
|
"options": {
|
||||||
|
"qdf": "enable viewing PDF code in a text editor",
|
||||||
|
"preserveUnreferenced": "preserve unreferenced objects",
|
||||||
|
"newlineBeforeEndstream": "force a newline before endstream",
|
||||||
|
"normalizeContent": "fix newlines in content streams",
|
||||||
|
"streamData": "control stream compression",
|
||||||
|
"compressStreams": "compress uncompressed streams",
|
||||||
|
"recompressFlate": "uncompress and recompress flate",
|
||||||
|
"decodeLevel": "control which streams to uncompress",
|
||||||
|
"decrypt": "remove encryption from input file",
|
||||||
|
"staticAesIv": "use a fixed AES vector",
|
||||||
|
"staticId": "use a fixed document ID",
|
||||||
|
"noOriginalObjectIds": "omit original object ID in qdf",
|
||||||
|
"copyEncryption": "copy another file's encryption details",
|
||||||
|
"encryptionFilePassword": "supply password for copyEncryption",
|
||||||
|
"linearize": "linearize (web-optimize) output",
|
||||||
|
"linearizePass1": "save pass 1 of linearization",
|
||||||
|
"objectStreams": "control use of object streams",
|
||||||
|
"minVersion": "set minimum PDF version",
|
||||||
|
"forceVersion": "set output PDF version",
|
||||||
|
"progress": "show progress when writing",
|
||||||
|
"encrypt": {
|
||||||
|
"userPassword": "user password",
|
||||||
|
"ownerPassword": "owner password",
|
||||||
|
"keyLength": "key length: 48, 128, 256",
|
||||||
|
"40Bit": {
|
||||||
|
"annotate": "restrict document annotation",
|
||||||
|
"extract": "restrict text/graphic extraction",
|
||||||
|
"modify": "restrict document modification",
|
||||||
|
"print": "restrict printing"
|
||||||
|
},
|
||||||
|
"128Bit": {
|
||||||
|
"accessibility": "restrict document accessibility",
|
||||||
|
"annotate": "restrict document annotation",
|
||||||
|
"assemble": "restrict document assembly",
|
||||||
|
"cleartextMetadata": "don't encrypt metadata",
|
||||||
|
"extract": "restrict text/graphic extraction",
|
||||||
|
"form": "restrict form filling",
|
||||||
|
"modifyOther": "restrict other modifications",
|
||||||
|
"modify": "restrict document modification",
|
||||||
|
"print": "restrict printing",
|
||||||
|
"forceV4": "force V=4 in encryption dictionary",
|
||||||
|
"useAes": "use AES with 128-bit encryption"
|
||||||
|
},
|
||||||
|
"256Bit": {
|
||||||
|
"accessibility": "restrict document accessibility",
|
||||||
|
"annotate": "restrict document annotation",
|
||||||
|
"assemble": "restrict document assembly",
|
||||||
|
"cleartextMetadata": "don't encrypt metadata",
|
||||||
|
"extract": "restrict text/graphic extraction",
|
||||||
|
"form": "restrict form filling",
|
||||||
|
"modifyOther": "restrict other modifications",
|
||||||
|
"modify": "restrict document modification",
|
||||||
|
"print": "restrict printing",
|
||||||
|
"allowInsecure": "allow empty owner passwords",
|
||||||
|
"forceR5": "use unsupported R=5 encryption"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"allowWeakCrypto": "allow insecure cryptographic algorithms",
|
||||||
|
"deterministicId": "generate ID deterministically",
|
||||||
|
"keepFilesOpen": "manage keeping multiple files open",
|
||||||
|
"keepFilesOpenThreshold": "set threshold for keepFilesOpen",
|
||||||
|
"noWarn": "suppress printing warning messages",
|
||||||
|
"verbose": "print additional information",
|
||||||
|
"warningExit0": "exit 0 even with warnings",
|
||||||
|
"ignoreXrefStreams": "use xref tables rather than streams",
|
||||||
|
"passwordIsHexKey": "provide hex-encoded encryption key",
|
||||||
|
"passwordMode": "tweak how qpdf encodes passwords",
|
||||||
|
"suppressPasswordRecovery": "don't try different password encodings",
|
||||||
|
"suppressRecovery": "suppress error recovery"
|
||||||
|
},
|
||||||
|
"inspect": {
|
||||||
|
"check": "partially check whether PDF is valid",
|
||||||
|
"checkLinearization": "check linearization tables",
|
||||||
|
"filteredStreamData": "show filtered stream data",
|
||||||
|
"isEncrypted": "silently test whether a file is encrypted",
|
||||||
|
"rawStreamData": "show raw stream data",
|
||||||
|
"requiresPassword": "silently test a file's password",
|
||||||
|
"showEncryption": "information about encrypted files",
|
||||||
|
"showEncryptionKey": "show key with showEncryption",
|
||||||
|
"showLinearization": "show linearization hint tables",
|
||||||
|
"showNpages": "show number of pages",
|
||||||
|
"showObject": "show contents of an object",
|
||||||
|
"showPages": "display page dictionary information",
|
||||||
|
"showXref": "show cross reference data",
|
||||||
|
"withImages": "include image details with showPages",
|
||||||
|
"listAttachments": "list embedded files",
|
||||||
|
"showAttachment": "export an embedded file",
|
||||||
|
"json": "show file in json format",
|
||||||
|
"jsonKey": [
|
||||||
|
null
|
||||||
|
],
|
||||||
|
"jsonObject": [
|
||||||
|
null
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"coalesceContents": "combine content streams",
|
||||||
|
"compressionLevel": "set compression level for flate",
|
||||||
|
"externalizeInlineImages": "convert inline to regular images",
|
||||||
|
"iiMinBytes": "set minimum size for externalizeInlineImages",
|
||||||
|
"removeUnreferencedResources": "remove unreferenced page resources"
|
||||||
|
},
|
||||||
|
"modify": {
|
||||||
|
"addAttachment": [
|
||||||
|
{
|
||||||
|
"file": "attachment to add",
|
||||||
|
"creationdate": "set attachment's creation date",
|
||||||
|
"description": "set attachment's description",
|
||||||
|
"filename": "set attachment's displayed filename",
|
||||||
|
"key": "specify attachment key",
|
||||||
|
"mimetype": "attachment mime type, e.g. application/pdf",
|
||||||
|
"moddate": "set attachment's modification date",
|
||||||
|
"replace": "replace attachment with same key"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"removeAttachment": "remove an embedded file",
|
||||||
|
"copyAttachmentsFrom": [
|
||||||
|
{
|
||||||
|
"file": "attachment source filename",
|
||||||
|
"password": "specify password",
|
||||||
|
"prefix": "key prefix for copying attachments"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"collate": "collate with pages",
|
||||||
|
"flattenAnnotations": "push annotations into content",
|
||||||
|
"flattenRotation": "remove rotation from page dictionary",
|
||||||
|
"generateAppearances": "generate appearances for form fields",
|
||||||
|
"keepInlineImages": "exclude inline images from optimization",
|
||||||
|
"oiMinArea": "minimum area for optimizeImages",
|
||||||
|
"oiMinHeight": "minimum height for optimizeImages",
|
||||||
|
"oiMinWidth": "minimum width for optimizeImages",
|
||||||
|
"optimizeImages": "use efficient compression for images",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"file": "source for for pages",
|
||||||
|
"password": "specify password",
|
||||||
|
"range": "page range"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"removePageLabels": "remove explicit page numbers",
|
||||||
|
"rotate": "rotate pages",
|
||||||
|
"overlay": {
|
||||||
|
"file": "source file for overlay",
|
||||||
|
"password": "specify password",
|
||||||
|
"from": "source pages for underlay/overlay",
|
||||||
|
"repeat": "overlay/underlay pages to repeat",
|
||||||
|
"to": "destination pages for underlay/overlay"
|
||||||
|
},
|
||||||
|
"underlay": {
|
||||||
|
"file": "source file for underlay",
|
||||||
|
"password": "specify password",
|
||||||
|
"from": "source pages for underlay/overlay",
|
||||||
|
"repeat": "overlay/underlay pages to repeat",
|
||||||
|
"to": "destination pages for underlay/overlay"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})";
|
Loading…
Reference in New Issue
Block a user