Available starting from PD4ML v4.1.1

Drop objects no longer reachable from a PDF's /Root//Info (typically left behind by an earlier incremental update) and collapse its cross-reference/trailer history into one fresh table - no code to write.

Main-Class com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli Commands one operation, no subcommands

1. Invocation

java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli [flags...]

Throughout this reference, pd4ml.jar stands for the pd4ml library jar (present in the current directory in every example below) - com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli isn't pd4ml.jar's own Main-Class (that's com.pd4ml.tools.Pd4Cmd, a different tool), so invoke it with -cp, not -jar. Running with no arguments, or help/--help/-h as the first argument, prints the same usage summary this page expands on.

There is exactly one operation (no subcommands, no page selection - the whole document is always cleaned). All flags use --key=value syntax; there is no short-flag form.

Exit codes

0

Success.

1

The operation failed for a business/runtime reason - bad password, malformed PDF, no /Root… The message on stderr explains why.

2

Usage error - missing/invalid flags. Usage text is printed to stderr alongside the message.

↑ Back to top

2. Flags

Input

--in=<file.pdf>
required
--password=<pw>
if the input is encrypted (tried as user and owner password; omit for an empty password)

Output

--out=<output.pdf>
required

Duplicate-content dedup optional

--no-dedup
skip merging byte-identical duplicate objects (e.g. the same font embedded twice); on by default

Byte-identical duplicate objects reachable after the unreferenced-object cleanup - typically the same font, image, or color space embedded twice under two different object numbers - are merged into one shared copy by default. /Type /Page//Type /Annot dictionaries and interactive form fields are never merged this way even if byte-identical (see the PD4ML PDF Optimizer Manual's §3.2). Pass --no-dedup to skip the extra content-hashing pass and keep only the reachability cleanup.

Output encryption optional

--encrypt-user=<pw>
open (user) password for the optimized output
--encrypt-owner=<pw>
owner password for the optimized output
--encrypt-alg=RC4_128|AES_128|AES_256
default AES_256 when any encrypt-* flag is given
--permissions=<int>
raw /P permission bits (ISO 32000-1 Table 22); default "everything allowed"

Giving any --encrypt-user/--encrypt-owner/--encrypt-alg/ --permissions flag turns on output encryption; the output otherwise stays plain even if the input was encrypted (see the callout below).

Encrypted input, plain output by default

/Encrypt lives only in the input's trailer, not under /Root - the reachability walk that drops unreferenced objects drops the old /Encrypt dictionary right along with everything else unreachable. Optimizing an encrypted PDF with no --encrypt-* flag therefore produces a plain, unencrypted output, not a re-encrypted one.

↑ Back to top

3. Examples

Clean a PDF that's accumulated incremental-update cruft:

$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli --in=bloated.pdf --out=cleaned.pdf

Optimize an encrypted input (output stays plain):

$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli --in=protected.pdf --password=secret --out=cleaned.pdf

Optimize and re-encrypt the output:

$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli \
      --in=A.pdf --out=cleaned-locked.pdf \
      --encrypt-user=open123 --encrypt-owner=owner456 --encrypt-alg=AES_256

A successful run reports what it did, including how many of the removed objects were merged as duplicate content specifically:

Optimized bloated.pdf -> cleaned.pdf (1070 -> 594 bytes, 2 object(s) removed out of 7 (1 of them duplicate content merged))

Skip the dedup pass:

$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli --in=bloated.pdf --out=cleaned.pdf --no-dedup
↑ Back to top

4. Troubleshooting

"is encrypted and the given password (or no password) did not open it"

Add --password=<pw> (either the input's user or owner password authenticates), or double-check the one given.

"Input PDF has no /Root in its trailer; nothing to optimize"

The file is malformed or not actually a PDF - there's no Catalog reference to walk from.

"0 object(s) removed" every time

Not a bug - a document with no incremental-update history (or one whose every incremental update only ever added things still referenced today) and no duplicate content genuinely has nothing to clean up. The trailer/xref history is still collapsed to one fresh table either way, even when the object count doesn't change; compare --in's and --out's byte sizes if you want to confirm that part happened.

Expecting a smaller file, but it barely shrank (or grew)

pd4optimizecli removes unreferenced objects, merges byte-identical duplicate objects (unless --no-dedup was given), and collapses trailer history - but it does not recompress streams, and dedup only catches objects that are byte-for-byte identical, not merely similar (see the PD4ML PDF Optimizer Manual's §6, "Not optimized"). A small, already-clean input, or one whose bloat is inside large already-compressed streams rather than unreferenced/duplicate objects, won't shrink much. Output encryption (if requested) also adds a modest amount of overhead (an /Encrypt dictionary plus per-object IV padding).

Structural editing, merging, or general COS work

pd4optimizecli only cleans a single document; for combining page ranges from several PDFs, see the pd4mergecli Reference (com.pd4ml.pdf.merge.cli.Pd4MergeCli). For arbitrary dictionary/array edits or COS-path queries, see the pd4coscli Reference (com.pd4ml.pdf.cos.cli.CosCli). For importing or exporting annotations and form field values via XFDF (which can itself call this same cleanup via its own --optimize flag), see the pd4xfdfcli Reference (com.pd4ml.pdf.xfdf.cli.Pd4XfdfCli).

↑ Back to top

5. See also

↑ Back to top
PD4ML PDF Optimizer CLI · Java 1.8 · com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli · no third-party PDF dependency