pdfnative 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -14
- package/dist/index.cjs +778 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +146 -4
- package/dist/index.d.ts +146 -4
- package/dist/index.js +772 -259
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +423 -187
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.js +423 -187
- package/dist/worker/index.js.map +1 -1
- package/fonts/noto-emoji-data.d.ts +27 -0
- package/fonts/noto-emoji-data.js +64 -0
- package/fonts/noto-sans-data.d.ts +22 -0
- package/fonts/noto-sans-data.js +64 -0
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -2155,12 +2155,12 @@ function shapeThaiText(str, fontData) {
|
|
|
2155
2155
|
function getAdv(gid) {
|
|
2156
2156
|
return widths[gid] !== void 0 ? widths[gid] : defaultWidth;
|
|
2157
2157
|
}
|
|
2158
|
-
function
|
|
2158
|
+
function getBaseAnchor2(baseGid, markClass) {
|
|
2159
2159
|
const base = markAnchors && markAnchors.bases && markAnchors.bases[baseGid];
|
|
2160
2160
|
if (!base) return null;
|
|
2161
2161
|
return base[markClass] ?? null;
|
|
2162
2162
|
}
|
|
2163
|
-
function
|
|
2163
|
+
function getMarkAnchor2(markGid) {
|
|
2164
2164
|
const mark = markAnchors && markAnchors.marks && markAnchors.marks[markGid];
|
|
2165
2165
|
if (!mark) return null;
|
|
2166
2166
|
return { classIdx: mark[0], x: mark[1], y: mark[2] };
|
|
@@ -2197,7 +2197,7 @@ function shapeThaiText(str, fontData) {
|
|
|
2197
2197
|
for (let ai = 0; ai < cluster.aboves.length; ai++) {
|
|
2198
2198
|
const abvCp = cluster.aboves[ai];
|
|
2199
2199
|
const markGid = resolveMarkGid(abvCp, isTallBase);
|
|
2200
|
-
const markAnchor =
|
|
2200
|
+
const markAnchor = getMarkAnchor2(markGid);
|
|
2201
2201
|
let dx = 0;
|
|
2202
2202
|
let dy = 0;
|
|
2203
2203
|
if (ai > 0 && prevAboveMarkGid !== null) {
|
|
@@ -2206,7 +2206,7 @@ function shapeThaiText(str, fontData) {
|
|
|
2206
2206
|
dx = prevAboveMarkDx + m2mOffset.dx;
|
|
2207
2207
|
dy = prevAboveMarkDy + m2mOffset.dy;
|
|
2208
2208
|
} else if (markAnchor) {
|
|
2209
|
-
const baseAnchor =
|
|
2209
|
+
const baseAnchor = getBaseAnchor2(baseGid, markAnchor.classIdx);
|
|
2210
2210
|
if (baseAnchor) {
|
|
2211
2211
|
dx = baseAnchor[0] - markAnchor.x - baseAdv;
|
|
2212
2212
|
dy = baseAnchor[1] - markAnchor.y;
|
|
@@ -2214,7 +2214,7 @@ function shapeThaiText(str, fontData) {
|
|
|
2214
2214
|
}
|
|
2215
2215
|
} else {
|
|
2216
2216
|
if (markAnchor) {
|
|
2217
|
-
const baseAnchor =
|
|
2217
|
+
const baseAnchor = getBaseAnchor2(baseGid, markAnchor.classIdx);
|
|
2218
2218
|
if (baseAnchor) {
|
|
2219
2219
|
dx = baseAnchor[0] - markAnchor.x - baseAdv;
|
|
2220
2220
|
dy = baseAnchor[1] - markAnchor.y;
|
|
@@ -2228,11 +2228,11 @@ function shapeThaiText(str, fontData) {
|
|
|
2228
2228
|
}
|
|
2229
2229
|
for (const blwCp of cluster.belows) {
|
|
2230
2230
|
const markGid = cmap[blwCp] || 0;
|
|
2231
|
-
const markAnchor =
|
|
2231
|
+
const markAnchor = getMarkAnchor2(markGid);
|
|
2232
2232
|
let dx = 0;
|
|
2233
2233
|
let dy = 0;
|
|
2234
2234
|
if (markAnchor) {
|
|
2235
|
-
const baseAnchor =
|
|
2235
|
+
const baseAnchor = getBaseAnchor2(baseGid, markAnchor.classIdx);
|
|
2236
2236
|
if (baseAnchor) {
|
|
2237
2237
|
dx = baseAnchor[0] - markAnchor.x - baseAdv;
|
|
2238
2238
|
dy = baseAnchor[1] - markAnchor.y;
|
|
@@ -2244,9 +2244,155 @@ function shapeThaiText(str, fontData) {
|
|
|
2244
2244
|
return shaped;
|
|
2245
2245
|
}
|
|
2246
2246
|
|
|
2247
|
+
// src/shaping/script-registry.ts
|
|
2248
|
+
var ARABIC_START = 1536;
|
|
2249
|
+
var ARABIC_END = 1791;
|
|
2250
|
+
var ARABIC_SUPPLEMENT_START = 1872;
|
|
2251
|
+
var ARABIC_SUPPLEMENT_END = 1919;
|
|
2252
|
+
var ARABIC_EXTENDED_A_START = 2208;
|
|
2253
|
+
var ARABIC_EXTENDED_A_END = 2303;
|
|
2254
|
+
var ARABIC_PRES_A_START = 64336;
|
|
2255
|
+
var ARABIC_PRES_A_END = 65023;
|
|
2256
|
+
var ARABIC_PRES_B_START = 65136;
|
|
2257
|
+
var ARABIC_PRES_B_END = 65279;
|
|
2258
|
+
var HEBREW_START = 1424;
|
|
2259
|
+
var HEBREW_END = 1535;
|
|
2260
|
+
var HEBREW_PRES_START = 64285;
|
|
2261
|
+
var HEBREW_PRES_END = 64335;
|
|
2262
|
+
var THAI_START = 3584;
|
|
2263
|
+
var THAI_END = 3711;
|
|
2264
|
+
var DEVANAGARI_START = 2304;
|
|
2265
|
+
var DEVANAGARI_END = 2431;
|
|
2266
|
+
var DEVANAGARI_EXT_START = 43232;
|
|
2267
|
+
var DEVANAGARI_EXT_END = 43263;
|
|
2268
|
+
var CYRILLIC_START = 1024;
|
|
2269
|
+
var CYRILLIC_END = 1279;
|
|
2270
|
+
var CYRILLIC_SUPPLEMENT_START = 1280;
|
|
2271
|
+
var CYRILLIC_SUPPLEMENT_END = 1327;
|
|
2272
|
+
var CYRILLIC_EXT_A_START = 11744;
|
|
2273
|
+
var CYRILLIC_EXT_A_END = 11775;
|
|
2274
|
+
var CYRILLIC_EXT_B_START = 42560;
|
|
2275
|
+
var CYRILLIC_EXT_B_END = 42655;
|
|
2276
|
+
var GEORGIAN_START = 4256;
|
|
2277
|
+
var GEORGIAN_END = 4351;
|
|
2278
|
+
var GEORGIAN_SUPPLEMENT_START = 11520;
|
|
2279
|
+
var GEORGIAN_SUPPLEMENT_END = 11567;
|
|
2280
|
+
var ARMENIAN_START = 1328;
|
|
2281
|
+
var ARMENIAN_END = 1423;
|
|
2282
|
+
var ARMENIAN_LIGATURES_START = 64275;
|
|
2283
|
+
var ARMENIAN_LIGATURES_END = 64279;
|
|
2284
|
+
var BENGALI_START = 2432;
|
|
2285
|
+
var BENGALI_END = 2559;
|
|
2286
|
+
var TAMIL_START = 2944;
|
|
2287
|
+
var TAMIL_END = 3071;
|
|
2288
|
+
var EMOJI_RANGES = [
|
|
2289
|
+
[127744, 128511],
|
|
2290
|
+
// Miscellaneous Symbols and Pictographs
|
|
2291
|
+
[128512, 128591],
|
|
2292
|
+
// Emoticons
|
|
2293
|
+
[128640, 128767],
|
|
2294
|
+
// Transport and Map Symbols
|
|
2295
|
+
[128768, 128895],
|
|
2296
|
+
// Alchemical Symbols (partial)
|
|
2297
|
+
[128896, 129023],
|
|
2298
|
+
// Geometric Shapes Extended
|
|
2299
|
+
[129024, 129279],
|
|
2300
|
+
// Supplemental Arrows-C
|
|
2301
|
+
[129280, 129535],
|
|
2302
|
+
// Supplemental Symbols and Pictographs
|
|
2303
|
+
[129536, 129647],
|
|
2304
|
+
// Chess Symbols
|
|
2305
|
+
[129648, 129791],
|
|
2306
|
+
// Symbols and Pictographs Extended-A
|
|
2307
|
+
[9728, 9983],
|
|
2308
|
+
// Miscellaneous Symbols
|
|
2309
|
+
[9984, 10175],
|
|
2310
|
+
// Dingbats
|
|
2311
|
+
[126976, 127023],
|
|
2312
|
+
// Mahjong Tiles
|
|
2313
|
+
[127136, 127231]
|
|
2314
|
+
// Playing Cards
|
|
2315
|
+
];
|
|
2316
|
+
var FITZPATRICK_START = 127995;
|
|
2317
|
+
var FITZPATRICK_END = 127999;
|
|
2318
|
+
function isArabicCodepoint(cp) {
|
|
2319
|
+
return cp >= ARABIC_START && cp <= ARABIC_END || cp >= ARABIC_SUPPLEMENT_START && cp <= ARABIC_SUPPLEMENT_END || cp >= ARABIC_EXTENDED_A_START && cp <= ARABIC_EXTENDED_A_END || cp >= ARABIC_PRES_A_START && cp <= ARABIC_PRES_A_END || cp >= ARABIC_PRES_B_START && cp <= ARABIC_PRES_B_END;
|
|
2320
|
+
}
|
|
2321
|
+
function isHebrewCodepoint(cp) {
|
|
2322
|
+
return cp >= HEBREW_START && cp <= HEBREW_END || cp >= HEBREW_PRES_START && cp <= HEBREW_PRES_END;
|
|
2323
|
+
}
|
|
2324
|
+
function isThaiCodepoint(cp) {
|
|
2325
|
+
return cp >= THAI_START && cp <= THAI_END;
|
|
2326
|
+
}
|
|
2327
|
+
function isCyrillicCodepoint(cp) {
|
|
2328
|
+
return cp >= CYRILLIC_START && cp <= CYRILLIC_END || cp >= CYRILLIC_SUPPLEMENT_START && cp <= CYRILLIC_SUPPLEMENT_END || cp >= CYRILLIC_EXT_A_START && cp <= CYRILLIC_EXT_A_END || cp >= CYRILLIC_EXT_B_START && cp <= CYRILLIC_EXT_B_END;
|
|
2329
|
+
}
|
|
2330
|
+
function isGeorgianCodepoint(cp) {
|
|
2331
|
+
return cp >= GEORGIAN_START && cp <= GEORGIAN_END || cp >= GEORGIAN_SUPPLEMENT_START && cp <= GEORGIAN_SUPPLEMENT_END;
|
|
2332
|
+
}
|
|
2333
|
+
function isArmenianCodepoint(cp) {
|
|
2334
|
+
return cp >= ARMENIAN_START && cp <= ARMENIAN_END || cp >= ARMENIAN_LIGATURES_START && cp <= ARMENIAN_LIGATURES_END;
|
|
2335
|
+
}
|
|
2336
|
+
function isBengaliCodepoint(cp) {
|
|
2337
|
+
return cp >= BENGALI_START && cp <= BENGALI_END;
|
|
2338
|
+
}
|
|
2339
|
+
function isTamilCodepoint(cp) {
|
|
2340
|
+
return cp >= TAMIL_START && cp <= TAMIL_END;
|
|
2341
|
+
}
|
|
2342
|
+
function isDevanagariCodepoint(cp) {
|
|
2343
|
+
return cp >= DEVANAGARI_START && cp <= DEVANAGARI_END || cp >= DEVANAGARI_EXT_START && cp <= DEVANAGARI_EXT_END;
|
|
2344
|
+
}
|
|
2345
|
+
function isEmojiCodepoint(cp) {
|
|
2346
|
+
if (cp >= FITZPATRICK_START && cp <= FITZPATRICK_END) return true;
|
|
2347
|
+
for (const [lo, hi] of EMOJI_RANGES) {
|
|
2348
|
+
if (cp >= lo && cp <= hi) return true;
|
|
2349
|
+
}
|
|
2350
|
+
return false;
|
|
2351
|
+
}
|
|
2352
|
+
function containsArabic(text) {
|
|
2353
|
+
for (let i = 0; i < text.length; ) {
|
|
2354
|
+
const cp = text.codePointAt(i) ?? 0;
|
|
2355
|
+
if (isArabicCodepoint(cp)) return true;
|
|
2356
|
+
i += cp > 65535 ? 2 : 1;
|
|
2357
|
+
}
|
|
2358
|
+
return false;
|
|
2359
|
+
}
|
|
2360
|
+
function containsHebrew(text) {
|
|
2361
|
+
for (let i = 0; i < text.length; ) {
|
|
2362
|
+
const cp = text.codePointAt(i) ?? 0;
|
|
2363
|
+
if (isHebrewCodepoint(cp)) return true;
|
|
2364
|
+
i += cp > 65535 ? 2 : 1;
|
|
2365
|
+
}
|
|
2366
|
+
return false;
|
|
2367
|
+
}
|
|
2368
|
+
function containsThai(str) {
|
|
2369
|
+
for (let i = 0; i < str.length; i++) {
|
|
2370
|
+
if (isThaiCodepoint(str.charCodeAt(i))) return true;
|
|
2371
|
+
}
|
|
2372
|
+
return false;
|
|
2373
|
+
}
|
|
2374
|
+
function containsBengali(str) {
|
|
2375
|
+
for (let i = 0; i < str.length; i++) {
|
|
2376
|
+
if (isBengaliCodepoint(str.charCodeAt(i))) return true;
|
|
2377
|
+
}
|
|
2378
|
+
return false;
|
|
2379
|
+
}
|
|
2380
|
+
function containsTamil(str) {
|
|
2381
|
+
for (let i = 0; i < str.length; i++) {
|
|
2382
|
+
if (isTamilCodepoint(str.charCodeAt(i))) return true;
|
|
2383
|
+
}
|
|
2384
|
+
return false;
|
|
2385
|
+
}
|
|
2386
|
+
function containsDevanagari(str) {
|
|
2387
|
+
for (let i = 0; i < str.length; i++) {
|
|
2388
|
+
if (isDevanagariCodepoint(str.charCodeAt(i))) return true;
|
|
2389
|
+
}
|
|
2390
|
+
return false;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2247
2393
|
// src/shaping/script-detect.ts
|
|
2248
2394
|
function needsUnicodeFont(lang) {
|
|
2249
|
-
return ["th", "ja", "zh", "ko", "el", "hi", "tr", "vi", "pl", "ar", "he", "ru", "ka", "hy"].includes(lang);
|
|
2395
|
+
return ["th", "ja", "zh", "ko", "el", "hi", "tr", "vi", "pl", "ar", "he", "ru", "ka", "hy", "emoji"].includes(lang);
|
|
2250
2396
|
}
|
|
2251
2397
|
function detectFallbackLangs(texts, primaryLang) {
|
|
2252
2398
|
const needed = /* @__PURE__ */ new Set();
|
|
@@ -2323,6 +2469,10 @@ function detectFallbackLangs(texts, primaryLang) {
|
|
|
2323
2469
|
needed.add("hy");
|
|
2324
2470
|
continue;
|
|
2325
2471
|
}
|
|
2472
|
+
if (isEmojiCodepoint(cp)) {
|
|
2473
|
+
needed.add("emoji");
|
|
2474
|
+
continue;
|
|
2475
|
+
}
|
|
2326
2476
|
}
|
|
2327
2477
|
}
|
|
2328
2478
|
needed.delete(primaryLang);
|
|
@@ -2343,6 +2493,7 @@ function detectCharLang(cp) {
|
|
|
2343
2493
|
if (cp >= 1024 && cp <= 1279 || cp >= 1280 && cp <= 1327) return "ru";
|
|
2344
2494
|
if (cp >= 4256 && cp <= 4351 || cp >= 11520 && cp <= 11567) return "ka";
|
|
2345
2495
|
if (cp >= 1328 && cp <= 1423 || cp >= 64275 && cp <= 64279) return "hy";
|
|
2496
|
+
if (isEmojiCodepoint(cp)) return "emoji";
|
|
2346
2497
|
return null;
|
|
2347
2498
|
}
|
|
2348
2499
|
|
|
@@ -2442,8 +2593,24 @@ function pdfString(str) {
|
|
|
2442
2593
|
}
|
|
2443
2594
|
function truncate(str, max) {
|
|
2444
2595
|
if (!str || str.length <= max) return str || "";
|
|
2445
|
-
if (max <=
|
|
2446
|
-
return str.slice(0, max -
|
|
2596
|
+
if (max <= 1) return "\u2026";
|
|
2597
|
+
return str.slice(0, max - 1) + "\u2026";
|
|
2598
|
+
}
|
|
2599
|
+
function truncateToWidth(str, maxWidthPt, sz, enc) {
|
|
2600
|
+
if (!str) return "";
|
|
2601
|
+
const measure = (s) => enc.isUnicode ? enc.tw(s, sz) : helveticaWidth(s, sz);
|
|
2602
|
+
if (measure(str) <= maxWidthPt) return str;
|
|
2603
|
+
const ell = "\u2026";
|
|
2604
|
+
const ellW = measure(ell);
|
|
2605
|
+
if (maxWidthPt <= ellW) return ell;
|
|
2606
|
+
let lo = 0;
|
|
2607
|
+
let hi = str.length;
|
|
2608
|
+
while (lo < hi) {
|
|
2609
|
+
const mid = lo + hi + 1 >> 1;
|
|
2610
|
+
if (measure(str.slice(0, mid) + ell) <= maxWidthPt) lo = mid;
|
|
2611
|
+
else hi = mid - 1;
|
|
2612
|
+
}
|
|
2613
|
+
return lo <= 0 ? ell : str.slice(0, lo) + ell;
|
|
2447
2614
|
}
|
|
2448
2615
|
function helveticaWidth(str, sz) {
|
|
2449
2616
|
let w = 0;
|
|
@@ -2469,113 +2636,25 @@ function helveticaWidth(str, sz) {
|
|
|
2469
2636
|
return w * sz / 1e3;
|
|
2470
2637
|
}
|
|
2471
2638
|
|
|
2472
|
-
// src/shaping/
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
var DEVANAGARI_START = 2304;
|
|
2490
|
-
var DEVANAGARI_END = 2431;
|
|
2491
|
-
var DEVANAGARI_EXT_START = 43232;
|
|
2492
|
-
var DEVANAGARI_EXT_END = 43263;
|
|
2493
|
-
var CYRILLIC_START = 1024;
|
|
2494
|
-
var CYRILLIC_END = 1279;
|
|
2495
|
-
var CYRILLIC_SUPPLEMENT_START = 1280;
|
|
2496
|
-
var CYRILLIC_SUPPLEMENT_END = 1327;
|
|
2497
|
-
var CYRILLIC_EXT_A_START = 11744;
|
|
2498
|
-
var CYRILLIC_EXT_A_END = 11775;
|
|
2499
|
-
var CYRILLIC_EXT_B_START = 42560;
|
|
2500
|
-
var CYRILLIC_EXT_B_END = 42655;
|
|
2501
|
-
var GEORGIAN_START = 4256;
|
|
2502
|
-
var GEORGIAN_END = 4351;
|
|
2503
|
-
var GEORGIAN_SUPPLEMENT_START = 11520;
|
|
2504
|
-
var GEORGIAN_SUPPLEMENT_END = 11567;
|
|
2505
|
-
var ARMENIAN_START = 1328;
|
|
2506
|
-
var ARMENIAN_END = 1423;
|
|
2507
|
-
var ARMENIAN_LIGATURES_START = 64275;
|
|
2508
|
-
var ARMENIAN_LIGATURES_END = 64279;
|
|
2509
|
-
var BENGALI_START = 2432;
|
|
2510
|
-
var BENGALI_END = 2559;
|
|
2511
|
-
var TAMIL_START = 2944;
|
|
2512
|
-
var TAMIL_END = 3071;
|
|
2513
|
-
function isArabicCodepoint(cp) {
|
|
2514
|
-
return cp >= ARABIC_START && cp <= ARABIC_END || cp >= ARABIC_SUPPLEMENT_START && cp <= ARABIC_SUPPLEMENT_END || cp >= ARABIC_EXTENDED_A_START && cp <= ARABIC_EXTENDED_A_END || cp >= ARABIC_PRES_A_START && cp <= ARABIC_PRES_A_END || cp >= ARABIC_PRES_B_START && cp <= ARABIC_PRES_B_END;
|
|
2515
|
-
}
|
|
2516
|
-
function isHebrewCodepoint(cp) {
|
|
2517
|
-
return cp >= HEBREW_START && cp <= HEBREW_END || cp >= HEBREW_PRES_START && cp <= HEBREW_PRES_END;
|
|
2518
|
-
}
|
|
2519
|
-
function isThaiCodepoint(cp) {
|
|
2520
|
-
return cp >= THAI_START && cp <= THAI_END;
|
|
2521
|
-
}
|
|
2522
|
-
function isCyrillicCodepoint(cp) {
|
|
2523
|
-
return cp >= CYRILLIC_START && cp <= CYRILLIC_END || cp >= CYRILLIC_SUPPLEMENT_START && cp <= CYRILLIC_SUPPLEMENT_END || cp >= CYRILLIC_EXT_A_START && cp <= CYRILLIC_EXT_A_END || cp >= CYRILLIC_EXT_B_START && cp <= CYRILLIC_EXT_B_END;
|
|
2524
|
-
}
|
|
2525
|
-
function isGeorgianCodepoint(cp) {
|
|
2526
|
-
return cp >= GEORGIAN_START && cp <= GEORGIAN_END || cp >= GEORGIAN_SUPPLEMENT_START && cp <= GEORGIAN_SUPPLEMENT_END;
|
|
2527
|
-
}
|
|
2528
|
-
function isArmenianCodepoint(cp) {
|
|
2529
|
-
return cp >= ARMENIAN_START && cp <= ARMENIAN_END || cp >= ARMENIAN_LIGATURES_START && cp <= ARMENIAN_LIGATURES_END;
|
|
2530
|
-
}
|
|
2531
|
-
function isBengaliCodepoint(cp) {
|
|
2532
|
-
return cp >= BENGALI_START && cp <= BENGALI_END;
|
|
2533
|
-
}
|
|
2534
|
-
function isTamilCodepoint(cp) {
|
|
2535
|
-
return cp >= TAMIL_START && cp <= TAMIL_END;
|
|
2536
|
-
}
|
|
2537
|
-
function isDevanagariCodepoint(cp) {
|
|
2538
|
-
return cp >= DEVANAGARI_START && cp <= DEVANAGARI_END || cp >= DEVANAGARI_EXT_START && cp <= DEVANAGARI_EXT_END;
|
|
2539
|
-
}
|
|
2540
|
-
function containsArabic(text) {
|
|
2541
|
-
for (let i = 0; i < text.length; ) {
|
|
2542
|
-
const cp = text.codePointAt(i) ?? 0;
|
|
2543
|
-
if (isArabicCodepoint(cp)) return true;
|
|
2544
|
-
i += cp > 65535 ? 2 : 1;
|
|
2545
|
-
}
|
|
2546
|
-
return false;
|
|
2547
|
-
}
|
|
2548
|
-
function containsHebrew(text) {
|
|
2549
|
-
for (let i = 0; i < text.length; ) {
|
|
2550
|
-
const cp = text.codePointAt(i) ?? 0;
|
|
2551
|
-
if (isHebrewCodepoint(cp)) return true;
|
|
2552
|
-
i += cp > 65535 ? 2 : 1;
|
|
2553
|
-
}
|
|
2554
|
-
return false;
|
|
2555
|
-
}
|
|
2556
|
-
function containsThai(str) {
|
|
2557
|
-
for (let i = 0; i < str.length; i++) {
|
|
2558
|
-
if (isThaiCodepoint(str.charCodeAt(i))) return true;
|
|
2559
|
-
}
|
|
2560
|
-
return false;
|
|
2561
|
-
}
|
|
2562
|
-
function containsBengali(str) {
|
|
2563
|
-
for (let i = 0; i < str.length; i++) {
|
|
2564
|
-
if (isBengaliCodepoint(str.charCodeAt(i))) return true;
|
|
2565
|
-
}
|
|
2566
|
-
return false;
|
|
2567
|
-
}
|
|
2568
|
-
function containsTamil(str) {
|
|
2569
|
-
for (let i = 0; i < str.length; i++) {
|
|
2570
|
-
if (isTamilCodepoint(str.charCodeAt(i))) return true;
|
|
2571
|
-
}
|
|
2572
|
-
return false;
|
|
2573
|
-
}
|
|
2574
|
-
function containsDevanagari(str) {
|
|
2575
|
-
for (let i = 0; i < str.length; i++) {
|
|
2576
|
-
if (isDevanagariCodepoint(str.charCodeAt(i))) return true;
|
|
2639
|
+
// src/shaping/gsub-driver.ts
|
|
2640
|
+
function tryLigature(gids, ligatures) {
|
|
2641
|
+
if (!ligatures || gids.length < 2) return null;
|
|
2642
|
+
const firstGid = gids[0];
|
|
2643
|
+
const entries = ligatures[firstGid];
|
|
2644
|
+
if (!entries) return null;
|
|
2645
|
+
for (const entry of entries) {
|
|
2646
|
+
const compCount = entry.length - 1;
|
|
2647
|
+
if (compCount > gids.length - 1) continue;
|
|
2648
|
+
let match = true;
|
|
2649
|
+
for (let ci = 0; ci < compCount; ci++) {
|
|
2650
|
+
if (gids[1 + ci] !== entry[1 + ci]) {
|
|
2651
|
+
match = false;
|
|
2652
|
+
break;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
if (match) return { resultGid: entry[0], consumed: compCount + 1 };
|
|
2577
2656
|
}
|
|
2578
|
-
return
|
|
2657
|
+
return null;
|
|
2579
2658
|
}
|
|
2580
2659
|
|
|
2581
2660
|
// src/shaping/bengali-shaper.ts
|
|
@@ -2704,43 +2783,27 @@ function shapeBengaliText(str, fontData) {
|
|
|
2704
2783
|
if (gsub[gid] !== void 0) return gsub[gid];
|
|
2705
2784
|
return gid;
|
|
2706
2785
|
}
|
|
2707
|
-
function
|
|
2708
|
-
|
|
2709
|
-
const firstGid = gids[0];
|
|
2710
|
-
const entries = ligatures[firstGid];
|
|
2711
|
-
if (!entries) return null;
|
|
2712
|
-
for (const entry of entries) {
|
|
2713
|
-
const compCount = entry.length - 1;
|
|
2714
|
-
if (compCount > gids.length - 1) continue;
|
|
2715
|
-
let match = true;
|
|
2716
|
-
for (let ci = 0; ci < compCount; ci++) {
|
|
2717
|
-
if (gids[1 + ci] !== entry[1 + ci]) {
|
|
2718
|
-
match = false;
|
|
2719
|
-
break;
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
if (match) return { resultGid: entry[0], consumed: compCount + 1 };
|
|
2723
|
-
}
|
|
2724
|
-
return null;
|
|
2786
|
+
function tryLig(gids) {
|
|
2787
|
+
return tryLigature(gids, ligatures);
|
|
2725
2788
|
}
|
|
2726
2789
|
function getAdv(gid) {
|
|
2727
2790
|
return widths[gid] !== void 0 ? widths[gid] : defaultWidth;
|
|
2728
2791
|
}
|
|
2729
|
-
function
|
|
2792
|
+
function getBaseAnchor2(baseGid, markClass) {
|
|
2730
2793
|
const base = markAnchors && markAnchors.bases && markAnchors.bases[baseGid];
|
|
2731
2794
|
if (!base) return null;
|
|
2732
2795
|
return base[markClass] ?? null;
|
|
2733
2796
|
}
|
|
2734
|
-
function
|
|
2797
|
+
function getMarkAnchor2(markGid) {
|
|
2735
2798
|
const mark = markAnchors && markAnchors.marks && markAnchors.marks[markGid];
|
|
2736
2799
|
if (!mark) return null;
|
|
2737
2800
|
return { classIdx: mark[0], x: mark[1], y: mark[2] };
|
|
2738
2801
|
}
|
|
2739
2802
|
function emitGlyph(gid, isZero, baseGid) {
|
|
2740
2803
|
if (isZero && baseGid !== void 0) {
|
|
2741
|
-
const markAnchor =
|
|
2804
|
+
const markAnchor = getMarkAnchor2(gid);
|
|
2742
2805
|
if (markAnchor) {
|
|
2743
|
-
const baseAnchorPt =
|
|
2806
|
+
const baseAnchorPt = getBaseAnchor2(baseGid, markAnchor.classIdx);
|
|
2744
2807
|
if (baseAnchorPt) {
|
|
2745
2808
|
const baseAdv = getAdv(baseGid);
|
|
2746
2809
|
shaped.push({
|
|
@@ -2801,7 +2864,7 @@ function shapeBengaliText(str, fontData) {
|
|
|
2801
2864
|
}
|
|
2802
2865
|
}
|
|
2803
2866
|
let ligConsumed = 0;
|
|
2804
|
-
const ligResult =
|
|
2867
|
+
const ligResult = tryLig(clusterGids);
|
|
2805
2868
|
if (ligResult) {
|
|
2806
2869
|
emitGlyph(ligResult.resultGid, false);
|
|
2807
2870
|
baseGid = ligResult.resultGid;
|
|
@@ -2809,7 +2872,7 @@ function shapeBengaliText(str, fontData) {
|
|
|
2809
2872
|
let gi = ligConsumed;
|
|
2810
2873
|
while (gi < clusterGids.length) {
|
|
2811
2874
|
const subSeq = clusterGids.slice(gi);
|
|
2812
|
-
const subLig =
|
|
2875
|
+
const subLig = tryLig(subSeq);
|
|
2813
2876
|
if (subLig) {
|
|
2814
2877
|
emitGlyph(subLig.resultGid, false);
|
|
2815
2878
|
gi += subLig.consumed;
|
|
@@ -2972,43 +3035,27 @@ function shapeTamilText(str, fontData) {
|
|
|
2972
3035
|
const normCp = cp === 8239 || cp === 160 ? 32 : cp;
|
|
2973
3036
|
return cmap[normCp] || 0;
|
|
2974
3037
|
}
|
|
2975
|
-
function
|
|
2976
|
-
|
|
2977
|
-
const firstGid = gids[0];
|
|
2978
|
-
const entries = ligatures[firstGid];
|
|
2979
|
-
if (!entries) return null;
|
|
2980
|
-
for (const entry of entries) {
|
|
2981
|
-
const compCount = entry.length - 1;
|
|
2982
|
-
if (compCount > gids.length - 1) continue;
|
|
2983
|
-
let match = true;
|
|
2984
|
-
for (let ci = 0; ci < compCount; ci++) {
|
|
2985
|
-
if (gids[1 + ci] !== entry[1 + ci]) {
|
|
2986
|
-
match = false;
|
|
2987
|
-
break;
|
|
2988
|
-
}
|
|
2989
|
-
}
|
|
2990
|
-
if (match) return { resultGid: entry[0], consumed: compCount + 1 };
|
|
2991
|
-
}
|
|
2992
|
-
return null;
|
|
3038
|
+
function tryLig(gids) {
|
|
3039
|
+
return tryLigature(gids, ligatures);
|
|
2993
3040
|
}
|
|
2994
3041
|
function getAdv(gid) {
|
|
2995
3042
|
return widths[gid] !== void 0 ? widths[gid] : defaultWidth;
|
|
2996
3043
|
}
|
|
2997
|
-
function
|
|
3044
|
+
function getBaseAnchor2(baseGid, markClass) {
|
|
2998
3045
|
const base = markAnchors && markAnchors.bases && markAnchors.bases[baseGid];
|
|
2999
3046
|
if (!base) return null;
|
|
3000
3047
|
return base[markClass] ?? null;
|
|
3001
3048
|
}
|
|
3002
|
-
function
|
|
3049
|
+
function getMarkAnchor2(markGid) {
|
|
3003
3050
|
const mark = markAnchors && markAnchors.marks && markAnchors.marks[markGid];
|
|
3004
3051
|
if (!mark) return null;
|
|
3005
3052
|
return { classIdx: mark[0], x: mark[1], y: mark[2] };
|
|
3006
3053
|
}
|
|
3007
3054
|
function emitGlyph(gid, isZero, baseGid) {
|
|
3008
3055
|
if (isZero && baseGid !== void 0) {
|
|
3009
|
-
const markAnchor =
|
|
3056
|
+
const markAnchor = getMarkAnchor2(gid);
|
|
3010
3057
|
if (markAnchor) {
|
|
3011
|
-
const baseAnchorPt =
|
|
3058
|
+
const baseAnchorPt = getBaseAnchor2(baseGid, markAnchor.classIdx);
|
|
3012
3059
|
if (baseAnchorPt) {
|
|
3013
3060
|
const baseAdv = getAdv(baseGid);
|
|
3014
3061
|
shaped.push({
|
|
@@ -3073,7 +3120,7 @@ function shapeTamilText(str, fontData) {
|
|
|
3073
3120
|
}
|
|
3074
3121
|
}
|
|
3075
3122
|
let ligConsumed = 0;
|
|
3076
|
-
const ligResult =
|
|
3123
|
+
const ligResult = tryLig(clusterGids);
|
|
3077
3124
|
if (ligResult) {
|
|
3078
3125
|
emitGlyph(ligResult.resultGid, false);
|
|
3079
3126
|
baseGid = ligResult.resultGid;
|
|
@@ -3081,7 +3128,7 @@ function shapeTamilText(str, fontData) {
|
|
|
3081
3128
|
let gi = ligConsumed;
|
|
3082
3129
|
while (gi < clusterGids.length) {
|
|
3083
3130
|
const subSeq = clusterGids.slice(gi);
|
|
3084
|
-
const subLig =
|
|
3131
|
+
const subLig = tryLig(subSeq);
|
|
3085
3132
|
if (subLig) {
|
|
3086
3133
|
emitGlyph(subLig.resultGid, false);
|
|
3087
3134
|
gi += subLig.consumed;
|
|
@@ -3130,6 +3177,30 @@ function shapeTamilText(str, fontData) {
|
|
|
3130
3177
|
return shaped;
|
|
3131
3178
|
}
|
|
3132
3179
|
|
|
3180
|
+
// src/shaping/gpos-positioner.ts
|
|
3181
|
+
function getBaseAnchor(markAnchors, baseGid, markClass) {
|
|
3182
|
+
if (!markAnchors) return null;
|
|
3183
|
+
const base = markAnchors.bases[baseGid];
|
|
3184
|
+
if (!base) return null;
|
|
3185
|
+
return base[markClass] ?? null;
|
|
3186
|
+
}
|
|
3187
|
+
function getMarkAnchor(markAnchors, markGid) {
|
|
3188
|
+
if (!markAnchors) return null;
|
|
3189
|
+
const mark = markAnchors.marks[markGid];
|
|
3190
|
+
if (!mark) return null;
|
|
3191
|
+
return { classIdx: mark[0], x: mark[1], y: mark[2] };
|
|
3192
|
+
}
|
|
3193
|
+
function positionMarkOnBase(markAnchors, markGid, baseGid, baseAdv) {
|
|
3194
|
+
const mark = getMarkAnchor(markAnchors, markGid);
|
|
3195
|
+
if (!mark) return null;
|
|
3196
|
+
const base = getBaseAnchor(markAnchors, baseGid, mark.classIdx);
|
|
3197
|
+
if (!base) return null;
|
|
3198
|
+
return {
|
|
3199
|
+
dx: base[0] - mark.x - baseAdv,
|
|
3200
|
+
dy: base[1] - mark.y
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3133
3204
|
// src/shaping/devanagari-shaper.ts
|
|
3134
3205
|
var HALANT2 = 2381;
|
|
3135
3206
|
var NUKTA2 = 2364;
|
|
@@ -3245,43 +3316,17 @@ function shapeDevanagariText(str, fontData) {
|
|
|
3245
3316
|
const normCp = cp === 8239 || cp === 160 ? 32 : cp;
|
|
3246
3317
|
return cmap[normCp] || 0;
|
|
3247
3318
|
}
|
|
3248
|
-
function
|
|
3249
|
-
|
|
3250
|
-
const firstGid = gids[0];
|
|
3251
|
-
const entries = ligatures[firstGid];
|
|
3252
|
-
if (!entries) return null;
|
|
3253
|
-
for (const entry of entries) {
|
|
3254
|
-
const compCount = entry.length - 1;
|
|
3255
|
-
if (compCount > gids.length - 1) continue;
|
|
3256
|
-
let match = true;
|
|
3257
|
-
for (let ci = 0; ci < compCount; ci++) {
|
|
3258
|
-
if (gids[1 + ci] !== entry[1 + ci]) {
|
|
3259
|
-
match = false;
|
|
3260
|
-
break;
|
|
3261
|
-
}
|
|
3262
|
-
}
|
|
3263
|
-
if (match) return { resultGid: entry[0], consumed: compCount + 1 };
|
|
3264
|
-
}
|
|
3265
|
-
return null;
|
|
3319
|
+
function tryLig(gids) {
|
|
3320
|
+
return tryLigature(gids, ligatures);
|
|
3266
3321
|
}
|
|
3267
3322
|
function getAdv(gid) {
|
|
3268
3323
|
return widths[gid] !== void 0 ? widths[gid] : defaultWidth;
|
|
3269
3324
|
}
|
|
3270
|
-
function getBaseAnchor(baseGid, markClass) {
|
|
3271
|
-
const base = markAnchors && markAnchors.bases && markAnchors.bases[baseGid];
|
|
3272
|
-
if (!base) return null;
|
|
3273
|
-
return base[markClass] ?? null;
|
|
3274
|
-
}
|
|
3275
|
-
function getMarkAnchor(markGid) {
|
|
3276
|
-
const mark = markAnchors && markAnchors.marks && markAnchors.marks[markGid];
|
|
3277
|
-
if (!mark) return null;
|
|
3278
|
-
return { classIdx: mark[0], x: mark[1], y: mark[2] };
|
|
3279
|
-
}
|
|
3280
3325
|
function emitGlyph(gid, isZero, baseGid) {
|
|
3281
3326
|
if (isZero && baseGid !== void 0) {
|
|
3282
|
-
const markAnchor = getMarkAnchor(gid);
|
|
3327
|
+
const markAnchor = getMarkAnchor(markAnchors, gid);
|
|
3283
3328
|
if (markAnchor) {
|
|
3284
|
-
const baseAnchorPt = getBaseAnchor(baseGid, markAnchor.classIdx);
|
|
3329
|
+
const baseAnchorPt = getBaseAnchor(markAnchors, baseGid, markAnchor.classIdx);
|
|
3285
3330
|
if (baseAnchorPt) {
|
|
3286
3331
|
const baseAdv = getAdv(baseGid);
|
|
3287
3332
|
shaped.push({
|
|
@@ -3329,7 +3374,7 @@ function shapeDevanagariText(str, fontData) {
|
|
|
3329
3374
|
if (hasReph) {
|
|
3330
3375
|
const raGid = resolveGid(RA2);
|
|
3331
3376
|
const halantGid = resolveGid(HALANT2);
|
|
3332
|
-
const rephLig =
|
|
3377
|
+
const rephLig = tryLig([raGid, halantGid]);
|
|
3333
3378
|
if (rephLig) {
|
|
3334
3379
|
emitGlyph(rephLig.resultGid, true, baseGid);
|
|
3335
3380
|
} else {
|
|
@@ -3352,14 +3397,14 @@ function shapeDevanagariText(str, fontData) {
|
|
|
3352
3397
|
break;
|
|
3353
3398
|
}
|
|
3354
3399
|
}
|
|
3355
|
-
const ligResult =
|
|
3400
|
+
const ligResult = tryLig(clusterGids);
|
|
3356
3401
|
if (ligResult) {
|
|
3357
3402
|
emitGlyph(ligResult.resultGid, false);
|
|
3358
3403
|
baseGid = ligResult.resultGid;
|
|
3359
3404
|
let gi = ligResult.consumed;
|
|
3360
3405
|
while (gi < clusterGids.length) {
|
|
3361
3406
|
const subSeq = clusterGids.slice(gi);
|
|
3362
|
-
const subLig =
|
|
3407
|
+
const subLig = tryLig(subSeq);
|
|
3363
3408
|
if (subLig) {
|
|
3364
3409
|
emitGlyph(subLig.resultGid, false);
|
|
3365
3410
|
gi += subLig.consumed;
|
|
@@ -3533,6 +3578,10 @@ function shapeArabicText(str, fontData) {
|
|
|
3533
3578
|
const forms = resolvePositionalForms(codePoints);
|
|
3534
3579
|
const glyphs = [];
|
|
3535
3580
|
const cmap = fontData.cmap;
|
|
3581
|
+
const widths = fontData.widths;
|
|
3582
|
+
const defaultWidth = fontData.defaultWidth;
|
|
3583
|
+
const markAnchors = fontData.markAnchors;
|
|
3584
|
+
let lastBaseGid = 0;
|
|
3536
3585
|
for (let i = 0; i < codePoints.length; i++) {
|
|
3537
3586
|
const cp = codePoints[i];
|
|
3538
3587
|
if (i < codePoints.length - 1 && isLamAlef(cp, codePoints[i + 1])) {
|
|
@@ -3543,6 +3592,7 @@ function shapeArabicText(str, fontData) {
|
|
|
3543
3592
|
const ligGid = cmap[ligCP];
|
|
3544
3593
|
if (ligGid) {
|
|
3545
3594
|
glyphs.push({ gid: ligGid, dx: 0, dy: 0, isZeroAdvance: false });
|
|
3595
|
+
lastBaseGid = ligGid;
|
|
3546
3596
|
i++;
|
|
3547
3597
|
continue;
|
|
3548
3598
|
}
|
|
@@ -3564,7 +3614,16 @@ function shapeArabicText(str, fontData) {
|
|
|
3564
3614
|
}
|
|
3565
3615
|
const joining = getJoiningType(cp);
|
|
3566
3616
|
const isZeroAdvance = joining === "T";
|
|
3617
|
+
if (isZeroAdvance && lastBaseGid !== 0) {
|
|
3618
|
+
const baseAdv = widths[lastBaseGid] !== void 0 ? widths[lastBaseGid] : defaultWidth;
|
|
3619
|
+
const offset = positionMarkOnBase(markAnchors, gid, lastBaseGid, baseAdv);
|
|
3620
|
+
if (offset) {
|
|
3621
|
+
glyphs.push({ gid, dx: offset.dx, dy: offset.dy, isZeroAdvance: true });
|
|
3622
|
+
continue;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3567
3625
|
glyphs.push({ gid, dx: 0, dy: 0, isZeroAdvance });
|
|
3626
|
+
if (!isZeroAdvance) lastBaseGid = gid;
|
|
3568
3627
|
}
|
|
3569
3628
|
return glyphs;
|
|
3570
3629
|
}
|
|
@@ -3577,7 +3636,7 @@ function classifyBidiType(cp) {
|
|
|
3577
3636
|
cp >= 1611 && cp <= 1631 || // Arabic harakat
|
|
3578
3637
|
cp >= 1648 && cp <= 1648 || // Arabic superscript alef
|
|
3579
3638
|
cp >= 1750 && cp <= 1756 || cp >= 1759 && cp <= 1764 || cp >= 1767 && cp <= 1768 || cp >= 1770 && cp <= 1773 || cp >= 65056 && cp <= 65071) return "NSM";
|
|
3580
|
-
if (cp === 8203 || cp === 8204 || cp === 8205 || cp === 8206 || cp === 8207 || cp === 65279) return "BN";
|
|
3639
|
+
if (cp === 8203 || cp === 8204 || cp === 8205 || cp === 8206 || cp === 8207 || cp === 65279 || cp === 8294 || cp === 8295 || cp === 8296 || cp === 8297) return "BN";
|
|
3581
3640
|
if (cp >= 1632 && cp <= 1641) return "AN";
|
|
3582
3641
|
if (cp >= 1776 && cp <= 1785) return "AN";
|
|
3583
3642
|
if (cp >= 48 && cp <= 57) return "EN";
|
|
@@ -3791,18 +3850,153 @@ function fixBracketPairing(types, codePoints, len) {
|
|
|
3791
3850
|
}
|
|
3792
3851
|
}
|
|
3793
3852
|
}
|
|
3853
|
+
function findOutermostIsolatePairs(codePoints) {
|
|
3854
|
+
const pairs = [];
|
|
3855
|
+
let i = 0;
|
|
3856
|
+
while (i < codePoints.length) {
|
|
3857
|
+
const cp = codePoints[i];
|
|
3858
|
+
if (cp === 8294 || cp === 8295 || cp === 8296) {
|
|
3859
|
+
let depth = 1;
|
|
3860
|
+
let close = -1;
|
|
3861
|
+
for (let j = i + 1; j < codePoints.length; j++) {
|
|
3862
|
+
const cj = codePoints[j];
|
|
3863
|
+
if (cj === 8294 || cj === 8295 || cj === 8296) depth++;
|
|
3864
|
+
else if (cj === 8297) {
|
|
3865
|
+
depth--;
|
|
3866
|
+
if (depth === 0) {
|
|
3867
|
+
close = j;
|
|
3868
|
+
break;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
if (close === -1) {
|
|
3873
|
+
i++;
|
|
3874
|
+
continue;
|
|
3875
|
+
}
|
|
3876
|
+
const kind = cp === 8294 ? "LRI" : cp === 8295 ? "RLI" : "FSI";
|
|
3877
|
+
pairs.push({ open: i, close, kind });
|
|
3878
|
+
i = close + 1;
|
|
3879
|
+
} else {
|
|
3880
|
+
i++;
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
return pairs;
|
|
3884
|
+
}
|
|
3794
3885
|
function resolveBidiRuns(text) {
|
|
3795
3886
|
if (!text) return [];
|
|
3796
3887
|
const codePoints = [];
|
|
3888
|
+
const cpToStr = [];
|
|
3889
|
+
for (let i = 0; i < text.length; ) {
|
|
3890
|
+
cpToStr.push(i);
|
|
3891
|
+
const cp = text.codePointAt(i) ?? 0;
|
|
3892
|
+
codePoints.push(cp);
|
|
3893
|
+
i += cp > 65535 ? 2 : 1;
|
|
3894
|
+
}
|
|
3895
|
+
cpToStr.push(text.length);
|
|
3896
|
+
const isolates = findOutermostIsolatePairs(codePoints);
|
|
3897
|
+
if (isolates.length === 0) {
|
|
3898
|
+
return resolveBidiCore(text, codePoints, cpToStr);
|
|
3899
|
+
}
|
|
3900
|
+
const insideIsolate = new Array(codePoints.length).fill(false);
|
|
3901
|
+
for (const p of isolates) {
|
|
3902
|
+
for (let k = p.open; k <= p.close; k++) insideIsolate[k] = true;
|
|
3903
|
+
}
|
|
3904
|
+
const outerTypes = codePoints.map((cp, idx) => insideIsolate[idx] ? "BN" : classifyBidiType(cp));
|
|
3905
|
+
const parentLevel = detectParagraphLevel(outerTypes);
|
|
3906
|
+
const out = [];
|
|
3907
|
+
const emitSegment = (cpStart, cpEnd, forced) => {
|
|
3908
|
+
if (cpStart >= cpEnd) return;
|
|
3909
|
+
const segText = text.substring(cpToStr[cpStart], cpToStr[cpEnd]);
|
|
3910
|
+
const segCps = codePoints.slice(cpStart, cpEnd);
|
|
3911
|
+
const baseStrIdx = cpToStr[cpStart];
|
|
3912
|
+
const segCpToStr = cpToStr.slice(cpStart, cpEnd + 1).map((x) => x - baseStrIdx);
|
|
3913
|
+
const segRuns = forced === void 0 ? resolveBidiRuns(segText) : resolveBidiCore(segText, segCps, segCpToStr, forced);
|
|
3914
|
+
for (const r of segRuns) {
|
|
3915
|
+
out.push({ text: r.text, level: r.level, start: r.start + baseStrIdx });
|
|
3916
|
+
}
|
|
3917
|
+
};
|
|
3918
|
+
let cursor = 0;
|
|
3919
|
+
for (const pair of isolates) {
|
|
3920
|
+
emitSegment(cursor, pair.open, parentLevel);
|
|
3921
|
+
const innerStart = pair.open + 1;
|
|
3922
|
+
const innerEnd = pair.close;
|
|
3923
|
+
let innerLevel;
|
|
3924
|
+
if (pair.kind === "LRI") innerLevel = 0;
|
|
3925
|
+
else if (pair.kind === "RLI") innerLevel = 1;
|
|
3926
|
+
else {
|
|
3927
|
+
const innerTypes = codePoints.slice(innerStart, innerEnd).map(classifyBidiType);
|
|
3928
|
+
innerLevel = detectParagraphLevel(innerTypes);
|
|
3929
|
+
}
|
|
3930
|
+
if (innerStart < innerEnd) {
|
|
3931
|
+
const innerText = text.substring(cpToStr[innerStart], cpToStr[innerEnd]);
|
|
3932
|
+
const innerRuns = resolveBidiRunsForced(innerText, innerLevel);
|
|
3933
|
+
const baseStrIdx = cpToStr[innerStart];
|
|
3934
|
+
for (const r of innerRuns) {
|
|
3935
|
+
out.push({ text: r.text, level: r.level, start: r.start + baseStrIdx });
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
cursor = pair.close + 1;
|
|
3939
|
+
}
|
|
3940
|
+
emitSegment(cursor, codePoints.length, parentLevel);
|
|
3941
|
+
return out;
|
|
3942
|
+
}
|
|
3943
|
+
function resolveBidiRunsForced(text, forcedLevel) {
|
|
3944
|
+
if (!text) return [];
|
|
3945
|
+
const codePoints = [];
|
|
3946
|
+
const cpToStr = [];
|
|
3797
3947
|
for (let i = 0; i < text.length; ) {
|
|
3948
|
+
cpToStr.push(i);
|
|
3798
3949
|
const cp = text.codePointAt(i) ?? 0;
|
|
3799
3950
|
codePoints.push(cp);
|
|
3800
3951
|
i += cp > 65535 ? 2 : 1;
|
|
3801
3952
|
}
|
|
3953
|
+
cpToStr.push(text.length);
|
|
3954
|
+
const isolates = findOutermostIsolatePairs(codePoints);
|
|
3955
|
+
if (isolates.length === 0) {
|
|
3956
|
+
return resolveBidiCore(text, codePoints, cpToStr, forcedLevel);
|
|
3957
|
+
}
|
|
3958
|
+
const out = [];
|
|
3959
|
+
const emit = (cpStart, cpEnd, forced) => {
|
|
3960
|
+
if (cpStart >= cpEnd) return;
|
|
3961
|
+
const segText = text.substring(cpToStr[cpStart], cpToStr[cpEnd]);
|
|
3962
|
+
const segCps = codePoints.slice(cpStart, cpEnd);
|
|
3963
|
+
const baseStrIdx = cpToStr[cpStart];
|
|
3964
|
+
const segCpToStr = cpToStr.slice(cpStart, cpEnd + 1).map((x) => x - baseStrIdx);
|
|
3965
|
+
const segRuns = resolveBidiCore(segText, segCps, segCpToStr, forced);
|
|
3966
|
+
for (const r of segRuns) {
|
|
3967
|
+
out.push({ text: r.text, level: r.level, start: r.start + baseStrIdx });
|
|
3968
|
+
}
|
|
3969
|
+
};
|
|
3970
|
+
let cursor = 0;
|
|
3971
|
+
for (const pair of isolates) {
|
|
3972
|
+
emit(cursor, pair.open, forcedLevel);
|
|
3973
|
+
const innerStart = pair.open + 1;
|
|
3974
|
+
const innerEnd = pair.close;
|
|
3975
|
+
let innerLevel;
|
|
3976
|
+
if (pair.kind === "LRI") innerLevel = 0;
|
|
3977
|
+
else if (pair.kind === "RLI") innerLevel = 1;
|
|
3978
|
+
else {
|
|
3979
|
+
const innerTypes = codePoints.slice(innerStart, innerEnd).map(classifyBidiType);
|
|
3980
|
+
innerLevel = detectParagraphLevel(innerTypes);
|
|
3981
|
+
}
|
|
3982
|
+
if (innerStart < innerEnd) {
|
|
3983
|
+
const innerText = text.substring(cpToStr[innerStart], cpToStr[innerEnd]);
|
|
3984
|
+
const innerRuns = resolveBidiRunsForced(innerText, innerLevel);
|
|
3985
|
+
const baseStrIdx = cpToStr[innerStart];
|
|
3986
|
+
for (const r of innerRuns) {
|
|
3987
|
+
out.push({ text: r.text, level: r.level, start: r.start + baseStrIdx });
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
cursor = pair.close + 1;
|
|
3991
|
+
}
|
|
3992
|
+
emit(cursor, codePoints.length, forcedLevel);
|
|
3993
|
+
return out;
|
|
3994
|
+
}
|
|
3995
|
+
function resolveBidiCore(text, codePoints, cpToStr, forcedLevel) {
|
|
3802
3996
|
const len = codePoints.length;
|
|
3803
3997
|
if (len === 0) return [];
|
|
3804
3998
|
const types = codePoints.map(classifyBidiType);
|
|
3805
|
-
const paraLevel = detectParagraphLevel(types);
|
|
3999
|
+
const paraLevel = forcedLevel !== void 0 ? forcedLevel : detectParagraphLevel(types);
|
|
3806
4000
|
resolveWeakTypes(types, paraLevel);
|
|
3807
4001
|
resolveNeutralTypes(types, paraLevel);
|
|
3808
4002
|
if (paraLevel === 1) {
|
|
@@ -3813,13 +4007,6 @@ function resolveBidiRuns(text) {
|
|
|
3813
4007
|
const runs = [];
|
|
3814
4008
|
let runStart = 0;
|
|
3815
4009
|
let runLevel = levels[0];
|
|
3816
|
-
const cpToStr = [];
|
|
3817
|
-
let strIdx = 0;
|
|
3818
|
-
for (let i = 0; i < len; i++) {
|
|
3819
|
-
cpToStr.push(strIdx);
|
|
3820
|
-
strIdx += codePoints[i] > 65535 ? 2 : 1;
|
|
3821
|
-
}
|
|
3822
|
-
cpToStr.push(strIdx);
|
|
3823
4010
|
for (let i = 1; i <= len; i++) {
|
|
3824
4011
|
if (i === len || levels[i] !== runLevel) {
|
|
3825
4012
|
const start = cpToStr[runStart];
|
|
@@ -3903,7 +4090,7 @@ function splitArabicNonArabic(text, fd) {
|
|
|
3903
4090
|
if (cur) segments.push({ text: cur, arabic: curArabic });
|
|
3904
4091
|
return segments;
|
|
3905
4092
|
}
|
|
3906
|
-
function buildTextRunsWithFallback(text, fontRef, fd, sz, trackGid) {
|
|
4093
|
+
function buildTextRunsWithFallback(text, fontRef, fd, sz, trackGid, pdfA = false) {
|
|
3907
4094
|
const upm = fd.metrics.unitsPerEm;
|
|
3908
4095
|
const result = [];
|
|
3909
4096
|
let mode = null;
|
|
@@ -3943,11 +4130,11 @@ function buildTextRunsWithFallback(text, fontRef, fd, sz, trackGid) {
|
|
|
3943
4130
|
const cp = rawCp === 8239 || rawCp === 160 ? 32 : rawCp;
|
|
3944
4131
|
const char = text.substring(i, i + charLen);
|
|
3945
4132
|
const gid = fd.cmap[cp] ?? 0;
|
|
3946
|
-
if (gid === 0 && isWinAnsi(cp)) {
|
|
4133
|
+
if (gid === 0 && isWinAnsi(cp) && !pdfA) {
|
|
3947
4134
|
if (mode === "cid") flushCid();
|
|
3948
4135
|
mode = "hel";
|
|
3949
4136
|
helChars += char;
|
|
3950
|
-
} else if (mode === "hel" && isWinAnsi(cp)) {
|
|
4137
|
+
} else if (mode === "hel" && isWinAnsi(cp) && !pdfA) {
|
|
3951
4138
|
helChars += char;
|
|
3952
4139
|
} else {
|
|
3953
4140
|
if (mode === "hel") flushHel();
|
|
@@ -3964,7 +4151,7 @@ function buildTextRunsWithFallback(text, fontRef, fd, sz, trackGid) {
|
|
|
3964
4151
|
if (mode === "hel") flushHel();
|
|
3965
4152
|
return result;
|
|
3966
4153
|
}
|
|
3967
|
-
function createEncodingContext(fontEntries) {
|
|
4154
|
+
function createEncodingContext(fontEntries, pdfA = false) {
|
|
3968
4155
|
if (!fontEntries || fontEntries.length === 0) {
|
|
3969
4156
|
return {
|
|
3970
4157
|
isUnicode: false,
|
|
@@ -4020,12 +4207,12 @@ function createEncodingContext(fontEntries) {
|
|
|
4020
4207
|
}
|
|
4021
4208
|
result.push({ text: seg.text, fontRef, fontData: fd, shaped: visual, hexStr: null, widthPt: designW * sz / upm });
|
|
4022
4209
|
} else {
|
|
4023
|
-
const subRuns = buildTextRunsWithFallback(seg.text, fontRef, fd, sz, _trackGid);
|
|
4210
|
+
const subRuns = buildTextRunsWithFallback(seg.text, fontRef, fd, sz, _trackGid, pdfA);
|
|
4024
4211
|
result.push(...subRuns);
|
|
4025
4212
|
}
|
|
4026
4213
|
}
|
|
4027
4214
|
} else if (isRTL) {
|
|
4028
|
-
const subRuns = buildTextRunsWithFallback(fRun.text, fontRef, fd, sz, _trackGid);
|
|
4215
|
+
const subRuns = buildTextRunsWithFallback(fRun.text, fontRef, fd, sz, _trackGid, pdfA);
|
|
4029
4216
|
result.push(...subRuns);
|
|
4030
4217
|
} else {
|
|
4031
4218
|
if (containsThai(fRun.text)) {
|
|
@@ -4069,7 +4256,7 @@ function createEncodingContext(fontEntries) {
|
|
|
4069
4256
|
}
|
|
4070
4257
|
result.push({ text: fRun.text, fontRef, fontData: fd, shaped, hexStr: null, widthPt: designW * sz / upm });
|
|
4071
4258
|
} else {
|
|
4072
|
-
const subRuns = buildTextRunsWithFallback(fRun.text, fontRef, fd, sz, _trackGid);
|
|
4259
|
+
const subRuns = buildTextRunsWithFallback(fRun.text, fontRef, fd, sz, _trackGid, pdfA);
|
|
4073
4260
|
result.push(...subRuns);
|
|
4074
4261
|
}
|
|
4075
4262
|
}
|
|
@@ -4126,7 +4313,7 @@ function createEncodingContext(fontEntries) {
|
|
|
4126
4313
|
}
|
|
4127
4314
|
return [{ text: run.text, fontRef, fontData: fd, shaped, hexStr: null, widthPt: designW * sz / upm }];
|
|
4128
4315
|
}
|
|
4129
|
-
return buildTextRunsWithFallback(run.text, fontRef, fd, sz, _trackGid);
|
|
4316
|
+
return buildTextRunsWithFallback(run.text, fontRef, fd, sz, _trackGid, pdfA);
|
|
4130
4317
|
});
|
|
4131
4318
|
},
|
|
4132
4319
|
ps(str) {
|
|
@@ -4640,7 +4827,7 @@ function buildPdfMetadata(now = /* @__PURE__ */ new Date()) {
|
|
|
4640
4827
|
const xmpDate = `${yyyy}-${mm}-${dd}T${hh}:${mi}:${ss}${tzSign}${tzH}:${tzM}`;
|
|
4641
4828
|
return { pdfDate, xmpDate };
|
|
4642
4829
|
}
|
|
4643
|
-
function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B", author) {
|
|
4830
|
+
function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B", author, subject, keywords) {
|
|
4644
4831
|
const escapedTitle = escapeXml(title);
|
|
4645
4832
|
const lines = [
|
|
4646
4833
|
'<?xpacket begin="\xEF\xBB\xBF" id="W5M0MpCehiHzreSzNTczkc9d"?>',
|
|
@@ -4656,13 +4843,21 @@ function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B"
|
|
|
4656
4843
|
if (author !== void 0 && author !== "") {
|
|
4657
4844
|
lines.push(` <dc:creator><rdf:Seq><rdf:li>${escapeXml(author)}</rdf:li></rdf:Seq></dc:creator>`);
|
|
4658
4845
|
}
|
|
4846
|
+
if (subject !== void 0 && subject !== "") {
|
|
4847
|
+
lines.push(` <dc:description><rdf:Alt><rdf:li xml:lang="x-default">${escapeXml(subject)}</rdf:li></rdf:Alt></dc:description>`);
|
|
4848
|
+
}
|
|
4659
4849
|
lines.push(
|
|
4660
4850
|
" <pdf:Producer>pdfnative</pdf:Producer>",
|
|
4661
4851
|
` <xmp:CreateDate>${createDate}</xmp:CreateDate>`,
|
|
4662
4852
|
` <xmp:ModifyDate>${createDate}</xmp:ModifyDate>`,
|
|
4663
4853
|
` <xmp:MetadataDate>${createDate}</xmp:MetadataDate>`,
|
|
4664
4854
|
` <pdfaid:part>${pdfaPart}</pdfaid:part>`,
|
|
4665
|
-
` <pdfaid:conformance>${pdfaConformance}</pdfaid:conformance
|
|
4855
|
+
` <pdfaid:conformance>${pdfaConformance}</pdfaid:conformance>`
|
|
4856
|
+
);
|
|
4857
|
+
if (keywords !== void 0 && keywords !== "") {
|
|
4858
|
+
lines.push(` <pdf:Keywords>${escapeXml(keywords)}</pdf:Keywords>`);
|
|
4859
|
+
}
|
|
4860
|
+
lines.push(
|
|
4666
4861
|
" </rdf:Description>",
|
|
4667
4862
|
" </rdf:RDF>",
|
|
4668
4863
|
"</x:xmpmeta>",
|
|
@@ -4670,6 +4865,35 @@ function buildXMPMetadata(title, createDate, pdfaPart = 2, pdfaConformance = "B"
|
|
|
4670
4865
|
);
|
|
4671
4866
|
return lines.join("\n");
|
|
4672
4867
|
}
|
|
4868
|
+
function utf8EncodeBinaryString(str) {
|
|
4869
|
+
let out = "";
|
|
4870
|
+
for (let i = 0; i < str.length; i++) {
|
|
4871
|
+
let cp = str.charCodeAt(i);
|
|
4872
|
+
if (cp >= 55296 && cp <= 56319 && i + 1 < str.length) {
|
|
4873
|
+
const lo = str.charCodeAt(i + 1);
|
|
4874
|
+
if (lo >= 56320 && lo <= 57343) {
|
|
4875
|
+
cp = (cp - 55296 << 10) + (lo - 56320) + 65536;
|
|
4876
|
+
i++;
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4879
|
+
if (cp < 128) {
|
|
4880
|
+
out += String.fromCharCode(cp);
|
|
4881
|
+
} else if (cp < 2048) {
|
|
4882
|
+
out += String.fromCharCode(192 | cp >> 6);
|
|
4883
|
+
out += String.fromCharCode(128 | cp & 63);
|
|
4884
|
+
} else if (cp < 65536) {
|
|
4885
|
+
out += String.fromCharCode(224 | cp >> 12);
|
|
4886
|
+
out += String.fromCharCode(128 | cp >> 6 & 63);
|
|
4887
|
+
out += String.fromCharCode(128 | cp & 63);
|
|
4888
|
+
} else {
|
|
4889
|
+
out += String.fromCharCode(240 | cp >> 18);
|
|
4890
|
+
out += String.fromCharCode(128 | cp >> 12 & 63);
|
|
4891
|
+
out += String.fromCharCode(128 | cp >> 6 & 63);
|
|
4892
|
+
out += String.fromCharCode(128 | cp & 63);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
return out;
|
|
4896
|
+
}
|
|
4673
4897
|
function buildOutputIntentDict(iccStreamObjNum, subtype = "GTS_PDFA1") {
|
|
4674
4898
|
return `<< /Type /OutputIntent /S /${subtype} /OutputConditionIdentifier (sRGB IEC61966-2.1) /RegistryName (http://www.color.org) /DestOutputProfile ${iccStreamObjNum} 0 R >>`;
|
|
4675
4899
|
}
|
|
@@ -5004,13 +5228,42 @@ var DEFAULT_COLUMNS = [
|
|
|
5004
5228
|
{ f: 0.18, a: "c", mx: 20, mxH: 20 }
|
|
5005
5229
|
];
|
|
5006
5230
|
function computeColumnPositions(columns, marginLeft, contentWidth) {
|
|
5007
|
-
const
|
|
5008
|
-
const cwi =
|
|
5231
|
+
const n = columns.length;
|
|
5232
|
+
const cwi = new Array(n).fill(0);
|
|
5233
|
+
const fixed = new Array(n).fill(false);
|
|
5234
|
+
let totalFixed = 0;
|
|
5235
|
+
let freeWeight = 0;
|
|
5236
|
+
for (let i = 0; i < n; i++) {
|
|
5237
|
+
const col = columns[i];
|
|
5238
|
+
let w = col.f * contentWidth;
|
|
5239
|
+
let clamped = false;
|
|
5240
|
+
if (col.minWidth !== void 0 && w < col.minWidth) {
|
|
5241
|
+
w = col.minWidth;
|
|
5242
|
+
clamped = true;
|
|
5243
|
+
}
|
|
5244
|
+
if (col.maxWidth !== void 0 && w > col.maxWidth) {
|
|
5245
|
+
w = col.maxWidth;
|
|
5246
|
+
clamped = true;
|
|
5247
|
+
}
|
|
5248
|
+
if (clamped) {
|
|
5249
|
+
cwi[i] = w;
|
|
5250
|
+
fixed[i] = true;
|
|
5251
|
+
totalFixed += w;
|
|
5252
|
+
} else {
|
|
5253
|
+
freeWeight += col.f;
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
const remaining = contentWidth - totalFixed;
|
|
5257
|
+
if (freeWeight > 0) {
|
|
5258
|
+
for (let i = 0; i < n; i++) {
|
|
5259
|
+
if (!fixed[i]) cwi[i] = columns[i].f / freeWeight * remaining;
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
const cx = new Array(n);
|
|
5009
5263
|
let x = marginLeft;
|
|
5010
|
-
for (
|
|
5011
|
-
cx
|
|
5012
|
-
|
|
5013
|
-
x += col.f * contentWidth;
|
|
5264
|
+
for (let i = 0; i < n; i++) {
|
|
5265
|
+
cx[i] = x;
|
|
5266
|
+
x += cwi[i];
|
|
5014
5267
|
}
|
|
5015
5268
|
return { cx, cwi };
|
|
5016
5269
|
}
|
|
@@ -5501,6 +5754,8 @@ var DEFAULT_TEXT_COLOR = "0.75 0.75 0.75";
|
|
|
5501
5754
|
var DEFAULT_TEXT_OPACITY = 0.15;
|
|
5502
5755
|
var DEFAULT_TEXT_ANGLE = -45;
|
|
5503
5756
|
var DEFAULT_IMAGE_OPACITY = 0.1;
|
|
5757
|
+
var DEFAULT_CAP_HEIGHT_RATIO = 0.718;
|
|
5758
|
+
var WATERMARK_SAFETY_MARGIN = 24;
|
|
5504
5759
|
function validateWatermark(watermark, pdfaLevel) {
|
|
5505
5760
|
if (pdfaLevel === "pdfa1b") {
|
|
5506
5761
|
const textOpacity = watermark.text?.opacity ?? DEFAULT_TEXT_OPACITY;
|
|
@@ -5546,19 +5801,35 @@ function buildWatermarkState(watermark, pgW, pgH, enc) {
|
|
|
5546
5801
|
};
|
|
5547
5802
|
}
|
|
5548
5803
|
function _buildTextWatermarkOps(wm, pgW, pgH, enc, gsName) {
|
|
5549
|
-
|
|
5804
|
+
let sz = wm.fontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
5550
5805
|
const color = parseColor(wm.color ?? DEFAULT_TEXT_COLOR);
|
|
5551
5806
|
const angle = (wm.angle ?? DEFAULT_TEXT_ANGLE) * DEG_TO_RAD;
|
|
5552
5807
|
const cos = Math.cos(angle);
|
|
5553
5808
|
const sin = Math.sin(angle);
|
|
5809
|
+
const fdMetrics = enc.fontData?.metrics;
|
|
5810
|
+
const capRatio = fdMetrics ? fdMetrics.capHeight / fdMetrics.unitsPerEm : DEFAULT_CAP_HEIGHT_RATIO;
|
|
5811
|
+
if (wm.autoFit !== false) {
|
|
5812
|
+
const textW = enc.tw(wm.text, sz);
|
|
5813
|
+
const textH = sz * capRatio;
|
|
5814
|
+
const aCos = Math.abs(cos);
|
|
5815
|
+
const aSin = Math.abs(sin);
|
|
5816
|
+
const rotW = textW * aCos + textH * aSin;
|
|
5817
|
+
const rotH = textW * aSin + textH * aCos;
|
|
5818
|
+
const safeW = pgW - WATERMARK_SAFETY_MARGIN * 2;
|
|
5819
|
+
const safeH = pgH - WATERMARK_SAFETY_MARGIN * 2;
|
|
5820
|
+
if (rotW > safeW || rotH > safeH) {
|
|
5821
|
+
const scale = Math.min(safeW / rotW, safeH / rotH);
|
|
5822
|
+
sz *= scale;
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5554
5825
|
const cx = pgW / 2;
|
|
5555
5826
|
const cy = pgH / 2;
|
|
5556
5827
|
const textWidth = enc.tw(wm.text, sz);
|
|
5557
5828
|
const offsetX = -textWidth / 2;
|
|
5558
|
-
const offsetY = -sz / 2;
|
|
5829
|
+
const offsetY = -sz * capRatio / 2;
|
|
5559
5830
|
const tx = cx + offsetX * cos - offsetY * sin;
|
|
5560
5831
|
const ty = cy + offsetX * sin + offsetY * cos;
|
|
5561
|
-
const escapedText =
|
|
5832
|
+
const escapedText = enc.ps(wm.text);
|
|
5562
5833
|
const ops = [
|
|
5563
5834
|
"q",
|
|
5564
5835
|
`${gsName} gs`,
|
|
@@ -5743,7 +6014,9 @@ function buildPDF(params, layoutOptions) {
|
|
|
5743
6014
|
const fs = layoutOptions?.fontSizes ? { ...DEFAULT_FONT_SIZES, ...layoutOptions.fontSizes } : DEFAULT_FONT_SIZES;
|
|
5744
6015
|
const { cx, cwi } = computeColumnPositions(columns, mg.l, cw);
|
|
5745
6016
|
const fontEntries = params.fontEntries || (fontData ? [{ fontData, fontRef: "/F3", lang: "unknown" }] : []);
|
|
5746
|
-
const
|
|
6017
|
+
const pdfaConfig = resolvePdfAConfig(layoutOptions?.tagged);
|
|
6018
|
+
const tagged = pdfaConfig.enabled;
|
|
6019
|
+
const enc = createEncodingContext(fontEntries, tagged);
|
|
5747
6020
|
const footerTpl = layoutOptions?.footerTemplate ?? {
|
|
5748
6021
|
left: footerText || void 0,
|
|
5749
6022
|
right: "{page}/{pages}"
|
|
@@ -5765,8 +6038,6 @@ function buildPDF(params, layoutOptions) {
|
|
|
5765
6038
|
totalPages = 1 + Math.ceil((totalRows - rowsPage1) / rowsPerPage);
|
|
5766
6039
|
}
|
|
5767
6040
|
if (totalPages < 1) totalPages = 1;
|
|
5768
|
-
const pdfaConfig = resolvePdfAConfig(layoutOptions?.tagged);
|
|
5769
|
-
const tagged = pdfaConfig.enabled;
|
|
5770
6041
|
const encryptionOpts = layoutOptions?.encryption;
|
|
5771
6042
|
if (tagged && encryptionOpts) {
|
|
5772
6043
|
throw new Error("PDF/A and encryption are mutually exclusive (ISO 19005-1 \xA76.3.2)");
|
|
@@ -5935,8 +6206,17 @@ function buildPDF(params, layoutOptions) {
|
|
|
5935
6206
|
kids.push(`${pageObjStart + p * 2} 0 R`);
|
|
5936
6207
|
}
|
|
5937
6208
|
emitObj(2, `<< /Type /Pages /Kids [${kids.join(" ")}] /Count ${totalPages} >>`);
|
|
5938
|
-
|
|
5939
|
-
|
|
6209
|
+
if (tagged) {
|
|
6210
|
+
const pf = fontEntries[0];
|
|
6211
|
+
const bfName = `/${pf.fontData.fontName.replace(/[^A-Za-z0-9-]/g, "")}`;
|
|
6212
|
+
const primaryBase = 5;
|
|
6213
|
+
const refDict = `<< /Type /Font /Subtype /Type0 /BaseFont ${bfName} /Encoding /Identity-H /DescendantFonts [${primaryBase + 1} 0 R] /ToUnicode ${primaryBase + 4} 0 R >>`;
|
|
6214
|
+
emitObj(3, refDict);
|
|
6215
|
+
emitObj(4, refDict);
|
|
6216
|
+
} else {
|
|
6217
|
+
emitObj(3, "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>");
|
|
6218
|
+
emitObj(4, "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>");
|
|
6219
|
+
}
|
|
5940
6220
|
for (let fi = 0; fi < fontEntries.length; fi++) {
|
|
5941
6221
|
const fe = fontEntries[fi];
|
|
5942
6222
|
const fd = fe.fontData;
|
|
@@ -6061,7 +6341,7 @@ function buildPDF(params, layoutOptions) {
|
|
|
6061
6341
|
structTreeRootObjNum = tree.structTreeRootObjNum;
|
|
6062
6342
|
totalObjs = treeStart + tree.totalObjects - 1;
|
|
6063
6343
|
xmpObjNum = totalObjs + 1;
|
|
6064
|
-
const xmpContent = buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance);
|
|
6344
|
+
const xmpContent = utf8EncodeBinaryString(buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance));
|
|
6065
6345
|
emitStreamObj(
|
|
6066
6346
|
xmpObjNum,
|
|
6067
6347
|
`<< /Type /Metadata /Subtype /XML /Length ${xmpContent.length}`,
|
|
@@ -6376,7 +6656,8 @@ function buildFormWidget(field, apObjNum, radioCtx) {
|
|
|
6376
6656
|
if (field.required) ff |= FF_REQUIRED;
|
|
6377
6657
|
const parts = [
|
|
6378
6658
|
"<< /Type /Annot /Subtype /Widget",
|
|
6379
|
-
`/Rect [${fmtNum2(x1)} ${fmtNum2(y1)} ${fmtNum2(x2)} ${fmtNum2(y2)}]
|
|
6659
|
+
`/Rect [${fmtNum2(x1)} ${fmtNum2(y1)} ${fmtNum2(x2)} ${fmtNum2(y2)}]`,
|
|
6660
|
+
"/F 4"
|
|
6380
6661
|
];
|
|
6381
6662
|
if (radioCtx) {
|
|
6382
6663
|
parts.push(`/Parent ${radioCtx.parentObjNum} 0 R`);
|
|
@@ -6475,13 +6756,13 @@ function buildLinkAnnotation(annot, objNum) {
|
|
|
6475
6756
|
const [x1, y1, x2, y2] = annot.rect;
|
|
6476
6757
|
const escapedUrl = escapeUrlForPdf(annot.url);
|
|
6477
6758
|
return `${objNum} 0 obj
|
|
6478
|
-
<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>
|
|
6759
|
+
<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>
|
|
6479
6760
|
endobj`;
|
|
6480
6761
|
}
|
|
6481
6762
|
function buildInternalLinkAnnotation(annot, pageObjNum, objNum) {
|
|
6482
6763
|
const [x1, y1, x2, y2] = annot.rect;
|
|
6483
6764
|
return `${objNum} 0 obj
|
|
6484
|
-
<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /A << /Type /Action /S /GoTo /D [${pageObjNum} 0 R /Fit] >> >>
|
|
6765
|
+
<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /A << /Type /Action /S /GoTo /D [${pageObjNum} 0 R /Fit] >> >>
|
|
6485
6766
|
endobj`;
|
|
6486
6767
|
}
|
|
6487
6768
|
function isLinkAnnotation(annot) {
|
|
@@ -8413,6 +8694,39 @@ function renderSvg(data, x, y, w, h, options) {
|
|
|
8413
8694
|
return allOps.join("\n");
|
|
8414
8695
|
}
|
|
8415
8696
|
|
|
8697
|
+
// src/core/pdf-column-fit.ts
|
|
8698
|
+
var CELL_PAD_LEFT = 3;
|
|
8699
|
+
var CELL_PAD_RIGHT = 3;
|
|
8700
|
+
var CELL_PAD_TOTAL = CELL_PAD_LEFT + CELL_PAD_RIGHT;
|
|
8701
|
+
function computeAutoFitColumns(columns, headers, rows, enc, thSize, tdSize) {
|
|
8702
|
+
const n = columns.length;
|
|
8703
|
+
if (n === 0) return [];
|
|
8704
|
+
const desired = new Array(n).fill(0);
|
|
8705
|
+
for (let i = 0; i < n; i++) {
|
|
8706
|
+
let max = 0;
|
|
8707
|
+
const hdr = headers[i];
|
|
8708
|
+
if (hdr) {
|
|
8709
|
+
const w = enc.tw(hdr, thSize);
|
|
8710
|
+
if (w > max) max = w;
|
|
8711
|
+
}
|
|
8712
|
+
for (const row of rows) {
|
|
8713
|
+
const cell = row.cells[i];
|
|
8714
|
+
if (!cell) continue;
|
|
8715
|
+
const w = enc.tw(cell, tdSize);
|
|
8716
|
+
if (w > max) max = w;
|
|
8717
|
+
}
|
|
8718
|
+
desired[i] = max + CELL_PAD_TOTAL;
|
|
8719
|
+
}
|
|
8720
|
+
let total = 0;
|
|
8721
|
+
for (let i = 0; i < n; i++) total += desired[i];
|
|
8722
|
+
if (total <= 0) return columns.slice();
|
|
8723
|
+
const out = new Array(n);
|
|
8724
|
+
for (let i = 0; i < n; i++) {
|
|
8725
|
+
out[i] = { ...columns[i], f: desired[i] / total };
|
|
8726
|
+
}
|
|
8727
|
+
return out;
|
|
8728
|
+
}
|
|
8729
|
+
|
|
8416
8730
|
// src/core/pdf-renderers.ts
|
|
8417
8731
|
var HEADING_SIZES = { 1: 18, 2: 14, 3: 11 };
|
|
8418
8732
|
var HEADING_SPACING = {
|
|
@@ -8632,10 +8946,15 @@ function renderList(block, y, enc, mgL, cw, tagCtx, documentChildren) {
|
|
|
8632
8946
|
}
|
|
8633
8947
|
function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren) {
|
|
8634
8948
|
const ops = [];
|
|
8635
|
-
const
|
|
8949
|
+
const baseColumns = block.columns ? [...block.columns] : DEFAULT_COLUMNS;
|
|
8636
8950
|
const fs = DEFAULT_FONT_SIZES;
|
|
8637
8951
|
const colors = DEFAULT_COLORS;
|
|
8952
|
+
const columns = block.autoFitColumns ? computeAutoFitColumns(baseColumns, block.headers, block.rows, enc, fs.th, fs.td) : baseColumns;
|
|
8638
8953
|
const { cx, cwi } = computeColumnPositions(columns, mgL, cw);
|
|
8954
|
+
const clip = block.clipCells !== false;
|
|
8955
|
+
const clipCell = (op, i, top, h) => clip ? `q ${fmtNum(cx[i])} ${fmtNum(top - h)} ${fmtNum(cwi[i])} ${fmtNum(h)} re W n
|
|
8956
|
+
${op}
|
|
8957
|
+
Q` : op;
|
|
8639
8958
|
const tableRows = [];
|
|
8640
8959
|
ops.push(`${colors.thBg} rg`);
|
|
8641
8960
|
ops.push(`${fmtNum(mgL)} ${fmtNum(y - TH_H)} ${fmtNum(cw)} ${fmtNum(TH_H)} re f`);
|
|
@@ -8649,19 +8968,19 @@ function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren)
|
|
|
8649
8968
|
const mcid = tagCtx.mcidAlloc.next(tagCtx.pageObjNum);
|
|
8650
8969
|
thChildren.push({ type: "TH", children: [{ mcid, pageObjNum: tagCtx.pageObjNum }] });
|
|
8651
8970
|
if (columns[i].a === "r") {
|
|
8652
|
-
ops.push(txtRTagged(t, cx[i] + cwi[i] - 3, y - TH_H + 4, enc.f2, fs.th, enc, mcid));
|
|
8971
|
+
ops.push(clipCell(txtRTagged(t, cx[i] + cwi[i] - 3, y - TH_H + 4, enc.f2, fs.th, enc, mcid), i, y, TH_H));
|
|
8653
8972
|
} else if (columns[i].a === "c") {
|
|
8654
|
-
ops.push(txtCTagged(t, cx[i], y - TH_H + 4, enc.f2, fs.th, cwi[i], enc, mcid));
|
|
8973
|
+
ops.push(clipCell(txtCTagged(t, cx[i], y - TH_H + 4, enc.f2, fs.th, cwi[i], enc, mcid), i, y, TH_H));
|
|
8655
8974
|
} else {
|
|
8656
|
-
ops.push(txtTagged(t, cx[i] + 3, y - TH_H + 4, enc.f2, fs.th, enc, mcid));
|
|
8975
|
+
ops.push(clipCell(txtTagged(t, cx[i] + 3, y - TH_H + 4, enc.f2, fs.th, enc, mcid), i, y, TH_H));
|
|
8657
8976
|
}
|
|
8658
8977
|
} else {
|
|
8659
8978
|
if (columns[i].a === "r") {
|
|
8660
|
-
ops.push(txtR(t, cx[i] + cwi[i] - 3, y - TH_H + 4, enc.f2, fs.th, enc));
|
|
8979
|
+
ops.push(clipCell(txtR(t, cx[i] + cwi[i] - 3, y - TH_H + 4, enc.f2, fs.th, enc), i, y, TH_H));
|
|
8661
8980
|
} else if (columns[i].a === "c") {
|
|
8662
|
-
ops.push(txtC(t, cx[i], y - TH_H + 4, enc.f2, fs.th, cwi[i], enc));
|
|
8981
|
+
ops.push(clipCell(txtC(t, cx[i], y - TH_H + 4, enc.f2, fs.th, cwi[i], enc), i, y, TH_H));
|
|
8663
8982
|
} else {
|
|
8664
|
-
ops.push(txt(t, cx[i] + 3, y - TH_H + 4, enc.f2, fs.th, enc));
|
|
8983
|
+
ops.push(clipCell(txt(t, cx[i] + 3, y - TH_H + 4, enc.f2, fs.th, enc), i, y, TH_H));
|
|
8665
8984
|
}
|
|
8666
8985
|
}
|
|
8667
8986
|
}
|
|
@@ -8681,19 +9000,19 @@ function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren)
|
|
|
8681
9000
|
const mcid = tagCtx.mcidAlloc.next(tagCtx.pageObjNum);
|
|
8682
9001
|
tdChildren.push({ type: "TD", children: [{ mcid, pageObjNum: tagCtx.pageObjNum }] });
|
|
8683
9002
|
if (columns[i].a === "r") {
|
|
8684
|
-
ops.push(txtRTagged(t, cx[i] + cwi[i] - 3, y - ROW_H + 3, font, fs.td, enc, mcid));
|
|
9003
|
+
ops.push(clipCell(txtRTagged(t, cx[i] + cwi[i] - 3, y - ROW_H + 3, font, fs.td, enc, mcid), i, y, ROW_H));
|
|
8685
9004
|
} else if (columns[i].a === "c") {
|
|
8686
|
-
ops.push(txtCTagged(t, cx[i], y - ROW_H + 3, font, fs.td, cwi[i], enc, mcid));
|
|
9005
|
+
ops.push(clipCell(txtCTagged(t, cx[i], y - ROW_H + 3, font, fs.td, cwi[i], enc, mcid), i, y, ROW_H));
|
|
8687
9006
|
} else {
|
|
8688
|
-
ops.push(txtTagged(t, cx[i] + 3, y - ROW_H + 3, font, fs.td, enc, mcid));
|
|
9007
|
+
ops.push(clipCell(txtTagged(t, cx[i] + 3, y - ROW_H + 3, font, fs.td, enc, mcid), i, y, ROW_H));
|
|
8689
9008
|
}
|
|
8690
9009
|
} else {
|
|
8691
9010
|
if (columns[i].a === "r") {
|
|
8692
|
-
ops.push(txtR(t, cx[i] + cwi[i] - 3, y - ROW_H + 3, font, fs.td, enc));
|
|
9011
|
+
ops.push(clipCell(txtR(t, cx[i] + cwi[i] - 3, y - ROW_H + 3, font, fs.td, enc), i, y, ROW_H));
|
|
8693
9012
|
} else if (columns[i].a === "c") {
|
|
8694
|
-
ops.push(txtC(t, cx[i], y - ROW_H + 3, font, fs.td, cwi[i], enc));
|
|
9013
|
+
ops.push(clipCell(txtC(t, cx[i], y - ROW_H + 3, font, fs.td, cwi[i], enc), i, y, ROW_H));
|
|
8695
9014
|
} else {
|
|
8696
|
-
ops.push(txt(t, cx[i] + 3, y - ROW_H + 3, font, fs.td, enc));
|
|
9015
|
+
ops.push(clipCell(txt(t, cx[i] + 3, y - ROW_H + 3, font, fs.td, enc), i, y, ROW_H));
|
|
8697
9016
|
}
|
|
8698
9017
|
}
|
|
8699
9018
|
}
|
|
@@ -8872,10 +9191,11 @@ function renderToc(tocBlock, headings, y, enc, mgL, cw, pageIndex, pageAnnotatio
|
|
|
8872
9191
|
const availTextW = dotLeaderEnd - entryX - 8;
|
|
8873
9192
|
let displayText = heading.text;
|
|
8874
9193
|
if (measureText(displayText, sz, enc) > availTextW) {
|
|
8875
|
-
|
|
9194
|
+
const ell = "\u2026";
|
|
9195
|
+
while (displayText.length > 1 && measureText(displayText + ell, sz, enc) > availTextW) {
|
|
8876
9196
|
displayText = displayText.slice(0, -1);
|
|
8877
9197
|
}
|
|
8878
|
-
displayText +=
|
|
9198
|
+
displayText += ell;
|
|
8879
9199
|
}
|
|
8880
9200
|
const textW = measureText(displayText, sz, enc);
|
|
8881
9201
|
const textY = y - sz;
|
|
@@ -9120,9 +9440,9 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9120
9440
|
const mg = layout?.margins ?? { ...DEFAULT_MARGINS };
|
|
9121
9441
|
const cw = pgW - mg.l - mg.r;
|
|
9122
9442
|
const fontEntries = params.fontEntries ? [...params.fontEntries] : [];
|
|
9123
|
-
const enc = createEncodingContext(fontEntries);
|
|
9124
9443
|
const pdfaConfig = resolvePdfAConfig(layout?.tagged);
|
|
9125
9444
|
const tagged = pdfaConfig.enabled;
|
|
9445
|
+
const enc = createEncodingContext(fontEntries, tagged);
|
|
9126
9446
|
const encryptionOpts = layout?.encryption;
|
|
9127
9447
|
if (tagged && encryptionOpts) {
|
|
9128
9448
|
throw new Error("PDF/A and encryption are mutually exclusive (ISO 19005-1 \xA76.3.2)");
|
|
@@ -9453,8 +9773,17 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9453
9773
|
kids.push(`${pageObjStart + p * 2} 0 R`);
|
|
9454
9774
|
}
|
|
9455
9775
|
emitObj(2, `<< /Type /Pages /Kids [${kids.join(" ")}] /Count ${totalPages} >>`);
|
|
9456
|
-
|
|
9457
|
-
|
|
9776
|
+
if (tagged) {
|
|
9777
|
+
const pf = fontEntries[0];
|
|
9778
|
+
const bfName = `/${pf.fontData.fontName.replace(/[^A-Za-z0-9-]/g, "")}`;
|
|
9779
|
+
const primaryBase = 5;
|
|
9780
|
+
const refDict = `<< /Type /Font /Subtype /Type0 /BaseFont ${bfName} /Encoding /Identity-H /DescendantFonts [${primaryBase + 1} 0 R] /ToUnicode ${primaryBase + 4} 0 R >>`;
|
|
9781
|
+
emitObj(3, refDict);
|
|
9782
|
+
emitObj(4, refDict);
|
|
9783
|
+
} else {
|
|
9784
|
+
emitObj(3, "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>");
|
|
9785
|
+
emitObj(4, "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>");
|
|
9786
|
+
}
|
|
9458
9787
|
for (let fi = 0; fi < fontEntries.length; fi++) {
|
|
9459
9788
|
const fe = fontEntries[fi];
|
|
9460
9789
|
const fd = fe.fontData;
|
|
@@ -9548,13 +9877,13 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9548
9877
|
const destName = pa.annot.url.slice(1);
|
|
9549
9878
|
emitObj(
|
|
9550
9879
|
objNum,
|
|
9551
|
-
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /Dest /${destName} >>`
|
|
9880
|
+
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /Dest /${destName} >>`
|
|
9552
9881
|
);
|
|
9553
9882
|
} else {
|
|
9554
9883
|
const escapedUrl = pa.annot.url.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
9555
9884
|
emitObj(
|
|
9556
9885
|
objNum,
|
|
9557
|
-
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>`
|
|
9886
|
+
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>`
|
|
9558
9887
|
);
|
|
9559
9888
|
}
|
|
9560
9889
|
annotIdx++;
|
|
@@ -9671,13 +10000,13 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9671
10000
|
const destName = pa.annot.url.slice(1);
|
|
9672
10001
|
emitObj(
|
|
9673
10002
|
objNum,
|
|
9674
|
-
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /Dest /${destName} >>`
|
|
10003
|
+
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /Dest /${destName} >>`
|
|
9675
10004
|
);
|
|
9676
10005
|
} else {
|
|
9677
10006
|
const escapedUrl = pa.annot.url.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
9678
10007
|
emitObj(
|
|
9679
10008
|
objNum,
|
|
9680
|
-
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>`
|
|
10009
|
+
`<< /Type /Annot /Subtype /Link /Rect [${fmtNum(x1)} ${fmtNum(y1)} ${fmtNum(x2)} ${fmtNum(y2)}] /Border [0 0 0] /F 4 /A << /Type /Action /S /URI /URI (${escapedUrl}) >> >>`
|
|
9681
10010
|
);
|
|
9682
10011
|
}
|
|
9683
10012
|
annotIdx++;
|
|
@@ -9754,7 +10083,7 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9754
10083
|
structTreeRootObjNum = tree.structTreeRootObjNum;
|
|
9755
10084
|
totalObjs = treeStart + tree.totalObjects - 1;
|
|
9756
10085
|
xmpObjNum = totalObjs + 1;
|
|
9757
|
-
const xmpContent = buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance, params.metadata?.author);
|
|
10086
|
+
const xmpContent = utf8EncodeBinaryString(buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance, params.metadata?.author, params.metadata?.subject, params.metadata?.keywords));
|
|
9758
10087
|
emitStreamObj(
|
|
9759
10088
|
xmpObjNum,
|
|
9760
10089
|
`<< /Type /Metadata /Subtype /XML /Length ${xmpContent.length}`,
|
|
@@ -11252,6 +11581,185 @@ function getTrailerRef(trailer, key) {
|
|
|
11252
11581
|
return void 0;
|
|
11253
11582
|
}
|
|
11254
11583
|
|
|
11584
|
+
// src/parser/pdf-decode-filters.ts
|
|
11585
|
+
var MAX_DECODE_OUTPUT = 256 * 1024 * 1024;
|
|
11586
|
+
function checkOutputSize(n, filter) {
|
|
11587
|
+
if (n > MAX_DECODE_OUTPUT) {
|
|
11588
|
+
throw new Error(
|
|
11589
|
+
`${filter} output exceeds ${MAX_DECODE_OUTPUT} bytes (possible zip-bomb)`
|
|
11590
|
+
);
|
|
11591
|
+
}
|
|
11592
|
+
}
|
|
11593
|
+
function decodeASCIIHex(data) {
|
|
11594
|
+
const out = [];
|
|
11595
|
+
let nibble = -1;
|
|
11596
|
+
for (let i = 0; i < data.length; i++) {
|
|
11597
|
+
const c = data[i];
|
|
11598
|
+
if (c === 62) break;
|
|
11599
|
+
if (c === 0 || c === 9 || c === 10 || c === 12 || c === 13 || c === 32) continue;
|
|
11600
|
+
let v;
|
|
11601
|
+
if (c >= 48 && c <= 57) v = c - 48;
|
|
11602
|
+
else if (c >= 65 && c <= 70) v = c - 65 + 10;
|
|
11603
|
+
else if (c >= 97 && c <= 102) v = c - 97 + 10;
|
|
11604
|
+
else throw new Error(`ASCIIHexDecode: invalid character 0x${c.toString(16)}`);
|
|
11605
|
+
if (nibble < 0) {
|
|
11606
|
+
nibble = v;
|
|
11607
|
+
} else {
|
|
11608
|
+
out.push(nibble << 4 | v);
|
|
11609
|
+
checkOutputSize(out.length, "ASCIIHexDecode");
|
|
11610
|
+
nibble = -1;
|
|
11611
|
+
}
|
|
11612
|
+
}
|
|
11613
|
+
if (nibble >= 0) out.push(nibble << 4);
|
|
11614
|
+
return Uint8Array.from(out);
|
|
11615
|
+
}
|
|
11616
|
+
function decodeASCII85(data) {
|
|
11617
|
+
const out = [];
|
|
11618
|
+
let group = 0;
|
|
11619
|
+
let count = 0;
|
|
11620
|
+
for (let i = 0; i < data.length; i++) {
|
|
11621
|
+
const c = data[i];
|
|
11622
|
+
if (c === 126) {
|
|
11623
|
+
if (i + 1 < data.length && data[i + 1] === 62) break;
|
|
11624
|
+
throw new Error("ASCII85Decode: lone ~ without >");
|
|
11625
|
+
}
|
|
11626
|
+
if (c === 62) break;
|
|
11627
|
+
if (c === 0 || c === 9 || c === 10 || c === 12 || c === 13 || c === 32) continue;
|
|
11628
|
+
if (c === 122) {
|
|
11629
|
+
if (count !== 0) throw new Error("ASCII85Decode: z inside group");
|
|
11630
|
+
out.push(0, 0, 0, 0);
|
|
11631
|
+
checkOutputSize(out.length, "ASCII85Decode");
|
|
11632
|
+
continue;
|
|
11633
|
+
}
|
|
11634
|
+
if (c < 33 || c > 117) throw new Error(`ASCII85Decode: invalid char 0x${c.toString(16)}`);
|
|
11635
|
+
group = group * 85 + (c - 33);
|
|
11636
|
+
count++;
|
|
11637
|
+
if (count === 5) {
|
|
11638
|
+
if (group > 4294967295) throw new Error("ASCII85Decode: group overflow");
|
|
11639
|
+
out.push(group >>> 24 & 255, group >>> 16 & 255, group >>> 8 & 255, group & 255);
|
|
11640
|
+
checkOutputSize(out.length, "ASCII85Decode");
|
|
11641
|
+
group = 0;
|
|
11642
|
+
count = 0;
|
|
11643
|
+
}
|
|
11644
|
+
}
|
|
11645
|
+
if (count > 0) {
|
|
11646
|
+
for (let k = count; k < 5; k++) group = group * 85 + 84;
|
|
11647
|
+
if (group > 4294967295) throw new Error("ASCII85Decode: trailing group overflow");
|
|
11648
|
+
const tail = [group >>> 24 & 255, group >>> 16 & 255, group >>> 8 & 255, group & 255];
|
|
11649
|
+
for (let k = 0; k < count - 1; k++) out.push(tail[k]);
|
|
11650
|
+
checkOutputSize(out.length, "ASCII85Decode");
|
|
11651
|
+
}
|
|
11652
|
+
return Uint8Array.from(out);
|
|
11653
|
+
}
|
|
11654
|
+
var LZW_CLEAR_CODE = 256;
|
|
11655
|
+
var LZW_EOD_CODE = 257;
|
|
11656
|
+
function decodeLZW(data) {
|
|
11657
|
+
const out = [];
|
|
11658
|
+
let bitBuf = 0;
|
|
11659
|
+
let bitCount = 0;
|
|
11660
|
+
let p = 0;
|
|
11661
|
+
let codeSize = 9;
|
|
11662
|
+
let dict = [];
|
|
11663
|
+
let prev = null;
|
|
11664
|
+
const resetDict = () => {
|
|
11665
|
+
dict = new Array(258);
|
|
11666
|
+
for (let i = 0; i < 256; i++) dict[i] = Uint8Array.of(i);
|
|
11667
|
+
codeSize = 9;
|
|
11668
|
+
prev = null;
|
|
11669
|
+
};
|
|
11670
|
+
resetDict();
|
|
11671
|
+
const readCode = () => {
|
|
11672
|
+
while (bitCount < codeSize) {
|
|
11673
|
+
if (p >= data.length) return -1;
|
|
11674
|
+
bitBuf = bitBuf << 8 | data[p++];
|
|
11675
|
+
bitCount += 8;
|
|
11676
|
+
}
|
|
11677
|
+
const shift = bitCount - codeSize;
|
|
11678
|
+
const code = bitBuf >>> shift & (1 << codeSize) - 1;
|
|
11679
|
+
bitBuf &= (1 << shift) - 1;
|
|
11680
|
+
bitCount = shift;
|
|
11681
|
+
return code;
|
|
11682
|
+
};
|
|
11683
|
+
for (; ; ) {
|
|
11684
|
+
const code = readCode();
|
|
11685
|
+
if (code < 0 || code === LZW_EOD_CODE) break;
|
|
11686
|
+
if (code === LZW_CLEAR_CODE) {
|
|
11687
|
+
resetDict();
|
|
11688
|
+
continue;
|
|
11689
|
+
}
|
|
11690
|
+
let entry;
|
|
11691
|
+
if (code < dict.length) {
|
|
11692
|
+
entry = dict[code];
|
|
11693
|
+
} else if (code === dict.length && prev) {
|
|
11694
|
+
entry = new Uint8Array(prev.length + 1);
|
|
11695
|
+
entry.set(prev);
|
|
11696
|
+
entry[prev.length] = prev[0];
|
|
11697
|
+
} else {
|
|
11698
|
+
throw new Error(`LZWDecode: invalid code ${code}`);
|
|
11699
|
+
}
|
|
11700
|
+
for (let i = 0; i < entry.length; i++) out.push(entry[i]);
|
|
11701
|
+
checkOutputSize(out.length, "LZWDecode");
|
|
11702
|
+
if (prev) {
|
|
11703
|
+
const next = new Uint8Array(prev.length + 1);
|
|
11704
|
+
next.set(prev);
|
|
11705
|
+
next[prev.length] = entry[0];
|
|
11706
|
+
dict.push(next);
|
|
11707
|
+
if (dict.length === (1 << codeSize) - 1 && codeSize < 12) codeSize++;
|
|
11708
|
+
}
|
|
11709
|
+
prev = entry;
|
|
11710
|
+
}
|
|
11711
|
+
return Uint8Array.from(out);
|
|
11712
|
+
}
|
|
11713
|
+
function decodeRunLength(data) {
|
|
11714
|
+
const out = [];
|
|
11715
|
+
let p = 0;
|
|
11716
|
+
while (p < data.length) {
|
|
11717
|
+
const n = data[p++];
|
|
11718
|
+
if (n === 128) break;
|
|
11719
|
+
if (n < 128) {
|
|
11720
|
+
const len = n + 1;
|
|
11721
|
+
if (p + len > data.length) throw new Error("RunLengthDecode: truncated literal");
|
|
11722
|
+
for (let i = 0; i < len; i++) out.push(data[p + i]);
|
|
11723
|
+
p += len;
|
|
11724
|
+
} else {
|
|
11725
|
+
if (p >= data.length) throw new Error("RunLengthDecode: truncated repeat");
|
|
11726
|
+
const v = data[p++];
|
|
11727
|
+
const len = 257 - n;
|
|
11728
|
+
for (let i = 0; i < len; i++) out.push(v);
|
|
11729
|
+
}
|
|
11730
|
+
checkOutputSize(out.length, "RunLengthDecode");
|
|
11731
|
+
}
|
|
11732
|
+
return Uint8Array.from(out);
|
|
11733
|
+
}
|
|
11734
|
+
function applyDecodeFilter(name, data) {
|
|
11735
|
+
switch (name) {
|
|
11736
|
+
case "ASCIIHexDecode":
|
|
11737
|
+
case "AHx":
|
|
11738
|
+
return decodeASCIIHex(data);
|
|
11739
|
+
case "ASCII85Decode":
|
|
11740
|
+
case "A85":
|
|
11741
|
+
return decodeASCII85(data);
|
|
11742
|
+
case "LZWDecode":
|
|
11743
|
+
case "LZW":
|
|
11744
|
+
return decodeLZW(data);
|
|
11745
|
+
case "RunLengthDecode":
|
|
11746
|
+
case "RL":
|
|
11747
|
+
return decodeRunLength(data);
|
|
11748
|
+
default:
|
|
11749
|
+
return data;
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
var KNOWN_DECODE_FILTERS = /* @__PURE__ */ new Set([
|
|
11753
|
+
"ASCIIHexDecode",
|
|
11754
|
+
"AHx",
|
|
11755
|
+
"ASCII85Decode",
|
|
11756
|
+
"A85",
|
|
11757
|
+
"LZWDecode",
|
|
11758
|
+
"LZW",
|
|
11759
|
+
"RunLengthDecode",
|
|
11760
|
+
"RL"
|
|
11761
|
+
]);
|
|
11762
|
+
|
|
11255
11763
|
// src/parser/pdf-reader.ts
|
|
11256
11764
|
function openPdf(bytes) {
|
|
11257
11765
|
const xref = parseXrefTable(bytes);
|
|
@@ -11311,10 +11819,15 @@ function openPdf(bytes) {
|
|
|
11311
11819
|
data = decodePNGPredictor(data, decodeParms);
|
|
11312
11820
|
}
|
|
11313
11821
|
}
|
|
11822
|
+
} else if (filterName !== void 0 && KNOWN_DECODE_FILTERS.has(filterName)) {
|
|
11823
|
+
data = applyDecodeFilter(filterName, data);
|
|
11314
11824
|
} else if (filter !== void 0 && isArray(filter)) {
|
|
11315
11825
|
for (const f of filter) {
|
|
11316
|
-
if (isName(f)
|
|
11826
|
+
if (!isName(f)) continue;
|
|
11827
|
+
if (f.value === "FlateDecode") {
|
|
11317
11828
|
data = inflateSync(data);
|
|
11829
|
+
} else if (KNOWN_DECODE_FILTERS.has(f.value)) {
|
|
11830
|
+
data = applyDecodeFilter(f.value, data);
|
|
11318
11831
|
}
|
|
11319
11832
|
}
|
|
11320
11833
|
}
|
|
@@ -11693,6 +12206,7 @@ exports.DEFAULT_MAX_INFLATE_OUTPUT = DEFAULT_MAX_INFLATE_OUTPUT;
|
|
|
11693
12206
|
exports.FT_H = FT_H;
|
|
11694
12207
|
exports.HEADER_H = HEADER_H;
|
|
11695
12208
|
exports.INFO_LN = INFO_LN;
|
|
12209
|
+
exports.KNOWN_DECODE_FILTERS = KNOWN_DECODE_FILTERS;
|
|
11696
12210
|
exports.MAX_PARSE_DEPTH = MAX_PARSE_DEPTH;
|
|
11697
12211
|
exports.MAX_XREF_CHAIN = MAX_XREF_CHAIN;
|
|
11698
12212
|
exports.PAGE_SIZES = PAGE_SIZES;
|
|
@@ -11703,6 +12217,7 @@ exports.TH_H = TH_H;
|
|
|
11703
12217
|
exports.TITLE_LN = TITLE_LN;
|
|
11704
12218
|
exports.WORKER_THRESHOLD = WORKER_THRESHOLD;
|
|
11705
12219
|
exports.WORKER_TIMEOUT_MS = WORKER_TIMEOUT_MS;
|
|
12220
|
+
exports.applyDecodeFilter = applyDecodeFilter;
|
|
11706
12221
|
exports.buildAcroFormDict = buildAcroFormDict;
|
|
11707
12222
|
exports.buildAppearanceStreamDict = buildAppearanceStreamDict;
|
|
11708
12223
|
exports.buildCmsSignedData = buildCmsSignedData;
|
|
@@ -11737,7 +12252,11 @@ exports.createEncodingContext = createEncodingContext;
|
|
|
11737
12252
|
exports.createModifier = createModifier;
|
|
11738
12253
|
exports.createPDF = createPDF;
|
|
11739
12254
|
exports.createTokenizer = createTokenizer;
|
|
12255
|
+
exports.decodeASCII85 = decodeASCII85;
|
|
12256
|
+
exports.decodeASCIIHex = decodeASCIIHex;
|
|
11740
12257
|
exports.decodeEcPublicKey = decodeEcPublicKey;
|
|
12258
|
+
exports.decodeLZW = decodeLZW;
|
|
12259
|
+
exports.decodeRunLength = decodeRunLength;
|
|
11741
12260
|
exports.defaultFieldHeight = defaultFieldHeight;
|
|
11742
12261
|
exports.derBitString = derBitString;
|
|
11743
12262
|
exports.derDecode = derDecode;
|
|
@@ -11847,6 +12366,7 @@ exports.streamByteLength = streamByteLength;
|
|
|
11847
12366
|
exports.toBytes = toBytes;
|
|
11848
12367
|
exports.toWinAnsi = toWinAnsi;
|
|
11849
12368
|
exports.truncate = truncate;
|
|
12369
|
+
exports.truncateToWidth = truncateToWidth;
|
|
11850
12370
|
exports.validateAttachments = validateAttachments;
|
|
11851
12371
|
exports.validateDocumentStreamable = validateDocumentStreamable;
|
|
11852
12372
|
exports.validateTableStreamable = validateTableStreamable;
|