Редагування полів форм
PDF Oxide забезпечує повноцінну роботу з полями форм: читання наявних значень, програмне заповнення полів, додавання нових полів, налаштування властивостей, зведення форм у статичний вміст і експорт даних у форматах FDF/XFDF. XFA-форми можна проаналізувати й перетворити на AcroForm.
Читання полів форм
Отримати всі поля форми
Rust
use pdf_oxide::editor::DocumentEditor;
let mut editor = DocumentEditor::open("form.pdf")?;
let fields = editor.get_form_fields()?;
for field in &fields {
println!("Field: {} = {:?}", field.name(), field.value());
if let Some(ft) = field.field_type() {
println!(" Type: {:?}", ft);
}
if let Some(tooltip) = field.tooltip() {
println!(" Tooltip: {}", tooltip);
}
}
WASM
const doc = new WasmPdfDocument(bytes);
const fields = doc.getFormFields();
for (const f of fields) {
console.log(`${f.name} (${f.fieldType}) = ${f.value}`);
}
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}")
Go
doc, _ := pdfoxide.Open("form.pdf")
defer doc.Close()
fields, _ := doc.FormFields()
for _, f := range fields {
fmt.Printf("%s (%s) = %s\n", f.Name, f.Type, f.Value)
}
C#
using var doc = PdfDocument.Open("form.pdf");
foreach (var f in doc.GetFormFields())
Console.WriteLine($"{f.Name} ({f.Type}) = {f.Value}");
Java
try (PdfDocument doc = PdfDocument.open(java.nio.file.Path.of("form.pdf"))) {
for (fyi.oxide.pdf.form.FormField f : doc.formFields()) {
System.out.println(f.name() + " (" + f.type() + ") = " + f.value().orElse(""));
}
}
Kotlin
PdfDocument.open(java.nio.file.Path.of("form.pdf")).use { doc ->
for (f in doc.formFields()) {
println("${f.name()} (${f.type()}) = ${f.value().orElse("")}")
}
}
Scala
Using.resource(PdfDocument.open("form.pdf")) { doc =>
doc.formFieldsSeq.foreach { f =>
println(s"${f.name} (${f.`type`}) = ${f.valueOption.getOrElse("")}")
}
}
Clojure
(with-open [doc (pdf/open "form.pdf")]
(doseq [f (pdf/form-fields doc)]
(println (.name f) "(" (.type f) ") =" (.orElse (.value f) ""))))
Ruby
PdfOxide::PdfDocument.open('form.pdf') do |doc|
doc.form_fields.each do |f|
puts "#{f[:name]} (#{f[:type]}) = #{f[:value]}"
end
end
C++
auto doc = pdf_oxide::Document::open("form.pdf");
for (const auto& f : doc.get_form_fields())
std::cout << f.name << " (" << f.type << ") = " << f.value << "\n";
Swift
let doc = try Document.open("form.pdf")
for f in try doc.formFields() {
print("\(f.name) (\(f.type)) = \(f.value)")
}
Dart
final doc = PdfDocument.open('form.pdf');
for (final f in doc.getFormFields()) {
print('${f.name} (${f.type}) = ${f.value}');
}
R
doc <- pdf_open("form.pdf")
for (f in pdf_get_form_fields(doc)) {
cat(sprintf("%s (%s) = %s\n", f$name, f$type, f$value))
}
Julia
doc = open_document("form.pdf")
for f in get_form_fields(doc)
println("$(f.name) ($(f.type)) = $(f.value)")
end
Zig
var doc = try pdf_oxide.Document.open("form.pdf");
var fields = try doc.formFields();
defer fields.deinit();
const n = try fields.count();
var i: i32 = 0;
while (i < n) : (i += 1) {
const name = try fields.getName(a, i);
defer a.free(name);
const ftype = try fields.getType(a, i);
defer a.free(ftype);
const value = try fields.getValue(a, i);
defer a.free(value);
std.debug.print("{s} ({s}) = {s}\n", .{ name, ftype, value });
}
Objective-C
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"form.pdf" error:&err];
for (POXFormField *f in [doc formFieldsWithError:&err]) {
NSLog(@"%@ (%@) = %@", f.name, f.type, f.value);
}
Elixir
{:ok, doc} = PdfOxide.open("form.pdf")
{:ok, fields} = PdfOxide.form_fields(doc)
for f <- fields do
IO.puts("#{f.name} (#{f.type}) = #{f.value}")
end
Отримати значення конкретного поля
Rust
let mut editor = DocumentEditor::open("form.pdf")?;
let value = editor.get_form_field_value("first_name")?;
println!("First name: {:?}", value);
WASM
const value = doc.getFormFieldValue("first_name");
console.log(`First name: ${value}`);
Python
value = doc.get_form_field_value("first_name")
print(f"First name: {value}")
Перевірити існування поля
let mut editor = DocumentEditor::open("form.pdf")?;
if editor.has_form_field("email")? {
println!("Email field exists");
}
Встановлення значень полів форм
Задати значення поля
Rust
use pdf_oxide::editor::DocumentEditor;
use pdf_oxide::editor::form_fields::FormFieldValue;
let mut editor = DocumentEditor::open("form.pdf")?;
// Set a text field
editor.set_form_field_value("first_name", FormFieldValue::Text("Jane".to_string()))?;
// Set a checkbox
editor.set_form_field_value("agree_terms", FormFieldValue::Boolean(true))?;
// Set a choice field
editor.set_form_field_value("country", FormFieldValue::Choice("United States".to_string()))?;
editor.save("filled.pdf")?;
WASM
const doc = new WasmPdfDocument(bytes);
doc.setFormFieldValue("first_name", "Jane");
doc.setFormFieldValue("agree_terms", true);
doc.setFormFieldValue("country", "United States");
writeFileSync("filled.pdf", doc.save());
doc.free();
Python
doc = PdfDocument("form.pdf")
doc.set_form_field_value("first_name", "Jane")
doc.set_form_field_value("agree_terms", True)
doc.set_form_field_value("country", "United States")
doc.save("filled.pdf")
Go
editor, _ := pdfoxide.OpenEditor("form.pdf")
defer editor.Close()
_ = editor.SetFormFieldValue("first_name", "Jane")
_ = editor.SetFormFieldValue("agree_terms", "Yes")
_ = editor.SetFormFieldValue("country", "United States")
_ = editor.Save("filled.pdf")
C#
using var editor = DocumentEditor.Open("form.pdf");
editor.SetFormFieldValue("first_name", "Jane");
editor.SetFormFieldValue("agree_terms", "Yes");
editor.SetFormFieldValue("country", "United States");
editor.Save("filled.pdf");
Java
try (DocumentEditor editor = DocumentEditor.open("form.pdf")) {
editor.setFormField("first_name", "Jane");
editor.setFormField("agree_terms", true);
editor.setFormField("country", "United States");
editor.saveTo(java.nio.file.Path.of("filled.pdf"));
}
Kotlin
DocumentEditor.open("form.pdf").use { editor ->
editor.setFormField("first_name", "Jane")
editor.setFormField("agree_terms", true)
editor.setFormField("country", "United States")
editor.saveTo(java.nio.file.Path.of("filled.pdf"))
}
Scala
Using.resource(DocumentEditor.open("form.pdf")) { editor =>
editor.setFormField("first_name", "Jane")
editor.setFormField("agree_terms", true)
editor.setFormField("country", "United States")
editor.saveTo(java.nio.file.Path.of("filled.pdf"))
}
Clojure
(with-open [editor (pdf/editor "form.pdf")]
(.setFormField editor "first_name" "Jane")
(.setFormField editor "agree_terms" true)
(.setFormField editor "country" "United States")
(.saveTo editor (java.nio.file.Path/of "filled.pdf" (into-array String []))))
Ruby
PdfOxide::DocumentEditor.open('form.pdf') do |editor|
editor.set_form_field('first_name', 'Jane')
editor.set_form_field('agree_terms', true)
editor.set_form_field('country', 'United States')
editor.save_to('filled.pdf')
end
C++
auto editor = pdf_oxide::DocumentEditor::open("form.pdf");
editor.set_form_field_value("first_name", "Jane");
editor.set_form_field_value("agree_terms", "Yes");
editor.set_form_field_value("country", "United States");
editor.save("filled.pdf");
Swift
let editor = try DocumentEditor.open("form.pdf")
try editor.setFormFieldValue("first_name", "Jane")
try editor.setFormFieldValue("agree_terms", "Yes")
try editor.setFormFieldValue("country", "United States")
try editor.save("filled.pdf")
Dart
final editor = DocumentEditor.open('form.pdf');
editor.setFormFieldValue('first_name', 'Jane');
editor.setFormFieldValue('agree_terms', 'Yes');
editor.setFormFieldValue('country', 'United States');
editor.save('filled.pdf');
R
editor <- pdf_editor_open("form.pdf")
pdf_editor_set_form_field_value(editor, "first_name", "Jane")
pdf_editor_set_form_field_value(editor, "agree_terms", "Yes")
pdf_editor_set_form_field_value(editor, "country", "United States")
pdf_editor_save(editor, "filled.pdf")
Julia
editor = open_editor("form.pdf")
set_form_field_value(editor, "first_name", "Jane")
set_form_field_value(editor, "agree_terms", "Yes")
set_form_field_value(editor, "country", "United States")
save(editor, "filled.pdf")
Zig
var editor = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor.deinit();
try editor.setFormFieldValue("first_name", "Jane");
try editor.setFormFieldValue("agree_terms", "Yes");
try editor.setFormFieldValue("country", "United States");
try editor.save("filled.pdf");
Objective-C
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"form.pdf" error:&err];
[editor setFormField:@"first_name" value:@"Jane" error:&err];
[editor setFormField:@"agree_terms" value:@"Yes" error:&err];
[editor setFormField:@"country" value:@"United States" error:&err];
[editor saveToPath:@"filled.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("form.pdf")
PdfOxide.set_form_field_value(editor, "first_name", "Jane")
PdfOxide.set_form_field_value(editor, "agree_terms", "Yes")
PdfOxide.set_form_field_value(editor, "country", "United States")
PdfOxide.editor_save(editor, "filled.pdf")
Варіанти FormFieldValue
| Варіант | Опис | Приклад |
|---|---|---|
Text(String) |
Значення текстового поля | FormFieldValue::Text("Hello".into()) |
Boolean(bool) |
Стан прапорця/радіокнопки | FormFieldValue::Boolean(true) |
Choice(String) |
Єдиний вибір | FormFieldValue::Choice("Option A".into()) |
MultiChoice(Vec<String>) |
Множинний вибір | FormFieldValue::MultiChoice(vec!["A".into(), "B".into()]) |
None |
Без значення / очистити поле | FormFieldValue::None |
Додавання полів форм
Додати нове поле форми
use pdf_oxide::editor::DocumentEditor;
use pdf_oxide::writer::form_fields::TextFieldWidget;
let mut editor = DocumentEditor::open("document.pdf")?;
// Create a text input field on page 0
let widget = TextFieldWidget::new("user_name")
.with_rect(100.0, 700.0, 200.0, 20.0)
.with_default_value("Enter name");
editor.add_form_field(widget, 0)?;
editor.save("with-form.pdf")?;
Додати ієрархічні поля
Створіть відносини батьківського та дочірніх полів для структурованих форм.
use pdf_oxide::editor::form_fields::ParentFieldConfig;
let mut editor = DocumentEditor::open("document.pdf")?;
// Create a parent field
let parent = ParentFieldConfig::new("address");
editor.add_parent_field(parent)?;
// Add child fields under the parent
let street = TextFieldWidget::new("street")
.with_rect(100.0, 600.0, 300.0, 20.0);
editor.add_child_field(street, 0, "address")?;
let city = TextFieldWidget::new("city")
.with_rect(100.0, 570.0, 150.0, 20.0);
editor.add_child_field(city, 0, "address")?;
editor.save("hierarchical-form.pdf")?;
Видалити поле форми
let mut editor = DocumentEditor::open("form.pdf")?;
editor.remove_form_field("obsolete_field")?;
editor.save("cleaned.pdf")?;
Властивості полів форм
Налаштування властивостей
Задайте властивості окремих полів за іменем.
let mut editor = DocumentEditor::open("form.pdf")?;
// Access control
editor.set_form_field_readonly("signature_date", true)?;
editor.set_form_field_required("email", true)?;
// Tooltip
editor.set_form_field_tooltip("phone", "Enter phone number with area code")?;
// Position and size
editor.set_form_field_rect("name", pdf_oxide::geometry::Rect::new(100.0, 700.0, 200.0, 20.0))?;
// Text constraints
editor.set_form_field_max_length("zip_code", 10)?;
editor.set_form_field_alignment("amount", 2)?; // 0=left, 1=center, 2=right
// Appearance
editor.set_form_field_background_color("highlight_field", [1.0, 1.0, 0.8])?;
editor.set_form_field_border_color("name", [0.0, 0.0, 0.0])?;
editor.set_form_field_border_width("name", 1.0)?;
editor.set_form_field_default_appearance("name", "/Helv 12 Tf 0 g")?;
// Raw flags
editor.set_form_field_flags("options", 0x100000)?;
editor.save("styled-form.pdf")?;
Властивості FormFieldWrapper
При роботі з об’єктами FormFieldWrapper, що повертаються get_form_fields():
| Метод | Повертає | Опис |
|---|---|---|
name() |
&str |
Повне ім’я поля |
partial_name() |
&str |
Часткове ім’я (без префікса батька) |
value() |
FormFieldValue |
Поточне значення поля |
set_value(value) |
() |
Задати значення поля |
field_type() |
Option<&FieldType> |
Тип поля |
page_index() |
usize |
Сторінка, що містить поле |
bounds() |
Option<Rect> |
Положення та розмір поля |
tooltip() |
Option<&str> |
Текст підказки |
is_modified() |
bool |
Чи було змінено значення |
is_new() |
bool |
Чи є поле новоствореним (не з джерела) |
is_readonly() |
bool |
Прапор «лише для читання» |
set_readonly(bool) |
() |
Встановити прапор «лише для читання» |
is_required() |
bool |
Прапор обов’язковості |
set_required(bool) |
() |
Встановити прапор обов’язковості |
is_no_export() |
bool |
Прапор заборони експорту |
set_no_export(bool) |
() |
Встановити прапор заборони експорту |
set_tooltip(text) |
() |
Задати текст підказки |
set_rect(rect) |
() |
Задати положення та розмір |
set_max_length(len) |
() |
Задати максимальну довжину тексту |
get_max_length() |
Option<u32> |
Отримати максимальну довжину тексту |
set_alignment(align) |
() |
Задати вирівнювання тексту |
get_alignment() |
Option<u32> |
Отримати вирівнювання тексту |
set_background_color(rgb) |
() |
Задати колір фону |
get_background_color() |
Option<[f32; 3]> |
Отримати колір фону |
set_border_color(rgb) |
() |
Задати колір рамки |
get_border_color() |
Option<[f32; 3]> |
Отримати колір рамки |
set_border_width(width) |
() |
Задати ширину рамки |
get_border_width() |
Option<f32> |
Отримати ширину рамки |
set_default_appearance(da) |
() |
Задати рядок зовнішнього вигляду за замовчуванням |
get_default_appearance() |
Option<&str> |
Отримати рядок зовнішнього вигляду за замовчуванням |
set_default_value(value) |
() |
Задати значення за замовчуванням |
get_default_value() |
Option<&FormFieldValue> |
Отримати значення за замовчуванням |
has_parent() |
bool |
Перевірити наявність батьківського поля |
parent_name() |
Option<&str> |
Ім’я батьківського поля |
Зведення форм
Зведення перетворює інтерактивні поля форм на статичний вміст сторінки. Значення полів стають частиною відображення сторінки й більше не можуть редагуватися.
Звести форму на одній сторінці
Rust
let mut editor = DocumentEditor::open("form.pdf")?;
editor.flatten_forms_on_page(0)?;
editor.save("flat-page0.pdf")?;
WASM
const doc = new WasmPdfDocument(bytes);
doc.flattenFormsOnPage(0);
writeFileSync("flat-page0.pdf", doc.save());
doc.free();
C++
auto editor = pdf_oxide::DocumentEditor::open("form.pdf");
editor.flatten_forms_on_page(0);
editor.save("flat-page0.pdf");
Swift
let editor = try DocumentEditor.open("form.pdf")
try editor.flattenFormsOnPage(0)
try editor.save("flat-page0.pdf")
Dart
final editor = DocumentEditor.open('form.pdf');
editor.flattenFormsOnPage(0);
editor.save('flat-page0.pdf');
R
editor <- pdf_editor_open("form.pdf")
pdf_editor_flatten_forms_on_page(editor, 0)
pdf_editor_save(editor, "flat-page0.pdf")
Julia
editor = open_editor("form.pdf")
flatten_forms_on_page(editor, 0)
save(editor, "flat-page0.pdf")
Zig
var editor = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor.deinit();
try editor.flattenFormsOnPage(0);
try editor.save("flat-page0.pdf");
Objective-C
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"form.pdf" error:&err];
[editor flattenFormsOnPage:0 error:&err];
[editor saveToPath:@"flat-page0.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("form.pdf")
PdfOxide.flatten_forms_on_page(editor, 0)
PdfOxide.editor_save(editor, "flat-page0.pdf")
Звести всі форми
Rust
let mut editor = DocumentEditor::open("form.pdf")?;
editor.flatten_forms()?;
editor.save("flat.pdf")?;
WASM
const doc = new WasmPdfDocument(bytes);
doc.flattenForms();
writeFileSync("flat.pdf", doc.save());
doc.free();
Go
editor, _ := pdfoxide.OpenEditor("form.pdf")
defer editor.Close()
_ = editor.FlattenForms()
_ = editor.Save("flat.pdf")
C#
using var editor = DocumentEditor.Open("form.pdf");
editor.FlattenForms();
editor.Save("flat.pdf");
C++
auto editor = pdf_oxide::DocumentEditor::open("form.pdf");
editor.flatten_forms();
editor.save("flat.pdf");
Swift
let editor = try DocumentEditor.open("form.pdf")
try editor.flattenForms()
try editor.save("flat.pdf")
Dart
final editor = DocumentEditor.open('form.pdf');
editor.flattenForms();
editor.save('flat.pdf');
R
editor <- pdf_editor_open("form.pdf")
pdf_editor_flatten_forms(editor)
pdf_editor_save(editor, "flat.pdf")
Julia
editor = open_editor("form.pdf")
flatten_forms(editor)
save(editor, "flat.pdf")
Zig
var editor = try pdf_oxide.DocumentEditor.openEditor("form.pdf");
defer editor.deinit();
try editor.flattenForms();
try editor.save("flat.pdf");
Objective-C
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"form.pdf" error:&err];
[editor flattenForms:&err];
[editor saveToPath:@"flat.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("form.pdf")
PdfOxide.flatten_forms(editor)
PdfOxide.editor_save(editor, "flat.pdf")
Перевірити статус зведення
editor.flatten_forms_on_page(0)?;
assert!(editor.is_page_marked_for_form_flatten(0));
assert!(editor.will_remove_acroform());
Експорт даних форми
Експортуйте значення полів форми у формат FDF або XFDF для зовнішньої обробки.
Експорт у FDF
Rust
let mut editor = DocumentEditor::open("filled-form.pdf")?;
editor.export_form_data_fdf("form-data.fdf")?;
WASM
const doc = new WasmPdfDocument(bytes);
const fdfData = doc.exportFormData("fdf");
writeFileSync("form-data.fdf", fdfData);
doc.free();
Python
doc = PdfDocument("filled-form.pdf")
doc.export_form_data("form-data.fdf", format="fdf")
C++
auto doc = pdf_oxide::Document::open("filled-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("filled-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('filled-form.pdf');
final fdf = doc.exportFormDataToBytes(0); // 0 = FDF
File('form-data.fdf').writeAsBytesSync(fdf);
R
doc <- pdf_open("filled-form.pdf")
fdf <- pdf_export_form_data_to_bytes(doc, 0) # 0 = FDF
writeBin(fdf, "form-data.fdf")
Julia
doc = open_document("filled-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("filled-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
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"filled-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("filled-form.pdf")
{:ok, fdf} = PdfOxide.export_form_data_to_bytes(doc, 0) # 0 = FDF
File.write!("form-data.fdf", fdf)
Експорт у XFDF
Rust
let mut editor = DocumentEditor::open("filled-form.pdf")?;
editor.export_form_data_xfdf("form-data.xfdf")?;
WASM
const doc = new WasmPdfDocument(bytes);
const xfdfData = doc.exportFormData("xfdf");
writeFileSync("form-data.xfdf", xfdfData);
doc.free();
C++
auto doc = pdf_oxide::Document::open("filled-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("filled-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('filled-form.pdf');
final xfdf = doc.exportFormDataToBytes(1); // 1 = XFDF
File('form-data.xfdf').writeAsBytesSync(xfdf);
R
doc <- pdf_open("filled-form.pdf")
xfdf <- pdf_export_form_data_to_bytes(doc, 1) # 1 = XFDF
writeBin(xfdf, "form-data.xfdf")
Julia
doc = open_document("filled-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("filled-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
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"filled-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("filled-form.pdf")
{:ok, xfdf} = PdfOxide.export_form_data_to_bytes(doc, 1) # 1 = XFDF
File.write!("form-data.xfdf", xfdf)
Імпорт даних форми
Зворотна до експорту операція: завантаження значень полів з файлу FDF або XFDF (або з «сирих» байт FDF/XFDF) назад у документ. Це дозволяє взяти дані, заповнені деінде — у настільному PDF-переглядачі, іншій бібліотеці, серверному конвеєрі — і застосувати їх до полів AcroForm.
Як імпортувати дані FDF або XFDF у PDF?
У C ABI оголошено спеціалізовану родину функцій імпорту, а обгортка Swift надає всі чотири точки входу:
| Символ C ABI | Метод Swift | Джерело даних |
|---|---|---|
pdf_form_import_from_file |
importFormFromFile(_:) |
Шлях до файлу FDF/XFDF |
pdf_document_import_form_data |
importFormData(_:) |
Шлях до файлу FDF/XFDF |
pdf_editor_import_fdf_bytes |
importFdfBytes(_:) |
Байти FDF у пам’яті |
pdf_editor_import_xfdf_bytes |
importXfdfBytes(_:) |
Байти XFDF у пам’яті |
Точні сигнатури C ABI (з include/pdf_oxide_c/pdf_oxide.h):
bool pdf_form_import_from_file(const void *document, const char *filename, int32_t *error_code);
int32_t pdf_document_import_form_data(const void *document, const char *data_path, int32_t *error_code);
int32_t pdf_editor_import_fdf_bytes(const void *document, const uint8_t *data, uintptr_t data_len, int32_t *error_code);
int32_t pdf_editor_import_xfdf_bytes(const void *document, const uint8_t *data, uintptr_t data_len, int32_t *error_code);
Доступність у v0.3.69. Усі чотири точки входу оголошено в C ABI і надано обгорткою Swift, однак базова реалізація ще не підключена: у v0.3.69 кожна з них повертає статус
Unsupported(код помилки8) під час виконання. Прив’язки Python, Node.js, Go та WASM їх взагалі не надають, а Rust-рівневого читача FDF/XFDF теж не існує (модульpdf_oxide::fdfмістить лише експортну сторонуFdfWriter/XfdfWriter). Поки шлях імпорту не реалізовано, використовуйте обхідний метод «розібрати й заповнити», описаний нижче, — він працює у всіх прив’язках уже сьогодні.
Swift (інтерфейс присутній; кидає Unsupported, доки не з’явиться бекенд)
import PdfOxide
let editor = try DocumentEditor.open(path: "form.pdf")
// From a file on disk (FDF or XFDF):
try editor.importFormFromFile("submission.fdf") // -> Bool
try editor.importFormData("submission.xfdf") // -> Int32 status
// From in-memory bytes:
let fdf = Array("%FDF-1.2\n...".utf8)
try editor.importFdfBytes(fdf) // -> Int32 status
let xfdf = Array("<?xml version=\"1.0\"?><xfdf>...</xfdf>".utf8)
try editor.importXfdfBytes(xfdf) // -> Int32 status
try editor.save(to: "filled.pdf")
Кожен метод повертає код статусу FFI (або Bool для importFormFromFile) і кидає PdfOxideError при ненульовому коді помилки, тому наразі слід очікувати помилку Unsupported, а не зміни полів.
Як застосувати дані FDF/XFDF зараз (міжмовний обхідний метод)?
Оскільки set_form_field_value доступний у всіх прив’язках, переносний спосіб імпорту даних форми у v0.3.69 — самостійно розібрати FDF/XFDF і записати кожну пару ім'я -> значення у документ. Обидва формати є невеликими, добре специфікованими текстовими форматами: FDF огортає значення у синтаксис словників PDF, а XFDF — це звичайний XML.
Python – імпорт файлу XFDF
# `defusedxml` guards against XXE and billion-laughs attacks when parsing
# untrusted XFDF (the stdlib xml parsers are unsafe by default):
# pip install defusedxml
import defusedxml.ElementTree as ET
from pdf_oxide import PdfDocument
# XFDF: <xfdf><fields><field name="..."><value>...</value></field></fields></xfdf>
tree = ET.parse("submission.xfdf")
ns = {"x": "http://ns.adobe.com/xfdf/"}
doc = PdfDocument("form.pdf")
for field in tree.findall(".//x:field", ns) or tree.findall(".//field"):
name = field.get("name")
value_el = field.find("x:value", ns)
if value_el is None:
value_el = field.find("value")
if name and value_el is not None:
doc.set_form_field_value(name, value_el.text or "")
doc.save("filled.pdf")
Rust – імпорт файлу XFDF через DocumentEditor
use pdf_oxide::editor::DocumentEditor;
use pdf_oxide::editor::form_fields::FormFieldValue;
fn import_xfdf(pdf: &str, xfdf: &str, out: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut editor = DocumentEditor::open(pdf)?;
let xml = std::fs::read_to_string(xfdf)?;
// Minimal extraction of <field name="..."><value>...</value></field> pairs.
for chunk in xml.split("<field ").skip(1) {
let name = chunk
.split("name=\"").nth(1)
.and_then(|s| s.split('"').next());
let value = chunk
.split("<value>").nth(1)
.and_then(|s| s.split("</value>").next());
if let (Some(name), Some(value)) = (name, value) {
editor.set_form_field_value(name, FormFieldValue::Text(value.to_string()))?;
}
}
editor.save(out)?;
Ok(())
}
Node.js – імпорт файлу XFDF
const fs = require("fs");
const { PdfDocument } = require("pdf-oxide");
const xfdf = fs.readFileSync("submission.xfdf", "utf8");
const doc = new PdfDocument("form.pdf");
const re = /<field\s+name="([^"]+)"[^>]*>\s*<value>([\s\S]*?)<\/value>/g;
let m;
while ((m = re.exec(xfdf)) !== null) {
doc.setFormFieldValue(m[1], m[2]);
}
fs.writeFileSync("filled.pdf", doc.save());
doc.close();
Той самий підхід працює для FDF: розберіть кожен запис /T (name) /V (value) з масиву /Fields і викличте set_form_field_value. Щойно нативний шлях імпорту буде реалізовано, ручний розбір можна прибрати і викликати importFdfBytes / importXfdfBytes / importFormFromFile безпосередньо.
Підтримка XFA-форм
PDF Oxide вміє виявляти, аналізувати й конвертувати XFA-форми у стандартний AcroForm.
Перевірити наявність XFA
Rust
let mut editor = DocumentEditor::open("xfa-form.pdf")?;
if editor.has_xfa()? {
println!("Document contains XFA form data");
}
WASM
const doc = new WasmPdfDocument(bytes);
if (doc.hasXfa()) {
console.log("Document contains XFA form data");
}
Python
doc = PdfDocument("xfa-form.pdf")
if doc.has_xfa():
print("Document contains XFA form data")
C++
auto doc = pdf_oxide::Document::open("xfa-form.pdf");
if (doc.has_xfa())
std::cout << "Document contains XFA form data\n";
Swift
let doc = try Document.open("xfa-form.pdf")
if try doc.hasXfa() {
print("Document contains XFA form data")
}
Dart
final doc = PdfDocument.open('xfa-form.pdf');
if (doc.hasXfa()) {
print('Document contains XFA form data');
}
R
doc <- pdf_open("xfa-form.pdf")
if (pdf_has_xfa(doc)) {
cat("Document contains XFA form data\n")
}
Julia
doc = open_document("xfa-form.pdf")
if has_xfa(doc)
println("Document contains XFA form data")
end
Zig
var doc = try pdf_oxide.Document.open("xfa-form.pdf");
if (doc.hasXfa()) {
std.debug.print("Document contains XFA form data\n", .{});
}
Objective-C
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"xfa-form.pdf" error:&err];
if ([doc hasXfa]) {
NSLog(@"Document contains XFA form data");
}
Elixir
{:ok, doc} = PdfOxide.open("xfa-form.pdf")
if PdfOxide.has_xfa?(doc) do
IO.puts("Document contains XFA form data")
end
Аналіз структури XFA
let mut editor = DocumentEditor::open("xfa-form.pdf")?;
let analysis = editor.analyze_xfa()?;
println!("XFA analysis: {:?}", analysis);
Перетворити XFA на AcroForm
Конвертуйте XFA-форми у стандартні поля AcroForm для ширшої сумісності.
let mut editor = DocumentEditor::open("xfa-form.pdf")?;
editor.convert_xfa_to_acroform(&Default::default())?;
editor.save("acroform.pdf")?;
Повний довідник API
Операції з полями
| Метод | Повертає | Опис |
|---|---|---|
get_form_fields() |
Result<Vec<FormFieldWrapper>> |
Список усіх полів форми |
get_form_field_value(name) |
Result<FormFieldValue> |
Отримати значення поля |
has_form_field(name) |
Result<bool> |
Перевірити існування поля |
set_form_field_value(name, value) |
Result<()> |
Задати значення поля |
add_form_field(widget, page) |
Result<()> |
Додати нове поле |
add_parent_field(config) |
Result<()> |
Додати батьківське поле |
add_child_field(widget, page, parent) |
Result<()> |
Додати дочірнє поле |
remove_form_field(name) |
Result<()> |
Видалити поле |
Властивості полів (за іменем)
| Метод | Повертає | Опис |
|---|---|---|
set_form_field_readonly(name, bool) |
Result<()> |
Задати «лише для читання» |
set_form_field_required(name, bool) |
Result<()> |
Задати обов’язковість |
set_form_field_tooltip(name, text) |
Result<()> |
Задати підказку |
set_form_field_rect(name, rect) |
Result<()> |
Задати положення та розмір |
set_form_field_max_length(name, len) |
Result<()> |
Задати максимальну довжину тексту |
set_form_field_alignment(name, align) |
Result<()> |
Задати вирівнювання тексту |
set_form_field_background_color(name, rgb) |
Result<()> |
Задати колір фону |
set_form_field_border_color(name, rgb) |
Result<()> |
Задати колір рамки |
set_form_field_border_width(name, width) |
Result<()> |
Задати ширину рамки |
set_form_field_default_appearance(name, da) |
Result<()> |
Задати зовнішній вигляд за замовчуванням |
set_form_field_flags(name, flags) |
Result<()> |
Задати «сирі» прапори поля |
Зведення
| Метод | Повертає | Опис |
|---|---|---|
flatten_forms_on_page(page) |
Result<()> |
Звести форми на одній сторінці |
flatten_forms() |
Result<()> |
Звести всі форми |
is_page_marked_for_form_flatten(page) |
bool |
Перевірити статус зведення |
will_remove_acroform() |
bool |
Перевірити, чи буде видалено AcroForm |
Експорт
| Метод | Повертає | Опис |
|---|---|---|
export_form_data_fdf(path) |
Result<()> |
Експортувати у файл FDF |
export_form_data_xfdf(path) |
Result<()> |
Експортувати у файл XFDF |
Імпорт (C ABI + Swift; повертає Unsupported під час виконання у v0.3.69)
| Символ C ABI | Метод Swift | Повертає | Опис |
|---|---|---|---|
pdf_form_import_from_file |
importFormFromFile(_:) |
bool / Bool |
Імпортувати FDF/XFDF зі шляху до файлу |
pdf_document_import_form_data |
importFormData(_:) |
int32_t / Int32 |
Імпортувати дані форми зі шляху до файлу |
pdf_editor_import_fdf_bytes |
importFdfBytes(_:) |
int32_t / Int32 |
Імпортувати FDF з байт у пам’яті |
pdf_editor_import_xfdf_bytes |
importXfdfBytes(_:) |
int32_t / Int32 |
Імпортувати XFDF з байт у пам’яті |
Повертають код помилки 8 (Unsupported), доки нативний бекенд імпорту не з’явиться; для застосування розібраних даних FDF/XFDF сьогодні використовуйте set_form_field_value.
XFA
| Метод | Повертає | Опис |
|---|---|---|
has_xfa() |
Result<bool> |
Перевірити наявність даних XFA-форми |
analyze_xfa() |
Result<XfaAnalysis> |
Проаналізувати структуру XFA |
convert_xfa_to_acroform(options) |
Result<()> |
Перетворити XFA на AcroForm |
Розширений приклад: пакетне заповнення та зведення
use pdf_oxide::editor::DocumentEditor;
use pdf_oxide::editor::form_fields::FormFieldValue;
let mut editor = DocumentEditor::open("template.pdf")?;
// Fill form fields
editor.set_form_field_value("name", FormFieldValue::Text("John Doe".to_string()))?;
editor.set_form_field_value("date", FormFieldValue::Text("2025-12-01".to_string()))?;
editor.set_form_field_value("approved", FormFieldValue::Boolean(true))?;
// Make the completed form non-editable
editor.flatten_forms()?;
// Export data before saving
editor.export_form_data_xfdf("submission.xfdf")?;
editor.save("completed.pdf")?;
Часті запитання
Чи підтримує PDF Oxide імпорт даних FDF/XFDF назад у PDF у v0.3.69?
Поки що ні — нативного одноразового імпорту немає. У C ABI оголошено pdf_form_import_from_file, pdf_document_import_form_data, pdf_editor_import_fdf_bytes і pdf_editor_import_xfdf_bytes, обгортка Swift їх надає, але під час виконання вони повертають статус Unsupported (код помилки 8). Розберіть FDF/XFDF і викликайте set_form_field_value для кожного поля — це працює у всіх прив’язках вже сьогодні.
Які прив’язки надають методи імпорту?
Лише C ABI і обгортка Swift надають інтерфейс імпорту. Прив’язки Python, Node.js, Go та WASM його не надають. Експорт (export_form_data_fdf / export_form_data_xfdf і export_form_data) повністю реалізовано в усіх прив’язках.
У чому різниця між FDF і XFDF?
FDF — похідний від PDF бінарний/текстовий контейнер (заголовок %FDF-1.2, масив /Fields). XFDF — його XML-еквівалент (<xfdf><fields>...), який зручніше генерувати та розбирати стандартними засобами. Обидва формати несуть однакові дані ім'я поля -> значення; PDF Oxide вміє експортувати обидва.
Чи достатньо швидке заповнення для пакетних завдань? Так. Ядро вилучення PDF Oxide показує середній час 0,8 мс зі 100%-ним рівнем успіху на контрольному корпусі, тому читання полів, встановлення значень і повторне збереження займають значно менше мілісекунди на рівні полів для типових форм.
Пов’язані сторінки
- Огляд редагування – відкриття, метадані та процес збереження
- Редагування тексту – безпосередня зміна текстового вмісту
- Редагування анотацій – додавання анотацій та керування ними
- Шифрування та безпека – обмеження редагування форм за допомогою дозволів