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