Khối sửa chuẩn Foxit: tách đoạn theo format, nền trong suốt, bullet, giữ in đậm
Build Windows portable / build (push) Canceled after 0s
Build Windows portable / build (push) Canceled after 0s
4 lỗi user báo khi test build 11 trên file thật: - Gom đoạn quá tham (tiêu đề + code + thân bài + nhãn đỏ 1 khối): đối chiếu Foxit (mỗi đoạn = 1 text block riêng) — paragraphLines chỉ gom dòng kề CÙNG format (family + đậm/nghiêng + màu, cỡ chênh <=1.25x). - Bullet hiện ô vuông trong ô sửa: bullet là run font Symbol mã PUA, DOM không render được — isMarkerRun/stripLineMarkers loại marker khỏi ô sửa/commit, bullet giữ nguyên trên trang (chuẩn Foxit); đúp trúng bullet vẫn mở khối chữ. - Ô sửa nền trắng: render ngầm bản trang đã ẩn run đang sửa rồi chuyển nền trong suốt — thấy nền gốc (dải màu/bullet) dưới chữ đang gõ; huỷ trả ảnh gốc; commit vẫn tính trên editBase. - Mất in đậm: engine thêm fallback đọc OS/2 usWeightClass + cờ italic từ bytes font nhúng (file Word xuất không khai /FontWeight, tên không có Bold); list_objects cache kiểu chữ theo tên font. Test Node trích hàm thật từ main.js: 11 case tách khối/bullet đều PASS. Chi tiết: docs/12-phase4-summary.md (Vá vòng 4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -166,7 +166,25 @@ fn text_object_style(t: &PdfPageTextObject) -> (String, bool, bool) {
|
||||
| Ok(PdfFontWeight::Weight900)
|
||||
) || matches!(t.font().weight(), Ok(PdfFontWeight::Custom(v)) if v >= 600);
|
||||
let angle_italic = t.font().italic_angle().map(|a| a != 0).unwrap_or(false);
|
||||
(family, weight_bold || name_bold, angle_italic || name_italic)
|
||||
|
||||
let mut bold = weight_bold || name_bold;
|
||||
let mut italic = angle_italic || name_italic;
|
||||
// Fallback: nhiều file (Word/Chrome xuất subset "ABCDEF+Xyz") không khai
|
||||
// weight trong descriptor và tên không chứa "Bold"/"Italic" → đọc thẳng
|
||||
// OS/2 usWeightClass + cờ italic từ bytes font nhúng.
|
||||
if (!bold || !italic) && t.font().is_embedded().unwrap_or(false) {
|
||||
if let Ok(bytes) = t.font().data() {
|
||||
let n = ttf_parser::fonts_in_collection(&bytes).unwrap_or(1).max(1);
|
||||
for i in 0..n {
|
||||
if let Ok(face) = ttf_parser::Face::parse(&bytes, i) {
|
||||
bold = bold || face.weight().to_number() >= 600;
|
||||
italic = italic || face.is_italic() || face.is_oblique();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(family, bold, italic)
|
||||
}
|
||||
|
||||
/// Liệt kê các page object của 1 trang để UI vẽ overlay chỉnh sửa.
|
||||
@@ -185,6 +203,9 @@ pub fn list_objects(
|
||||
.map_err(|e| EngineError::Pdfium(format!("không lấy được trang {page_index}: {e}")))?;
|
||||
|
||||
let mut out = Vec::new();
|
||||
// Cache kiểu chữ theo tên font: fallback đậm/nghiêng phải đọc bytes font
|
||||
// nhúng — file Word xuất hay có 200+ run chung vài font, không đọc lại.
|
||||
let mut style_cache: HashMap<String, (String, bool, bool)> = HashMap::new();
|
||||
for (i, object) in page.objects().iter().enumerate() {
|
||||
let kind = ObjectKind::from_pdfium(object.object_type());
|
||||
let rect = object
|
||||
@@ -206,9 +227,22 @@ pub fn list_objects(
|
||||
color: None,
|
||||
};
|
||||
if let Some(t) = object.as_text_object() {
|
||||
let (family, bold, italic) = text_object_style(t);
|
||||
let raw_name = t.font().name();
|
||||
// Tên rỗng không cache được (nhiều font khác nhau cùng key "").
|
||||
let (family, bold, italic) = if raw_name.trim().is_empty() {
|
||||
text_object_style(t)
|
||||
} else {
|
||||
match style_cache.get(&raw_name) {
|
||||
Some(s) => s.clone(),
|
||||
None => {
|
||||
let s = text_object_style(t);
|
||||
style_cache.insert(raw_name.clone(), s.clone());
|
||||
s
|
||||
}
|
||||
}
|
||||
};
|
||||
info.text = Some(t.text());
|
||||
info.font_name = Some(t.font().name());
|
||||
info.font_name = Some(raw_name);
|
||||
info.font_family = Some(family);
|
||||
info.font_bold = Some(bold);
|
||||
info.font_italic = Some(italic);
|
||||
|
||||
Reference in New Issue
Block a user