# pd4optimizecli Reference

_Available starting from PD4ML v4.1.1_

Command-line front end for [`com.pd4ml.pdf.optimizer`](https://pd4ml.com/javadoc/com/pd4ml/pdf/optimizer/package-summary.html): 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 cross-reference section - no code to write.

**Main-Class:** [`com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli`](https://pd4ml.com/javadoc/com/pd4ml/pdf/optimizer/cli/Pd4OptimizeCli.html)

## 1. Invocation

```
java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli [flags...]
```

Throughout this document, `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`](https://pd4ml.com/javadoc/com/pd4ml/tools/Pd4Cmd.html), 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

| Code | Meaning                                                                                                                             |
| ---- | --------------------------------------------------------------------------------------------------------------------------------- |
| `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.                                         |

## 2. Flags

### Input

| Flag              | Notes                                                                                      |
| ----------------- | -------------------------------------------------------------------------------------------- |
| `--in=<file.pdf>` | required                                                                                   |
| `--password=<pw>` | if the input is encrypted (tried as user _and_ owner password; omit for an empty password) |

### Output

| Flag                 | Notes    |
| -------------------- | -------- |
| `--out=<output.pdf>` | required |

### Duplicate-content dedup - optional

| Flag         | Notes                                                                                            |
| ------------ | -------------------------------------------------------------------------------------------------- |
| `--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 API manual's §3.2). Pass `--no-dedup` to skip the extra content-hashing pass and keep only the reachability cleanup.

### Output encryption - optional

| Flag                                      | Notes                                                                         |
| -------------------------------------------- | ---------------------------------------------------------------------------------- |
| `--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.

### Linearized output - optional

| Flag          | Notes |
| ------------- | ----- |
| `--linearize` | write the output linearized ("Fast Web View"); _from v4.2.0_ |

A viewer that loads a linearized file over a network shows the first page, and then any other page, before the whole file has arrived (see the API manual's §6). `--linearize` cannot be combined with output encryption: together with any `--encrypt-*` or `--permissions` flag it is a usage error (exit code `2`). An encrypted input is fine with `--password`: the output is written linearized and plain.

## 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))
```

Write the output linearized, for viewing over the web:

```
$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli --in=report.pdf --out=report-web.pdf --linearize
```

The report line then ends with `, linearized`.

Skip the dedup pass:

```
$ java -cp pd4ml.jar com.pd4ml.pdf.optimizer.cli.Pd4OptimizeCli --in=bloated.pdf --out=cleaned.pdf --no-dedup
```

## 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."--linearize cannot be combined with --encrypt-user/--encrypt-owner/--encrypt-alg/--permissions" A linearized file cannot be encrypted: drop one of the two."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. A PDF 1.5 or later input is written in the compact layout (object streams and a cross-reference stream, from v4.2.0); a PDF 1.4 input, encrypted output and `--linearize` use the classic layout, every object on its own, which is larger when the input packed its objects into object streams. Streams themselves are never recompressed, and dedup only catches objects that are byte-for-byte identical, not merely similar (see the API manual's §7, "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**](../pd4ml-pdf-merge/pd4mergecli-reference) ([`com.pd4ml.pdf.merge.cli.Pd4MergeCli`](https://pd4ml.com/javadoc/com/pd4ml/pdf/merge/cli/Pd4MergeCli.html)). For arbitrary dictionary/array edits or COS-path queries, see the [**pd4coscli Reference**](../pd4ml-pdf-cos/pd4coscli-reference) ([`com.pd4ml.pdf.cos.cli.CosCli`](https://pd4ml.com/javadoc/com/pd4ml/pdf/cos/cli/CosCli.html)). 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](../pd4ml-pdf-xfdf/pd4xfdfcli-reference) ([`com.pd4ml.pdf.xfdf.cli.Pd4XfdfCli`](https://pd4ml.com/javadoc/com/pd4ml/pdf/xfdf/cli/Pd4XfdfCli.html)).
