# Pdfium Impl Document Features

> Use when reading PDF document metadata (title, author, dates), extracting or creating embedded file attachments, inspecting permission flags, or reading digital signatures with pdfium-render. Prevents guessing wrong permission method names, expecting metadata or signature write APIs that do not exist, deleting attachments by ascending index, and treating permission flags as enforcement. Covers PdfMetadata, PdfAttachments, PdfPermissions, PdfSignatures, the read-only-versus-writable asymmetry, and the 0.5.1 to 0.9.x version history. Keywords: pdfium-render metadata, PDF title author, PdfMetadata, get PdfDocumentMetadataTagType, PDF attachments, embedded files, PdfAttachments, create_attachment_from_bytes, delete_at_index, extract attachment, PDF permissions, PdfPermissions, can_print_high_quality, can_modify_document_content, digital signature, PdfSignatures, PdfSignature, signing_date, read PDF metadata in Rust, how do I get the PDF author, is this PDF signed

- Skill: `impertio-studio/pdfium-impl-document-features` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add impertio-studio/pdfium-impl-document-features`
- Raw SKILL.md: https://api.skillmd.com/api/skills/impertio-studio/pdfium-impl-document-features/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- License: MIT
- Author: Impertio-Studio (https://skillmd.com/u/impertio-studio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/impertio-studio/pdfium-impl-document-features

---


# pdfium-impl-document-features

Work with the four document-level feature collections in pdfium-render:
metadata, embedded attachments, permission flags, and digital signatures. Each
hangs off a `PdfDocument` handle.

Scope: document-level features. For page content see `pdfium-syntax-pages` and
`pdfium-impl-page-objects-edit`. For bookmarks, links, and destinations see
`pdfium-impl-navigation`. For saving edits see `pdfium-impl-saving`.

Default API surface is 0.9.x. All four collections predate 0.8.x and are fully
available in both the 0.8.x and 0.9.x lines.

## The one rule that dominates this area

Three of the four collections are READ-ONLY. Only attachments can be written.

| Collection | Accessor | Writable? |
|------------|----------|-----------|
| Metadata | `document.metadata()` | NO. Read-only, no setters. |
| Attachments | `document.attachments()` / `attachments_mut()` | YES. Create and delete. |
| Permissions | `document.permissions()` | NO. Read-only. |
| Signatures | `document.signatures()` | NO. Read existing only. |

ONLY attachments has a `_mut()` accessor. There is no `metadata_mut()`,
`permissions_mut()`, or `signatures_mut()`. pdfium-render does not write
metadata, does not change permissions, and does not create signatures.

## Quick Reference

### Metadata

| Goal | Call | Returns |
|------|------|---------|
| Count tags | `metadata.len()` | `usize` |
| Read one tag | `metadata.get(PdfDocumentMetadataTagType::Title)` | `Option<PdfDocumentMetadataTag>` |
| Read all tags | `metadata.iter()` | iterator of `PdfDocumentMetadataTag` |
| Tag kind | `tag.tag_type()` | `PdfDocumentMetadataTagType` |
| Tag string | `tag.value()` | `&str` |

`PdfDocumentMetadataTagType` has exactly eight variants: `Title`, `Author`,
`Subject`, `Keywords`, `Creator`, `Producer`, `CreationDate`,
`ModificationDate`. There is NO `Trapped` variant. `get()` returns `None` when
a tag is absent.

### Attachments

| Goal | Call | Returns |
|------|------|---------|
| Count | `attachments.len()` | `PdfAttachmentIndex` |
| Get one | `attachments.get(index)` | `Result<PdfAttachment, PdfiumError>` |
| Iterate | `attachments.iter()` | iterator of `PdfAttachment` |
| Create from bytes | `attachments_mut().create_attachment_from_bytes(name, &[u8])` | `Result<PdfAttachment, PdfiumError>` |
| Create from file | `attachments_mut().create_attachment_from_file(name, path)` | `Result<PdfAttachment, PdfiumError>` |
| Create from reader | `attachments_mut().create_attachment_from_reader(name, reader)` | `Result<PdfAttachment, PdfiumError>` |
| Delete | `attachments_mut().delete_at_index(index)` | `Result<(), PdfiumError>` |
| Attachment name | `attachment.name()` | `String` |
| Attachment size | `attachment.len()` | `usize` |
| Extract to memory | `attachment.save_to_bytes()` | `Result<Vec<u8>, PdfiumError>` |
| Extract to disk | `attachment.save_to_file(path)` | `Result<(), PdfiumError>` |

### Permissions

Every getter returns `Result<bool, PdfiumError>` (or
`Result<PdfSecurityHandlerRevision, PdfiumError>` for the revision).

```
security_handler_revision    can_print_high_quality
can_print_only_low_quality   can_assemble_document
can_modify_document_content  can_extract_text_and_graphics
can_fill_existing_interactive_form_fields
can_create_new_interactive_form_fields
can_add_or_modify_text_annotations
```

`PdfSecurityHandlerRevision` has four variants: `Unprotected`, `Revision2`,
`Revision3`, `Revision4`.

### Signatures

| Goal | Call | Returns |
|------|------|---------|
| Count | `signatures.len()` | `PdfSignatureIndex` |
| Get one | `signatures.get(index)` | `Result<PdfSignature, PdfiumError>` |
| Iterate | `signatures.iter()` | iterator of `PdfSignature` |
| Raw blob | `signature.bytes()` | `Vec<u8>` |
| Signing reason | `signature.reason()` | `Option<String>` |
| Signing date | `signature.signing_date()` | `Option<String>` |
| MDP level | `signature.modification_detection_permission()` | `Result<PdfSignatureModificationDetectionPermission, PdfiumError>` |

`PdfSignatureModificationDetectionPermission` has three variants: `Mdp1`,
`Mdp2`, `Mdp3`.

Full signatures and version annotations: `references/methods.md`.

## Patterns

Condensed patterns below. Complete runnable code is in `references/examples.md`.

### Pattern 1: Read metadata

```rust
let document = pdfium.load_pdf_from_file("doc.pdf", None)?;
let metadata = document.metadata();
for tag in metadata.iter() {
    println!("{:?} = {}", tag.tag_type(), tag.value());
}
if let Some(author) = metadata.get(PdfDocumentMetadataTagType::Author) {
    println!("Author: {}", author.value());
}
```

`CreationDate` and `ModificationDate` values are raw, UNPARSED PDF date strings
in `D:YYYYMMDDHHmmSS` format. Parse them yourself if a typed date is needed.

### Pattern 2: Extract attachments

```rust
for attachment in document.attachments().iter() {
    let data = attachment.save_to_bytes()?; // Vec<u8> of the file content
    println!("{}: {} bytes", attachment.name(), data.len());
}
```

`PdfAttachment` has no `bytes()` accessor. Extraction goes through
`save_to_bytes()` (memory) or `save_to_file()` (disk).

### Pattern 3: Create an attachment

```rust
let mut document = pdfium.load_pdf_from_file("doc.pdf", None)?;
document
    .attachments_mut()
    .create_attachment_from_bytes("notes.txt", b"payload")?;
document.save_to_file("doc-with-attachment.pdf")?; // mandatory
```

Creation needs `&mut PdfDocument` via `attachments_mut()`. The new attachment
lives in memory until the document is saved. See `pdfium-impl-saving`.

### Pattern 4: Delete attachments

```rust
let count = document.attachments().len();
for index in (0..count).rev() { // downward: deleting shifts later indices
    document.attachments_mut().delete_at_index(index)?;
}
document.save_to_file("doc-cleaned.pdf")?;
```

`delete_at_index` is the ONLY deletion method. Deleting shifts every later index
down by one, so deleting multiple attachments ALWAYS goes from the highest index
downward.

### Pattern 5: Query permissions

```rust
let perms = document.permissions();
println!("print HQ:       {:?}", perms.can_print_high_quality());
println!("modify content: {:?}", perms.can_modify_document_content());
```

### Pattern 6: Read signatures

```rust
for signature in document.signatures().iter() {
    println!("reason: {:?}, signed: {:?}",
        signature.reason(), signature.signing_date());
}
```

`PdfSignatures` is read-only. There is no signature-creation API and no
cryptographic verification. The signer identity lives inside the `bytes()`
PKCS#7 blob, which a separate cryptography crate must parse.

## Permission flags are reported, not enforced

`PdfPermissions` getters REPORT the flags stored in the document. They do NOT
gate any pdfium-render operation. `can_modify_document_content()` returning
`false` does not stop `attachments_mut()`, `annotations_mut()`, or any edit
call. To respect a permission, check the flag and branch in your own code
BEFORE calling an edit method.

## Common mistakes

| Mistake | Correct approach |
|---------|------------------|
| `metadata().set_title(...)` | metadata is read-only; no setters exist |
| `perms.can_print()` | use `can_print_high_quality` + `can_print_only_low_quality` |
| `perms.can_copy_or_extract_text()` | the name is `can_extract_text_and_graphics` |
| `if let Some(a) = attachments.get(0)` | `get` returns `Result`, not `Option` |
| `delete_attachment(...)` | only `delete_at_index(index)` exists |
| Deleting attachments by ascending index | iterate `(0..count).rev()` |
| Create attachment, drop document | save with `save_to_file` / `save_to_bytes` |
| `attachment.bytes()` | use `save_to_bytes()` / `save_to_file()` |
| `signature.signer()` | not exposed; parse the `bytes()` PKCS#7 blob |
| `signatures_mut()` to create a signature | no creation API; signatures are read-only |

Each mistake is explained with root cause and fix in
`references/anti-patterns.md`.

## Reference files

- `references/methods.md`: complete API signatures with version annotations.
- `references/examples.md`: working, verified Rust examples.
- `references/anti-patterns.md`: real failures, why they fail, and the fix.

## Related skills

- `pdfium-syntax-document-loading`: loading the document these features hang off.
- `pdfium-impl-navigation`: bookmarks, links, and destinations.
- `pdfium-impl-saving`: persisting attachment create and delete changes.
- `pdfium-impl-form-fields`: interactive form fields (a separate feature).
- `pdfium-errors-runtime`: handling `PdfiumError` from these calls.

