編集の概要
PDF Oxideは、既存のPDFを編集するために2つのレベルのAPIを提供しています。高レベルのPdfクラス(推奨)と、より低レベルのDocumentEditorです。どちらを使っても、PDFを開き、コンテンツとメタデータを変更し、変更を追跡して結果を保存できます。
編集機能のバインディング対応状況。 最も豊富な編集機能を持つのは Python、Rust、WASM で、ページ操作、テキスト・画像編集、注釈操作、暗号化、墨消しが利用できます。Go では充実したエディタAPI(メタデータ、ページの回転・移動・削除、領域の消去、フォームの入力・平坦化、切り抜き、結合、暗号化保存)が提供されています。C# では現在、メタデータ編集(
Title/Author/Subject)、フォーム入力(SetFormFieldValue)、FlattenForms、およびDocumentEditor上のSave/SaveAsyncが利用可能です。ページレベルの操作、暗号化、墨消し、テキスト・画像編集はまだC#のパブリックAPIには公開されていないため、これらの操作にはCLI、Go、Python、またはRustバインディングをご使用ください。
編集用にPDFを開く
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("input.pdf")
エディタは最初の変更時に遅延初期化されます。読み取りはすぐに開始でき、set_title()やpage()などの変更メソッドを呼び出したタイミングでエディタが有効になります。
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
const bytes = new Uint8Array(/* file bytes */);
const doc = new WasmPdfDocument(bytes);
Rust
統合されたPdf APIを使用する場合:
use pdf_oxide::api::Pdf;
let mut doc = Pdf::open("input.pdf")?;
低レベルの制御が必要な場合はDocumentEditorを直接使用します:
use pdf_oxide::editor::DocumentEditor;
let mut editor = DocumentEditor::open("input.pdf")?;
Go
package main
import (
"log"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
func main() {
editor, err := pdfoxide.OpenEditor("input.pdf")
if err != nil { log.Fatal(err) }
defer editor.Close()
}
C#
using PdfOxide;
using var editor = DocumentEditor.Open("input.pdf");
Java
import fyi.oxide.pdf.DocumentEditor;
import java.nio.file.Path;
try (DocumentEditor editor = DocumentEditor.open(Path.of("input.pdf"))) {
// ...
}
Kotlin
import fyi.oxide.pdf.DocumentEditor
import java.nio.file.Path
DocumentEditor.open(Path.of("input.pdf")).use { editor ->
// ...
}
Scala
import fyi.oxide.pdf.DocumentEditor
import scala.util.Using
Using.resource(DocumentEditor.open("input.pdf")) { editor =>
// ...
}
Clojure
(require '[pdf-oxide.core :as pdf])
(with-open [editor (pdf/editor "input.pdf")]
;; ...
)
Ruby
require 'pdf_oxide'
PdfOxide::DocumentEditor.open('input.pdf') do |editor|
# ...
end
PHP
use PdfOxide\DocumentEditor;
$editor = DocumentEditor::open('input.pdf');
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto editor = pdf_oxide::DocumentEditor::open("input.pdf");
Swift
import PdfOxide
let editor = try DocumentEditor.open("input.pdf")
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final editor = DocumentEditor.open('input.pdf');
R
library(pdfoxide)
editor <- pdf_editor_open("input.pdf")
Julia
using PdfOxide
editor = open_editor("input.pdf")
Zig
const pdf_oxide = @import("pdf_oxide");
var editor = try pdf_oxide.DocumentEditor.open("input.pdf");
defer editor.deinit();
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"input.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("input.pdf")
変更の確認
保存前に変更が行われたかどうかを確認できます:
Python
doc = PdfDocument("input.pdf")
print(doc.is_modified) # False -- no changes yet
doc.set_title("Updated Title")
print(doc.is_modified) # True
Rust
let mut doc = Pdf::open("input.pdf")?;
assert!(!doc.is_modified());
doc.editor().unwrap().set_title("Updated Title");
assert!(doc.is_modified());
Go
editor, _ := pdfoxide.OpenEditor("input.pdf")
defer editor.Close()
modified, _ := editor.IsModified()
fmt.Println(modified) // false
_ = editor.SetTitle("Updated Title")
modified, _ = editor.IsModified()
fmt.Println(modified) // true
C#
using var editor = DocumentEditor.Open("input.pdf");
Console.WriteLine(editor.IsModified); // false
editor.Title = "Updated Title";
Console.WriteLine(editor.IsModified); // true
PHP
$editor = DocumentEditor::open('input.pdf');
var_dump($editor->isModified()); // false
$editor->setProducer('pdf_oxide');
var_dump($editor->isModified()); // true
C++
auto editor = pdf_oxide::DocumentEditor::open("input.pdf");
bool before = editor.is_modified(); // false
editor.set_producer("pdf_oxide");
bool after = editor.is_modified(); // true
Swift
let editor = try DocumentEditor.open("input.pdf")
try editor.isModified() // false
try editor.setProducer("pdf_oxide")
try editor.isModified() // true
Dart
final editor = DocumentEditor.open('input.pdf');
editor.isModified(); // false
editor.setProducer('pdf_oxide');
editor.isModified(); // true
R
editor <- pdf_editor_open("input.pdf")
pdf_editor_is_modified(editor) # FALSE
pdf_editor_set_producer(editor, "pdf_oxide")
pdf_editor_is_modified(editor) # TRUE
Julia
editor = open_editor("input.pdf")
is_modified(editor) # false
set_producer(editor, "pdf_oxide")
is_modified(editor) # true
Zig
var editor = try pdf_oxide.DocumentEditor.open("input.pdf");
defer editor.deinit();
_ = editor.isModified(); // false
try editor.setProducer("pdf_oxide");
_ = editor.isModified(); // true
Objective-C
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"input.pdf" error:&err];
[editor isModified]; // NO
[editor setProducer:@"pdf_oxide" error:&err];
[editor isModified]; // YES
Elixir
{:ok, editor} = PdfOxide.open_editor("input.pdf")
PdfOxide.editor_modified?(editor) # false
PdfOxide.set_producer(editor, "pdf_oxide")
PdfOxide.editor_modified?(editor) # true
保存
Python
doc = PdfDocument("input.pdf")
doc.set_title("New Title")
doc.save("output.pdf")
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
const bytes = new Uint8Array(/* file bytes */);
const doc = new WasmPdfDocument(bytes);
doc.setTitle("New Title");
const output = doc.save();
doc.free();
Rust
let mut doc = Pdf::open("input.pdf")?;
doc.editor().unwrap().set_title("New Title");
doc.save("output.pdf")?;
// Or save to a new path
doc.save_as("copy.pdf")?;
Go
editor, _ := pdfoxide.OpenEditor("input.pdf")
defer editor.Close()
_ = editor.SetTitle("New Title")
_ = editor.Save("output.pdf")
C#
using var editor = DocumentEditor.Open("input.pdf");
editor.Title = "New Title";
editor.Save("output.pdf");
PHP
$editor = DocumentEditor::open('input.pdf');
$editor->setProducer('pdf_oxide');
$editor->saveTo('output.pdf');
C++
auto editor = pdf_oxide::DocumentEditor::open("input.pdf");
editor.set_producer("pdf_oxide");
editor.save("output.pdf");
Swift
let editor = try DocumentEditor.open("input.pdf")
try editor.setProducer("pdf_oxide")
try editor.save("output.pdf")
Dart
final editor = DocumentEditor.open('input.pdf');
editor.setProducer('pdf_oxide');
editor.save('output.pdf');
R
editor <- pdf_editor_open("input.pdf")
pdf_editor_set_producer(editor, "pdf_oxide")
pdf_editor_save(editor, "output.pdf")
Julia
editor = open_editor("input.pdf")
set_producer(editor, "pdf_oxide")
save(editor, "output.pdf")
Zig
var editor = try pdf_oxide.DocumentEditor.open("input.pdf");
defer editor.deinit();
try editor.setProducer("pdf_oxide");
try editor.save("output.pdf");
Objective-C
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"input.pdf" error:&err];
[editor setProducer:@"pdf_oxide" error:&err];
[editor saveToPath:@"output.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("input.pdf")
PdfOxide.set_producer(editor, "pdf_oxide")
PdfOxide.editor_save(editor, "output.pdf")
save()メソッドはデフォルトでPDFを完全に書き直します。高度な保存オプション(増分更新、暗号化)については、暗号化とセキュリティをご覧ください。
ドキュメントメタデータ
タイトル、著者、件名、キーワードといった標準的なPDFメタデータフィールドを読み書きできます。
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("input.pdf")
# Set metadata
doc.set_title("Quarterly Report")
doc.set_author("Jane Smith")
doc.set_subject("Q4 2025 Financial Results")
doc.set_keywords("finance, quarterly, 2025")
doc.save("output.pdf")
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
const bytes = new Uint8Array(/* file bytes */);
const doc = new WasmPdfDocument(bytes);
// Set metadata
doc.setTitle("Quarterly Report");
doc.setAuthor("Jane Smith");
doc.setSubject("Q4 2025 Financial Results");
doc.setKeywords("finance, quarterly, 2025");
const output = doc.save();
doc.free();
Rust
use pdf_oxide::editor::DocumentEditor;
let mut editor = DocumentEditor::open("input.pdf")?;
// Read metadata
if let Some(title) = editor.title()? {
println!("Current title: {}", title);
}
if let Some(author) = editor.author()? {
println!("Current author: {}", author);
}
if let Some(subject) = editor.subject()? {
println!("Current subject: {}", subject);
}
if let Some(keywords) = editor.keywords()? {
println!("Current keywords: {}", keywords);
}
// Set metadata
editor.set_title("Quarterly Report");
editor.set_author("Jane Smith");
editor.set_subject("Q4 2025 Financial Results");
editor.set_keywords("finance, quarterly, 2025");
editor.save("output.pdf")?;
Go
editor, _ := pdfoxide.OpenEditor("input.pdf")
defer editor.Close()
if t, err := editor.Title(); err == nil { fmt.Println("Current title:", t) }
if a, err := editor.Author(); err == nil { fmt.Println("Current author:", a) }
_ = editor.SetTitle("Quarterly Report")
_ = editor.SetAuthor("Jane Smith")
_ = editor.SetSubject("Q4 2025 Financial Results")
_ = editor.Save("output.pdf")
C#
using var editor = DocumentEditor.Open("input.pdf");
if (editor.Title is { } t) Console.WriteLine($"Current title: {t}");
if (editor.Author is { } a) Console.WriteLine($"Current author: {a}");
if (editor.Subject is { } s) Console.WriteLine($"Current subject: {s}");
editor.Title = "Quarterly Report";
editor.Author = "Jane Smith";
editor.Subject = "Q4 2025 Financial Results";
editor.Save("output.pdf");
ドキュメント情報
ソースパスとバージョン
use pdf_oxide::editor::DocumentEditor;
let editor = DocumentEditor::open("input.pdf")?;
// Path to the original file
println!("Source: {}", editor.source_path());
// PDF version as (major, minor)
let (major, minor) = editor.version();
println!("PDF version: {}.{}", major, minor);
// Number of pages
println!("Pages: {}", editor.current_page_count());
完全なAPIリファレンス
DocumentEditor
| メソッド | 戻り値 | 説明 |
|---|---|---|
open(path) |
Result<DocumentEditor> |
編集用にPDFを開く |
is_modified() |
bool |
変更が加えられたか確認する |
source_path() |
&str |
ソースPDFへのパス |
source() |
&PdfDocument |
ソースドキュメントへの読み取り専用アクセス |
version() |
(u8, u8) |
PDFバージョン(メジャー、マイナー) |
current_page_count() |
usize |
ドキュメントのページ数 |
title() |
Result<Option<String>> |
ドキュメントタイトルを取得 |
set_title(title) |
() |
ドキュメントタイトルを設定 |
author() |
Result<Option<String>> |
ドキュメント著者を取得 |
set_author(author) |
() |
ドキュメント著者を設定 |
subject() |
Result<Option<String>> |
ドキュメント件名を取得 |
set_subject(subject) |
() |
ドキュメント件名を設定 |
keywords() |
Result<Option<String>> |
ドキュメントキーワードを取得 |
set_keywords(keywords) |
() |
ドキュメントキーワードを設定 |
save(path) |
Result<()> |
完全な書き直しで保存 |
save_with_options(path, options) |
Result<()> |
カスタムオプションで保存 |
Pdf(統合API)
| メソッド | 戻り値 | 説明 |
|---|---|---|
Pdf::open(path) |
Result<Pdf> |
編集用にPDFを開く |
Pdf::open_editor(path) |
Result<DocumentEditor> |
DocumentEditorとして直接開く |
is_modified() |
bool |
変更があるか確認する |
save(path) |
Result<()> |
ドキュメントを保存 |
save_as(path) |
Result<()> |
新しいパスに保存 |
page(index) |
Result<PdfPage> |
DOM編集用にページを取得 |
save_page(page) |
Result<()> |
変更したページを書き戻す |
editor() |
Option<&mut DocumentEditor> |
基礎となるエディタにアクセス |
EditableDocument トレイト
EditableDocumentトレイトはコア編集コントラクトを定義します:
pub trait EditableDocument {
fn get_info(&mut self) -> Result<DocumentInfo>;
fn set_info(&mut self, info: DocumentInfo) -> Result<()>;
fn page_count(&mut self) -> Result<usize>;
fn get_page_info(&mut self, index: usize) -> Result<PageInfo>;
fn remove_page(&mut self, index: usize) -> Result<()>;
fn move_page(&mut self, from: usize, to: usize) -> Result<()>;
fn duplicate_page(&mut self, index: usize) -> Result<usize>;
fn save(&mut self, path: impl AsRef<Path>) -> Result<()>;
fn save_with_options(&mut self, path: impl AsRef<Path>, options: SaveOptions) -> Result<()>;
}
DocumentEditor メソッド一覧
以下の表はRustにおけるDocumentEditor / Pdfエディタのパブリックメソッドをすべて列挙しています。各行は該当する詳細ガイドにリンクしています。バインディングの対応状況も記載されています。Go / C#の例は各ページをご覧ください。
メタデータ
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
title / set_title |
✓ | ✓ | ✓ | ✓ | ✓ | 概要 |
author / set_author |
✓ | ✓ | ✓ | ✓ | ✓ | 概要 |
subject / set_subject |
✓ | ✓ | ✓ | ✓ | ✓ | 概要 |
keywords / set_keywords |
✓ | ✓ | ✓ | ✓ | — | 概要 |
producer / set_producer |
✓ | ✓ | — | ✓ | — | 概要 |
creation_date / set_creation_date |
✓ | ✓ | — | ✓ | — | 概要 |
apply_metadata(info) |
✓ | ✓ | — | ✓ | — | 概要 |
ページ操作
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
remove_page / delete_page |
✓ | ✓ | ✓ | ✓ | — | ページ |
move_page(from, to) |
✓ | ✓ | — | ✓ | — | ページ |
duplicate_page(i) |
✓ | ✓ | — | — | — | ページ |
get_page_rotation / set_page_rotation |
✓ | ✓ | ✓ | ✓ | — | ページ |
rotate_page_by(i, deg) |
✓ | ✓ | — | — | — | ページ |
rotate_all_pages(deg) |
✓ | ✓ | ✓ | — | — | ページ |
get_page_media_box / set_page_media_box |
✓ | ✓ | ✓ | — | — | ページ |
get_page_crop_box / set_page_crop_box |
✓ | ✓ | ✓ | — | — | ページ |
crop_margins(l, r, t, b) |
✓ | ✓ | ✓ | ✓ | — | ページ |
erase_region(page, rect) |
✓ | ✓ | ✓ | ✓ | — | ページ |
erase_regions(page, rects) |
✓ | ✓ | ✓ | — | — | ページ |
clear_erase_regions(page) |
✓ | ✓ | — | — | — | ページ |
結合・分割
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
merge_from(path) |
✓ | ✓ | — | ✓ | — | 結合と分割 |
merge_pages_from(path, pages) |
✓ | ✓ | — | — | — | 結合と分割 |
extract_pages(pages, output) |
✓ | ✓ | ✓ | — | — | 結合と分割 |
Merge([]paths) トップレベル |
— | — | — | ✓ | — | 結合と分割 |
フォーム
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
get_form_fields() |
✓ | ✓ | ✓ | ✓ | ✓ | フォーム |
get_form_field_value(name) |
✓ | ✓ | ✓ | — | — | フォーム |
has_form_field(name) |
✓ | ✓ | — | — | — | フォーム |
set_form_field_value(name, value) |
✓ | ✓ | ✓ | ✓ | ✓ | フォーム |
add_form_field(widget, page) |
✓ | — | — | — | — | フォーム作成 |
add_parent_field / add_child_field |
✓ | — | — | — | — | フォーム作成 |
remove_form_field(name) |
✓ | ✓ | — | — | — | フォーム |
set_form_field_* (readonly, required, tooltip, rect, max_length, alignment, colors, flags) |
✓ | ✓ | — | — | — | フォーム |
flatten_forms_on_page(page) |
✓ | ✓ | ✓ | ✓ | — | フォーム |
flatten_forms() |
✓ | ✓ | ✓ | ✓ | ✓ | フォーム |
export_form_data_fdf(path) |
✓ | ✓ | ✓ | — | — | フォーム |
export_form_data_xfdf(path) |
✓ | ✓ | ✓ | — | — | フォーム |
注釈
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
flatten_page_annotations(page) |
✓ | ✓ | ✓ | ✓ | — | 注釈 |
flatten_all_annotations() |
✓ | ✓ | ✓ | ✓ | — | 注釈 |
is_page_marked_for_annotation_flatten(page) |
✓ | ✓ | — | — | — | 注釈 |
unmark_page_for_annotation_flatten(page) |
✓ | ✓ | — | — | — | 注釈 |
墨消し
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
apply_page_redactions(page) |
✓ | ✓ | ✓ | — | — | 墨消し |
apply_all_redactions() |
✓ | ✓ | ✓ | — | — | 墨消し |
is_page_marked_for_redaction(page) |
✓ | ✓ | — | — | — | 墨消し |
unmark_page_for_redaction(page) |
✓ | ✓ | — | — | — | 墨消し |
XFA
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
has_xfa() |
✓ | ✓ | ✓ | ✓ | ✓ | XFAフォーム |
analyze_xfa() |
✓ | ✓ | — | — | — | XFAフォーム |
convert_xfa_to_acroform(opts) |
✓ | — | — | — | — | XFAフォーム |
保存
| メソッド | Rust | Python | WASM | Go | C# | ページ |
|---|---|---|---|---|---|---|
save(path) |
✓ | ✓ | ✓ | ✓ | ✓ | 概要 |
save_with_options(path, opts) |
✓ | ✓ | — | — | — | 暗号化 |
save_encrypted(path, user, owner) |
✓ | ✓ | ✓ | ✓ | — | 暗号化 |
save_with_encryption(path, cfg) |
✓ | ✓ | — | — | — | 暗号化 |
save_async / SaveAsync |
— | — | — | — | ✓ | 非同期 |
ハウスキーピング(Goの便利メソッド)
GoでDocumentEditorのメソッドとして公開されているもの。Rustではeditor.source()経由で利用:
| メソッド | Rust | Python | WASM | Go | C# |
|---|---|---|---|---|---|
IsModified |
is_modified() |
is_modified |
— | IsModified() |
IsModified |
SourcePath |
source_path() |
source_path |
— | SourcePath() |
SourcePath |
Version |
version() |
version() |
— | Version() |
— |
PageCount |
current_page_count() |
page_count() |
pageCount() |
PageCount() |
PageCount |
RemoveHeaders / RemoveFooters / RemoveArtifacts |
✓ | ✓ | — | ✓ | ✓ |
Close / Dispose |
Drop |
context manager | free() |
Close() |
Dispose() |
完全な編集ワークフロー
このサンプルは、開く・確認・メタデータ変更・コンテンツ編集・保存という一連の編集セッションを示しています。
Python
from pdf_oxide import PdfDocument
# Open the document
doc = PdfDocument("report.pdf")
print(f"Pages: {doc.page_count()}")
# Update metadata
doc.set_title("Annual Report 2025")
doc.set_author("Finance Team")
# Edit text on page 0
page = doc.page(0)
for text in page.find_text_containing("DRAFT"):
page.set_text(text.id, "FINAL")
doc.save_page(page)
# Save
doc.save("report-final.pdf")
Rust
use pdf_oxide::api::Pdf;
let mut doc = Pdf::open("report.pdf")?;
println!("Pages: {}", doc.page_count()?);
// Update metadata
{
let editor = doc.editor().unwrap();
editor.set_title("Annual Report 2025");
editor.set_author("Finance Team");
}
// Edit text on page 0
let mut page = doc.page(0)?;
let drafts = page.find_text_containing("DRAFT");
for t in &drafts {
page.set_text(t.id(), "FINAL")?;
}
doc.save_page(page)?;
// Save
doc.save("report-final.pdf")?;
関連ページ
- テキスト編集 – テキストの検索・置換、フォントと配置の変更
- ページ操作 – 回転、切り抜き、結合、ページの抽出
- フォームフィールド編集 – フォームフィールドの入力、追加、平坦化
- 暗号化とセキュリティ – パスワード保護と権限設定