PdfElixide.Editor (pdf_elixide v0.10.0)

Copy Markdown View Source

Mutable, in-memory PDF editor backed by pdf_oxide's DocumentEditor.

Where PdfElixide.Document only reads, an editor accumulates changes in memory and writes them out on demand. The shape is open, mutate, write:

editor = PdfElixide.Editor.open!("form.pdf")
:ok = PdfElixide.Form.set_value(editor, "name", {:text, "Ada"})
:ok = PdfElixide.Editor.save(editor, "filled.pdf")
:ok = PdfElixide.Editor.close(editor)

Nothing is written until save/3 or to_binary/2 runs, and neither consumes the editor — you can keep editing and write again. close/1 discards unsaved edits, so write before you close.

The editor mutates, and the underlying DocumentEditor exposes even its readers as mutations, so every call on an editor takes the handle's lock exclusively — including PdfElixide.Form.fields/1, which only reads. Where a document's reads take that lock shared and run concurrently, concurrent use of a single editor serializes; give each process its own editor if you need them to work at once. See the Concurrency guide.

Summary

Functions

Releases the editor's native memory immediately.

Returns whether the editor has been released with close/1.

Opens a PDF document for editing from the given binary data.

Opens a PDF document for editing from the given binary data, raising an error if it fails.

Opens a PDF document for editing from the specified file path.

Opens a PDF document for editing from the specified file path, raising an error if it fails.

Writes all in-memory changes to a PDF file at the given path.

Writes all in-memory changes to a PDF file at the given path, raising an error if it fails.

Returns the file path from which the editor was loaded, or nil if it was loaded from binary data.

Serialises all in-memory changes into a PDF binary.

Serialises all in-memory changes into a PDF binary, raising an error if it fails.

Types

save_opts()

@type save_opts() :: [
  incremental: boolean(),
  compress: boolean(),
  linearize: boolean(),
  garbage_collect: boolean()
]

Options accepted by save/3, save!/3, to_binary/2, and to_binary!/2.

  • :incremental — write an incremental update instead of a full rewrite. Defaults to false.
  • :compress — compress streams. Defaults to true.
  • :linearize — linearize the output for fast web view. Defaults to false.
  • :garbage_collect — drop unreferenced objects. Defaults to true.

Defaults mirror pdf_oxide's SaveOptions::full_rewrite(), so calling save/2 is equivalent to save/3 with no options.

An unknown key, or a declared key given a value that is not a boolean, raises ArgumentError naming the offending key; see the "Errors versus exceptions" section of PdfElixide.Error.

t()

@type t() :: %PdfElixide.Editor{ref: reference(), source_path: Path.t() | nil}

Functions

close(editor)

@spec close(t()) :: :ok

Releases the editor's native memory immediately.

An editor holds the source document plus its pending edits in memory on the Rust side, normally freed only when the BEAM garbage-collects the handle. close/1 frees it now, which matters for long-lived processes that open many documents. Calling it is optional and idempotent.

It takes the same lock every other call on the handle takes, so it waits for an in-flight call on the same editor — a save can hold that lock for seconds. Immediately means as soon as the handle is idle, not preemptively.

Unsaved edits are discarded — call save/3 or to_binary/2 first. Afterwards, functions that read or mutate the editor return {:error, %PdfElixide.Error{reason: :closed}}, and their bang variants raise it. source_path/1 keeps working, since it reads the struct rather than the native handle.

editor = PdfElixide.Editor.open!("form.pdf")
:ok = PdfElixide.Form.set_value(editor, "name", {:text, "Ada"})
:ok = PdfElixide.Editor.save(editor, "filled.pdf")
:ok = PdfElixide.Editor.close(editor)

closed?(editor)

@spec closed?(t()) :: boolean()

Returns whether the editor has been released with close/1.

from_binary(bytes)

@spec from_binary(binary()) :: {:ok, t()} | {:error, PdfElixide.Error.t()}

Opens a PDF document for editing from the given binary data.

from_binary!(bytes)

@spec from_binary!(binary()) :: t()

Opens a PDF document for editing from the given binary data, raising an error if it fails.

open(path)

@spec open(Path.t()) :: {:ok, t()} | {:error, PdfElixide.Error.t()}

Opens a PDF document for editing from the specified file path.

The path must be a valid-UTF-8 binary — see the "File paths" section of PdfElixide.

open!(path)

@spec open!(Path.t()) :: t()

Opens a PDF document for editing from the specified file path, raising an error if it fails.

The path must be a valid-UTF-8 binary — see the "File paths" section of PdfElixide.

save(editor, path, opts \\ [])

@spec save(t(), Path.t(), save_opts()) :: :ok | {:error, PdfElixide.Error.t()}

Writes all in-memory changes to a PDF file at the given path.

The path must be a valid-UTF-8 binary — see the "File paths" section of PdfElixide.

save!(editor, path, opts \\ [])

@spec save!(t(), Path.t(), save_opts()) :: :ok

Writes all in-memory changes to a PDF file at the given path, raising an error if it fails.

The path must be a valid-UTF-8 binary — see the "File paths" section of PdfElixide.

source_path(editor)

@spec source_path(t()) :: Path.t() | nil

Returns the file path from which the editor was loaded, or nil if it was loaded from binary data.

to_binary(editor, opts \\ [])

@spec to_binary(t(), save_opts()) :: {:ok, binary()} | {:error, PdfElixide.Error.t()}

Serialises all in-memory changes into a PDF binary.

The result is a fully self-contained PDF that can be written to disk, stored in a database, or streamed over HTTP.

Accepts the same save_opts/0 keyword list as save/3. Note that :incremental is not supported here — upstream returns {:error, _} because incremental updates can only be appended to the original file.

The whole document is serialised in native memory before being copied into the returned binary, so peak usage is roughly twice the output size (on top of the editor itself). For very large documents prefer save/3, which streams to the file without that second buffer.

to_binary!(editor, opts \\ [])

@spec to_binary!(t(), save_opts()) :: binary()

Serialises all in-memory changes into a PDF binary, raising an error if it fails.