pd4coscli Reference
Available starting from PD4ML v4.1.1

A command-line tool for com.pd4ml.pdf.cos alone: structural inspection, COS-path queries, object listing, page-tree walking, and stream extraction - plus single-key edits applied as a PDF incremental update. No dependency on com.pd4ml.pdf.sign.

Class com.pd4ml.pdf.cos.cli.CosCli Commands inspect · list · pages · dump · set · delete

1. Invocation

java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli <command> [args...]

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

Six commands: inspect, list, pages, dump, set, delete. Flags use --key=value syntax; a flag with no =value (e.g. --raw) is a boolean switch, true by its mere presence. There is no short-flag form.

Exit codes

0

Success.

1

The operation failed for a business/runtime reason - bad password, malformed PDF, an unresolvable COS path, an out-of-range index, an attempt to edit a non-indirect object… The message on stderr explains why.

2

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

↑ Back to top

2. inspect structural summary + COS-path queries

pd4coscli inspect <input.pdf> [--password=...] [cos-path-expr ...]

Parses input.pdf with com.pd4ml.pdf.cos.parser.COSParser and prints:

  • PDF version
  • indirect object count
  • whether the document is encrypted (and, if so, whether the given/empty password was accepted)
  • page count (/Root/Pages/Count)
  • whether an /AcroForm is present

Each trailing positional argument is evaluated as a COS path expression:

RootStarts at
(none), /..., trailer/...the document trailer dictionary
Root/... or catalog/...shorthand for trailer/Root/...
N G R/...an explicit indirect object N G R
StepMeaning
/Name or bare Namelook up a key in the current dictionary/stream node
[N] or a bare integer Nindex into the current array node
N G Rjump directly to an indirect object, ignoring the current node

A name may contain \//\[/\\ escapes and #xx hex escapes. Indirect references are followed transparently at every step. A stream value's decoded bytes (or raw bytes, if the filter chain isn't fully understood) are previewed, truncated to 200 characters - use dump to extract the full, untruncated bytes.

--password=<pw>
Tried as both the user and owner password if the PDF is encrypted; omit for an empty password.

Examples

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli inspect report.pdf
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli inspect report.pdf "/Root/Pages/Count" "/Root/Pages/Kids[0]/MediaBox"
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli inspect protected.pdf --password=secret "trailer/Size"
↑ Back to top

3. list enumerate every indirect object

pd4coscli list <input.pdf> [--password=...] [--type=<Name>]

Prints one line per indirect object: its object number/generation, the resolved Java class (COSDictionary/COSArray/COSStream/...), and - for a dictionary or stream - its /Type and /Subtype if present. A stream also shows its raw (still-encoded) byte count. A summary line reports how many objects were printed out of the document's total.

--type=<Name>
filters to dictionaries/streams whose /Type exactly equals <Name> (e.g. Page, Font, XObject).

Example

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli list report.pdf
1 0 obj  COSDictionary  /Type=/Catalog
2 0 obj  COSDictionary  /Type=/Pages
3 0 obj  COSDictionary  /Type=/Page
4 0 obj  COSStream  (40 raw bytes)
5 0 obj  COSDictionary  /Type=/Font  /Subtype=/Type1

5 objects listed out of 5 total.

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli list report.pdf --type=Page
3 0 obj  COSDictionary  /Type=/Page

1 object listed (filtered to /Type=/Page) out of 5 total.
↑ Back to top

4. pages walk the page tree

pd4coscli pages <input.pdf> [--password=...]

For each page 0..Count-1 (via com.pd4ml.pdf.cos.util.PageTree), prints its own object reference (or (inline, no object number) if it has none), its /MediaBox, its /Rotate (default 0), and whether /Resources is set directly on the page dictionary (own) or inherited from an ancestor (inherited). Prints (no usable page tree found) rather than an error if the catalog or /Pages is missing or malformed.

Example

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli pages report.pdf
page 0: 3 0 R  MediaBox=[0 0 612 792]  Rotate=0  Resources=own
page 1: 7 0 R  MediaBox=[0 0 612 792]  Rotate=90  Resources=inherited
↑ Back to top

5. dump extract a stream's bytes, or print any node's PDF syntax

pd4coscli dump <input.pdf> <cos-path> [--password=...] [--out=<file>] [--raw]

Evaluates <cos-path> strictly - an unresolvable path is a runtime error (exit 1), never silent empty output. If the result is a stream, writes its decoded bytes by default, or its raw, still-encoded bytes with --raw; if the filter chain isn't fully understood, a note on stderr explains the fallback to raw bytes even without --raw. If the result is anything else, prints its PDF-syntax representation.

Without --out=<file>, the bytes go straight to stdout; with it, they're written to that file and a byte count is printed instead.

Examples

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli dump report.pdf "/Root/Pages/Kids[0]/Contents" > page0-content.txt
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli dump report.pdf "/Root/Pages/Kids[0]/Resources/XObject/Im0" --raw --out=image0.raw
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli dump report.pdf "/Root/Pages/Kids[0]"
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>
↑ Back to top

6. set change one dictionary key or array element

pd4coscli set <input.pdf> <output.pdf> <parent-cos-path> <key> <value> [--password=...] [--type=string|name|int|float|bool]

Resolves <parent-cos-path>, applies the edit to that resolved node directly, then appends a PDF incremental update (com.pd4ml.pdf.cos.writer.IncrementalUpdateWriter) containing just the rewritten object, and writes the result to <output.pdf> - the same mechanism pd4signcli sign/ltv use to append a signature or /DSS, just for an arbitrary key instead. The original bytes are never modified.

Must be an indirect object

<parent-cos-path> must resolve to an indirect (independently object-numbered) COSDictionary or COSArray - one with its own N G obj. A node embedded inline inside its parent (no object number of its own - common for small arrays like /MediaBox, sometimes /Kids) can't be independently rewritten this way; pd4coscli reports this plainly rather than doing nothing silently. Use list to see which objects are indirect, and inspect/dump to check a path first.

<key> is a dictionary key name (added if new, overwritten if present) when the parent is a dictionary; an integer array index when the parent is an array - an existing index (0..size-1) replaces that element, and exactly size appends a new one.

Value types

--typeProducesExample value
string (default)COSString"Approved by QA"
nameCOSNameApproved (becomes /Approved)
intCOSInteger90
floatCOSFloat1.5
boolCOSBooleantrue

Examples

# rotate a page 90 degrees
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli set report.pdf out.pdf "/Root/Pages/Kids[0]" Rotate 90 --type=int

# add a custom flag to the catalog
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli set report.pdf out.pdf "/Root" CustomFlag true --type=bool

# append to an indirect array (size 3 -> index 3 appends)
$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli set report.pdf out.pdf "/Root/Pages/Kids[0]/Extra" 3 "D"
↑ Back to top

7. delete remove one dictionary key or array element

pd4coscli delete <input.pdf> <output.pdf> <parent-cos-path> <key> [--password=...]

Same <parent-cos-path> requirement as set. <key> is a dictionary key name - it must already be present; deleting an absent key is a runtime error (exit 1), not a silent no-op - or an array index, which must be in range (0..size-1).

Example

$ java -cp pd4ml.jar com.pd4ml.pdf.cos.cli.CosCli delete report.pdf out.pdf "/Root/Info" Keywords
↑ Back to top

8. Troubleshooting

"'<path>' is not an indirect object (no object number)..."

The target of a set/delete is embedded inline inside its parent rather than being its own N G obj. Pick a path to an indirect ancestor instead (a Page, the Catalog, an indirect Resources dictionary, ...); list shows which objects actually have their own object number.

"Index N out of range for an array of size M"

Array indices for set run 0..size (size appends); for delete, 0..size-1.

"Key '<key>' not present at <path>"

delete targeted a key that isn't there. Run inspect/dump on the parent path to see what actually exists.

"Could not resolve '<path>': ..."

The COS path expression itself doesn't exist in this document (a missing key, an out-of-range index, or a step applied to the wrong kind of node) - the message names exactly which step failed.

Encryption / signing / verification

pd4coscli reads an encrypted PDF transparently once given the right password, but has no support for writing a re-encrypted or decrypted copy - set/delete refuse encrypted input for that reason. Digital signing, timestamping, DocMDP certification, and PAdES-LT/LTV are entirely out of scope for pd4coscli - see the pd4signcli Reference for all of that.

Merging, cleanup, or annotations/form values

pd4coscli only edits one document's COS objects directly; for combining page ranges from several PDFs, see the pd4mergecli Reference. For reachability/duplicate-content cleanup, see the pd4optimizecli Reference. For importing or exporting annotations and form field values via XFDF, see the pd4xfdfcli Reference.

↑ Back to top

9. See also

↑ Back to top