Cong an toan cho mo goi form: so render truoc/sau (page_render_mismatch), lech >0.5% pixel -> huy + chan sua voi thong diep ro. E2E tren CV Canva that phat hien generator PDFium lossy (font subset trung ten bi gop lam mat glyph, anh inline bi bo, z-order xao tron) - khong ship flatten mu quang; ke hoach iteration sau (phau thuat stream bang lopdf) ghi trong docs.
Build Windows portable / build (push) Canceled after 0s
Build Windows portable / build (push) Canceled after 0s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1321,7 +1321,26 @@ fn edit_flatten_to_temp(input: String, page: u16, password: Option<String>) -> R
|
||||
password.as_deref(),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(if n > 0 { Some(out.to_string_lossy().into_owned()) } else { None })
|
||||
if n == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
// CỔNG AN TOÀN: mở gói phải giữ nguyên hiển thị. Generator của PDFium
|
||||
// lossy với file phức tạp (font subset TRÙNG TÊN bị gộp làm mất glyph,
|
||||
// ảnh inline bị bỏ, z-order form lồng nhau xáo trộn) — so render 2 bản,
|
||||
// lệch quá 0.5% điểm ảnh → HUỶ, giữ nguyên file gốc.
|
||||
let mismatch =
|
||||
ff_engine::page_render_mismatch(&pdfium, std::path::Path::new(&input), &out, page, 500)
|
||||
.map_err(|e| e.to_string())?;
|
||||
if mismatch > 0.005 {
|
||||
let _ = std::fs::remove_file(&out);
|
||||
return Err(format!(
|
||||
"Trang gói nội dung trong Form XObject quá phức tạp — mở gói làm lệch hiển thị \
|
||||
{:.1}% điểm ảnh nên đã huỷ để bảo toàn file. Xem/chú thích vẫn bình thường; \
|
||||
SỬA NỘI DUNG file dạng này sẽ hỗ trợ ở bản sau.",
|
||||
mismatch * 100.0
|
||||
));
|
||||
}
|
||||
Ok(Some(out.to_string_lossy().into_owned()))
|
||||
}
|
||||
|
||||
/// Dọn các file làm việc tạm của chế độ sửa (undo stack). Chỉ xoá file có tên
|
||||
|
||||
+16
-2
@@ -40,6 +40,7 @@ const state = {
|
||||
editPendingImage: null, // đường dẫn ảnh chờ đặt (Thêm ảnh)
|
||||
editPendingPoint: null, // điểm PDF chờ mở ô sửa (đúp chuột từ viewer thường)
|
||||
editFlatBase: null, // bản "mở gói" Form XObject — không tính là thay đổi
|
||||
editFlattenFailed: null, // cổng an toàn từ chối mở gói — thông điệp chặn sửa
|
||||
editColor: [0, 0, 0], // màu chữ áp khi sửa/thêm text
|
||||
editTemps: [], // mọi file tạm đã materialize trong phiên sửa (để dọn)
|
||||
secMode: false, // thanh Bảo mật (Phase 5) đang mở
|
||||
@@ -2056,6 +2057,7 @@ function enterEditMode(pageIndex) {
|
||||
state.editArm = null;
|
||||
state.editPendingImage = null;
|
||||
state.editFlatBase = null;
|
||||
state.editFlattenFailed = null;
|
||||
$("annobar").classList.add("hidden");
|
||||
$("editBar").classList.remove("hidden");
|
||||
$("viewport").classList.add("hidden");
|
||||
@@ -2140,10 +2142,14 @@ async function loadEditPage() {
|
||||
state.editTemps.push(flat);
|
||||
state.editBase = flat;
|
||||
state.editFlatBase = flat;
|
||||
state.editFlattenFailed = null;
|
||||
return loadEditPage();
|
||||
}
|
||||
} catch (e) {
|
||||
$("editHint").textContent = "Không mở gói được form: " + e;
|
||||
// Cổng an toàn từ chối (mở gói làm lệch hiển thị) → vẫn xem được,
|
||||
// nhưng chặn sửa các phần nằm trong form với thông điệp rõ.
|
||||
state.editFlattenFailed = String(e);
|
||||
$("editHint").textContent = String(e);
|
||||
}
|
||||
}
|
||||
$("editImg").src = url;
|
||||
@@ -2610,7 +2616,15 @@ function paragraphLines(o) {
|
||||
// đường code duy nhất, giữ nguyên cấu trúc xuống dòng, commit qua reflow.
|
||||
// `ev` (nếu có) = sự kiện chuột để đặt con trỏ đúng chỗ vừa đúp.
|
||||
function startTextEdit(o, ev) {
|
||||
startBlockTextEdit(o, paragraphLines(o), ev);
|
||||
const lines = paragraphLines(o);
|
||||
// Trang gói form phức tạp không mở gói được an toàn → text vẫn nằm TRONG
|
||||
// form, engine không lưu sửa đổi được — báo rõ thay vì mở ô sửa vô dụng.
|
||||
if (lines.some((l) => l.runs.some((r) => r.nested))) {
|
||||
$("editHint").textContent =
|
||||
state.editFlattenFailed || "Phần này nằm trong Form XObject — chưa sửa được trên file này.";
|
||||
return;
|
||||
}
|
||||
startBlockTextEdit(o, lines, ev);
|
||||
}
|
||||
|
||||
// Sửa cả đoạn WYSIWYG (chuẩn Foxit Edit Text): contenteditable phủ kín khối,
|
||||
|
||||
Reference in New Issue
Block a user