Dot 1 "edit chuan moi PDF": CID/Identity-H font, format TUNG CHU, edit OCR, bu metrics, splash, Open-with
Build Windows portable / build (push) Canceled after 0s
Build Windows portable / build (push) Canceled after 0s
1) fontfix v2 (PDF tu Word/InDesign): tong hop bang name/post khi subset
thieu (OTS bat buoc); font CID/Identity-H KHONG co cmap -> dung cmap
(3,1) fmt4 tu /ToUnicode x /CIDToGIDMap (Identity: GID=CID; stream 2B/CID
parse tu descendant font); chan GID >= numGlyphs (maxp). tounicode.rs tra
FontMapping {code_to_uni, is_cid, cid_to_gid}.
2) Format TUNG CHU trong o sua (chuan Word/Foxit): boi den -> B/I (nut
toolbar khong cuop focus + Ctrl+B/I). UI tach span theo vung chon, dat
data-bold/italic-override; commit gui override tung doan (RichSegDto
bold/italic). Engine: bang style rich key theo (run nguon, override) -
doi bien the thi lay font BIEN THE THAT cung ho (fontmatch -> builtin ->
substitute), khong dung lai font goc. Test:
rich_seg_bold_italic_override_uses_variant_font.
3) Edit file OCR (scan + text an): khoi toan run render-mode INVISIBLE ->
ve rect TRANG che vung chu cu tren anh + ve text moi HIEN mau den (ca 4
duong ve: rich chinh/fallback tu, 1-style chinh/fallback). Test:
ocr_invisible_block_becomes_visible_with_cover.
4) Bu metrics kieu Adobe Sans MM trong o sua: span mang data-pdfw (be rong
that tren trang); fitEditLinesToPdf them pass letter-spacing de moi nhom
style chiem DUNG quang goc khi font thay the lech metrics (>2%); kep
+/-18% co chu.
5) Khoi dong het "do": cua so tao AN (visible:false), UI show() ngay khi
frontend san sang + man splash che phan nap dau; luoi an toan Rust hien
cua so sau 4s neu JS chet som.
6) Open with FoFreeXit.exe: co che argv (initial_file) van hoat dong - loi
nam o registry Applications tro exe CU (ban portable bi di chuyen/ghi
de) lam Windows hien lai hop chon app. Fix tu chua: moi lan khoi dong
dang ky lai HKCU (Applications command + ProgID FoFreeXit.pdf +
OpenWithProgids .pdf) tro exe hien tai, chay nen qua reg.exe.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,15 +10,26 @@ use lopdf::{Dictionary, Document as LoDoc, Object};
|
||||
|
||||
use crate::formsurgery::{deref, stream_bytes};
|
||||
|
||||
/// Map mã→Unicode của font có BaseFont khớp `font_name` (so phần sau prefix
|
||||
/// subset "ABCDEF+") trên trang `page_index`; tìm cả trong resources của Form
|
||||
/// Thông tin giải mã của 1 font trong PDF — đủ để fontfix dựng cmap Unicode.
|
||||
pub(crate) struct FontMapping {
|
||||
/// Mã trong content stream → Unicode (từ /ToUnicode).
|
||||
pub code_to_uni: HashMap<u32, u32>,
|
||||
/// Font CID (Type0/Identity-H): mã = CID. `cid_to_gid`: None = Identity
|
||||
/// (GID = CID — trường hợp phổ biến của Word/InDesign), Some = bảng tra
|
||||
/// từ stream /CIDToGIDMap (2 byte big-endian mỗi CID).
|
||||
pub is_cid: bool,
|
||||
pub cid_to_gid: Option<Vec<u16>>,
|
||||
}
|
||||
|
||||
/// Mapping của font có BaseFont khớp `font_name` (so phần sau prefix subset
|
||||
/// "ABCDEF+") trên trang `page_index`; tìm cả trong resources của Form
|
||||
/// XObject (sâu tối đa 3). Không thấy/không parse được → None (fontfix rơi về
|
||||
/// ASCII identity + MacRoman).
|
||||
pub(crate) fn code_to_unicode(
|
||||
pub(crate) fn font_mapping(
|
||||
input: &Path,
|
||||
page_index: u16,
|
||||
font_name: &str,
|
||||
) -> Option<HashMap<u32, u32>> {
|
||||
) -> Option<FontMapping> {
|
||||
let want = font_name.rsplit('+').next().unwrap_or(font_name).trim();
|
||||
if want.is_empty() {
|
||||
return None;
|
||||
@@ -36,7 +47,7 @@ fn scan_resources(
|
||||
res: &Dictionary,
|
||||
want: &str,
|
||||
depth: usize,
|
||||
) -> Option<HashMap<u32, u32>> {
|
||||
) -> Option<FontMapping> {
|
||||
if depth > 3 {
|
||||
return None;
|
||||
}
|
||||
@@ -54,14 +65,51 @@ fn scan_resources(
|
||||
if suffix != want {
|
||||
continue;
|
||||
}
|
||||
let Ok(tu) = fd.get(b"ToUnicode") else { continue };
|
||||
if let Object::Stream(s) = deref(doc, tu) {
|
||||
if let Some(m) = parse_cmap(&stream_bytes(s)) {
|
||||
if !m.is_empty() {
|
||||
return Some(m);
|
||||
let mut code_to_uni = HashMap::new();
|
||||
if let Ok(tu) = fd.get(b"ToUnicode") {
|
||||
if let Object::Stream(s) = deref(doc, tu) {
|
||||
if let Some(m) = parse_cmap(&stream_bytes(s)) {
|
||||
code_to_uni = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Type0 (Identity-H): mã = CID; GID tra qua /CIDToGIDMap của
|
||||
// descendant font (Name "Identity" hoặc stream 2B/CID).
|
||||
let subtype = fd
|
||||
.get(b"Subtype")
|
||||
.ok()
|
||||
.and_then(|o| deref(doc, o).as_name().ok())
|
||||
.map(|n| n.to_vec())
|
||||
.unwrap_or_default();
|
||||
let is_cid = subtype == b"Type0";
|
||||
let mut cid_to_gid = None;
|
||||
if is_cid {
|
||||
if let Ok(desc) = fd.get(b"DescendantFonts") {
|
||||
let desc = deref(doc, desc);
|
||||
let first = match desc {
|
||||
Object::Array(a) => a.first().map(|o| deref(doc, o)),
|
||||
other => Some(other),
|
||||
};
|
||||
if let Some(Ok(dd)) = first.map(|o| o.as_dict()) {
|
||||
if let Ok(map) = dd.get(b"CIDToGIDMap") {
|
||||
if let Object::Stream(s) = deref(doc, map) {
|
||||
let raw = stream_bytes(s);
|
||||
cid_to_gid = Some(
|
||||
raw.chunks(2)
|
||||
.map(|c| {
|
||||
u16::from_be_bytes([c[0], *c.get(1).unwrap_or(&0)])
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if code_to_uni.is_empty() {
|
||||
continue; // không có ToUnicode — thử font trùng tên khác
|
||||
}
|
||||
return Some(FontMapping { code_to_uni, is_cid, cid_to_gid });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user