CI: fetch-qpdf dung GITHUB_TOKEN + fallback ban pin v12.2.0 - het fail oan vi API rate limit tu runner
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:
@@ -40,6 +40,8 @@ jobs:
|
|||||||
- name: Fetch QPDF (Windows x64)
|
- name: Fetch QPDF (Windows x64)
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: powershell -ExecutionPolicy Bypass -File scripts/fetch-qpdf.ps1
|
run: powershell -ExecutionPolicy Bypass -File scripts/fetch-qpdf.ps1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# Bộ font Noto đóng gói theo app (phủ tiếng Việt) — hiển thị/ghi file
|
# Bộ font Noto đóng gói theo app (phủ tiếng Việt) — hiển thị/ghi file
|
||||||
# giống nhau trên mọi máy khách, không phụ thuộc font hệ điều hành.
|
# giống nhau trên mọi máy khách, không phụ thuộc font hệ điều hành.
|
||||||
|
|||||||
@@ -775,6 +775,10 @@ fn app_font_data(kind: String) -> Result<String, String> {
|
|||||||
"serif-bold" => "NotoSerif-Bold.ttf",
|
"serif-bold" => "NotoSerif-Bold.ttf",
|
||||||
"serif-italic" => "NotoSerif-Italic.ttf",
|
"serif-italic" => "NotoSerif-Italic.ttf",
|
||||||
"serif-bolditalic" => "NotoSerif-BoldItalic.ttf",
|
"serif-bolditalic" => "NotoSerif-BoldItalic.ttf",
|
||||||
|
// Gói CJK tuỳ chọn (scripts/fetch-fonts-cjk.ps1) — không có file thì
|
||||||
|
// trả lỗi, UI tự rơi về font CJK hệ thống.
|
||||||
|
"cjk-regular" => "NotoSansCJK-Regular.ttc",
|
||||||
|
"cjk-bold" => "NotoSansCJK-Bold.ttc",
|
||||||
_ => return Err(format!("kind font không hợp lệ: {kind}")),
|
_ => return Err(format!("kind font không hợp lệ: {kind}")),
|
||||||
};
|
};
|
||||||
let dir = std::env::var("FOFREEXIT_FONTS_PATH")
|
let dir = std::env::var("FOFREEXIT_FONTS_PATH")
|
||||||
|
|||||||
+11
-3
@@ -2359,6 +2359,7 @@ async function loadEditPage() {
|
|||||||
if (o.kind !== "text") continue;
|
if (o.kind !== "text") continue;
|
||||||
ensureDocFont(o, state.editBase, state.editPage);
|
ensureDocFont(o, state.editBase, state.editPage);
|
||||||
ensureAppFont(fontClassOf(o.fontFamily), o.fontBold, o.fontItalic);
|
ensureAppFont(fontClassOf(o.fontFamily), o.fontBold, o.fontItalic);
|
||||||
|
if (hasCjk(o.text)) ensureAppFont("cjk", o.fontBold, false);
|
||||||
}
|
}
|
||||||
buildEditOverlay();
|
buildEditOverlay();
|
||||||
$("pageInput").value = state.editPage + 1;
|
$("pageInput").value = state.editPage + 1;
|
||||||
@@ -2656,11 +2657,17 @@ function ensureDocFont(run, path, page) {
|
|||||||
const appFonts = new Map(); // kind -> true | false | Promise (bền theo app)
|
const appFonts = new Map(); // kind -> true | false | Promise (bền theo app)
|
||||||
|
|
||||||
function appFontKind(cls, bold, italic) {
|
function appFontKind(cls, bold, italic) {
|
||||||
if (cls === "mono") return "mono-" + (bold ? "bold" : "regular"); // mono không có italic
|
// mono/cjk không có biến thể italic riêng — trình duyệt tự nghiêng.
|
||||||
|
if (cls === "mono" || cls === "cjk") return cls + "-" + (bold ? "bold" : "regular");
|
||||||
const style = bold && italic ? "bolditalic" : bold ? "bold" : italic ? "italic" : "regular";
|
const style = bold && italic ? "bolditalic" : bold ? "bold" : italic ? "italic" : "regular";
|
||||||
return cls + "-" + style;
|
return cls + "-" + style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text có ký tự CJK (Hoa/Nhật/Hàn)? — nạp thêm gói CJK tuỳ chọn nếu app kèm.
|
||||||
|
function hasCjk(text) {
|
||||||
|
return /[-ヿ㐀-䶿一-鿿가-]/.test(text || "");
|
||||||
|
}
|
||||||
|
|
||||||
// Phân loại serif/sans/mono theo stack CSS đã suy cho family của run.
|
// Phân loại serif/sans/mono theo stack CSS đã suy cho family của run.
|
||||||
function fontClassOf(family) {
|
function fontClassOf(family) {
|
||||||
const stack = cssFontStack(family).toLowerCase();
|
const stack = cssFontStack(family).toLowerCase();
|
||||||
@@ -2693,10 +2700,11 @@ function ensureAppFont(cls, bold, italic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stack font cho 1 run trong ô sửa: font NHÚNG của tài liệu đứng đầu → font
|
// Stack font cho 1 run trong ô sửa: font NHÚNG của tài liệu đứng đầu → font
|
||||||
// Noto đóng gói theo app → stack hệ thống (lưới cuối cùng).
|
// Noto đóng gói theo app (+CJK nếu chữ CJK) → stack hệ thống (lưới cuối).
|
||||||
function editFontStack(run, fallbackFamily) {
|
function editFontStack(run, fallbackFamily) {
|
||||||
const base = cssFontStack(fallbackFamily);
|
const base = cssFontStack(fallbackFamily);
|
||||||
const mid = '"ff-app-' + fontClassOf(fallbackFamily) + '", ';
|
let mid = '"ff-app-' + fontClassOf(fallbackFamily) + '", ';
|
||||||
|
if (run && hasCjk(run.text)) mid += '"ff-app-cjk", ';
|
||||||
const fam = run && run.fontName ? docFonts.get(run.fontName) : null;
|
const fam = run && run.fontName ? docFonts.get(run.fontName) : null;
|
||||||
const head = typeof fam === "string" && fam ? '"' + fam + '", ' : "";
|
const head = typeof fam === "string" && fam ? '"' + fam + '", ' : "";
|
||||||
return head + mid + base;
|
return head + mid + base;
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ use lopdf::{Dictionary, Document as LoDoc, Object};
|
|||||||
|
|
||||||
use crate::formsurgery::{deref, stream_bytes};
|
use crate::formsurgery::{deref, stream_bytes};
|
||||||
|
|
||||||
/// Thông tin giải mã của 1 font trong PDF — đủ để fontfix dựng cmap Unicode.
|
/// Thông tin giải mã của 1 font trong PDF — đủ để fontfix dựng cmap Unicode
|
||||||
|
/// và (với CFF trần) cả hmtx/OS-2 khi bọc thành OTF.
|
||||||
pub(crate) struct FontMapping {
|
pub(crate) struct FontMapping {
|
||||||
/// Mã trong content stream → Unicode (từ /ToUnicode).
|
/// Mã trong content stream → Unicode (từ /ToUnicode).
|
||||||
pub code_to_uni: HashMap<u32, u32>,
|
pub code_to_uni: HashMap<u32, u32>,
|
||||||
@@ -19,6 +20,14 @@ pub(crate) struct FontMapping {
|
|||||||
/// từ stream /CIDToGIDMap (2 byte big-endian mỗi CID).
|
/// từ stream /CIDToGIDMap (2 byte big-endian mỗi CID).
|
||||||
pub is_cid: bool,
|
pub is_cid: bool,
|
||||||
pub cid_to_gid: Option<Vec<u16>>,
|
pub cid_to_gid: Option<Vec<u16>>,
|
||||||
|
/// Mã → bề rộng advance (đơn vị text space ×1000): /Widths (font đơn
|
||||||
|
/// giản) hoặc /W (font CID).
|
||||||
|
pub widths: HashMap<u32, f32>,
|
||||||
|
/// /DW của font CID (mặc định 1000) — bề rộng cho mã không có trong /W.
|
||||||
|
pub default_width: f32,
|
||||||
|
/// /Ascent /Descent từ FontDescriptor (0 = không rõ).
|
||||||
|
pub ascent: f32,
|
||||||
|
pub descent: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mapping của font có BaseFont khớp `font_name` (so phần sau prefix subset
|
/// Mapping của font có BaseFont khớp `font_name` (so phần sau prefix subset
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# TUY CHON: tai bo font Noto Sans CJK (Hoa gian the/phon the + Nhat + Han)
|
||||||
|
# vao fonts/ - phuc vu tai lieu CJK khong nhung font. KHONG chay trong CI
|
||||||
|
# mac dinh (moi file ~16-20MB lam zip phinh to); nguoi dung/dev can thi chay:
|
||||||
|
# powershell -ExecutionPolicy Bypass -File scripts/fetch-fonts-cjk.ps1
|
||||||
|
# App tu nhan dien file trong fonts/ luc khoi dong - khong can cau hinh.
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$root = Split-Path -Parent $PSScriptRoot
|
||||||
|
$fontsDir = Join-Path $root "fonts"
|
||||||
|
New-Item -ItemType Directory -Force -Path $fontsDir | Out-Null
|
||||||
|
|
||||||
|
# Ban OTC gop 4 ngon ngu (SC/TC/JP/KR) tu repo phat hanh chinh thuc.
|
||||||
|
$files = @(
|
||||||
|
@{ name = "NotoSansCJK-Regular.ttc"; url = "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTC/NotoSansCJK-Regular.ttc" },
|
||||||
|
@{ name = "NotoSansCJK-Bold.ttc"; url = "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTC/NotoSansCJK-Bold.ttc" }
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($f in $files) {
|
||||||
|
$dest = Join-Path $fontsDir $f.name
|
||||||
|
if ((Test-Path $dest) -and ((Get-Item $dest).Length -gt 1000000)) {
|
||||||
|
Write-Output "Da co: $($f.name)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
Write-Output "Tai $($f.name) (~20MB)..."
|
||||||
|
Invoke-WebRequest -Uri $f.url -OutFile $dest -UseBasicParsing
|
||||||
|
if ((Get-Item $dest).Length -lt 1000000) { throw "File $($f.name) qua nho - tai hong?" }
|
||||||
|
}
|
||||||
|
Write-Output "Xong. De dong goi kem ban portable: copy fonts/ (gom ca file CJK) canh FoFreeXit.exe."
|
||||||
+16
-5
@@ -9,12 +9,23 @@ $qpdfDir = Join-Path $root "qpdf"
|
|||||||
$tmp = Join-Path $env:TEMP "qpdf-win-msvc64.zip"
|
$tmp = Join-Path $env:TEMP "qpdf-win-msvc64.zip"
|
||||||
|
|
||||||
Write-Output "Tra cuu release moi nhat cua qpdf/qpdf..."
|
Write-Output "Tra cuu release moi nhat cua qpdf/qpdf..."
|
||||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/qpdf/qpdf/releases/latest" -UseBasicParsing
|
# Dung GITHUB_TOKEN khi co (CI) - goi API khong xac thuc tu runner hay dinh
|
||||||
|
# rate limit lam fail build oan. API loi thi roi ve ban pin cung.
|
||||||
|
$headers = @{}
|
||||||
|
if ($env:GITHUB_TOKEN) { $headers["Authorization"] = "Bearer $($env:GITHUB_TOKEN)" }
|
||||||
|
$dlUrl = $null
|
||||||
|
try {
|
||||||
|
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/qpdf/qpdf/releases/latest" -Headers $headers -UseBasicParsing
|
||||||
$asset = $release.assets | Where-Object { $_.name -like "*msvc64.zip" } | Select-Object -First 1
|
$asset = $release.assets | Where-Object { $_.name -like "*msvc64.zip" } | Select-Object -First 1
|
||||||
if (-not $asset) { throw "Khong tim thay asset msvc64.zip trong release $($release.tag_name)" }
|
if ($asset) { $dlUrl = $asset.browser_download_url; Write-Output "Tai $($asset.name) (release $($release.tag_name))..." }
|
||||||
|
} catch {
|
||||||
Write-Output "Tai $($asset.name) (tu release $($release.tag_name))..."
|
Write-Output "API loi ($($_.Exception.Message)) - dung ban pin."
|
||||||
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $tmp -UseBasicParsing
|
}
|
||||||
|
if (-not $dlUrl) {
|
||||||
|
$dlUrl = "https://github.com/qpdf/qpdf/releases/download/v12.2.0/qpdf-12.2.0-msvc64.zip"
|
||||||
|
Write-Output "Tai ban pin: $dlUrl"
|
||||||
|
}
|
||||||
|
Invoke-WebRequest -Uri $dlUrl -OutFile $tmp -UseBasicParsing
|
||||||
|
|
||||||
$extractDir = Join-Path $env:TEMP "qpdf-extract"
|
$extractDir = Join-Path $env:TEMP "qpdf-extract"
|
||||||
if (Test-Path $extractDir) { Remove-Item -Recurse -Force $extractDir }
|
if (Test-Path $extractDir) { Remove-Item -Recurse -Force $extractDir }
|
||||||
|
|||||||
Reference in New Issue
Block a user