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.
1. Invocation
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
Success.
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.
Usage error - missing/invalid arguments or flags. Usage text is printed to stderr alongside the message.
2. inspect structural summary + COS-path queries
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
/AcroFormis present
Each trailing positional argument is evaluated as a COS path expression:
| Root | Starts at |
|---|---|
(none), /..., trailer/... | the document trailer dictionary |
Root/... or catalog/... | shorthand for trailer/Root/... |
N G R/... | an explicit indirect object N G R |
| Step | Meaning |
|---|---|
/Name or bare Name | look up a key in the current dictionary/stream node |
[N] or a bare integer N | index into the current array node |
N G R | jump 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
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
/Typeexactly 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
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
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
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.
<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
--type | Produces | Example value |
|---|---|---|
string (default) | COSString | "Approved by QA" |
name | COSName | Approved (becomes /Approved) |
int | COSInteger | 90 |
float | COSFloat | 1.5 |
bool | COSBoolean | true |
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
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
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.
Array indices for set run 0..size (size appends); for
delete, 0..size-1.
delete targeted a key that isn't there. Run inspect/dump on
the parent path to see what actually exists.
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.
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.
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.
9. See also
- PD4ML COS API Manual - the programmer's manual behind this CLI (object model, COS-path grammar, the writer, filters, encryption reading)
- PD4ML COS Examples - runnable
com.pd4ml.pdf.cosuse-case examples - pd4signcli Reference - digital
signing, timestamping, DocMDP certification, and PAdES-LT/LTV, built on the same
com.pd4ml.pdf.cosfoundation - pd4mergecli Reference - combining page ranges from two or more PDFs
- pd4optimizecli Reference - cleaning up unreferenced objects and incremental-update history
- pd4xfdfcli Reference - importing or exporting annotations and form field values via XFDF
