Form XObject vòng 4 — kiến trúc cuối: MỞ GÓI form ra cấp trang trước khi sửa
Build Windows portable / build (push) Canceled after 0s
Build Windows portable / build (push) Canceled after 0s
Kết luận sau 3 vòng CI + đọc nguyên văn source PDFium: PDFium hiện KHÔNG ghi lại được stream của Form XObject — CPDF_PageContentManager chỉ biết key /Contents (trang), form là stream tự thân nên nội dung regenerate rơi vào key /Contents vô nghĩa trên dict form, stream thật giữ nguyên. Mọi cách sửa "trong form" đều không thể lưu. - Engine mới: flatten_form_xobjects — rút từng con khỏi form (FPDFFormObj_RemoveObject), nhân ma trận form vào con, chèn lại vào TRANG, xoá form rỗng; lặp <=4 vòng cho form lồng form. Hiển thị y hệt, mọi object thành cấp trang, sửa bằng đường page-level đã test kỹ. - Tauri: command edit_flatten_to_temp; UI loadEditPage thấy object nested → tự mở gói một lần rồi nạp lại (bản mở gói không tính là "có thay đổi"). - apply_edits: gỡ toàn bộ đường sửa-trong-form (NestedRecreate, rút con, đánh thức trang — đã chứng minh không thể lưu); op nhắm vào object trong form khi chưa flatten → lỗi rõ "trang chưa được mở gói" (có test). - Test viết lại theo flow flatten: 6 test (liệt kê nested, flatten giữ vị trí/nội dung, settext/reflow/delete sau flatten, từ chối op nested). Docs 12-phase4-summary.md cập nhật kết luận + giới hạn (mất clip/ExtGState mức form khi flatten; cấu trúc file đổi khi lưu). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1302,6 +1302,28 @@ fn pick_save_pem(app: tauri::AppHandle) -> Option<String> {
|
||||
.map(|fp| fp.to_string())
|
||||
}
|
||||
|
||||
/// "Mở gói" mọi Form XObject của trang ra cấp trang (file Canva/Illustrator
|
||||
/// gói cả trang vào form — PDFium không ghi lại được stream form nên phải
|
||||
/// flatten trước khi sửa). Trả None nếu trang không có form (không tạo file).
|
||||
#[tauri::command]
|
||||
fn edit_flatten_to_temp(input: String, page: u16, password: Option<String>) -> Result<Option<String>, String> {
|
||||
let pdfium = pdfium()?;
|
||||
let nanos = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_nanos())
|
||||
.unwrap_or(0);
|
||||
let out = std::env::temp_dir().join(format!("ff_edit_flat_{}_{}.pdf", std::process::id(), nanos));
|
||||
let n = ff_engine::flatten_form_xobjects(
|
||||
&pdfium,
|
||||
std::path::Path::new(&input),
|
||||
page,
|
||||
&out,
|
||||
password.as_deref(),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(if n > 0 { Some(out.to_string_lossy().into_owned()) } else { None })
|
||||
}
|
||||
|
||||
/// Dọn các file làm việc tạm của chế độ sửa (undo stack). Chỉ xoá file có tên
|
||||
/// `ff_edit_*` nằm đúng trong thư mục temp — không bao giờ đụng file người dùng.
|
||||
#[tauri::command]
|
||||
@@ -1362,6 +1384,7 @@ fn main() {
|
||||
edit_apply_to_temp,
|
||||
edit_preview,
|
||||
edit_cleanup,
|
||||
edit_flatten_to_temp,
|
||||
redact_apply,
|
||||
security_encrypt,
|
||||
security_decrypt,
|
||||
|
||||
Reference in New Issue
Block a user