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.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
|
}
|
|
@@ -5499,6 +5752,8 @@ var DEFAULT_TEXT_COLOR = "0.75 0.75 0.75";
|
|
|
5499
5752
|
var DEFAULT_TEXT_OPACITY = 0.15;
|
|
5500
5753
|
var DEFAULT_TEXT_ANGLE = -45;
|
|
5501
5754
|
var DEFAULT_IMAGE_OPACITY = 0.1;
|
|
5755
|
+
var DEFAULT_CAP_HEIGHT_RATIO = 0.718;
|
|
5756
|
+
var WATERMARK_SAFETY_MARGIN = 24;
|
|
5502
5757
|
function validateWatermark(watermark, pdfaLevel) {
|
|
5503
5758
|
if (pdfaLevel === "pdfa1b") {
|
|
5504
5759
|
const textOpacity = watermark.text?.opacity ?? DEFAULT_TEXT_OPACITY;
|
|
@@ -5544,19 +5799,35 @@ function buildWatermarkState(watermark, pgW, pgH, enc) {
|
|
|
5544
5799
|
};
|
|
5545
5800
|
}
|
|
5546
5801
|
function _buildTextWatermarkOps(wm, pgW, pgH, enc, gsName) {
|
|
5547
|
-
|
|
5802
|
+
let sz = wm.fontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
5548
5803
|
const color = parseColor(wm.color ?? DEFAULT_TEXT_COLOR);
|
|
5549
5804
|
const angle = (wm.angle ?? DEFAULT_TEXT_ANGLE) * DEG_TO_RAD;
|
|
5550
5805
|
const cos = Math.cos(angle);
|
|
5551
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
|
+
}
|
|
5552
5823
|
const cx = pgW / 2;
|
|
5553
5824
|
const cy = pgH / 2;
|
|
5554
5825
|
const textWidth = enc.tw(wm.text, sz);
|
|
5555
5826
|
const offsetX = -textWidth / 2;
|
|
5556
|
-
const offsetY = -sz / 2;
|
|
5827
|
+
const offsetY = -sz * capRatio / 2;
|
|
5557
5828
|
const tx = cx + offsetX * cos - offsetY * sin;
|
|
5558
5829
|
const ty = cy + offsetX * sin + offsetY * cos;
|
|
5559
|
-
const escapedText =
|
|
5830
|
+
const escapedText = enc.ps(wm.text);
|
|
5560
5831
|
const ops = [
|
|
5561
5832
|
"q",
|
|
5562
5833
|
`${gsName} gs`,
|
|
@@ -5741,7 +6012,9 @@ function buildPDF(params, layoutOptions) {
|
|
|
5741
6012
|
const fs = layoutOptions?.fontSizes ? { ...DEFAULT_FONT_SIZES, ...layoutOptions.fontSizes } : DEFAULT_FONT_SIZES;
|
|
5742
6013
|
const { cx, cwi } = computeColumnPositions(columns, mg.l, cw);
|
|
5743
6014
|
const fontEntries = params.fontEntries || (fontData ? [{ fontData, fontRef: "/F3", lang: "unknown" }] : []);
|
|
5744
|
-
const
|
|
6015
|
+
const pdfaConfig = resolvePdfAConfig(layoutOptions?.tagged);
|
|
6016
|
+
const tagged = pdfaConfig.enabled;
|
|
6017
|
+
const enc = createEncodingContext(fontEntries, tagged);
|
|
5745
6018
|
const footerTpl = layoutOptions?.footerTemplate ?? {
|
|
5746
6019
|
left: footerText || void 0,
|
|
5747
6020
|
right: "{page}/{pages}"
|
|
@@ -5763,8 +6036,6 @@ function buildPDF(params, layoutOptions) {
|
|
|
5763
6036
|
totalPages = 1 + Math.ceil((totalRows - rowsPage1) / rowsPerPage);
|
|
5764
6037
|
}
|
|
5765
6038
|
if (totalPages < 1) totalPages = 1;
|
|
5766
|
-
const pdfaConfig = resolvePdfAConfig(layoutOptions?.tagged);
|
|
5767
|
-
const tagged = pdfaConfig.enabled;
|
|
5768
6039
|
const encryptionOpts = layoutOptions?.encryption;
|
|
5769
6040
|
if (tagged && encryptionOpts) {
|
|
5770
6041
|
throw new Error("PDF/A and encryption are mutually exclusive (ISO 19005-1 \xA76.3.2)");
|
|
@@ -5933,8 +6204,17 @@ function buildPDF(params, layoutOptions) {
|
|
|
5933
6204
|
kids.push(`${pageObjStart + p * 2} 0 R`);
|
|
5934
6205
|
}
|
|
5935
6206
|
emitObj(2, `<< /Type /Pages /Kids [${kids.join(" ")}] /Count ${totalPages} >>`);
|
|
5936
|
-
|
|
5937
|
-
|
|
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
|
+
}
|
|
5938
6218
|
for (let fi = 0; fi < fontEntries.length; fi++) {
|
|
5939
6219
|
const fe = fontEntries[fi];
|
|
5940
6220
|
const fd = fe.fontData;
|
|
@@ -6059,7 +6339,7 @@ function buildPDF(params, layoutOptions) {
|
|
|
6059
6339
|
structTreeRootObjNum = tree.structTreeRootObjNum;
|
|
6060
6340
|
totalObjs = treeStart + tree.totalObjects - 1;
|
|
6061
6341
|
xmpObjNum = totalObjs + 1;
|
|
6062
|
-
const xmpContent = buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance);
|
|
6342
|
+
const xmpContent = utf8EncodeBinaryString(buildXMPMetadata(infoTitle, isoDate, pdfaConfig.pdfaPart, pdfaConfig.pdfaConformance));
|
|
6063
6343
|
emitStreamObj(
|
|
6064
6344
|
xmpObjNum,
|
|
6065
6345
|
`<< /Type /Metadata /Subtype /XML /Length ${xmpContent.length}`,
|
|
@@ -6374,7 +6654,8 @@ function buildFormWidget(field, apObjNum, radioCtx) {
|
|
|
6374
6654
|
if (field.required) ff |= FF_REQUIRED;
|
|
6375
6655
|
const parts = [
|
|
6376
6656
|
"<< /Type /Annot /Subtype /Widget",
|
|
6377
|
-
`/Rect [${fmtNum2(x1)} ${fmtNum2(y1)} ${fmtNum2(x2)} ${fmtNum2(y2)}]
|
|
6657
|
+
`/Rect [${fmtNum2(x1)} ${fmtNum2(y1)} ${fmtNum2(x2)} ${fmtNum2(y2)}]`,
|
|
6658
|
+
"/F 4"
|
|
6378
6659
|
];
|
|
6379
6660
|
if (radioCtx) {
|
|
6380
6661
|
parts.push(`/Parent ${radioCtx.parentObjNum} 0 R`);
|
|
@@ -6473,13 +6754,13 @@ function buildLinkAnnotation(annot, objNum) {
|
|
|
6473
6754
|
const [x1, y1, x2, y2] = annot.rect;
|
|
6474
6755
|
const escapedUrl = escapeUrlForPdf(annot.url);
|
|
6475
6756
|
return `${objNum} 0 obj
|
|
6476
|
-
<< /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}) >> >>
|
|
6477
6758
|
endobj`;
|
|
6478
6759
|
}
|
|
6479
6760
|
function buildInternalLinkAnnotation(annot, pageObjNum, objNum) {
|
|
6480
6761
|
const [x1, y1, x2, y2] = annot.rect;
|
|
6481
6762
|
return `${objNum} 0 obj
|
|
6482
|
-
<< /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] >> >>
|
|
6483
6764
|
endobj`;
|
|
6484
6765
|
}
|
|
6485
6766
|
function isLinkAnnotation(annot) {
|
|
@@ -8411,6 +8692,39 @@ function renderSvg(data, x, y, w, h, options) {
|
|
|
8411
8692
|
return allOps.join("\n");
|
|
8412
8693
|
}
|
|
8413
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
|
+
|
|
8414
8728
|
// src/core/pdf-renderers.ts
|
|
8415
8729
|
var HEADING_SIZES = { 1: 18, 2: 14, 3: 11 };
|
|
8416
8730
|
var HEADING_SPACING = {
|
|
@@ -8630,10 +8944,15 @@ function renderList(block, y, enc, mgL, cw, tagCtx, documentChildren) {
|
|
|
8630
8944
|
}
|
|
8631
8945
|
function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren) {
|
|
8632
8946
|
const ops = [];
|
|
8633
|
-
const
|
|
8947
|
+
const baseColumns = block.columns ? [...block.columns] : DEFAULT_COLUMNS;
|
|
8634
8948
|
const fs = DEFAULT_FONT_SIZES;
|
|
8635
8949
|
const colors = DEFAULT_COLORS;
|
|
8950
|
+
const columns = block.autoFitColumns ? computeAutoFitColumns(baseColumns, block.headers, block.rows, enc, fs.th, fs.td) : baseColumns;
|
|
8636
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;
|
|
8637
8956
|
const tableRows = [];
|
|
8638
8957
|
ops.push(`${colors.thBg} rg`);
|
|
8639
8958
|
ops.push(`${fmtNum(mgL)} ${fmtNum(y - TH_H)} ${fmtNum(cw)} ${fmtNum(TH_H)} re f`);
|
|
@@ -8647,19 +8966,19 @@ function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren)
|
|
|
8647
8966
|
const mcid = tagCtx.mcidAlloc.next(tagCtx.pageObjNum);
|
|
8648
8967
|
thChildren.push({ type: "TH", children: [{ mcid, pageObjNum: tagCtx.pageObjNum }] });
|
|
8649
8968
|
if (columns[i].a === "r") {
|
|
8650
|
-
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));
|
|
8651
8970
|
} else if (columns[i].a === "c") {
|
|
8652
|
-
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));
|
|
8653
8972
|
} else {
|
|
8654
|
-
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));
|
|
8655
8974
|
}
|
|
8656
8975
|
} else {
|
|
8657
8976
|
if (columns[i].a === "r") {
|
|
8658
|
-
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));
|
|
8659
8978
|
} else if (columns[i].a === "c") {
|
|
8660
|
-
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));
|
|
8661
8980
|
} else {
|
|
8662
|
-
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));
|
|
8663
8982
|
}
|
|
8664
8983
|
}
|
|
8665
8984
|
}
|
|
@@ -8679,19 +8998,19 @@ function renderTable(block, y, enc, mgL, mgR, pgW, cw, tagCtx, documentChildren)
|
|
|
8679
8998
|
const mcid = tagCtx.mcidAlloc.next(tagCtx.pageObjNum);
|
|
8680
8999
|
tdChildren.push({ type: "TD", children: [{ mcid, pageObjNum: tagCtx.pageObjNum }] });
|
|
8681
9000
|
if (columns[i].a === "r") {
|
|
8682
|
-
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));
|
|
8683
9002
|
} else if (columns[i].a === "c") {
|
|
8684
|
-
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));
|
|
8685
9004
|
} else {
|
|
8686
|
-
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));
|
|
8687
9006
|
}
|
|
8688
9007
|
} else {
|
|
8689
9008
|
if (columns[i].a === "r") {
|
|
8690
|
-
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));
|
|
8691
9010
|
} else if (columns[i].a === "c") {
|
|
8692
|
-
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));
|
|
8693
9012
|
} else {
|
|
8694
|
-
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));
|
|
8695
9014
|
}
|
|
8696
9015
|
}
|
|
8697
9016
|
}
|
|
@@ -8870,10 +9189,11 @@ function renderToc(tocBlock, headings, y, enc, mgL, cw, pageIndex, pageAnnotatio
|
|
|
8870
9189
|
const availTextW = dotLeaderEnd - entryX - 8;
|
|
8871
9190
|
let displayText = heading.text;
|
|
8872
9191
|
if (measureText(displayText, sz, enc) > availTextW) {
|
|
8873
|
-
|
|
9192
|
+
const ell = "\u2026";
|
|
9193
|
+
while (displayText.length > 1 && measureText(displayText + ell, sz, enc) > availTextW) {
|
|
8874
9194
|
displayText = displayText.slice(0, -1);
|
|
8875
9195
|
}
|
|
8876
|
-
displayText +=
|
|
9196
|
+
displayText += ell;
|
|
8877
9197
|
}
|
|
8878
9198
|
const textW = measureText(displayText, sz, enc);
|
|
8879
9199
|
const textY = y - sz;
|
|
@@ -9118,9 +9438,9 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9118
9438
|
const mg = layout?.margins ?? { ...DEFAULT_MARGINS };
|
|
9119
9439
|
const cw = pgW - mg.l - mg.r;
|
|
9120
9440
|
const fontEntries = params.fontEntries ? [...params.fontEntries] : [];
|
|
9121
|
-
const enc = createEncodingContext(fontEntries);
|
|
9122
9441
|
const pdfaConfig = resolvePdfAConfig(layout?.tagged);
|
|
9123
9442
|
const tagged = pdfaConfig.enabled;
|
|
9443
|
+
const enc = createEncodingContext(fontEntries, tagged);
|
|
9124
9444
|
const encryptionOpts = layout?.encryption;
|
|
9125
9445
|
if (tagged && encryptionOpts) {
|
|
9126
9446
|
throw new Error("PDF/A and encryption are mutually exclusive (ISO 19005-1 \xA76.3.2)");
|
|
@@ -9451,8 +9771,17 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9451
9771
|
kids.push(`${pageObjStart + p * 2} 0 R`);
|
|
9452
9772
|
}
|
|
9453
9773
|
emitObj(2, `<< /Type /Pages /Kids [${kids.join(" ")}] /Count ${totalPages} >>`);
|
|
9454
|
-
|
|
9455
|
-
|
|
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
|
+
}
|
|
9456
9785
|
for (let fi = 0; fi < fontEntries.length; fi++) {
|
|
9457
9786
|
const fe = fontEntries[fi];
|
|
9458
9787
|
const fd = fe.fontData;
|
|
@@ -9546,13 +9875,13 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9546
9875
|
const destName = pa.annot.url.slice(1);
|
|
9547
9876
|
emitObj(
|
|
9548
9877
|
objNum,
|
|
9549
|
-
`<< /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} >>`
|
|
9550
9879
|
);
|
|
9551
9880
|
} else {
|
|
9552
9881
|
const escapedUrl = pa.annot.url.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
9553
9882
|
emitObj(
|
|
9554
9883
|
objNum,
|
|
9555
|
-
`<< /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}) >> >>`
|
|
9556
9885
|
);
|
|
9557
9886
|
}
|
|
9558
9887
|
annotIdx++;
|
|
@@ -9669,13 +9998,13 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9669
9998
|
const destName = pa.annot.url.slice(1);
|
|
9670
9999
|
emitObj(
|
|
9671
10000
|
objNum,
|
|
9672
|
-
`<< /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} >>`
|
|
9673
10002
|
);
|
|
9674
10003
|
} else {
|
|
9675
10004
|
const escapedUrl = pa.annot.url.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
9676
10005
|
emitObj(
|
|
9677
10006
|
objNum,
|
|
9678
|
-
`<< /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}) >> >>`
|
|
9679
10008
|
);
|
|
9680
10009
|
}
|
|
9681
10010
|
annotIdx++;
|
|
@@ -9752,7 +10081,7 @@ function buildDocumentPDF(params, layoutOptions) {
|
|
|
9752
10081
|
structTreeRootObjNum = tree.structTreeRootObjNum;
|
|
9753
10082
|
totalObjs = treeStart + tree.totalObjects - 1;
|
|
9754
10083
|
xmpObjNum = totalObjs + 1;
|
|
9755
|
-
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));
|
|
9756
10085
|
emitStreamObj(
|
|
9757
10086
|
xmpObjNum,
|
|
9758
10087
|
`<< /Type /Metadata /Subtype /XML /Length ${xmpContent.length}`,
|
|
@@ -11250,6 +11579,185 @@ function getTrailerRef(trailer, key) {
|
|
|
11250
11579
|
return void 0;
|
|
11251
11580
|
}
|
|
11252
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
|
+
|
|
11253
11761
|
// src/parser/pdf-reader.ts
|
|
11254
11762
|
function openPdf(bytes) {
|
|
11255
11763
|
const xref = parseXrefTable(bytes);
|
|
@@ -11309,10 +11817,15 @@ function openPdf(bytes) {
|
|
|
11309
11817
|
data = decodePNGPredictor(data, decodeParms);
|
|
11310
11818
|
}
|
|
11311
11819
|
}
|
|
11820
|
+
} else if (filterName !== void 0 && KNOWN_DECODE_FILTERS.has(filterName)) {
|
|
11821
|
+
data = applyDecodeFilter(filterName, data);
|
|
11312
11822
|
} else if (filter !== void 0 && isArray(filter)) {
|
|
11313
11823
|
for (const f of filter) {
|
|
11314
|
-
if (isName(f)
|
|
11824
|
+
if (!isName(f)) continue;
|
|
11825
|
+
if (f.value === "FlateDecode") {
|
|
11315
11826
|
data = inflateSync(data);
|
|
11827
|
+
} else if (KNOWN_DECODE_FILTERS.has(f.value)) {
|
|
11828
|
+
data = applyDecodeFilter(f.value, data);
|
|
11316
11829
|
}
|
|
11317
11830
|
}
|
|
11318
11831
|
}
|
|
@@ -11681,6 +12194,6 @@ async function createPDF(pdfParams, options) {
|
|
|
11681
12194
|
return generatePDFMainThread(pdfParams, options?.layoutOptions);
|
|
11682
12195
|
}
|
|
11683
12196
|
|
|
11684
|
-
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 };
|
|
11685
12198
|
//# sourceMappingURL=index.js.map
|
|
11686
12199
|
//# sourceMappingURL=index.js.map
|