web-doc 0.9.0 → 0.10.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/THIRD_PARTY_NOTICES.md +14 -0
- package/dist/adapters/office.js +2 -1
- package/dist/contracts.d.ts +9 -0
- package/dist/edit/pdf/engine/cff.d.ts +28 -0
- package/dist/edit/pdf/engine/cff.js +416 -0
- package/dist/edit/pdf/engine/document.d.ts +3 -1
- package/dist/edit/pdf/engine/document.js +21 -1
- package/dist/edit/pdf/engine/elements.d.ts +7 -0
- package/dist/edit/pdf/engine/elements.js +12 -1
- package/dist/edit/pdf/engine/existing-text.js +6 -4
- package/dist/edit/pdf/engine/glyph-names.d.ts +2 -0
- package/dist/edit/pdf/engine/glyph-names.js +163 -0
- package/dist/edit/pdf/engine/handler.js +2 -0
- package/dist/edit/pdf/engine/opentype.d.ts +14 -0
- package/dist/edit/pdf/engine/opentype.js +317 -0
- package/dist/edit/pdf/engine/text-font.d.ts +4 -0
- package/dist/edit/pdf/engine/text-font.js +81 -0
- package/dist/edit/pdf/provider.d.ts +3 -1
- package/dist/edit/pdf/provider.js +3 -0
- package/dist/edit/pdf/session.d.ts +2 -1
- package/dist/edit/pdf/session.js +3 -0
- package/dist/edit/pdf/types.d.ts +40 -0
- package/dist/edit/pptx/session.d.ts +7 -2
- package/dist/edit/pptx/session.js +41 -3
- package/dist/viewport.js +83 -20
- package/dist/worker-protocol.d.ts +1 -1
- package/dist/workers/pdf-edit-worker.js +1118 -184
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Glyph names and the code points they stand for: the Adobe Glyph List For
|
|
3
|
+
* New Fonts 1.7 (aglfn.txt), and from the Adobe Glyph List 2.0
|
|
4
|
+
* (glyphlist.txt) the ligatures, superior figures and no-break space that
|
|
5
|
+
* font subsets commonly name, from https://github.com/adobe-type-tools/agl-aglfn.
|
|
6
|
+
* Each is listed as a name and its code point in hexadecimal.
|
|
7
|
+
*
|
|
8
|
+
* Copyright 2002-2019 Adobe (http://www.adobe.com/).
|
|
9
|
+
*
|
|
10
|
+
* Redistribution and use in source and binary forms, with or
|
|
11
|
+
* without modification, are permitted provided that the
|
|
12
|
+
* following conditions are met:
|
|
13
|
+
*
|
|
14
|
+
* Redistributions of source code must retain the above
|
|
15
|
+
* copyright notice, this list of conditions and the following
|
|
16
|
+
* disclaimer.
|
|
17
|
+
*
|
|
18
|
+
* Redistributions in binary form must reproduce the above
|
|
19
|
+
* copyright notice, this list of conditions and the following
|
|
20
|
+
* disclaimer in the documentation and/or other materials
|
|
21
|
+
* provided with the distribution.
|
|
22
|
+
*
|
|
23
|
+
* Neither the name of Adobe nor the names of its contributors
|
|
24
|
+
* may be used to endorse or promote products derived from this
|
|
25
|
+
* software without specific prior written permission.
|
|
26
|
+
*
|
|
27
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
28
|
+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
29
|
+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
30
|
+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
31
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
32
|
+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
33
|
+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
34
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
35
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
36
|
+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
37
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
38
|
+
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
39
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
40
|
+
*/
|
|
41
|
+
const AGLFN = `
|
|
42
|
+
A 0041 AE 00C6 AEacute 01FC Aacute 00C1 Abreve 0102 Acircumflex 00C2
|
|
43
|
+
Adieresis 00C4 Agrave 00C0 Alpha 0391 Alphatonos 0386 Amacron 0100
|
|
44
|
+
Aogonek 0104 Aring 00C5 Aringacute 01FA Atilde 00C3 B 0042 Beta 0392 C 0043
|
|
45
|
+
Cacute 0106 Ccaron 010C Ccedilla 00C7 Ccircumflex 0108 Cdotaccent 010A
|
|
46
|
+
Chi 03A7 D 0044 Dcaron 010E Dcroat 0110 Delta 2206 E 0045 Eacute 00C9
|
|
47
|
+
Ebreve 0114 Ecaron 011A Ecircumflex 00CA Edieresis 00CB Edotaccent 0116
|
|
48
|
+
Egrave 00C8 Emacron 0112 Eng 014A Eogonek 0118 Epsilon 0395
|
|
49
|
+
Epsilontonos 0388 Eta 0397 Etatonos 0389 Eth 00D0 Euro 20AC F 0046 G 0047
|
|
50
|
+
Gamma 0393 Gbreve 011E Gcaron 01E6 Gcircumflex 011C Gdotaccent 0120 H 0048
|
|
51
|
+
H18533 25CF H18543 25AA H18551 25AB H22073 25A1 Hbar 0126 Hcircumflex 0124
|
|
52
|
+
I 0049 IJ 0132 Iacute 00CD Ibreve 012C Icircumflex 00CE Idieresis 00CF
|
|
53
|
+
Idotaccent 0130 Ifraktur 2111 Igrave 00CC Imacron 012A Iogonek 012E
|
|
54
|
+
Iota 0399 Iotadieresis 03AA Iotatonos 038A Itilde 0128 J 004A
|
|
55
|
+
Jcircumflex 0134 K 004B Kappa 039A L 004C Lacute 0139 Lambda 039B
|
|
56
|
+
Lcaron 013D Ldot 013F Lslash 0141 M 004D Mu 039C N 004E Nacute 0143
|
|
57
|
+
Ncaron 0147 Ntilde 00D1 Nu 039D O 004F OE 0152 Oacute 00D3 Obreve 014E
|
|
58
|
+
Ocircumflex 00D4 Odieresis 00D6 Ograve 00D2 Ohorn 01A0 Ohungarumlaut 0150
|
|
59
|
+
Omacron 014C Omega 2126 Omegatonos 038F Omicron 039F Omicrontonos 038C
|
|
60
|
+
Oslash 00D8 Oslashacute 01FE Otilde 00D5 P 0050 Phi 03A6 Pi 03A0 Psi 03A8
|
|
61
|
+
Q 0051 R 0052 Racute 0154 Rcaron 0158 Rfraktur 211C Rho 03A1 S 0053
|
|
62
|
+
SF010000 250C SF020000 2514 SF030000 2510 SF040000 2518 SF050000 253C
|
|
63
|
+
SF060000 252C SF070000 2534 SF080000 251C SF090000 2524 SF100000 2500
|
|
64
|
+
SF110000 2502 SF190000 2561 SF200000 2562 SF210000 2556 SF220000 2555
|
|
65
|
+
SF230000 2563 SF240000 2551 SF250000 2557 SF260000 255D SF270000 255C
|
|
66
|
+
SF280000 255B SF360000 255E SF370000 255F SF380000 255A SF390000 2554
|
|
67
|
+
SF400000 2569 SF410000 2566 SF420000 2560 SF430000 2550 SF440000 256C
|
|
68
|
+
SF450000 2567 SF460000 2568 SF470000 2564 SF480000 2565 SF490000 2559
|
|
69
|
+
SF500000 2558 SF510000 2552 SF520000 2553 SF530000 256B SF540000 256A
|
|
70
|
+
Sacute 015A Scaron 0160 Scedilla 015E Scircumflex 015C Sigma 03A3 T 0054
|
|
71
|
+
Tau 03A4 Tbar 0166 Tcaron 0164 Theta 0398 Thorn 00DE U 0055 Uacute 00DA
|
|
72
|
+
Ubreve 016C Ucircumflex 00DB Udieresis 00DC Ugrave 00D9 Uhorn 01AF
|
|
73
|
+
Uhungarumlaut 0170 Umacron 016A Uogonek 0172 Upsilon 03A5 Upsilon1 03D2
|
|
74
|
+
Upsilondieresis 03AB Upsilontonos 038E Uring 016E Utilde 0168 V 0056 W 0057
|
|
75
|
+
Wacute 1E82 Wcircumflex 0174 Wdieresis 1E84 Wgrave 1E80 X 0058 Xi 039E
|
|
76
|
+
Y 0059 Yacute 00DD Ycircumflex 0176 Ydieresis 0178 Ygrave 1EF2 Z 005A
|
|
77
|
+
Zacute 0179 Zcaron 017D Zdotaccent 017B Zeta 0396 a 0061 aacute 00E1
|
|
78
|
+
abreve 0103 acircumflex 00E2 acute 00B4 acutecomb 0301 adieresis 00E4
|
|
79
|
+
ae 00E6 aeacute 01FD agrave 00E0 aleph 2135 alpha 03B1 alphatonos 03AC
|
|
80
|
+
amacron 0101 ampersand 0026 angle 2220 angleleft 2329 angleright 232A
|
|
81
|
+
anoteleia 0387 aogonek 0105 approxequal 2248 aring 00E5 aringacute 01FB
|
|
82
|
+
arrowboth 2194 arrowdblboth 21D4 arrowdbldown 21D3 arrowdblleft 21D0
|
|
83
|
+
arrowdblright 21D2 arrowdblup 21D1 arrowdown 2193 arrowleft 2190
|
|
84
|
+
arrowright 2192 arrowup 2191 arrowupdn 2195 arrowupdnbse 21A8
|
|
85
|
+
asciicircum 005E asciitilde 007E asterisk 002A asteriskmath 2217 at 0040
|
|
86
|
+
atilde 00E3 b 0062 backslash 005C bar 007C beta 03B2 block 2588
|
|
87
|
+
braceleft 007B braceright 007D bracketleft 005B bracketright 005D breve 02D8
|
|
88
|
+
brokenbar 00A6 bullet 2022 c 0063 cacute 0107 caron 02C7 carriagereturn 21B5
|
|
89
|
+
ccaron 010D ccedilla 00E7 ccircumflex 0109 cdotaccent 010B cedilla 00B8
|
|
90
|
+
cent 00A2 chi 03C7 circle 25CB circlemultiply 2297 circleplus 2295
|
|
91
|
+
circumflex 02C6 club 2663 colon 003A colonmonetary 20A1 comma 002C
|
|
92
|
+
congruent 2245 copyright 00A9 currency 00A4 d 0064 dagger 2020
|
|
93
|
+
daggerdbl 2021 dcaron 010F dcroat 0111 degree 00B0 delta 03B4 diamond 2666
|
|
94
|
+
dieresis 00A8 dieresistonos 0385 divide 00F7 dkshade 2593 dnblock 2584
|
|
95
|
+
dollar 0024 dong 20AB dotaccent 02D9 dotbelowcomb 0323 dotlessi 0131
|
|
96
|
+
dotmath 22C5 e 0065 eacute 00E9 ebreve 0115 ecaron 011B ecircumflex 00EA
|
|
97
|
+
edieresis 00EB edotaccent 0117 egrave 00E8 eight 0038 element 2208
|
|
98
|
+
ellipsis 2026 emacron 0113 emdash 2014 emptyset 2205 endash 2013 eng 014B
|
|
99
|
+
eogonek 0119 epsilon 03B5 epsilontonos 03AD equal 003D equivalence 2261
|
|
100
|
+
estimated 212E eta 03B7 etatonos 03AE eth 00F0 exclam 0021 exclamdbl 203C
|
|
101
|
+
exclamdown 00A1 existential 2203 f 0066 female 2640 figuredash 2012
|
|
102
|
+
filledbox 25A0 filledrect 25AC five 0035 fiveeighths 215D florin 0192
|
|
103
|
+
four 0034 fraction 2044 franc 20A3 g 0067 gamma 03B3 gbreve 011F gcaron 01E7
|
|
104
|
+
gcircumflex 011D gdotaccent 0121 germandbls 00DF gradient 2207 grave 0060
|
|
105
|
+
gravecomb 0300 greater 003E greaterequal 2265 guillemotleft 00AB
|
|
106
|
+
guillemotright 00BB guilsinglleft 2039 guilsinglright 203A h 0068 hbar 0127
|
|
107
|
+
hcircumflex 0125 heart 2665 hookabovecomb 0309 house 2302 hungarumlaut 02DD
|
|
108
|
+
hyphen 002D i 0069 iacute 00ED ibreve 012D icircumflex 00EE idieresis 00EF
|
|
109
|
+
igrave 00EC ij 0133 imacron 012B infinity 221E integral 222B integralbt 2321
|
|
110
|
+
integraltp 2320 intersection 2229 invbullet 25D8 invcircle 25D9
|
|
111
|
+
invsmileface 263B iogonek 012F iota 03B9 iotadieresis 03CA
|
|
112
|
+
iotadieresistonos 0390 iotatonos 03AF itilde 0129 j 006A jcircumflex 0135
|
|
113
|
+
k 006B kappa 03BA kgreenlandic 0138 l 006C lacute 013A lambda 03BB
|
|
114
|
+
lcaron 013E ldot 0140 less 003C lessequal 2264 lfblock 258C lira 20A4
|
|
115
|
+
logicaland 2227 logicalnot 00AC logicalor 2228 longs 017F lozenge 25CA
|
|
116
|
+
lslash 0142 ltshade 2591 m 006D macron 00AF male 2642 minus 2212 minute 2032
|
|
117
|
+
mu 00B5 multiply 00D7 musicalnote 266A musicalnotedbl 266B n 006E
|
|
118
|
+
nacute 0144 napostrophe 0149 ncaron 0148 nine 0039 notelement 2209
|
|
119
|
+
notequal 2260 notsubset 2284 ntilde 00F1 nu 03BD numbersign 0023 o 006F
|
|
120
|
+
oacute 00F3 obreve 014F ocircumflex 00F4 odieresis 00F6 oe 0153 ogonek 02DB
|
|
121
|
+
ograve 00F2 ohorn 01A1 ohungarumlaut 0151 omacron 014D omega 03C9
|
|
122
|
+
omega1 03D6 omegatonos 03CE omicron 03BF omicrontonos 03CC one 0031
|
|
123
|
+
onedotenleader 2024 oneeighth 215B onehalf 00BD onequarter 00BC
|
|
124
|
+
onethird 2153 openbullet 25E6 ordfeminine 00AA ordmasculine 00BA
|
|
125
|
+
orthogonal 221F oslash 00F8 oslashacute 01FF otilde 00F5 p 0070
|
|
126
|
+
paragraph 00B6 parenleft 0028 parenright 0029 partialdiff 2202 percent 0025
|
|
127
|
+
period 002E periodcentered 00B7 perpendicular 22A5 perthousand 2030
|
|
128
|
+
peseta 20A7 phi 03C6 phi1 03D5 pi 03C0 plus 002B plusminus 00B1
|
|
129
|
+
prescription 211E product 220F propersubset 2282 propersuperset 2283
|
|
130
|
+
proportional 221D psi 03C8 q 0071 question 003F questiondown 00BF
|
|
131
|
+
quotedbl 0022 quotedblbase 201E quotedblleft 201C quotedblright 201D
|
|
132
|
+
quoteleft 2018 quotereversed 201B quoteright 2019 quotesinglbase 201A
|
|
133
|
+
quotesingle 0027 r 0072 racute 0155 radical 221A rcaron 0159
|
|
134
|
+
reflexsubset 2286 reflexsuperset 2287 registered 00AE revlogicalnot 2310
|
|
135
|
+
rho 03C1 ring 02DA rtblock 2590 s 0073 sacute 015B scaron 0161 scedilla 015F
|
|
136
|
+
scircumflex 015D second 2033 section 00A7 semicolon 003B seven 0037
|
|
137
|
+
seveneighths 215E shade 2592 sigma 03C3 sigma1 03C2 similar 223C six 0036
|
|
138
|
+
slash 002F smileface 263A space 0020 spade 2660 sterling 00A3 suchthat 220B
|
|
139
|
+
summation 2211 sun 263C t 0074 tau 03C4 tbar 0167 tcaron 0165 therefore 2234
|
|
140
|
+
theta 03B8 theta1 03D1 thorn 00FE three 0033 threeeighths 215C
|
|
141
|
+
threequarters 00BE tilde 02DC tildecomb 0303 tonos 0384 trademark 2122
|
|
142
|
+
triagdn 25BC triaglf 25C4 triagrt 25BA triagup 25B2 two 0032
|
|
143
|
+
twodotenleader 2025 twothirds 2154 u 0075 uacute 00FA ubreve 016D
|
|
144
|
+
ucircumflex 00FB udieresis 00FC ugrave 00F9 uhorn 01B0 uhungarumlaut 0171
|
|
145
|
+
umacron 016B underscore 005F underscoredbl 2017 union 222A universal 2200
|
|
146
|
+
uogonek 0173 upblock 2580 upsilon 03C5 upsilondieresis 03CB
|
|
147
|
+
upsilondieresistonos 03B0 upsilontonos 03CD uring 016F utilde 0169 v 0076
|
|
148
|
+
w 0077 wacute 1E83 wcircumflex 0175 wdieresis 1E85 weierstrass 2118
|
|
149
|
+
wgrave 1E81 x 0078 xi 03BE y 0079 yacute 00FD ycircumflex 0177
|
|
150
|
+
ydieresis 00FF yen 00A5 ygrave 1EF3 z 007A zacute 017A zcaron 017E
|
|
151
|
+
zdotaccent 017C zero 0030 zeta 03B6
|
|
152
|
+
`;
|
|
153
|
+
const AGL_EXTRAS = `
|
|
154
|
+
fi FB01 fl FB02 ff FB00 ffi FB03 ffl FB04 onesuperior 00B9 twosuperior 00B2
|
|
155
|
+
threesuperior 00B3 nbspace 00A0
|
|
156
|
+
`;
|
|
157
|
+
/** Code points by glyph name. */
|
|
158
|
+
export const GLYPH_UNICODE = new Map(`${AGLFN} ${AGL_EXTRAS}`
|
|
159
|
+
.trim()
|
|
160
|
+
.split(/\s+/)
|
|
161
|
+
.flatMap((word, index, words) => index % 2 === 0
|
|
162
|
+
? [[word, Number.parseInt(words[index + 1], 16)]]
|
|
163
|
+
: []));
|
|
@@ -94,6 +94,8 @@ export function createPdfEditHandler(host) {
|
|
|
94
94
|
const { pageIndex, elementIds, scale } = payload;
|
|
95
95
|
return engine().renderPageWithout(pageIndex, elementIds, scale);
|
|
96
96
|
}
|
|
97
|
+
case "edit-text-font":
|
|
98
|
+
return engine().textFont(payload.id);
|
|
97
99
|
case "edit-page-layout":
|
|
98
100
|
return engine().pageLayout(payload.pageIndex);
|
|
99
101
|
case "edit-dispose":
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CffFont } from "./cff.js";
|
|
2
|
+
/**
|
|
3
|
+
* The OpenType file, or `undefined` when no glyph has a code point or the
|
|
4
|
+
* program's name cannot be made one a browser accepts.
|
|
5
|
+
*/
|
|
6
|
+
export declare function cffOpenType(program: Uint8Array, font: CffFont, unicode: ReadonlyMap<number, number>): Uint8Array | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* An embedded TrueType or OpenType program with the OS/2, name and post
|
|
9
|
+
* tables it lacks, laid out on four-byte boundaries; `undefined` when its
|
|
10
|
+
* table directory or core tables are broken.
|
|
11
|
+
*/
|
|
12
|
+
export declare function completeSfnt(program: Uint8Array, fontName: string): Uint8Array | undefined;
|
|
13
|
+
/** The sfnt file maps Unicode: a cmap subtable for platform 0, or for Windows Unicode BMP or full repertoire. */
|
|
14
|
+
export declare function hasUnicodeCmap(program: Uint8Array): boolean;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { cffWithSafeName } from "./cff.js";
|
|
2
|
+
/*
|
|
3
|
+
* Fonts a browser loads with `FontFace`. A PDF's CFF program gets a minimal
|
|
4
|
+
* OpenType font around it: the CFF table as the PDF holds it, a Unicode cmap,
|
|
5
|
+
* and the tables a font loader requires (head, hhea, hmtx, maxp, name, OS/2,
|
|
6
|
+
* post), filled from what the CFF says. A PDF's TrueType program keeps its
|
|
7
|
+
* tables; subsetting tools leave out the OS/2, name and post tables and pack
|
|
8
|
+
* tables off four-byte boundaries, which browsers refuse, so those tables are
|
|
9
|
+
* added and the file laid out again. Nothing in a program's tables changes.
|
|
10
|
+
*/
|
|
11
|
+
const SFNT_TRUETYPE = 0x00010000;
|
|
12
|
+
const SFNT_CFF = 0x4f54544f; // "OTTO"
|
|
13
|
+
/**
|
|
14
|
+
* The OpenType file, or `undefined` when no glyph has a code point or the
|
|
15
|
+
* program's name cannot be made one a browser accepts.
|
|
16
|
+
*/
|
|
17
|
+
export function cffOpenType(program, font, unicode) {
|
|
18
|
+
const safe = cffWithSafeName(program);
|
|
19
|
+
if (unicode.size === 0 || !safe)
|
|
20
|
+
return undefined;
|
|
21
|
+
const em = font.unitsPerEm;
|
|
22
|
+
const [xMin, yMin, xMax, yMax] = fontBox(font.bbox, em);
|
|
23
|
+
const glyphCount = font.widths.length;
|
|
24
|
+
const widths = font.widths.map((width) => Math.max(0, Math.min(0xffff, Math.round(width))));
|
|
25
|
+
const codes = [...unicode.keys()].sort((a, b) => a - b);
|
|
26
|
+
const tables = new Map([
|
|
27
|
+
["CFF ", safe],
|
|
28
|
+
["OS/2", os2(em, widths, codes, yMin, yMax)],
|
|
29
|
+
["cmap", cmap(unicode, codes)],
|
|
30
|
+
["head", head(em, xMin, yMin, xMax, yMax)],
|
|
31
|
+
["hhea", hhea(widths, glyphCount, xMin, yMin, xMax, yMax)],
|
|
32
|
+
["hmtx", concat(widths.map((width) => bytes(u16(width), i16(0))))],
|
|
33
|
+
["maxp", bytes(u32(0x00005000), u16(glyphCount))],
|
|
34
|
+
["name", names(postScriptName(font.name))],
|
|
35
|
+
["post", post(em)],
|
|
36
|
+
]);
|
|
37
|
+
return assemble(tables, SFNT_CFF);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The font box in int16 font units, in order; a font without one, which CFF
|
|
41
|
+
* allows, gets a box of the usual proportions so its line has a height.
|
|
42
|
+
*/
|
|
43
|
+
function fontBox(box, em) {
|
|
44
|
+
const clamp = (value) => Math.max(-0x8000, Math.min(0x7fff, Math.round(value)));
|
|
45
|
+
const [x0 = 0, y0 = 0, x1 = 0, y1 = 0] = box.map(clamp);
|
|
46
|
+
if (y1 <= y0)
|
|
47
|
+
return [0, clamp(-em * 0.2), clamp(em), clamp(em * 0.8)];
|
|
48
|
+
return [Math.min(x0, x1), y0, Math.max(x0, x1), y1];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* An embedded TrueType or OpenType program with the OS/2, name and post
|
|
52
|
+
* tables it lacks, laid out on four-byte boundaries; `undefined` when its
|
|
53
|
+
* table directory or core tables are broken.
|
|
54
|
+
*/
|
|
55
|
+
export function completeSfnt(program, fontName) {
|
|
56
|
+
const tables = sfntTables(program);
|
|
57
|
+
const headTable = tables?.get("head");
|
|
58
|
+
const hheaTable = tables?.get("hhea");
|
|
59
|
+
const maxpTable = tables?.get("maxp");
|
|
60
|
+
const hmtxTable = tables?.get("hmtx");
|
|
61
|
+
if (!tables ||
|
|
62
|
+
!tables.has("cmap") ||
|
|
63
|
+
!headTable ||
|
|
64
|
+
headTable.length < 54 ||
|
|
65
|
+
!hheaTable ||
|
|
66
|
+
hheaTable.length < 36 ||
|
|
67
|
+
!maxpTable ||
|
|
68
|
+
maxpTable.length < 6 ||
|
|
69
|
+
!hmtxTable)
|
|
70
|
+
return undefined;
|
|
71
|
+
const view = (table) => new DataView(table.buffer, table.byteOffset, table.byteLength);
|
|
72
|
+
const headView = view(headTable);
|
|
73
|
+
const em = headView.getUint16(18);
|
|
74
|
+
const yMin = headView.getInt16(38);
|
|
75
|
+
const yMax = headView.getInt16(42);
|
|
76
|
+
// The adjustment is the file's, so it is worked out again.
|
|
77
|
+
const ownHead = headTable.slice();
|
|
78
|
+
ownHead.fill(0, 8, 12);
|
|
79
|
+
tables.set("head", ownHead);
|
|
80
|
+
if (!tables.has("OS/2")) {
|
|
81
|
+
const metrics = view(hheaTable).getUint16(34);
|
|
82
|
+
const widths = Array.from({ length: Math.min(metrics, hmtxTable.length >> 2) }, (_, glyph) => view(hmtxTable).getUint16(glyph * 4));
|
|
83
|
+
tables.set("OS/2", os2(em, widths, [], yMin, yMax));
|
|
84
|
+
}
|
|
85
|
+
if (!tables.has("name"))
|
|
86
|
+
tables.set("name", names(postScriptName(fontName)));
|
|
87
|
+
if (!tables.has("post"))
|
|
88
|
+
tables.set("post", post(em));
|
|
89
|
+
const version = view(program).getUint32(0);
|
|
90
|
+
return assemble(tables, version === SFNT_CFF ? SFNT_CFF : SFNT_TRUETYPE);
|
|
91
|
+
}
|
|
92
|
+
/** The sfnt file maps Unicode: a cmap subtable for platform 0, or for Windows Unicode BMP or full repertoire. */
|
|
93
|
+
export function hasUnicodeCmap(program) {
|
|
94
|
+
const table = sfntTables(program)?.get("cmap");
|
|
95
|
+
if (!table || table.length < 4)
|
|
96
|
+
return false;
|
|
97
|
+
const view = new DataView(table.buffer, table.byteOffset, table.byteLength);
|
|
98
|
+
const count = Math.min(view.getUint16(2), (table.length - 4) >> 3);
|
|
99
|
+
for (let index = 0; index < count; index += 1) {
|
|
100
|
+
const platform = view.getUint16(4 + index * 8);
|
|
101
|
+
const encoding = view.getUint16(6 + index * 8);
|
|
102
|
+
if (platform === 0 ||
|
|
103
|
+
(platform === 3 && (encoding === 1 || encoding === 10)))
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
/** The tables of an sfnt file by tag, or `undefined` when its directory is broken. */
|
|
109
|
+
function sfntTables(program) {
|
|
110
|
+
if (program.length < 12)
|
|
111
|
+
return undefined;
|
|
112
|
+
const view = new DataView(program.buffer, program.byteOffset, program.byteLength);
|
|
113
|
+
const count = view.getUint16(4);
|
|
114
|
+
if (count === 0 || 12 + count * 16 > program.length)
|
|
115
|
+
return undefined;
|
|
116
|
+
const tables = new Map();
|
|
117
|
+
for (let index = 0; index < count; index += 1) {
|
|
118
|
+
const record = 12 + index * 16;
|
|
119
|
+
const tag = String.fromCharCode(...program.subarray(record, record + 4));
|
|
120
|
+
const offset = view.getUint32(record + 8);
|
|
121
|
+
const length = view.getUint32(record + 12);
|
|
122
|
+
if (tables.has(tag) || offset + length > program.length)
|
|
123
|
+
return undefined;
|
|
124
|
+
tables.set(tag, program.subarray(offset, offset + length));
|
|
125
|
+
}
|
|
126
|
+
return tables;
|
|
127
|
+
}
|
|
128
|
+
/** The PostScript name without a subset tag, in the characters a name table takes. */
|
|
129
|
+
function postScriptName(name) {
|
|
130
|
+
return (name
|
|
131
|
+
.replace(/^[A-Z]{6}\+/, "")
|
|
132
|
+
.replace(/[^\x21-\x7e]|[[\](){}<>/%]/g, "")
|
|
133
|
+
.slice(0, 63) || "Embedded");
|
|
134
|
+
}
|
|
135
|
+
function post(em) {
|
|
136
|
+
// Version 3: no glyph names.
|
|
137
|
+
return bytes(u32(0x00030000), u32(0), i16(-Math.round(em / 10)), i16(Math.round(em / 20)), u32(0), u32(0), u32(0), u32(0), u32(0));
|
|
138
|
+
}
|
|
139
|
+
function head(em, xMin, yMin, xMax, yMax) {
|
|
140
|
+
return bytes(u32(0x00010000), u32(0x00010000), u32(0), // checkSumAdjustment, set once the font is assembled
|
|
141
|
+
u32(0x5f0f3cf5), u16(0x000b), u16(em), u32(0), u32(0), u32(0), u32(0), i16(xMin), i16(yMin), i16(xMax), i16(yMax), u16(0), u16(8), i16(2), i16(0), i16(0));
|
|
142
|
+
}
|
|
143
|
+
function hhea(widths, glyphCount, xMin, yMin, xMax, yMax) {
|
|
144
|
+
return bytes(u32(0x00010000), i16(yMax), i16(yMin), i16(0), u16(widths.reduce((most, width) => Math.max(most, width), 0)), i16(xMin), i16(0), i16(xMax), i16(1), i16(0), i16(0), i16(0), i16(0), i16(0), i16(0), i16(0), u16(glyphCount));
|
|
145
|
+
}
|
|
146
|
+
function os2(em, widths, codes, yMin, yMax) {
|
|
147
|
+
const scaled = (fraction) => Math.round(em * fraction);
|
|
148
|
+
const drawn = widths.filter((width) => width > 0);
|
|
149
|
+
const average = drawn.length
|
|
150
|
+
? Math.round(drawn.reduce((sum, width) => sum + width, 0) / drawn.length)
|
|
151
|
+
: 0;
|
|
152
|
+
return bytes(u16(4), i16(average), u16(400), u16(5), u16(0), i16(scaled(0.65)), i16(scaled(0.6)), i16(0), i16(scaled(0.075)), i16(scaled(0.65)), i16(scaled(0.6)), i16(0), i16(scaled(0.35)), i16(scaled(0.05)), i16(scaled(0.25)), i16(0), new Array(10).fill(0), u32(0), u32(0), u32(0), u32(0), [0x57, 0x44, 0x4f, 0x43], // "WDOC"
|
|
153
|
+
u16(0x0040), // regular
|
|
154
|
+
u16(Math.min(codes[0] ?? 0x20, 0xffff)), u16(Math.min(codes.at(-1) ?? 0xffff, 0xffff)), i16(yMax), i16(yMin), i16(0), u16(Math.max(0, yMax)), u16(Math.max(0, -yMin)), u32(1), u32(0), i16(scaled(0.5)), i16(scaled(0.7)), u16(0), u16(32), u16(0));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Format 4 for the BMP, and format 12 as well when a code point lies beyond
|
|
158
|
+
* it or the BMP takes more segments than format 4 holds. Records are in
|
|
159
|
+
* platform and encoding order, as the specification requires.
|
|
160
|
+
*/
|
|
161
|
+
function cmap(unicode, codes) {
|
|
162
|
+
const basic = codes.filter((code) => code <= 0xffff);
|
|
163
|
+
const format4 = cmapFormat4(unicode, basic);
|
|
164
|
+
const format12 = !format4 || codes.length > basic.length
|
|
165
|
+
? cmapFormat12(unicode, codes)
|
|
166
|
+
: undefined;
|
|
167
|
+
const subtables = [
|
|
168
|
+
...(format4 ? [{ platform: 0, encoding: 3, data: format4 }] : []),
|
|
169
|
+
...(format12 ? [{ platform: 0, encoding: 4, data: format12 }] : []),
|
|
170
|
+
...(format4 ? [{ platform: 3, encoding: 1, data: format4 }] : []),
|
|
171
|
+
...(format12 ? [{ platform: 3, encoding: 10, data: format12 }] : []),
|
|
172
|
+
];
|
|
173
|
+
// Subtables shared by two records are written once.
|
|
174
|
+
const unique = [...new Set(subtables.map((subtable) => subtable.data))];
|
|
175
|
+
const headerSize = 4 + subtables.length * 8;
|
|
176
|
+
const offsets = new Map();
|
|
177
|
+
let offset = headerSize;
|
|
178
|
+
for (const data of unique) {
|
|
179
|
+
offsets.set(data, offset);
|
|
180
|
+
offset += data.length;
|
|
181
|
+
}
|
|
182
|
+
return concat([
|
|
183
|
+
bytes(u16(0), u16(subtables.length)),
|
|
184
|
+
...subtables.map(({ platform, encoding, data }) => bytes(u16(platform), u16(encoding), u32(offsets.get(data)))),
|
|
185
|
+
...unique,
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
/** `undefined` when the segments overflow the subtable's 16-bit length. */
|
|
189
|
+
function cmapFormat4(unicode, codes) {
|
|
190
|
+
// Runs of consecutive code points on consecutive glyphs share one delta.
|
|
191
|
+
const segments = [];
|
|
192
|
+
for (const code of codes) {
|
|
193
|
+
const glyph = unicode.get(code);
|
|
194
|
+
const last = segments.at(-1);
|
|
195
|
+
if (last &&
|
|
196
|
+
code === last.end + 1 &&
|
|
197
|
+
glyph === last.glyph + (code - last.start))
|
|
198
|
+
last.end = code;
|
|
199
|
+
else
|
|
200
|
+
segments.push({ start: code, end: code, glyph });
|
|
201
|
+
}
|
|
202
|
+
segments.push({ start: 0xffff, end: 0xffff, glyph: 0 });
|
|
203
|
+
const count = segments.length;
|
|
204
|
+
if (16 + count * 8 > 0xffff)
|
|
205
|
+
return undefined;
|
|
206
|
+
const searchRange = 2 * 2 ** Math.floor(Math.log2(count));
|
|
207
|
+
const delta = (segment) => segment.start === 0xffff ? 1 : (segment.glyph - segment.start) & 0xffff;
|
|
208
|
+
return bytes(u16(4), u16(16 + count * 8), u16(0), u16(count * 2), u16(searchRange), u16(Math.floor(Math.log2(count))), u16(count * 2 - searchRange), segments.flatMap((segment) => u16(segment.end)), u16(0), segments.flatMap((segment) => u16(segment.start)), segments.flatMap((segment) => u16(delta(segment))), segments.flatMap(() => u16(0)));
|
|
209
|
+
}
|
|
210
|
+
function cmapFormat12(unicode, codes) {
|
|
211
|
+
const groups = [];
|
|
212
|
+
for (const code of codes) {
|
|
213
|
+
const glyph = unicode.get(code);
|
|
214
|
+
const last = groups.at(-1);
|
|
215
|
+
if (last &&
|
|
216
|
+
code === last.end + 1 &&
|
|
217
|
+
glyph === last.glyph + (code - last.start))
|
|
218
|
+
last.end = code;
|
|
219
|
+
else
|
|
220
|
+
groups.push({ start: code, end: code, glyph });
|
|
221
|
+
}
|
|
222
|
+
return bytes(u16(12), u16(0), u32(16 + groups.length * 12), u32(0), u32(groups.length), groups.flatMap((group) => [
|
|
223
|
+
...u32(group.start),
|
|
224
|
+
...u32(group.end),
|
|
225
|
+
...u32(group.glyph),
|
|
226
|
+
]));
|
|
227
|
+
}
|
|
228
|
+
function names(postScript) {
|
|
229
|
+
const records = [
|
|
230
|
+
[1, postScript],
|
|
231
|
+
[2, "Regular"],
|
|
232
|
+
[3, `${postScript}-web-doc`],
|
|
233
|
+
[4, postScript],
|
|
234
|
+
[5, "Version 1.0"],
|
|
235
|
+
[6, postScript],
|
|
236
|
+
];
|
|
237
|
+
const strings = records.map(([, text]) => [...text].flatMap((character) => u16(character.charCodeAt(0))));
|
|
238
|
+
let offset = 0;
|
|
239
|
+
const entries = records.map(([id], index) => {
|
|
240
|
+
const entry = [
|
|
241
|
+
...u16(3),
|
|
242
|
+
...u16(1),
|
|
243
|
+
...u16(0x0409),
|
|
244
|
+
...u16(id),
|
|
245
|
+
...u16(strings[index].length),
|
|
246
|
+
...u16(offset),
|
|
247
|
+
];
|
|
248
|
+
offset += strings[index].length;
|
|
249
|
+
return entry;
|
|
250
|
+
});
|
|
251
|
+
return bytes(u16(0), u16(records.length), u16(6 + records.length * 12), entries.flat(), strings.flat());
|
|
252
|
+
}
|
|
253
|
+
/** The table directory, the tables padded to four bytes, and the head checksum adjustment. */
|
|
254
|
+
function assemble(tables, version) {
|
|
255
|
+
const tags = [...tables.keys()].sort();
|
|
256
|
+
const count = tags.length;
|
|
257
|
+
const selector = Math.floor(Math.log2(count));
|
|
258
|
+
const headerSize = 12 + count * 16;
|
|
259
|
+
let offset = headerSize;
|
|
260
|
+
const placed = tags.map((tag) => {
|
|
261
|
+
const data = tables.get(tag);
|
|
262
|
+
const at = offset;
|
|
263
|
+
offset += (data.length + 3) & ~3;
|
|
264
|
+
return { tag, data, at };
|
|
265
|
+
});
|
|
266
|
+
const font = new Uint8Array(offset);
|
|
267
|
+
font.set(bytes(u32(version), u16(count), u16(2 ** selector * 16), u16(selector), u16(count * 16 - 2 ** selector * 16), placed.flatMap(({ tag, data, at }) => [
|
|
268
|
+
...[...tag].map((character) => character.charCodeAt(0)),
|
|
269
|
+
...u32(checksum(data)),
|
|
270
|
+
...u32(at),
|
|
271
|
+
...u32(data.length),
|
|
272
|
+
])));
|
|
273
|
+
for (const { data, at } of placed)
|
|
274
|
+
font.set(data, at);
|
|
275
|
+
const head = placed.find((table) => table.tag === "head");
|
|
276
|
+
const adjustment = (0xb1b0afba - checksum(font)) >>> 0;
|
|
277
|
+
font.set(u32(adjustment), head.at + 8);
|
|
278
|
+
return font;
|
|
279
|
+
}
|
|
280
|
+
function checksum(data) {
|
|
281
|
+
let sum = 0;
|
|
282
|
+
for (let offset = 0; offset < data.length; offset += 4)
|
|
283
|
+
sum =
|
|
284
|
+
(sum +
|
|
285
|
+
(((data[offset] ?? 0) << 24) |
|
|
286
|
+
((data[offset + 1] ?? 0) << 16) |
|
|
287
|
+
((data[offset + 2] ?? 0) << 8) |
|
|
288
|
+
(data[offset + 3] ?? 0))) >>>
|
|
289
|
+
0;
|
|
290
|
+
return sum;
|
|
291
|
+
}
|
|
292
|
+
function u16(value) {
|
|
293
|
+
return [(value >> 8) & 0xff, value & 0xff];
|
|
294
|
+
}
|
|
295
|
+
function i16(value) {
|
|
296
|
+
return u16(value < 0 ? value + 0x10000 : value);
|
|
297
|
+
}
|
|
298
|
+
function u32(value) {
|
|
299
|
+
return [
|
|
300
|
+
(value >>> 24) & 0xff,
|
|
301
|
+
(value >>> 16) & 0xff,
|
|
302
|
+
(value >>> 8) & 0xff,
|
|
303
|
+
value & 0xff,
|
|
304
|
+
];
|
|
305
|
+
}
|
|
306
|
+
function bytes(...parts) {
|
|
307
|
+
return concat(parts.map((part) => Uint8Array.from(part)));
|
|
308
|
+
}
|
|
309
|
+
function concat(parts) {
|
|
310
|
+
const out = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
|
|
311
|
+
let offset = 0;
|
|
312
|
+
for (const part of parts) {
|
|
313
|
+
out.set(part, offset);
|
|
314
|
+
offset += part.length;
|
|
315
|
+
}
|
|
316
|
+
return out;
|
|
317
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { glyphUnicode, readCff } from "./cff.js";
|
|
2
|
+
import { textStyle } from "./elements.js";
|
|
3
|
+
import { cffOpenType, completeSfnt, hasUnicodeCmap } from "./opentype.js";
|
|
4
|
+
export function textFaceOf(pdfium, object, cache) {
|
|
5
|
+
const { lib } = pdfium;
|
|
6
|
+
const font = lib.FPDFTextObj_GetFont(object);
|
|
7
|
+
const family = textStyle(pdfium, object).fontFamily;
|
|
8
|
+
const baseName = pdfium.readUtf8String((buffer, bytes) => lib.FPDFFont_GetBaseFontName(font, buffer, bytes));
|
|
9
|
+
if (!lib.FPDFFont_GetIsEmbedded(font))
|
|
10
|
+
return { key: `name:${baseName}`, family, missing: "not-embedded" };
|
|
11
|
+
// A Type 3 font is embedded as drawings, with no program to read.
|
|
12
|
+
const program = fontProgram(pdfium, font);
|
|
13
|
+
if (!program)
|
|
14
|
+
return { key: `embedded:${baseName}`, family, missing: "unreadable" };
|
|
15
|
+
const key = `${baseName}#${fnv1a(program).toString(16)}`;
|
|
16
|
+
const known = cache.get(key);
|
|
17
|
+
if (known)
|
|
18
|
+
return { ...known, family };
|
|
19
|
+
const face = { key, family, ...faceOf(program, baseName) };
|
|
20
|
+
cache.set(key, face);
|
|
21
|
+
return face;
|
|
22
|
+
}
|
|
23
|
+
function faceOf(program, baseName) {
|
|
24
|
+
const tag = String.fromCharCode(...program.subarray(0, 4));
|
|
25
|
+
const truetype = tag === "true" ||
|
|
26
|
+
(program[0] === 0 &&
|
|
27
|
+
program[1] === 1 &&
|
|
28
|
+
program[2] === 0 &&
|
|
29
|
+
program[3] === 0);
|
|
30
|
+
if (truetype || tag === "OTTO") {
|
|
31
|
+
if (!hasUnicodeCmap(program))
|
|
32
|
+
return { missing: "no-unicode" };
|
|
33
|
+
const data = completeSfnt(program, baseName);
|
|
34
|
+
return data
|
|
35
|
+
? { face: { data, format: truetype ? "truetype" : "opentype" } }
|
|
36
|
+
: { missing: "unreadable" };
|
|
37
|
+
}
|
|
38
|
+
// Type 1 programs start with "%!" in clear text, or with a PFB segment.
|
|
39
|
+
if (tag.startsWith("%!") || program[0] === 0x80)
|
|
40
|
+
return { missing: "type1" };
|
|
41
|
+
const cff = readCff(program);
|
|
42
|
+
if (!cff)
|
|
43
|
+
return { missing: "unreadable" };
|
|
44
|
+
if (cff.cid)
|
|
45
|
+
return { missing: "cid-keyed" };
|
|
46
|
+
const unicode = new Map();
|
|
47
|
+
cff.glyphNames.forEach((name, glyph) => {
|
|
48
|
+
const code = glyphUnicode(name);
|
|
49
|
+
if (code !== undefined && !unicode.has(code))
|
|
50
|
+
unicode.set(code, glyph);
|
|
51
|
+
});
|
|
52
|
+
const data = cffOpenType(program, cff, unicode);
|
|
53
|
+
return data
|
|
54
|
+
? { face: { data, format: "opentype" } }
|
|
55
|
+
: { missing: "no-unicode" };
|
|
56
|
+
}
|
|
57
|
+
/** The font program a PDF font object embeds, or `undefined` for a font it does not embed. */
|
|
58
|
+
function fontProgram(pdfium, font) {
|
|
59
|
+
const { lib } = pdfium;
|
|
60
|
+
const size = pdfium.readNumbers(1, "i32", ([out]) => lib.FPDFFont_GetFontData(font, 0, 0, out))?.[0];
|
|
61
|
+
if (!size)
|
|
62
|
+
return undefined;
|
|
63
|
+
const buffer = pdfium.malloc(size);
|
|
64
|
+
const out = pdfium.malloc(4);
|
|
65
|
+
try {
|
|
66
|
+
return lib.FPDFFont_GetFontData(font, buffer, size, out)
|
|
67
|
+
? pdfium.readBytes(buffer, size)
|
|
68
|
+
: undefined;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
pdfium.free(out);
|
|
72
|
+
pdfium.free(buffer);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** FNV-1a over the program: a cheap, stable key for one font. */
|
|
76
|
+
function fnv1a(bytes) {
|
|
77
|
+
let hash = 0x811c9dc5;
|
|
78
|
+
for (const byte of bytes)
|
|
79
|
+
hash = Math.imul(hash ^ byte, 0x01000193);
|
|
80
|
+
return hash >>> 0;
|
|
81
|
+
}
|
|
@@ -2,10 +2,11 @@ import { type WorkerLike } from "../../worker-client.js";
|
|
|
2
2
|
import type { EditEngineContext } from "../engine.js";
|
|
3
3
|
import type { PagePoint, PageRect, TextPosition, TextRange } from "../types.js";
|
|
4
4
|
import { WorkerEngineClient } from "../worker-engine.js";
|
|
5
|
-
import type { PageBitmap, PageLayout, TextLayout } from "./types.js";
|
|
5
|
+
import type { PageBitmap, PageLayout, TextFont, TextLayout } from "./types.js";
|
|
6
6
|
/** The reads behind the overlay primitives, beyond the core engine interface. */
|
|
7
7
|
export interface PdfEngineReads {
|
|
8
8
|
textLayout(id: string, signal: AbortSignal): Promise<TextLayout | undefined>;
|
|
9
|
+
textFont(id: string, signal: AbortSignal): Promise<TextFont | undefined>;
|
|
9
10
|
positionAt(pageIndex: number, point: PagePoint, signal: AbortSignal): Promise<TextPosition | undefined>;
|
|
10
11
|
rangeRects(range: TextRange, signal: AbortSignal): Promise<readonly PageRect[]>;
|
|
11
12
|
renderWithout(pageIndex: number, elementIds: readonly string[], scale: number, signal: AbortSignal): Promise<PageBitmap>;
|
|
@@ -28,6 +29,7 @@ export declare class PdfEditEngineClient extends WorkerEngineClient implements P
|
|
|
28
29
|
readonly schemas: import("../types.js").OperationSchemaSet;
|
|
29
30
|
start(original: Uint8Array, options: PdfEditProviderOptions): Promise<void>;
|
|
30
31
|
textLayout(id: string, signal: AbortSignal): Promise<TextLayout | undefined>;
|
|
32
|
+
textFont(id: string, signal: AbortSignal): Promise<TextFont | undefined>;
|
|
31
33
|
positionAt(pageIndex: number, point: PagePoint, signal: AbortSignal): Promise<TextPosition | undefined>;
|
|
32
34
|
rangeRects(range: TextRange, signal: AbortSignal): Promise<readonly PageRect[]>;
|
|
33
35
|
renderWithout(pageIndex: number, elementIds: readonly string[], scale: number, signal: AbortSignal): Promise<PageBitmap>;
|
|
@@ -53,6 +53,9 @@ export class PdfEditEngineClient extends WorkerEngineClient {
|
|
|
53
53
|
textLayout(id, signal) {
|
|
54
54
|
return this.request("edit-text-layout", { id }, signal);
|
|
55
55
|
}
|
|
56
|
+
textFont(id, signal) {
|
|
57
|
+
return this.request("edit-text-font", { id }, signal);
|
|
58
|
+
}
|
|
56
59
|
positionAt(pageIndex, point, signal) {
|
|
57
60
|
return this.request("edit-position-at", { pageIndex, point }, signal);
|
|
58
61
|
}
|
|
@@ -2,7 +2,7 @@ import type { TextSelection } from "../../contracts.js";
|
|
|
2
2
|
import type { DescribeOptions, DocumentDescription, EditCheckpoint, OutlineOptions, OutlineResult, TargetCandidate, TargetQuery, ToolCall, ToolCallOptions, ToolResult, ToolSet } from "../ai/types.js";
|
|
3
3
|
import type { EditSessionCore } from "../engine.js";
|
|
4
4
|
import type { ApplyOptions, AssetOptions, EditFindOptions, EditOperation, EditReceipt, EditState, ElementQuery, HistoryOptions, OperationSchemaSet, PagePoint, PageRect, ReadItem, ReadOptions, ReadResult, SavedDocument, TextPosition, TextRange, TextTarget } from "../types.js";
|
|
5
|
-
import type { DeleteElementOperation, DeletePageOperation, Fields, InsertImageOperation, InsertPageOperation, InsertShapeOperation, InsertTableOperation, InsertTextBoxOperation, MoveElementOperation, MovePageOperation, PdfEditSession, PdfElement, PdfOperation, PdfSaveOptions, ReplaceTextOperation, ResizeElementOperation, RotatePageOperation, SetShapeStyleOperation, SetTableCellOperation, PageBitmap, PageLayout, RenderOptions, SetTextStyleOperation, TextLayout } from "./types.js";
|
|
5
|
+
import type { DeleteElementOperation, DeletePageOperation, Fields, InsertImageOperation, InsertPageOperation, InsertShapeOperation, InsertTableOperation, InsertTextBoxOperation, MoveElementOperation, MovePageOperation, PdfEditSession, PdfElement, PdfOperation, PdfSaveOptions, ReplaceTextOperation, ResizeElementOperation, RotatePageOperation, SetShapeStyleOperation, SetTableCellOperation, PageBitmap, PageLayout, RenderOptions, SetTextStyleOperation, TextFont, TextLayout } from "./types.js";
|
|
6
6
|
/**
|
|
7
7
|
* The PDF session: the core session narrowed to PDF operations and elements.
|
|
8
8
|
* Typed methods are added here as their operations ship; each is `apply()`
|
|
@@ -39,6 +39,7 @@ export declare class PdfSession implements PdfEditSession {
|
|
|
39
39
|
get tools(): ToolSet;
|
|
40
40
|
callTool(call: ToolCall, options?: ToolCallOptions): Promise<ToolResult>;
|
|
41
41
|
getTextLayout(elementId: string, options?: ReadOptions): Promise<ReadItem<TextLayout>>;
|
|
42
|
+
getTextFont(elementId: string, options?: ReadOptions): Promise<ReadItem<TextFont>>;
|
|
42
43
|
positionAt(pageIndex: number, point: PagePoint, options?: ReadOptions): Promise<ReadItem<TextPosition>>;
|
|
43
44
|
rangeRects(range: TextRange, options?: ReadOptions): Promise<ReadResult<PageRect>>;
|
|
44
45
|
getPageLayout(pageIndex: number, options?: ReadOptions): Promise<ReadItem<PageLayout>>;
|
package/dist/edit/pdf/session.js
CHANGED
|
@@ -198,6 +198,9 @@ export class PdfSession {
|
|
|
198
198
|
getTextLayout(elementId, options) {
|
|
199
199
|
return this.#core.readItem(options, (engine, signal) => pdfReads(engine).textLayout(elementId, signal));
|
|
200
200
|
}
|
|
201
|
+
getTextFont(elementId, options) {
|
|
202
|
+
return this.#core.readItem(options, (engine, signal) => pdfReads(engine).textFont(elementId, signal));
|
|
203
|
+
}
|
|
201
204
|
positionAt(pageIndex, point, options) {
|
|
202
205
|
return this.#core.readItem(options, (engine, signal) => pdfReads(engine).positionAt(pageIndex, point, signal));
|
|
203
206
|
}
|