Skip to content

フォームデータの抽出

PDF Oxideは、PDFドキュメントからインタラクティブなフォームフィールド(AcroForms)を抽出します。テキストフィールド、チェックボックス、ラジオボタン、選択フィールド、署名フィールドに対応しています。抽出したフォームデータはFDFまたはXFDF形式にエクスポートして他のアプリケーションと連携できます。XFAフォーム(XML Forms Architecture)の解析と変換にも対応しています。

クイックサンプル

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
fields = doc.get_form_fields()
for field in fields:
    print(f"{field.name} ({field.field_type}): {field.value}")

Node.js

const { PdfDocument } = require("pdf-oxide");

const doc = new PdfDocument("form.pdf");
const fields = doc.getFormFields();
for (const field of fields) {
  console.log(`${field.name} (${field.fieldType}): ${field.value}`);
}
doc.close();

Go

import pdfoxide "github.com/yfedoseev/pdf_oxide/go"

doc, _ := pdfoxide.Open("form.pdf")
defer doc.Close()
fields, _ := doc.FormFields()
for _, field := range fields {
    fmt.Printf("%s (%s): %s\n", field.Name, field.FieldType, field.Value)
}

C#

using PdfOxide.Core;

using var doc = PdfDocument.Open("form.pdf");
var fields = doc.GetFormFields();
foreach (var field in fields)
{
    Console.WriteLine($"{field.Name} ({field.FieldType}): {field.Value}");
}

WASM

const doc = new WasmPdfDocument(bytes);
const fields = doc.getFormFields();
for (const field of fields) {
    console.log(`${field.name} (${field.fieldType}): ${field.value}`);
}

Rust

use pdf_oxide::extractors::FormExtractor;
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("form.pdf")?;
let fields = FormExtractor::extract_fields(&mut doc)?;
for field in &fields {
    println!("{} ({:?}): {:?}", field.full_name, field.field_type, field.value);
}

Java

import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.form.FormField;

try (PdfDocument doc = PdfDocument.open("form.pdf")) {
    for (FormField field : doc.formFields()) {
        System.out.printf("%s (%s): %s%n",
            field.name(), field.type(), field.value().orElse(""));
    }
}

Ruby

require 'pdf_oxide'

PdfOxide::PdfDocument.open('form.pdf') do |doc|
  doc.form_fields.each do |field|
    puts "#{field[:name]} (#{field[:type]}): #{field[:value]}"
  end
end

C++

#include <pdf_oxide/pdf_oxide.hpp>

auto doc = pdf_oxide::Document::open("form.pdf");
for (const auto& field : doc.get_form_fields()) {
    std::cout << field.name << " (" << field.type << "): " << field.value << "\n";
}

Swift

import PdfOxide

let doc = try Document.open("form.pdf")
for field in try doc.formFields() {
    print("\(field.name) (\(field.type)): \(field.value)")
}

Kotlin

import fyi.oxide.pdf.PdfDocument

PdfDocument.open("form.pdf").use { doc ->
    doc.formFields().forEach { field ->
        println("${field.name()} (${field.type()}): ${field.valueOrNull() ?: ""}")
    }
}

Dart

import 'package:pdf_oxide/pdf_oxide.dart';

final doc = PdfDocument.open('form.pdf');
for (final field in doc.getFormFields()) {
  print('${field.name} (${field.type}): ${field.value}');
}

R

library(pdfoxide)

doc <- pdf_open("form.pdf")
for (field in pdf_get_form_fields(doc)) {
  cat(sprintf("%s (%s): %s\n", field$name, field$type, field$value))
}

Julia

using PdfOxide

doc = open_document("form.pdf")
for field in get_form_fields(doc)
    println("$(field.name) ($(field.type)): $(field.value)")
end

Zig

const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;

var doc = try pdf_oxide.Document.open("form.pdf");
var fields = try doc.formFields();
defer fields.deinit();
const count = try fields.count();
var i: i32 = 0;
while (i < count) : (i += 1) {
    const name = try fields.getName(a, i);
    const ftype = try fields.getType(a, i);
    const value = try fields.getValue(a, i);
    std.debug.print("{s} ({s}): {s}\n", .{ name, ftype, value });
}

Scala

import fyi.oxide.pdf.{PdfDocument, valueOption}
import scala.util.Using

Using.resource(PdfDocument.open("form.pdf")) { doc =>
  doc.formFieldsSeq.foreach { field =>
    println(s"${field.name} (${field.`type`}): ${field.valueOption.getOrElse("")}")
  }
}

Clojure

(require '[pdf-oxide.core :as pdf])

(with-open [doc (pdf/open "form.pdf")]
  (doseq [field (pdf/form-fields doc)]
    (println (format "%s (%s): %s"
                     (.name field) (.type field) (.orElse (.value field) "")))))

Objective-C

#import "POXPdfOxide.h"
NSError *err = nil;

POXDocument *doc = [POXDocument openPath:@"form.pdf" error:&err];
for (POXFormField *field in [doc formFieldsWithError:&err]) {
    NSLog(@"%@ (%@): %@", field.name, field.type, field.value);
}

Elixir

{:ok, doc} = PdfOxide.open("form.pdf")
{:ok, fields} = PdfOxide.form_fields(doc)
Enum.each(fields, fn field ->
  IO.puts("#{field.name} (#{field.type}): #{field.value}")
end)

PyMuPDF の get_form_fields() からの移行

PyMuPDFからの移行を検討している場合、APIは似ていますがPDF Oxideはよりリッチなデータを返し、XFAフォームにも対応しています。

PyMuPDF:

import fitz

doc = fitz.open("form.pdf")
# Returns dict of {field_name: field_value} — loses type info
fields = doc.get_form_fields()

# Or iterate widgets for more detail
for page in doc:
    for widget in page.widgets():
        print(widget.field_name, widget.field_value)

PDF Oxide:

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
# Returns structured objects with name, value, type, options, rect
fields = doc.get_form_fields()
for field in fields:
    print(f"{field.name} ({field.field_type}): {field.value}")

# Also handles XFA forms that PyMuPDF cannot read
xfa = doc.has_xfa()

主な違い:

  • PDF Oxideは構造化されたフィールドオブジェクトを返す(辞書ではない)
  • フィールドタイプ、バウンディングRect、選択フィールドのオプションを含む
  • XFAフォームに対応 — PyMuPDFの get_form_fields() はXFA専用PDFに対して空を返す
  • FDF/XFDF形式へのエクスポートでフォームデータを他システムと交換可能

PyMuPDF、pypdf、pdfplumber、pdfminerを含む完全な移行ガイドはPDF Oxideへの移行を参照してください。


フォームフィールドの読み取り

全フィールドの取得

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("tax-form.pdf")
fields = doc.get_form_fields()

for field in fields:
    print(f"Name: {field.name}")
    print(f"  Type: {field.field_type}")
    print(f"  Value: {field.value}")
    print(f"  Required: {field.is_required}")
    print(f"  Read-only: {field.is_readonly}")
    if field.max_length:
        print(f"  Max length: {field.max_length}")

Node.js

const doc = new PdfDocument("tax-form.pdf");
const fields = doc.getFormFields();

for (const field of fields) {
  console.log(`Name: ${field.name}`);
  console.log(`  Type: ${field.fieldType}`);
  console.log(`  Value: ${field.value}`);
}
doc.close();

Go

doc, _ := pdfoxide.Open("tax-form.pdf")
defer doc.Close()
fields, _ := doc.FormFields()

for _, field := range fields {
    fmt.Printf("Name: %s\n", field.Name)
    fmt.Printf("  Type: %s\n", field.FieldType)
    fmt.Printf("  Value: %s\n", field.Value)
}

C#

using var doc = PdfDocument.Open("tax-form.pdf");
var fields = doc.GetFormFields();

foreach (var field in fields)
{
    Console.WriteLine($"Name: {field.Name}");
    Console.WriteLine($"  Type: {field.FieldType}");
    Console.WriteLine($"  Value: {field.Value}");
}

WASM

const doc = new WasmPdfDocument(bytes);
const fields = doc.getFormFields();

for (const field of fields) {
    console.log(`Name: ${field.name}`);
    console.log(`  Type: ${field.fieldType}`);
    console.log(`  Value: ${field.value}`);
    console.log(`  Flags: ${field.flags}`);
}

Rust

use pdf_oxide::extractors::{FormExtractor, FieldType};
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("tax-form.pdf")?;
let fields = FormExtractor::extract_fields(&mut doc)?;

for field in &fields {
    let type_str = match &field.field_type {
        FieldType::Button => "Button",
        FieldType::Text => "Text",
        FieldType::Choice => "Choice",
        FieldType::Signature => "Signature",
        FieldType::Unknown(s) => s.as_str(),
    };

    println!("[{}] {} = {:?}", type_str, field.full_name, field.value);

    if let Some(tooltip) = &field.tooltip {
        println!("  Tooltip: {}", tooltip);
    }
    if let Some(bounds) = &field.bounds {
        println!("  Bounds: [{:.1}, {:.1}, {:.1}, {:.1}]",
            bounds[0], bounds[1], bounds[2], bounds[3]);
    }
}

Java

import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.form.FormField;

try (PdfDocument doc = PdfDocument.open("tax-form.pdf")) {
    for (FormField field : doc.formFields()) {
        System.out.println("Name: " + field.name());
        System.out.println("  Type: " + field.type());
        System.out.println("  Value: " + field.value().orElse(""));
    }
}

Ruby

PdfOxide::PdfDocument.open('tax-form.pdf') do |doc|
  doc.form_fields.each do |field|
    puts "Name: #{field[:name]}"
    puts "  Type: #{field[:type]}"
    puts "  Value: #{field[:value]}"
  end
end

C++

auto doc = pdf_oxide::Document::open("tax-form.pdf");
for (const auto& field : doc.get_form_fields()) {
    std::cout << "Name: " << field.name << "\n";
    std::cout << "  Type: " << field.type << "\n";
    std::cout << "  Value: " << field.value << "\n";
    std::cout << "  Read-only: " << field.readonly << "\n";
    std::cout << "  Required: " << field.required << "\n";
}

Swift

let doc = try Document.open("tax-form.pdf")
for field in try doc.formFields() {
    print("Name: \(field.name)")
    print("  Type: \(field.type)")
    print("  Value: \(field.value)")
    print("  Read-only: \(field.readonly)")
    print("  Required: \(field.required)")
}

Kotlin

PdfDocument.open("tax-form.pdf").use { doc ->
    doc.formFields().forEach { field ->
        println("Name: ${field.name()}")
        println("  Type: ${field.type()}")
        println("  Value: ${field.valueOrNull() ?: ""}")
    }
}

Dart

final doc = PdfDocument.open('tax-form.pdf');
for (final field in doc.getFormFields()) {
  print('Name: ${field.name}');
  print('  Type: ${field.type}');
  print('  Value: ${field.value}');
  print('  Read-only: ${field.readonly}');
  print('  Required: ${field.required}');
}

R

doc <- pdf_open("tax-form.pdf")
for (field in pdf_get_form_fields(doc)) {
  cat(sprintf("Name: %s\n", field$name))
  cat(sprintf("  Type: %s\n", field$type))
  cat(sprintf("  Value: %s\n", field$value))
  cat(sprintf("  Read-only: %s\n", field$readonly))
  cat(sprintf("  Required: %s\n", field$required))
}

Julia

doc = open_document("tax-form.pdf")
for field in get_form_fields(doc)
    println("Name: $(field.name)")
    println("  Type: $(field.type)")
    println("  Value: $(field.value)")
    println("  Read-only: $(field.readonly)")
    println("  Required: $(field.required)")
end

Zig

var doc = try pdf_oxide.Document.open("tax-form.pdf");
var fields = try doc.formFields();
defer fields.deinit();
const count = try fields.count();
var i: i32 = 0;
while (i < count) : (i += 1) {
    const name = try fields.getName(a, i);
    const ftype = try fields.getType(a, i);
    const value = try fields.getValue(a, i);
    std.debug.print("Name: {s}\n  Type: {s}\n  Value: {s}\n", .{ name, ftype, value });
    std.debug.print("  Read-only: {}\n  Required: {}\n", .{
        try fields.isReadonly(i), try fields.isRequired(i),
    });
}

Scala

Using.resource(PdfDocument.open("tax-form.pdf")) { doc =>
  doc.formFieldsSeq.foreach { field =>
    println(s"Name: ${field.name}")
    println(s"  Type: ${field.`type`}")
    println(s"  Value: ${field.valueOption.getOrElse("")}")
  }
}

Clojure

(with-open [doc (pdf/open "tax-form.pdf")]
  (doseq [field (pdf/form-fields doc)]
    (println "Name:" (.name field))
    (println "  Type:" (.type field))
    (println "  Value:" (.orElse (.value field) ""))))

Objective-C

POXDocument *doc = [POXDocument openPath:@"tax-form.pdf" error:&err];
for (POXFormField *field in [doc formFieldsWithError:&err]) {
    NSLog(@"Name: %@", field.name);
    NSLog(@"  Type: %@", field.type);
    NSLog(@"  Value: %@", field.value);
    NSLog(@"  Read-only: %d", field.readonly);
    NSLog(@"  Required: %d", field.required);
}

Elixir

{:ok, doc} = PdfOxide.open("tax-form.pdf")
{:ok, fields} = PdfOxide.form_fields(doc)
Enum.each(fields, fn field ->
  IO.puts("Name: #{field.name}")
  IO.puts("  Type: #{field.type}")
  IO.puts("  Value: #{field.value}")
  IO.puts("  Read-only: #{field.read_only}")
  IO.puts("  Required: #{field.required}")
end)

特定フィールドの値を取得

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")

name = doc.get_form_field_value("employee_name")
ssn = doc.get_form_field_value("ssn")
agreed = doc.get_form_field_value("agree_to_terms")

print(f"Name: {name}")       # "John Doe"
print(f"SSN: {ssn}")         # "123-45-6789"
print(f"Agreed: {agreed}")   # True

WASM

const doc = new WasmPdfDocument(bytes);

const name = doc.getFormFieldValue("employee_name");
const ssn = doc.getFormFieldValue("ssn");
const agreed = doc.getFormFieldValue("agree_to_terms");

console.log(`Name: ${name}`);     // "John Doe"
console.log(`SSN: ${ssn}`);       // "123-45-6789"
console.log(`Agreed: ${agreed}`); // true

Rust

use pdf_oxide::editor::{DocumentEditor, EditableDocument};

let mut editor = DocumentEditor::open("form.pdf")?;

if let Some(value) = editor.get_form_field_value("employee_name")? {
    println!("Name: {:?}", value);
}

フォームへの入力

フィールド値の設定

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")

# Set text fields
doc.set_form_field_value("full_name", "Jane Doe")
doc.set_form_field_value("email", "jane@example.com")

# Set checkboxes
doc.set_form_field_value("agree_to_terms", True)

# Save the filled form
doc.save("filled_form.pdf")

WASM

const doc = new WasmPdfDocument(bytes);

// Set text fields
doc.setFormFieldValue("full_name", "Jane Doe");
doc.setFormFieldValue("email", "jane@example.com");

// Set checkboxes
doc.setFormFieldValue("agree_to_terms", true);

// Save the filled form
const filledBytes = doc.save();

Rust

use pdf_oxide::editor::{DocumentEditor, EditableDocument, FormFieldValue};

let mut editor = DocumentEditor::open("form.pdf")?;

// Set text fields
editor.set_form_field_value("full_name", FormFieldValue::Text("Jane Doe".into()))?;
editor.set_form_field_value("email", FormFieldValue::Text("jane@example.com".into()))?;

// Set checkboxes
editor.set_form_field_value("agree_to_terms", FormFieldValue::Boolean(true))?;

// Set choice fields
editor.set_form_field_value("state", FormFieldValue::Choice("California".into()))?;

editor.save("filled_form.pdf")?;

Java

import fyi.oxide.pdf.DocumentEditor;

try (DocumentEditor editor = DocumentEditor.open("form.pdf")) {
    // Set text fields
    editor.setFormField("full_name", "Jane Doe");
    editor.setFormField("email", "jane@example.com");

    // Set checkboxes
    editor.setFormField("agree_to_terms", true);

    editor.saveTo(java.nio.file.Path.of("filled_form.pdf"));
}

Ruby

PdfOxide::DocumentEditor.open('form.pdf') do |editor|
  # Set text fields
  editor.set_form_field('full_name', 'Jane Doe')
  editor.set_form_field('email', 'jane@example.com')

  # Set checkboxes
  editor.set_form_field('agree_to_terms', true)

  editor.save_to('filled_form.pdf')
end

C++

auto editor = pdf_oxide::DocumentEditor::open("form.pdf");

// Set text fields
editor.set_form_field_value("full_name", "Jane Doe");
editor.set_form_field_value("email", "jane@example.com");

// Set checkboxes
editor.set_form_field_value("agree_to_terms", "true");

editor.save("filled_form.pdf");

Swift

let editor = try DocumentEditor.openEditor("form.pdf")

// Set text fields
try editor.setFormFieldValue("full_name", "Jane Doe")
try editor.setFormFieldValue("email", "jane@example.com")

// Set checkboxes
try editor.setFormFieldValue("agree_to_terms", "true")

try editor.save("filled_form.pdf")

Kotlin

import fyi.oxide.pdf.DocumentEditor

DocumentEditor.open("form.pdf").use { editor ->
    // Set text fields
    editor.setFormField("full_name", "Jane Doe")
    editor.setFormField("email", "jane@example.com")

    // Set checkboxes
    editor.setFormField("agree_to_terms", true)

    editor.saveTo(java.nio.file.Path.of("filled_form.pdf"))
}

Dart

final editor = DocumentEditor.open('form.pdf');

// Set text fields
editor.setFormFieldValue('full_name', 'Jane Doe');
editor.setFormFieldValue('email', 'jane@example.com');

// Set checkboxes
editor.setFormFieldValue('agree_to_terms', 'true');

editor.save('filled_form.pdf');

R

editor <- pdf_editor_open("form.pdf")

# Set text fields
pdf_editor_set_form_field_value(editor, "full_name", "Jane Doe")
pdf_editor_set_form_field_value(editor, "email", "jane@example.com")

# Set checkboxes
pdf_editor_set_form_field_value(editor, "agree_to_terms", "true")

pdf_editor_save(editor, "filled_form.pdf")

Julia

editor = open_editor("form.pdf")

# Set text fields
set_form_field_value(editor, "full_name", "Jane Doe")
set_form_field_value(editor, "email", "jane@example.com")

# Set checkboxes
set_form_field_value(editor, "agree_to_terms", "true")

save(editor, "filled_form.pdf")

Zig

var editor = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor.deinit();

// Set text fields
try editor.setFormFieldValue("full_name", "Jane Doe");
try editor.setFormFieldValue("email", "jane@example.com");

// Set checkboxes
try editor.setFormFieldValue("agree_to_terms", "true");

try editor.save("filled_form.pdf");

Scala

import fyi.oxide.pdf.DocumentEditor
import scala.util.Using

Using.resource(DocumentEditor.open("form.pdf")) { editor =>
  // Set text fields
  editor.setFormField("full_name", "Jane Doe")
  editor.setFormField("email", "jane@example.com")

  // Set checkboxes
  editor.setFormField("agree_to_terms", true)

  editor.saveTo(java.nio.file.Path.of("filled_form.pdf"))
}

Clojure

(with-open [editor (pdf/editor "form.pdf")]
  ;; Set text fields
  (.setFormField editor "full_name" "Jane Doe")
  (.setFormField editor "email" "jane@example.com")

  ;; Set checkboxes
  (.setFormField editor "agree_to_terms" true)

  (.saveTo editor (java.nio.file.Path/of "filled_form.pdf" (make-array String 0))))

Objective-C

POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"form.pdf" error:&err];

// Set text fields
[editor setFormField:@"full_name" value:@"Jane Doe" error:&err];
[editor setFormField:@"email" value:@"jane@example.com" error:&err];

// Set checkboxes
[editor setFormField:@"agree_to_terms" value:@"true" error:&err];

[editor saveToPath:@"filled_form.pdf" error:&err];

Elixir

{:ok, editor} = PdfOxide.open_editor("form.pdf")

# Set text fields
PdfOxide.set_form_field_value(editor, "full_name", "Jane Doe")
PdfOxide.set_form_field_value(editor, "email", "jane@example.com")

# Set checkboxes
PdfOxide.set_form_field_value(editor, "agree_to_terms", "true")

PdfOxide.editor_save(editor, "filled_form.pdf")

フォームデータのエクスポート

フォームフィールドデータをFDFまたはXFDF形式にエクスポートして他のアプリケーションと連携できます。

FDFエクスポート

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
doc.export_form_data("form_data.fdf")

WASM

const doc = new WasmPdfDocument(bytes);
const fdfBytes = doc.exportFormData("fdf");
// fdfBytes is a Uint8Array

Rust

use pdf_oxide::extractors::FormExtractor;
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("form.pdf")?;
let fields = FormExtractor::extract_fields(&mut doc)?;
let fdf_bytes = FormExtractor::export_fdf(&mut doc, fields)?;
std::fs::write("form_data.fdf", &fdf_bytes)?;

C++

auto doc = pdf_oxide::Document::open("form.pdf");
auto fdf = doc.export_form_data_to_bytes(0); // 0 = FDF
std::ofstream("form_data.fdf", std::ios::binary)
    .write(reinterpret_cast<const char*>(fdf.data()), fdf.size());

Swift

let doc = try Document.open("form.pdf")
let fdf = try doc.exportFormData(formatType: 0) // 0 = FDF
try Data(fdf).write(to: URL(fileURLWithPath: "form_data.fdf"))

Dart

final doc = PdfDocument.open('form.pdf');
final fdf = doc.exportFormDataToBytes(0); // 0 = FDF
File('form_data.fdf').writeAsBytesSync(fdf);

R

doc <- pdf_open("form.pdf")
fdf <- pdf_export_form_data_to_bytes(doc, format_type = 0L) # 0 = FDF
writeBin(fdf, "form_data.fdf")

Julia

doc = open_document("form.pdf")
fdf = export_form_data_to_bytes(doc, 0) # 0 = FDF
write("form_data.fdf", fdf)

Zig

var doc = try pdf_oxide.Document.open("form.pdf");
const fdf = try doc.exportFormDataToBytes(a, 0); // 0 = FDF
defer a.free(fdf);
try std.fs.cwd().writeFile(.{ .sub_path = "form_data.fdf", .data = fdf });

Objective-C

POXDocument *doc = [POXDocument openPath:@"form.pdf" error:&err];
NSData *fdf = [doc exportFormDataToBytes:0 error:&err]; // 0 = FDF
[fdf writeToFile:@"form_data.fdf" atomically:YES];

Elixir

{:ok, doc} = PdfOxide.open("form.pdf")
{:ok, fdf} = PdfOxide.export_form_data_to_bytes(doc, 0) # 0 = FDF
File.write!("form_data.fdf", fdf)

XFDFエクスポート

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
doc.export_form_data("form_data.xfdf", format="xfdf")

WASM

const doc = new WasmPdfDocument(bytes);
const xfdfBytes = doc.exportFormData("xfdf");

Rust

use pdf_oxide::extractors::FormExtractor;
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("form.pdf")?;
let fields = FormExtractor::extract_fields(&mut doc)?;
let xfdf = FormExtractor::export_xfdf(&mut doc, fields)?;
std::fs::write("form_data.xfdf", &xfdf)?;

C++

auto doc = pdf_oxide::Document::open("form.pdf");
auto xfdf = doc.export_form_data_to_bytes(1); // 1 = XFDF
std::ofstream("form_data.xfdf", std::ios::binary)
    .write(reinterpret_cast<const char*>(xfdf.data()), xfdf.size());

Swift

let doc = try Document.open("form.pdf")
let xfdf = try doc.exportFormData(formatType: 1) // 1 = XFDF
try Data(xfdf).write(to: URL(fileURLWithPath: "form_data.xfdf"))

Dart

final doc = PdfDocument.open('form.pdf');
final xfdf = doc.exportFormDataToBytes(1); // 1 = XFDF
File('form_data.xfdf').writeAsBytesSync(xfdf);

R

doc <- pdf_open("form.pdf")
xfdf <- pdf_export_form_data_to_bytes(doc, format_type = 1L) # 1 = XFDF
writeBin(xfdf, "form_data.xfdf")

Julia

doc = open_document("form.pdf")
xfdf = export_form_data_to_bytes(doc, 1) # 1 = XFDF
write("form_data.xfdf", xfdf)

Zig

var doc = try pdf_oxide.Document.open("form.pdf");
const xfdf = try doc.exportFormDataToBytes(a, 1); // 1 = XFDF
defer a.free(xfdf);
try std.fs.cwd().writeFile(.{ .sub_path = "form_data.xfdf", .data = xfdf });

Objective-C

POXDocument *doc = [POXDocument openPath:@"form.pdf" error:&err];
NSData *xfdf = [doc exportFormDataToBytes:1 error:&err]; // 1 = XFDF
[xfdf writeToFile:@"form_data.xfdf" atomically:YES];

Elixir

{:ok, doc} = PdfOxide.open("form.pdf")
{:ok, xfdf} = PdfOxide.export_form_data_to_bytes(doc, 1) # 1 = XFDF
File.write!("form_data.xfdf", xfdf)

データのインポートについて

エクスポートはラウンドトリップの読み取り側です。FDF/XFDFデータをPDFに書き戻す書き込み側については編集ドキュメントをご参照ください。C ABIとSwiftバインディングでは pdf_editor_import_fdf_bytes、pdf_editor_import_xfdf_bytes、pdf_form_import_from_file、pdf_document_import_form_data が宣言されていますが、v0.3.69ではこれらは Unsupported ステータスを返します。移植性の高いアプローチとしては、FDF/XFDFを手動で解析して set_form_field_value を呼び出す方法を推奨します。実行可能なインポート例についてはフォームフィールドの編集 → フォームデータのインポートを参照してください。


MarkdownおよびHTMLへのフォームフィールド出力

フォームフィールドの値はデフォルトでMarkdownおよびHTMLへの変換時に含まれます。include_form_fields パラメータで制御できます。

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")

# Include form field values (default)
md = doc.to_markdown(0, include_form_fields=True)

# Exclude form fields
md = doc.to_markdown(0, include_form_fields=False)

WASM

const doc = new WasmPdfDocument(bytes);

// Include form fields (default: true)
const md = doc.toMarkdown(0, true, true, true);

// Exclude form fields (4th parameter)
const md2 = doc.toMarkdown(0, true, true, false);

Rust

use pdf_oxide::PdfDocument;
use pdf_oxide::converters::ConversionOptions;

let doc = PdfDocument::open("form.pdf")?;
let options = ConversionOptions {
    include_form_fields: true,
    ..Default::default()
};
let md = doc.to_markdown(0, &options)?;

フォームのフラット化

フォームフィールドをページコンテンツに統合して編集不可にします。最終版PDFの作成に便利です。

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")

# Flatten all form fields
doc.flatten_forms()
doc.save("flattened.pdf")

# Or flatten a single page
doc2 = PdfDocument("form.pdf")
doc2.flatten_forms_on_page(0)
doc2.save("flattened_page0.pdf")

WASM

const doc = new WasmPdfDocument(bytes);

// Flatten all form fields
doc.flattenForms();
const flattened = doc.save();

// Or flatten a single page
const doc2 = new WasmPdfDocument(bytes);
doc2.flattenFormsOnPage(0);
const flattened2 = doc2.save();

Rust

use pdf_oxide::Pdf;

let mut pdf = Pdf::open("form.pdf")?;

// Mark a specific page for flattening
pdf.flatten_page_annotations(0);
pdf.save("flattened.pdf")?;

// Or flatten all pages
let mut pdf2 = Pdf::open("form.pdf")?;
pdf2.flatten_all_annotations();
pdf2.save("flattened_all.pdf")?;

C++

auto editor = pdf_oxide::DocumentEditor::open("form.pdf");

// Flatten all form fields
editor.flatten_forms();
editor.save("flattened.pdf");

// Or flatten a single page
auto editor2 = pdf_oxide::DocumentEditor::open("form.pdf");
editor2.flatten_forms_on_page(0);
editor2.save("flattened_page0.pdf");

Swift

let editor = try DocumentEditor.openEditor("form.pdf")

// Flatten all form fields
try editor.flattenForms()
try editor.save("flattened.pdf")

// Or flatten a single page
let editor2 = try DocumentEditor.openEditor("form.pdf")
try editor2.flattenFormsOnPage(0)
try editor2.save("flattened_page0.pdf")

Dart

final editor = DocumentEditor.open('form.pdf');

// Flatten all form fields
editor.flattenForms();
editor.save('flattened.pdf');

// Or flatten a single page
final editor2 = DocumentEditor.open('form.pdf');
editor2.flattenFormsOnPage(0);
editor2.save('flattened_page0.pdf');

R

editor <- pdf_editor_open("form.pdf")

# Flatten all form fields
pdf_editor_flatten_forms(editor)
pdf_editor_save(editor, "flattened.pdf")

# Or flatten a single page
editor2 <- pdf_editor_open("form.pdf")
pdf_editor_flatten_forms_on_page(editor2, 0)
pdf_editor_save(editor2, "flattened_page0.pdf")

Julia

editor = open_editor("form.pdf")

# Flatten all form fields
flatten_forms(editor)
save(editor, "flattened.pdf")

# Or flatten a single page
editor2 = open_editor("form.pdf")
flatten_forms_on_page(editor2, 0)
save(editor2, "flattened_page0.pdf")

Zig

var editor = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor.deinit();

// Flatten all form fields
try editor.flattenForms();
try editor.save("flattened.pdf");

// Or flatten a single page
var editor2 = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor2.deinit();
try editor2.flattenFormsOnPage(0);
try editor2.save("flattened_page0.pdf");

Objective-C

POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"form.pdf" error:&err];

// Flatten all form fields
[editor flattenForms:&err];
[editor saveToPath:@"flattened.pdf" error:&err];

// Or flatten a single page
POXDocumentEditor *editor2 = [POXDocumentEditor openEditor:@"form.pdf" error:&err];
[editor2 flattenFormsOnPage:0 error:&err];
[editor2 saveToPath:@"flattened_page0.pdf" error:&err];

Elixir

{:ok, editor} = PdfOxide.open_editor("form.pdf")

# Flatten all form fields
PdfOxide.flatten_forms(editor)
PdfOxide.editor_save(editor, "flattened.pdf")

# Or flatten a single page
{:ok, editor2} = PdfOxide.open_editor("form.pdf")
PdfOxide.flatten_forms_on_page(editor2, 0)
PdfOxide.editor_save(editor2, "flattened_page0.pdf")

XFAフォーム

XFA(XML Forms Architecture)フォームのコンテンツを解析できます。XFAフォームはAcroFormフィールドではなくXMLベースのテンプレートを使用しており、政府機関や企業向けフォームで広く使われています。

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("xfa-form.pdf")
if doc.has_xfa():
    print("This document contains an XFA form")
    fields = doc.get_form_fields()  # Extracts AcroForm fallback fields
    for field in fields:
        print(f"  {field.name}: {field.value}")

Node.js

const doc = new PdfDocument("xfa-form.pdf");
if (doc.hasXFA()) {
  console.log("This document contains an XFA form");
  const fields = doc.getFormFields();
  for (const field of fields) {
    console.log(`  ${field.name}: ${field.value}`);
  }
}
doc.close();

Go

doc, _ := pdfoxide.Open("xfa-form.pdf")
defer doc.Close()
if doc.HasXfa() {
    fmt.Println("This document contains an XFA form")
    fields, _ := doc.FormFields()
    for _, field := range fields {
        fmt.Printf("  %s: %s\n", field.Name, field.Value)
    }
}

C#

using var doc = PdfDocument.Open("xfa-form.pdf");
if (doc.HasXfa)
{
    Console.WriteLine("This document contains an XFA form");
    var fields = doc.GetFormFields();
    foreach (var field in fields)
    {
        Console.WriteLine($"  {field.Name}: {field.Value}");
    }
}

WASM

const doc = new WasmPdfDocument(bytes);
if (doc.hasXfa()) {
    console.log("This document contains an XFA form");
    const fields = doc.getFormFields(); // AcroForm fallback fields
    for (const field of fields) {
        console.log(`  ${field.name}: ${field.value}`);
    }
}

Rust

use pdf_oxide::xfa::analyze_xfa_document;
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("xfa-form.pdf")?;
let analysis = analyze_xfa_document(&mut doc)?;
println!("XFA form detected: {} fields", analysis.fields.len());
for field in &analysis.fields {
    println!("  {} ({:?})", field.name, field.field_type);
}

C++

auto doc = pdf_oxide::Document::open("xfa-form.pdf");
if (doc.has_xfa()) {
    std::cout << "This document contains an XFA form\n";
    for (const auto& field : doc.get_form_fields()) { // AcroForm fallback
        std::cout << "  " << field.name << ": " << field.value << "\n";
    }
}

Swift

let doc = try Document.open("xfa-form.pdf")
if try doc.hasXfa() {
    print("This document contains an XFA form")
    for field in try doc.formFields() { // AcroForm fallback
        print("  \(field.name): \(field.value)")
    }
}

Dart

final doc = PdfDocument.open('xfa-form.pdf');
if (doc.hasXfa()) {
  print('This document contains an XFA form');
  for (final field in doc.getFormFields()) { // AcroForm fallback
    print('  ${field.name}: ${field.value}');
  }
}

R

doc <- pdf_open("xfa-form.pdf")
if (pdf_has_xfa(doc)) {
  cat("This document contains an XFA form\n")
  for (field in pdf_get_form_fields(doc)) { # AcroForm fallback
    cat(sprintf("  %s: %s\n", field$name, field$value))
  }
}

Julia

doc = open_document("xfa-form.pdf")
if has_xfa(doc)
    println("This document contains an XFA form")
    for field in get_form_fields(doc) # AcroForm fallback
        println("  $(field.name): $(field.value)")
    end
end

Zig

var doc = try pdf_oxide.Document.open("xfa-form.pdf");
if (doc.hasXfa()) {
    std.debug.print("This document contains an XFA form\n", .{});
    var fields = try doc.formFields(); // AcroForm fallback
    defer fields.deinit();
    const count = try fields.count();
    var i: i32 = 0;
    while (i < count) : (i += 1) {
        const name = try fields.getName(a, i);
        const value = try fields.getValue(a, i);
        std.debug.print("  {s}: {s}\n", .{ name, value });
    }
}

Objective-C

POXDocument *doc = [POXDocument openPath:@"xfa-form.pdf" error:&err];
if ([doc hasXfa]) {
    NSLog(@"This document contains an XFA form");
    for (POXFormField *field in [doc formFieldsWithError:&err]) { // AcroForm fallback
        NSLog(@"  %@: %@", field.name, field.value);
    }
}

Elixir

{:ok, doc} = PdfOxide.open("xfa-form.pdf")
if PdfOxide.has_xfa?(doc) do
  IO.puts("This document contains an XFA form")
  {:ok, fields} = PdfOxide.form_fields(doc) # AcroForm fallback
  Enum.each(fields, fn field -> IO.puts("  #{field.name}: #{field.value}") end)
end

APIリファレンス

Python API

メソッド 説明
doc.get_form_fields() すべてのフォームフィールドを FormField オブジェクトとして取得
doc.get_form_field_value(name) 指定した名前のフィールド値を取得
doc.set_form_field_value(name, value) フォームフィールドの値を設定
doc.export_form_data(path, format="fdf") フォームデータをFDFまたはXFDFファイルにエクスポート
doc.has_xfa() ドキュメントにXFAフォームが含まれているか確認
doc.flatten_forms() すべてのフォームフィールドをページコンテンツに統合
doc.flatten_forms_on_page(page) 指定ページのフォームフィールドを統合

Python FormFieldプロパティ

プロパティ 型 説明
name str フィールド名
field_type str フィールドタイプ(text、checkbox、radio、choice、signature)
value str | bool | None 現在のフィールド値
is_required bool 必須フィールドかどうか
is_readonly bool 読み取り専用かどうか
max_length int | None テキストフィールドの最大文字数

JavaScript API

メソッド 説明
doc.getFormFields() すべてのフォームフィールドを取得
doc.getFormFieldValue(name) 指定した名前のフィールド値を取得
doc.setFormFieldValue(name, value) フォームフィールドの値を設定
doc.exportFormData(format?) FDF(デフォルト)またはXFDFとしてエクスポート、Uint8Array を返す
doc.hasXfa() ドキュメントにXFAフォームが含まれているか確認
doc.flattenForms() すべてのフォームフィールドをページコンテンツに統合
doc.flattenFormsOnPage(pageIndex) 指定ページのフォームフィールドを統合

JavaScript FormFieldプロパティ

プロパティ 型 説明
name string フィールド名
fieldType string フィールドタイプ
value string | boolean | null 現在の値
flags number フィールドフラグ

Rust API

関数 説明
FormExtractor::extract_fields(doc) AcroForm辞書からすべてのフォームフィールドを抽出
FormExtractor::export_fdf(doc, fields) FDFバイト列としてエクスポート
FormExtractor::export_xfdf(doc, fields) XFDF文字列としてエクスポート
analyze_xfa_document(doc) XFAフォーム構造を解析
editor.get_form_fields() DocumentEditor経由でフィールドを取得
editor.get_form_field_value(name) 名前でフィールド値を取得
editor.set_form_field_value(name, value) フィールド値を設定

FormFieldフィールド(Rust)

フィールド 型 説明
name String /T キーからのフィールド名
full_name String 完全修飾名(ドット区切り)
field_type FieldType Button、Text、Choice、Signature、Unknown
value FieldValue 現在のフィールド値
tooltip Option<String> /TU キーからのツールチップ
bounds Option<[f64; 4]> バウンディングボックス [x1, y1, x2, y2]
flags Option<u32> フィールドフラグ(ReadOnly、Required、NoExport)
default_value Option<FieldValue> /DV キーからのデフォルト値
max_length Option<u32> テキストフィールドの最大長

FieldTypeバリアント

バリアント 説明
Button チェックボックス、ラジオボタン、またはプッシュボタン(/Btn)
Text 単一行または複数行のテキストフィールド(/Tx)
Choice リストボックスまたはコンボボックス(/Ch)
Signature デジタル署名フィールド(/Sig)
Unknown(String) 認識できないフィールドタイプ

FieldValueバリアント

バリアント 説明
Text(String) テキスト文字列値
Boolean(bool) ブール値(チェックボックス)
Name(String) 名前値(ラジオボタン、選択フィールド)
Array(Vec<String>) 複数値(複数選択リストボックス)
None 値なし

応用例:必須フィールドの確認

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
fields = doc.get_form_fields()

missing = [f for f in fields if f.is_required and not f.value]
if missing:
    print("Missing required fields:")
    for f in missing:
        print(f"  - {f.name}")

Rust

use pdf_oxide::extractors::{FormExtractor, FieldValue};
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("form.pdf")?;
let fields = FormExtractor::extract_fields(&mut doc)?;

let required_empty: Vec<_> = fields.iter()
    .filter(|f| {
        f.flags.map_or(false, |flags| flags & 0x02 != 0)
            && matches!(f.value, FieldValue::None | FieldValue::Text(ref s) if s.is_empty())
    })
    .collect();

if !required_empty.is_empty() {
    println!("Missing required fields:");
    for f in &required_empty {
        println!("  - {}", f.full_name);
    }
}

C++

auto doc = pdf_oxide::Document::open("form.pdf");
for (const auto& field : doc.get_form_fields()) {
    if (field.required && field.value.empty()) {
        std::cout << "Missing required field: " << field.name << "\n";
    }
}

Swift

let doc = try Document.open("form.pdf")
for field in try doc.formFields() where field.required && field.value.isEmpty {
    print("Missing required field: \(field.name)")
}

Dart

final doc = PdfDocument.open('form.pdf');
for (final field in doc.getFormFields()) {
  if (field.required && field.value.isEmpty) {
    print('Missing required field: ${field.name}');
  }
}

R

doc <- pdf_open("form.pdf")
for (field in pdf_get_form_fields(doc)) {
  if (field$required && field$value == "") {
    cat(sprintf("Missing required field: %s\n", field$name))
  }
}

Julia

doc = open_document("form.pdf")
for field in get_form_fields(doc)
    if field.required && isempty(field.value)
        println("Missing required field: $(field.name)")
    end
end

Zig

var doc = try pdf_oxide.Document.open("form.pdf");
var fields = try doc.formFields();
defer fields.deinit();
const count = try fields.count();
var i: i32 = 0;
while (i < count) : (i += 1) {
    const value = try fields.getValue(a, i);
    if (try fields.isRequired(i) and value.len == 0) {
        const name = try fields.getName(a, i);
        std.debug.print("Missing required field: {s}\n", .{name});
    }
}

Objective-C

POXDocument *doc = [POXDocument openPath:@"form.pdf" error:&err];
for (POXFormField *field in [doc formFieldsWithError:&err]) {
    if (field.required && field.value.length == 0) {
        NSLog(@"Missing required field: %@", field.name);
    }
}

Elixir

{:ok, doc} = PdfOxide.open("form.pdf")
{:ok, fields} = PdfOxide.form_fields(doc)
fields
|> Enum.filter(fn f -> f.required and f.value in [nil, ""] end)
|> Enum.each(fn f -> IO.puts("Missing required field: #{f.name}") end)

関連ページ