react-web-pdf-editor 0.0.0-stage → 0.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.
@@ -0,0 +1,246 @@
1
+ // src/lib/drawPaths.ts
2
+ var MIN_POINT_GAP = 2e-3;
3
+ var SIMPLIFY_EPSILON = 3e-3;
4
+ function distance(a, b) {
5
+ return Math.hypot(b.x - a.x, b.y - a.y);
6
+ }
7
+ function pathLength(points) {
8
+ let length = 0;
9
+ for (let index = 1; index < points.length; index += 1) {
10
+ length += distance(points[index - 1], points[index]);
11
+ }
12
+ return length;
13
+ }
14
+ function appendPoint(points, next) {
15
+ const last = points[points.length - 1];
16
+ if (last && distance(last, next) < MIN_POINT_GAP) {
17
+ return points;
18
+ }
19
+ return [...points, next];
20
+ }
21
+ function pointToSegmentDistance(point, start, end) {
22
+ const dx = end.x - start.x;
23
+ const dy = end.y - start.y;
24
+ const lengthSq = dx * dx + dy * dy;
25
+ if (lengthSq === 0) {
26
+ return distance(point, start);
27
+ }
28
+ const t = Math.max(
29
+ 0,
30
+ Math.min(1, ((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSq)
31
+ );
32
+ return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));
33
+ }
34
+ function simplifyPoints(points, epsilon = SIMPLIFY_EPSILON) {
35
+ if (points.length <= 2) {
36
+ return points;
37
+ }
38
+ let maxDistance = 0;
39
+ let maxIndex = 0;
40
+ const first = points[0];
41
+ const last = points[points.length - 1];
42
+ for (let index = 1; index < points.length - 1; index += 1) {
43
+ const current = pointToSegmentDistance(points[index], first, last);
44
+ if (current > maxDistance) {
45
+ maxDistance = current;
46
+ maxIndex = index;
47
+ }
48
+ }
49
+ if (maxDistance <= epsilon) {
50
+ return [first, last];
51
+ }
52
+ const left = simplifyPoints(points.slice(0, maxIndex + 1), epsilon);
53
+ const right = simplifyPoints(points.slice(maxIndex), epsilon);
54
+ return [...left.slice(0, -1), ...right];
55
+ }
56
+ function formatCoord(value) {
57
+ return value.toFixed(4);
58
+ }
59
+ function pointsToSvgPath(points) {
60
+ if (points.length === 0) {
61
+ return "";
62
+ }
63
+ const first = points[0];
64
+ if (points.length === 1) {
65
+ const x = formatCoord(first.x);
66
+ const y = formatCoord(first.y);
67
+ return `M ${x} ${y} L ${x} ${y}`;
68
+ }
69
+ if (points.length === 2) {
70
+ const second = points[1];
71
+ return `M ${formatCoord(first.x)} ${formatCoord(first.y)} L ${formatCoord(second.x)} ${formatCoord(second.y)}`;
72
+ }
73
+ let path = `M ${formatCoord(first.x)} ${formatCoord(first.y)}`;
74
+ for (let index = 1; index < points.length - 1; index += 1) {
75
+ const current = points[index];
76
+ const next = points[index + 1];
77
+ const midX = (current.x + next.x) / 2;
78
+ const midY = (current.y + next.y) / 2;
79
+ path += ` Q ${formatCoord(current.x)} ${formatCoord(current.y)} ${formatCoord(midX)} ${formatCoord(midY)}`;
80
+ }
81
+ const last = points[points.length - 1];
82
+ path += ` T ${formatCoord(last.x)} ${formatCoord(last.y)}`;
83
+ return path;
84
+ }
85
+ function translatePoints(points, dx, dy) {
86
+ if (dx === 0 && dy === 0) {
87
+ return points;
88
+ }
89
+ return points.map((point) => ({
90
+ x: point.x + dx,
91
+ y: point.y + dy
92
+ }));
93
+ }
94
+ function strokeBounds(points, pad = 0) {
95
+ let minX = 1;
96
+ let minY = 1;
97
+ let maxX = 0;
98
+ let maxY = 0;
99
+ for (const point of points) {
100
+ minX = Math.min(minX, point.x);
101
+ minY = Math.min(minY, point.y);
102
+ maxX = Math.max(maxX, point.x);
103
+ maxY = Math.max(maxY, point.y);
104
+ }
105
+ return {
106
+ left: Math.max(0, minX - pad),
107
+ top: Math.max(0, minY - pad),
108
+ width: Math.min(1, maxX + pad) - Math.max(0, minX - pad),
109
+ height: Math.min(1, maxY + pad) - Math.max(0, minY - pad)
110
+ };
111
+ }
112
+ function hitTestStroke(points, point, threshold) {
113
+ if (points.length === 0) {
114
+ return false;
115
+ }
116
+ if (points.length === 1) {
117
+ return distance(points[0], point) <= threshold;
118
+ }
119
+ for (let index = 1; index < points.length; index += 1) {
120
+ if (pointToSegmentDistance(point, points[index - 1], points[index]) <= threshold) {
121
+ return true;
122
+ }
123
+ }
124
+ return false;
125
+ }
126
+
127
+ // src/lib/geometry.ts
128
+ function normalizeDegrees(angle) {
129
+ return (angle % 360 + 360) % 360;
130
+ }
131
+ function snapDegrees(angle, increment) {
132
+ return Math.round(angle / increment) * increment;
133
+ }
134
+ function pointerDeltaToLocal(deltaX, deltaY, rotationDeg) {
135
+ const rad = rotationDeg * Math.PI / 180;
136
+ const cos = Math.cos(rad);
137
+ const sin = Math.sin(rad);
138
+ return {
139
+ x: deltaX * cos + deltaY * sin,
140
+ y: -deltaX * sin + deltaY * cos
141
+ };
142
+ }
143
+ function angleDeltaDegrees(centerX, centerY, fromX, fromY, toX, toY) {
144
+ const from = Math.atan2(fromY - centerY, fromX - centerX);
145
+ const to = Math.atan2(toY - centerY, toX - centerX);
146
+ return (to - from) * 180 / Math.PI;
147
+ }
148
+ function rotatePoint(x, y, cx, cy, angleDeg) {
149
+ const rad = angleDeg * Math.PI / 180;
150
+ const dx = x - cx;
151
+ const dy = y - cy;
152
+ return {
153
+ x: cx + dx * Math.cos(rad) - dy * Math.sin(rad),
154
+ y: cy + dx * Math.sin(rad) + dy * Math.cos(rad)
155
+ };
156
+ }
157
+ function clampBoxTranslation(bounds, dx, dy) {
158
+ return {
159
+ dx: Math.min(Math.max(dx, -bounds.left), 1 - (bounds.left + bounds.width)),
160
+ dy: Math.min(Math.max(dy, -bounds.top), 1 - (bounds.top + bounds.height))
161
+ };
162
+ }
163
+ function cssBoxToPdfDrawOrigin(left, top, width, height, visualHeight, cssRotation) {
164
+ const angle = -cssRotation;
165
+ const rad = angle * Math.PI / 180;
166
+ const centerX = left + width / 2;
167
+ const centerY = visualHeight - top - height / 2;
168
+ const hx = width / 2;
169
+ const hy = height / 2;
170
+ return {
171
+ x: centerX - (hx * Math.cos(rad) - hy * Math.sin(rad)),
172
+ y: centerY - (hx * Math.sin(rad) + hy * Math.cos(rad)),
173
+ angle
174
+ };
175
+ }
176
+
177
+ // src/lib/textLayout.ts
178
+ var TEXT_PADDING_X = 8;
179
+ var TEXT_PADDING_Y = 4;
180
+ var TEXT_LINE_HEIGHT = 1.25;
181
+ function normalizeTextNewlines(text) {
182
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
183
+ }
184
+ function wrapMeasuredLines(text, measure, maxWidth) {
185
+ const paragraphs = normalizeTextNewlines(text).split("\n");
186
+ if (maxWidth === void 0 || maxWidth <= 0) {
187
+ return paragraphs;
188
+ }
189
+ const lines = [];
190
+ for (const paragraph of paragraphs) {
191
+ if (paragraph === "") {
192
+ lines.push("");
193
+ continue;
194
+ }
195
+ const tokens = paragraph.split(/(\s+)/);
196
+ let current = "";
197
+ const pushCurrent = () => {
198
+ if (current !== "") {
199
+ lines.push(current);
200
+ current = "";
201
+ }
202
+ };
203
+ const appendBroken = (token) => {
204
+ let chunk = "";
205
+ for (const char of token) {
206
+ const trial = chunk + char;
207
+ if (chunk && measure(trial) > maxWidth) {
208
+ lines.push(chunk);
209
+ chunk = char;
210
+ } else {
211
+ chunk = trial;
212
+ }
213
+ }
214
+ current = chunk;
215
+ };
216
+ for (const token of tokens) {
217
+ if (!token) {
218
+ continue;
219
+ }
220
+ const next = current + token;
221
+ if (measure(next) <= maxWidth || current === "") {
222
+ if (current === "" && measure(token) > maxWidth) {
223
+ appendBroken(token);
224
+ continue;
225
+ }
226
+ current = next;
227
+ continue;
228
+ }
229
+ pushCurrent();
230
+ if (measure(token) > maxWidth) {
231
+ appendBroken(token);
232
+ } else {
233
+ current = /^\s+$/.test(token) ? "" : token;
234
+ }
235
+ }
236
+ pushCurrent();
237
+ }
238
+ return lines;
239
+ }
240
+ function textBoxFontCss(annotation) {
241
+ return `${annotation.fontStyle} ${annotation.fontWeight} ${annotation.fontSize}px "${annotation.fontFamily}", sans-serif`;
242
+ }
243
+
244
+ export { TEXT_LINE_HEIGHT, TEXT_PADDING_X, TEXT_PADDING_Y, angleDeltaDegrees, appendPoint, clampBoxTranslation, cssBoxToPdfDrawOrigin, hitTestStroke, normalizeDegrees, pathLength, pointerDeltaToLocal, pointsToSvgPath, rotatePoint, simplifyPoints, snapDegrees, strokeBounds, textBoxFontCss, translatePoints, wrapMeasuredLines };
245
+ //# sourceMappingURL=chunk-PAHIBB7W.js.map
246
+ //# sourceMappingURL=chunk-PAHIBB7W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/drawPaths.ts","../src/lib/geometry.ts","../src/lib/textLayout.ts"],"names":[],"mappings":";AAEA,IAAM,aAAA,GAAgB,IAAA;AACtB,IAAM,gBAAA,GAAmB,IAAA;AAEzB,SAAS,QAAA,CAAS,GAAc,CAAA,EAAc;AAC5C,EAAA,OAAO,IAAA,CAAK,MAAM,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACxC;AAEO,SAAS,WAAW,MAAA,EAAqB;AAC9C,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG;AACrD,IAAA,MAAA,IAAU,SAAS,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA,EAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,WAAA,CAAY,QAAqB,IAAA,EAA8B;AAC7E,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AACrC,EAAA,IAAI,IAAA,IAAQ,QAAA,CAAS,IAAA,EAAM,IAAI,IAAI,aAAA,EAAe;AAChD,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,CAAC,GAAG,MAAA,EAAQ,IAAI,CAAA;AACzB;AAEA,SAAS,sBAAA,CAAuB,KAAA,EAAkB,KAAA,EAAkB,GAAA,EAAgB;AAClF,EAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA;AACzB,EAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA;AACzB,EAAA,MAAM,QAAA,GAAW,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAA;AAEhC,EAAA,IAAI,aAAa,CAAA,EAAG;AAClB,IAAA,OAAO,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,EAC9B;AAEA,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA;AAAA,IACb,CAAA;AAAA,IACA,IAAA,CAAK,GAAA,CAAI,CAAA,EAAA,CAAA,CAAK,KAAA,CAAM,CAAA,GAAI,KAAA,CAAM,CAAA,IAAK,EAAA,GAAA,CAAM,KAAA,CAAM,CAAA,GAAI,KAAA,CAAM,CAAA,IAAK,MAAM,QAAQ;AAAA,GAC9E;AAEA,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,CAAA,IAAK,KAAA,CAAM,CAAA,GAAI,CAAA,GAAI,EAAA,CAAA,EAAK,KAAA,CAAM,CAAA,IAAK,KAAA,CAAM,CAAA,GAAI,IAAI,EAAA,CAAG,CAAA;AAC9E;AAEO,SAAS,cAAA,CAAe,MAAA,EAAqB,OAAA,GAAU,gBAAA,EAA+B;AAC3F,EAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACtB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AAErC,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,OAAO,MAAA,GAAS,CAAA,EAAG,SAAS,CAAA,EAAG;AACzD,IAAA,MAAM,UAAU,sBAAA,CAAuB,MAAA,CAAO,KAAK,CAAA,EAAG,OAAO,IAAI,CAAA;AACjE,IAAA,IAAI,UAAU,WAAA,EAAa;AACzB,MAAA,WAAA,GAAc,OAAA;AACd,MAAA,QAAA,GAAW,KAAA;AAAA,IACb;AAAA,EACF;AAEA,EAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,IAAA,OAAO,CAAC,OAAO,IAAI,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,IAAA,GAAO,eAAe,MAAA,CAAO,KAAA,CAAM,GAAG,QAAA,GAAW,CAAC,GAAG,OAAO,CAAA;AAClE,EAAA,MAAM,QAAQ,cAAA,CAAe,MAAA,CAAO,KAAA,CAAM,QAAQ,GAAG,OAAO,CAAA;AAC5D,EAAA,OAAO,CAAC,GAAG,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,CAAA,EAAG,GAAG,KAAK,CAAA;AACxC;AAEA,SAAS,YAAY,KAAA,EAAe;AAClC,EAAA,OAAO,KAAA,CAAM,QAAQ,CAAC,CAAA;AACxB;AAEO,SAAS,gBAAgB,MAAA,EAA6B;AAC3D,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,OAAO,KAAK,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,GAAA,EAAM,CAAC,IAAI,CAAC,CAAA,CAAA;AAAA,EAChC;AAEA,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,MAAA,GAAS,OAAO,CAAC,CAAA;AACvB,IAAA,OAAO,KAAK,WAAA,CAAY,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAI,YAAY,KAAA,CAAM,CAAC,CAAC,CAAA,GAAA,EAAM,WAAA,CAAY,OAAO,CAAC,CAAC,IAAI,WAAA,CAAY,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA;AAAA,EAC9G;AAEA,EAAA,IAAI,IAAA,GAAO,CAAA,EAAA,EAAK,WAAA,CAAY,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAE5D,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,OAAO,MAAA,GAAS,CAAA,EAAG,SAAS,CAAA,EAAG;AACzD,IAAA,MAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAC5B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA;AAC7B,IAAA,MAAM,IAAA,GAAA,CAAQ,OAAA,CAAQ,CAAA,GAAI,IAAA,CAAK,CAAA,IAAK,CAAA;AACpC,IAAA,MAAM,IAAA,GAAA,CAAQ,OAAA,CAAQ,CAAA,GAAI,IAAA,CAAK,CAAA,IAAK,CAAA;AACpC,IAAA,IAAA,IAAQ,MAAM,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAC,IAAI,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAC,IAAI,WAAA,CAAY,IAAI,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,IAAI,CAAC,CAAA,CAAA;AAAA,EAC1G;AAEA,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AACrC,EAAA,IAAA,IAAQ,CAAA,GAAA,EAAM,YAAY,IAAA,CAAK,CAAC,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,IAAA,CAAK,CAAC,CAAC,CAAA,CAAA;AACxD,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,eAAA,CAAgB,MAAA,EAAqB,EAAA,EAAY,EAAA,EAAyB;AACxF,EAAA,IAAI,EAAA,KAAO,CAAA,IAAK,EAAA,KAAO,CAAA,EAAG;AACxB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,IAC5B,CAAA,EAAG,MAAM,CAAA,GAAI,EAAA;AAAA,IACb,CAAA,EAAG,MAAM,CAAA,GAAI;AAAA,GACf,CAAE,CAAA;AACJ;AAEO,SAAS,YAAA,CAAa,MAAA,EAAqB,GAAA,GAAM,CAAA,EAAG;AACzD,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAAA,EAC/B;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,GAAG,CAAA;AAAA,IAC5B,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,GAAG,CAAA;AAAA,IAC3B,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,GAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,GAAG,CAAA;AAAA,IACvD,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,GAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,GAAG;AAAA,GAC1D;AACF;AAEO,SAAS,aAAA,CAAc,MAAA,EAAqB,KAAA,EAAkB,SAAA,EAAmB;AACtF,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,EAAG,KAAK,CAAA,IAAK,SAAA;AAAA,EACvC;AAEA,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG;AACrD,IAAA,IAAI,sBAAA,CAAuB,KAAA,EAAO,MAAA,CAAO,KAAA,GAAQ,CAAC,GAAG,MAAA,CAAO,KAAK,CAAC,CAAA,IAAK,SAAA,EAAW;AAChF,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACzJO,SAAS,iBAAiB,KAAA,EAAuB;AACtD,EAAA,OAAA,CAAS,KAAA,GAAQ,MAAO,GAAA,IAAO,GAAA;AACjC;AAEO,SAAS,WAAA,CAAY,OAAe,SAAA,EAA2B;AACpE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,SAAS,CAAA,GAAI,SAAA;AACzC;AAEO,SAAS,mBAAA,CACd,MAAA,EACA,MAAA,EACA,WAAA,EAC0B;AAC1B,EAAA,MAAM,GAAA,GAAO,WAAA,GAAc,IAAA,CAAK,EAAA,GAAM,GAAA;AACtC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,MAAA,GAAS,GAAA,GAAM,MAAA,GAAS,GAAA;AAAA,IAC3B,CAAA,EAAG,CAAC,MAAA,GAAS,GAAA,GAAM,MAAA,GAAS;AAAA,GAC9B;AACF;AAEO,SAAS,kBACd,OAAA,EACA,OAAA,EACA,KAAA,EACA,KAAA,EACA,KACA,GAAA,EACQ;AACR,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,OAAA,EAAS,QAAQ,OAAO,CAAA;AACxD,EAAA,MAAM,KAAK,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,OAAA,EAAS,MAAM,OAAO,CAAA;AAClD,EAAA,OAAA,CAAS,EAAA,GAAK,IAAA,IAAQ,GAAA,GAAO,IAAA,CAAK,EAAA;AACpC;AAEO,SAAS,WAAA,CACd,CAAA,EACA,CAAA,EACA,EAAA,EACA,IACA,QAAA,EAC0B;AAC1B,EAAA,MAAM,GAAA,GAAO,QAAA,GAAW,IAAA,CAAK,EAAA,GAAM,GAAA;AACnC,EAAA,MAAM,KAAK,CAAA,GAAI,EAAA;AACf,EAAA,MAAM,KAAK,CAAA,GAAI,EAAA;AACf,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,EAAA,GAAK,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAAA,IAC9C,CAAA,EAAG,EAAA,GAAK,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG;AAAA,GAChD;AACF;AAEO,SAAS,mBAAA,CACd,MAAA,EACA,EAAA,EACA,EAAA,EACA;AACA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,EAAA,EAAI,CAAC,MAAA,CAAO,IAAI,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,IAAA,GAAO,OAAO,KAAA,CAAM,CAAA;AAAA,IACzE,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,EAAA,EAAI,CAAC,MAAA,CAAO,GAAG,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,GAAA,GAAM,OAAO,MAAA,CAAO;AAAA,GAC1E;AACF;AAGO,SAAS,sBACd,IAAA,EACA,GAAA,EACA,KAAA,EACA,MAAA,EACA,cACA,WAAA,EACyC;AACzC,EAAA,MAAM,QAAQ,CAAC,WAAA;AACf,EAAA,MAAM,GAAA,GAAO,KAAA,GAAQ,IAAA,CAAK,EAAA,GAAM,GAAA;AAChC,EAAA,MAAM,OAAA,GAAU,OAAO,KAAA,GAAQ,CAAA;AAC/B,EAAA,MAAM,OAAA,GAAU,YAAA,GAAe,GAAA,GAAM,MAAA,GAAS,CAAA;AAC9C,EAAA,MAAM,KAAK,KAAA,GAAQ,CAAA;AACnB,EAAA,MAAM,KAAK,MAAA,GAAS,CAAA;AAEpB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,OAAA,IAAW,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,CAAA;AAAA,IACpD,CAAA,EAAG,OAAA,IAAW,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,CAAA;AAAA,IACpD;AAAA,GACF;AACF;;;ACnFO,IAAM,cAAA,GAAiB;AACvB,IAAM,cAAA,GAAiB;AACvB,IAAM,gBAAA,GAAmB;AAEzB,SAAS,sBAAsB,IAAA,EAAsB;AAC1D,EAAA,OAAO,KAAK,OAAA,CAAQ,OAAA,EAAS,IAAI,CAAA,CAAE,OAAA,CAAQ,OAAO,IAAI,CAAA;AACxD;AAEO,SAAS,iBAAA,CACd,IAAA,EACA,OAAA,EACA,QAAA,EACU;AACV,EAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,IAAI,CAAA,CAAE,MAAM,IAAI,CAAA;AAEzD,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,IAAY,CAAA,EAAG;AAC3C,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,IAAI,cAAc,EAAA,EAAI;AACpB,MAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,KAAA,CAAM,OAAO,CAAA;AACtC,IAAA,IAAI,OAAA,GAAU,EAAA;AAEd,IAAA,MAAM,cAAc,MAAM;AACxB,MAAA,IAAI,YAAY,EAAA,EAAI;AAClB,QAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAClB,QAAA,OAAA,GAAU,EAAA;AAAA,MACZ;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAAkB;AACtC,MAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,MAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,QAAA,MAAM,QAAQ,KAAA,GAAQ,IAAA;AACtB,QAAA,IAAI,KAAA,IAAS,OAAA,CAAQ,KAAK,CAAA,GAAI,QAAA,EAAU;AACtC,UAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,UAAA,KAAA,GAAQ,IAAA;AAAA,QACV,CAAA,MAAO;AACL,UAAA,KAAA,GAAQ,KAAA;AAAA,QACV;AAAA,MACF;AACA,MAAA,OAAA,GAAU,KAAA;AAAA,IACZ,CAAA;AAEA,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,OAAO,OAAA,GAAU,KAAA;AACvB,MAAA,IAAI,OAAA,CAAQ,IAAI,CAAA,IAAK,QAAA,IAAY,YAAY,EAAA,EAAI;AAC/C,QAAA,IAAI,OAAA,KAAY,EAAA,IAAM,OAAA,CAAQ,KAAK,IAAI,QAAA,EAAU;AAC/C,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA;AAAA,QACF;AACA,QAAA,OAAA,GAAU,IAAA;AACV,QAAA;AAAA,MACF;AAEA,MAAA,WAAA,EAAY;AACZ,MAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,GAAI,QAAA,EAAU;AAC7B,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB,CAAA,MAAO;AACL,QAAA,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,GAAI,EAAA,GAAK,KAAA;AAAA,MACvC;AAAA,IACF;AAEA,IAAA,WAAA,EAAY;AAAA,EACd;AAEA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,eAAe,UAAA,EAKpB;AACT,EAAA,OAAO,CAAA,EAAG,UAAA,CAAW,SAAS,CAAA,CAAA,EAAI,UAAA,CAAW,UAAU,CAAA,CAAA,EAAI,UAAA,CAAW,QAAQ,CAAA,IAAA,EAAO,UAAA,CAAW,UAAU,CAAA,aAAA,CAAA;AAC5G","file":"chunk-PAHIBB7W.js","sourcesContent":["import type { DrawPoint } from \"../types\";\r\n\r\nconst MIN_POINT_GAP = 0.002;\r\nconst SIMPLIFY_EPSILON = 0.003;\r\n\r\nfunction distance(a: DrawPoint, b: DrawPoint) {\r\n return Math.hypot(b.x - a.x, b.y - a.y);\r\n}\r\n\r\nexport function pathLength(points: DrawPoint[]) {\r\n let length = 0;\r\n for (let index = 1; index < points.length; index += 1) {\r\n length += distance(points[index - 1], points[index]);\r\n }\r\n return length;\r\n}\r\n\r\nexport function appendPoint(points: DrawPoint[], next: DrawPoint): DrawPoint[] {\r\n const last = points[points.length - 1];\r\n if (last && distance(last, next) < MIN_POINT_GAP) {\r\n return points;\r\n }\r\n return [...points, next];\r\n}\r\n\r\nfunction pointToSegmentDistance(point: DrawPoint, start: DrawPoint, end: DrawPoint) {\r\n const dx = end.x - start.x;\r\n const dy = end.y - start.y;\r\n const lengthSq = dx * dx + dy * dy;\r\n\r\n if (lengthSq === 0) {\r\n return distance(point, start);\r\n }\r\n\r\n const t = Math.max(\r\n 0,\r\n Math.min(1, ((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSq),\r\n );\r\n\r\n return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));\r\n}\r\n\r\nexport function simplifyPoints(points: DrawPoint[], epsilon = SIMPLIFY_EPSILON): DrawPoint[] {\r\n if (points.length <= 2) {\r\n return points;\r\n }\r\n\r\n let maxDistance = 0;\r\n let maxIndex = 0;\r\n const first = points[0];\r\n const last = points[points.length - 1];\r\n\r\n for (let index = 1; index < points.length - 1; index += 1) {\r\n const current = pointToSegmentDistance(points[index], first, last);\r\n if (current > maxDistance) {\r\n maxDistance = current;\r\n maxIndex = index;\r\n }\r\n }\r\n\r\n if (maxDistance <= epsilon) {\r\n return [first, last];\r\n }\r\n\r\n const left = simplifyPoints(points.slice(0, maxIndex + 1), epsilon);\r\n const right = simplifyPoints(points.slice(maxIndex), epsilon);\r\n return [...left.slice(0, -1), ...right];\r\n}\r\n\r\nfunction formatCoord(value: number) {\r\n return value.toFixed(4);\r\n}\r\n\r\nexport function pointsToSvgPath(points: DrawPoint[]): string {\r\n if (points.length === 0) {\r\n return \"\";\r\n }\r\n\r\n const first = points[0];\r\n if (points.length === 1) {\r\n const x = formatCoord(first.x);\r\n const y = formatCoord(first.y);\r\n return `M ${x} ${y} L ${x} ${y}`;\r\n }\r\n\r\n if (points.length === 2) {\r\n const second = points[1];\r\n return `M ${formatCoord(first.x)} ${formatCoord(first.y)} L ${formatCoord(second.x)} ${formatCoord(second.y)}`;\r\n }\r\n\r\n let path = `M ${formatCoord(first.x)} ${formatCoord(first.y)}`;\r\n\r\n for (let index = 1; index < points.length - 1; index += 1) {\r\n const current = points[index];\r\n const next = points[index + 1];\r\n const midX = (current.x + next.x) / 2;\r\n const midY = (current.y + next.y) / 2;\r\n path += ` Q ${formatCoord(current.x)} ${formatCoord(current.y)} ${formatCoord(midX)} ${formatCoord(midY)}`;\r\n }\r\n\r\n const last = points[points.length - 1];\r\n path += ` T ${formatCoord(last.x)} ${formatCoord(last.y)}`;\r\n return path;\r\n}\r\n\r\nexport function translatePoints(points: DrawPoint[], dx: number, dy: number): DrawPoint[] {\r\n if (dx === 0 && dy === 0) {\r\n return points;\r\n }\r\n\r\n return points.map((point) => ({\r\n x: point.x + dx,\r\n y: point.y + dy,\r\n }));\r\n}\r\n\r\nexport function strokeBounds(points: DrawPoint[], pad = 0) {\r\n let minX = 1;\r\n let minY = 1;\r\n let maxX = 0;\r\n let maxY = 0;\r\n\r\n for (const point of points) {\r\n minX = Math.min(minX, point.x);\r\n minY = Math.min(minY, point.y);\r\n maxX = Math.max(maxX, point.x);\r\n maxY = Math.max(maxY, point.y);\r\n }\r\n\r\n return {\r\n left: Math.max(0, minX - pad),\r\n top: Math.max(0, minY - pad),\r\n width: Math.min(1, maxX + pad) - Math.max(0, minX - pad),\r\n height: Math.min(1, maxY + pad) - Math.max(0, minY - pad),\r\n };\r\n}\r\n\r\nexport function hitTestStroke(points: DrawPoint[], point: DrawPoint, threshold: number) {\r\n if (points.length === 0) {\r\n return false;\r\n }\r\n\r\n if (points.length === 1) {\r\n return distance(points[0], point) <= threshold;\r\n }\r\n\r\n for (let index = 1; index < points.length; index += 1) {\r\n if (pointToSegmentDistance(point, points[index - 1], points[index]) <= threshold) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n","export function normalizeDegrees(angle: number): number {\r\n return ((angle % 360) + 360) % 360;\r\n}\r\n\r\nexport function snapDegrees(angle: number, increment: number): number {\r\n return Math.round(angle / increment) * increment;\r\n}\r\n\r\nexport function pointerDeltaToLocal(\r\n deltaX: number,\r\n deltaY: number,\r\n rotationDeg: number,\r\n): { x: number; y: number } {\r\n const rad = (rotationDeg * Math.PI) / 180;\r\n const cos = Math.cos(rad);\r\n const sin = Math.sin(rad);\r\n return {\r\n x: deltaX * cos + deltaY * sin,\r\n y: -deltaX * sin + deltaY * cos,\r\n };\r\n}\r\n\r\nexport function angleDeltaDegrees(\r\n centerX: number,\r\n centerY: number,\r\n fromX: number,\r\n fromY: number,\r\n toX: number,\r\n toY: number,\r\n): number {\r\n const from = Math.atan2(fromY - centerY, fromX - centerX);\r\n const to = Math.atan2(toY - centerY, toX - centerX);\r\n return ((to - from) * 180) / Math.PI;\r\n}\r\n\r\nexport function rotatePoint(\r\n x: number,\r\n y: number,\r\n cx: number,\r\n cy: number,\r\n angleDeg: number,\r\n): { x: number; y: number } {\r\n const rad = (angleDeg * Math.PI) / 180;\r\n const dx = x - cx;\r\n const dy = y - cy;\r\n return {\r\n x: cx + dx * Math.cos(rad) - dy * Math.sin(rad),\r\n y: cy + dx * Math.sin(rad) + dy * Math.cos(rad),\r\n };\r\n}\r\n\r\nexport function clampBoxTranslation(\r\n bounds: { left: number; top: number; width: number; height: number },\r\n dx: number,\r\n dy: number,\r\n) {\r\n return {\r\n dx: Math.min(Math.max(dx, -bounds.left), 1 - (bounds.left + bounds.width)),\r\n dy: Math.min(Math.max(dy, -bounds.top), 1 - (bounds.top + bounds.height)),\r\n };\r\n}\r\n\r\n/** CSS clockwise rotation around center → PDF draw origin (y-up) and PDF angle. */\r\nexport function cssBoxToPdfDrawOrigin(\r\n left: number,\r\n top: number,\r\n width: number,\r\n height: number,\r\n visualHeight: number,\r\n cssRotation: number,\r\n): { x: number; y: number; angle: number } {\r\n const angle = -cssRotation;\r\n const rad = (angle * Math.PI) / 180;\r\n const centerX = left + width / 2;\r\n const centerY = visualHeight - top - height / 2;\r\n const hx = width / 2;\r\n const hy = height / 2;\r\n\r\n return {\r\n x: centerX - (hx * Math.cos(rad) - hy * Math.sin(rad)),\r\n y: centerY - (hx * Math.sin(rad) + hy * Math.cos(rad)),\r\n angle,\r\n };\r\n}\r\n","export const TEXT_PADDING_X = 8;\r\nexport const TEXT_PADDING_Y = 4;\r\nexport const TEXT_LINE_HEIGHT = 1.25;\r\n\r\nexport function normalizeTextNewlines(text: string): string {\r\n return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\r\n}\r\n\r\nexport function wrapMeasuredLines(\r\n text: string,\r\n measure: (value: string) => number,\r\n maxWidth?: number,\r\n): string[] {\r\n const paragraphs = normalizeTextNewlines(text).split(\"\\n\");\r\n\r\n if (maxWidth === undefined || maxWidth <= 0) {\r\n return paragraphs;\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n for (const paragraph of paragraphs) {\r\n if (paragraph === \"\") {\r\n lines.push(\"\");\r\n continue;\r\n }\r\n\r\n const tokens = paragraph.split(/(\\s+)/);\r\n let current = \"\";\r\n\r\n const pushCurrent = () => {\r\n if (current !== \"\") {\r\n lines.push(current);\r\n current = \"\";\r\n }\r\n };\r\n\r\n const appendBroken = (token: string) => {\r\n let chunk = \"\";\r\n for (const char of token) {\r\n const trial = chunk + char;\r\n if (chunk && measure(trial) > maxWidth) {\r\n lines.push(chunk);\r\n chunk = char;\r\n } else {\r\n chunk = trial;\r\n }\r\n }\r\n current = chunk;\r\n };\r\n\r\n for (const token of tokens) {\r\n if (!token) {\r\n continue;\r\n }\r\n\r\n const next = current + token;\r\n if (measure(next) <= maxWidth || current === \"\") {\r\n if (current === \"\" && measure(token) > maxWidth) {\r\n appendBroken(token);\r\n continue;\r\n }\r\n current = next;\r\n continue;\r\n }\r\n\r\n pushCurrent();\r\n if (measure(token) > maxWidth) {\r\n appendBroken(token);\r\n } else {\r\n current = /^\\s+$/.test(token) ? \"\" : token;\r\n }\r\n }\r\n\r\n pushCurrent();\r\n }\r\n\r\n return lines;\r\n}\r\n\r\nexport function textBoxFontCss(annotation: {\r\n fontStyle: string;\r\n fontWeight: string;\r\n fontSize: number;\r\n fontFamily: string;\r\n}): string {\r\n return `${annotation.fontStyle} ${annotation.fontWeight} ${annotation.fontSize}px \"${annotation.fontFamily}\", sans-serif`;\r\n}\r\n"]}
@@ -0,0 +1,341 @@
1
+ import { TEXT_PADDING_X, TEXT_LINE_HEIGHT, TEXT_PADDING_Y, rotatePoint, pointsToSvgPath, cssBoxToPdfDrawOrigin, wrapMeasuredLines } from './chunk-PAHIBB7W.js';
2
+ import { PDFDocument, StandardFonts, degrees, LineCapStyle, rgb } from 'pdf-lib';
3
+
4
+ var WINANSI_REPLACEMENTS = {
5
+ "\u2018": "'",
6
+ "\u2019": "'",
7
+ "\u201C": '"',
8
+ "\u201D": '"',
9
+ "\u2013": "-",
10
+ "\u2014": "-",
11
+ "\u2026": "...",
12
+ "\xA0": " "
13
+ };
14
+ function parseColor(value) {
15
+ const hex = value.trim().replace("#", "");
16
+ const normalized = hex.length === 3 ? hex.split("").map((part) => part + part).join("") : hex.padEnd(6, "0").slice(0, 6);
17
+ const red = Number.parseInt(normalized.slice(0, 2), 16);
18
+ const green = Number.parseInt(normalized.slice(2, 4), 16);
19
+ const blue = Number.parseInt(normalized.slice(4, 6), 16);
20
+ return rgb(
21
+ (Number.isFinite(red) ? red : 0) / 255,
22
+ (Number.isFinite(green) ? green : 0) / 255,
23
+ (Number.isFinite(blue) ? blue : 0) / 255
24
+ );
25
+ }
26
+ function resolveStandardFont(family, weight, style) {
27
+ const isBold = weight === "bold";
28
+ const isItalic = style === "italic";
29
+ const lower = family.toLowerCase();
30
+ const isTimes = lower.includes("times") || lower.includes("georgia");
31
+ const isCourier = lower.includes("courier");
32
+ if (isTimes) {
33
+ if (isBold && isItalic) return StandardFonts.TimesRomanBoldItalic;
34
+ if (isBold) return StandardFonts.TimesRomanBold;
35
+ if (isItalic) return StandardFonts.TimesRomanItalic;
36
+ return StandardFonts.TimesRoman;
37
+ }
38
+ if (isCourier) {
39
+ if (isBold && isItalic) return StandardFonts.CourierBoldOblique;
40
+ if (isBold) return StandardFonts.CourierBold;
41
+ if (isItalic) return StandardFonts.CourierOblique;
42
+ return StandardFonts.Courier;
43
+ }
44
+ if (isBold && isItalic) return StandardFonts.HelveticaBoldOblique;
45
+ if (isBold) return StandardFonts.HelveticaBold;
46
+ if (isItalic) return StandardFonts.HelveticaOblique;
47
+ return StandardFonts.Helvetica;
48
+ }
49
+ function toWinAnsi(text) {
50
+ let result = "";
51
+ for (const char of text) {
52
+ if (char === " ") {
53
+ result += " ";
54
+ continue;
55
+ }
56
+ if (char === "\n") {
57
+ result += "\n";
58
+ continue;
59
+ }
60
+ if (char === "\r") {
61
+ continue;
62
+ }
63
+ const replacement = WINANSI_REPLACEMENTS[char];
64
+ if (replacement) {
65
+ result += replacement;
66
+ continue;
67
+ }
68
+ const code = char.charCodeAt(0);
69
+ if (code < 32) {
70
+ continue;
71
+ }
72
+ result += code <= 255 ? char : "?";
73
+ }
74
+ return result;
75
+ }
76
+ function wrapText(text, font, fontSize, maxWidth) {
77
+ return wrapMeasuredLines(
78
+ toWinAnsi(text),
79
+ (value) => font.widthOfTextAtSize(value, fontSize),
80
+ maxWidth
81
+ );
82
+ }
83
+ function normalizeRotation(angle) {
84
+ return (angle % 360 + 360) % 360;
85
+ }
86
+ function getVisualSize(page) {
87
+ const { width, height } = page.getSize();
88
+ const rotation = normalizeRotation(page.getRotation().angle);
89
+ if (rotation === 90 || rotation === 270) {
90
+ return { width: height, height: width };
91
+ }
92
+ return { width, height };
93
+ }
94
+ function visualToPdf(page, visualX, visualYFromBottom) {
95
+ const { width, height } = page.getSize();
96
+ const rotation = normalizeRotation(page.getRotation().angle);
97
+ switch (rotation) {
98
+ case 90:
99
+ return { x: width - visualYFromBottom, y: visualX };
100
+ case 180:
101
+ return { x: width - visualX, y: height - visualYFromBottom };
102
+ case 270:
103
+ return { x: visualYFromBottom, y: height - visualX };
104
+ default:
105
+ return { x: visualX, y: visualYFromBottom };
106
+ }
107
+ }
108
+ var HIGHLIGHT_OPACITY = 0.38;
109
+ function drawHighlight(page, highlight) {
110
+ const visual = getVisualSize(page);
111
+ const color = parseColor(highlight.color);
112
+ for (const rect of highlight.rects) {
113
+ const left = rect.left * visual.width;
114
+ const top = rect.top * visual.height;
115
+ const width = rect.width * visual.width;
116
+ const height = rect.height * visual.height;
117
+ const corners = [
118
+ visualToPdf(page, left, visual.height - top),
119
+ visualToPdf(page, left + width, visual.height - top),
120
+ visualToPdf(page, left, visual.height - top - height),
121
+ visualToPdf(page, left + width, visual.height - top - height)
122
+ ];
123
+ const xs = corners.map((corner) => corner.x);
124
+ const ys = corners.map((corner) => corner.y);
125
+ const x = Math.min(...xs);
126
+ const y = Math.min(...ys);
127
+ page.drawRectangle({
128
+ x,
129
+ y,
130
+ width: Math.max(0, Math.max(...xs) - x),
131
+ height: Math.max(0, Math.max(...ys) - y),
132
+ color,
133
+ opacity: HIGHLIGHT_OPACITY,
134
+ borderWidth: 0
135
+ });
136
+ }
137
+ }
138
+ function drawStroke(page, stroke) {
139
+ if (stroke.points.length === 0) {
140
+ return;
141
+ }
142
+ const visual = getVisualSize(page);
143
+ const pdfPoints = stroke.points.map((point) => {
144
+ const visualX = point.x * visual.width;
145
+ const visualYFromTop = point.y * visual.height;
146
+ const pdfPoint = visualToPdf(page, visualX, visual.height - visualYFromTop);
147
+ return { x: pdfPoint.x, y: -pdfPoint.y };
148
+ });
149
+ const path = pointsToSvgPath(pdfPoints);
150
+ if (!path) {
151
+ return;
152
+ }
153
+ page.drawSvgPath(path, {
154
+ x: 0,
155
+ y: 0,
156
+ borderColor: parseColor(stroke.color),
157
+ borderWidth: stroke.width,
158
+ borderLineCap: LineCapStyle.Round
159
+ });
160
+ }
161
+ function dataUrlToBytes(dataUrl) {
162
+ const comma = dataUrl.indexOf(",");
163
+ const base64 = comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl;
164
+ const binary = atob(base64);
165
+ const bytes = new Uint8Array(binary.length);
166
+ for (let index = 0; index < binary.length; index += 1) {
167
+ bytes[index] = binary.charCodeAt(index);
168
+ }
169
+ return bytes;
170
+ }
171
+ function dataUrlKind(src) {
172
+ if (src.startsWith("data:image/jpeg") || src.startsWith("data:image/jpg")) {
173
+ return "jpg";
174
+ }
175
+ return "png";
176
+ }
177
+ function drawPlacedImage(page, box, image) {
178
+ const visual = getVisualSize(page);
179
+ const left = box.x * visual.width;
180
+ const top = box.y * visual.height;
181
+ const width = box.width * visual.width;
182
+ const height = box.height * visual.height;
183
+ const pageRotation = normalizeRotation(page.getRotation().angle);
184
+ const origin = cssBoxToPdfDrawOrigin(
185
+ left,
186
+ top,
187
+ width,
188
+ height,
189
+ visual.height,
190
+ box.rotation ?? 0
191
+ );
192
+ const point = visualToPdf(page, origin.x, origin.y);
193
+ page.drawImage(image, {
194
+ x: point.x,
195
+ y: point.y,
196
+ width,
197
+ height,
198
+ rotate: degrees(normalizeRotation(pageRotation + origin.angle)),
199
+ opacity: box.opacity ?? 1
200
+ });
201
+ }
202
+ function drawAnnotation(page, annotation, font) {
203
+ if (!annotation.text) {
204
+ return;
205
+ }
206
+ const visual = getVisualSize(page);
207
+ const boxLeft = annotation.x * visual.width;
208
+ const boxTop = annotation.y * visual.height;
209
+ const boxWidth = annotation.width !== void 0 ? annotation.width * visual.width : void 0;
210
+ const maxTextWidth = boxWidth !== void 0 ? Math.max(0, boxWidth - TEXT_PADDING_X * 2) : void 0;
211
+ const lines = wrapText(
212
+ annotation.text,
213
+ font,
214
+ annotation.fontSize,
215
+ maxTextWidth
216
+ );
217
+ const color = parseColor(annotation.color);
218
+ const pageRotation = normalizeRotation(page.getRotation().angle);
219
+ const cssRotation = annotation.rotation ?? 0;
220
+ const pdfAngle = -cssRotation;
221
+ const resolvedWidth = boxWidth ?? Math.max(
222
+ ...lines.map((line) => line ? font.widthOfTextAtSize(line, annotation.fontSize) : 0),
223
+ 0
224
+ ) + TEXT_PADDING_X * 2;
225
+ const lineBox = annotation.fontSize * TEXT_LINE_HEIGHT;
226
+ const resolvedHeight = annotation.height !== void 0 ? annotation.height * visual.height : TEXT_PADDING_Y * 2 + Math.max(lines.length, 1) * lineBox;
227
+ const ascent = font.heightAtSize(annotation.fontSize, { descender: false });
228
+ const fontHeight = font.heightAtSize(annotation.fontSize);
229
+ const halfLeading = (lineBox - fontHeight) / 2;
230
+ const centerX = boxLeft + resolvedWidth / 2;
231
+ const centerY = visual.height - boxTop - resolvedHeight / 2;
232
+ lines.forEach((line, index) => {
233
+ const lineWidth = line ? font.widthOfTextAtSize(line, annotation.fontSize) : 0;
234
+ let textX = boxLeft + TEXT_PADDING_X;
235
+ if (boxWidth !== void 0) {
236
+ if (annotation.textAlign === "center") {
237
+ textX = boxLeft + (boxWidth - lineWidth) / 2;
238
+ } else if (annotation.textAlign === "right") {
239
+ textX = boxLeft + boxWidth - TEXT_PADDING_X - lineWidth;
240
+ }
241
+ }
242
+ const lineTop = TEXT_PADDING_Y + index * lineBox;
243
+ if (lineTop + lineBox > resolvedHeight + 0.5) {
244
+ return;
245
+ }
246
+ const textTop = boxTop + lineTop + halfLeading + ascent;
247
+ const origin = rotatePoint(
248
+ textX,
249
+ visual.height - textTop,
250
+ centerX,
251
+ centerY,
252
+ pdfAngle
253
+ );
254
+ const point = visualToPdf(page, origin.x, origin.y);
255
+ if (!line) {
256
+ return;
257
+ }
258
+ page.drawText(line, {
259
+ x: point.x,
260
+ y: point.y,
261
+ size: annotation.fontSize,
262
+ font,
263
+ color,
264
+ rotate: degrees(normalizeRotation(pageRotation + pdfAngle))
265
+ });
266
+ });
267
+ }
268
+ async function exportPdfBytes(pdfBytes, annotations, drawings = [], highlights = [], signatures = [], images = []) {
269
+ if (annotations.length === 0 && drawings.length === 0 && highlights.length === 0 && signatures.length === 0 && images.length === 0) {
270
+ return pdfBytes.slice();
271
+ }
272
+ const pdf = await PDFDocument.load(pdfBytes);
273
+ const fontCache = /* @__PURE__ */ new Map();
274
+ const embedFont = async (key) => {
275
+ const cached = fontCache.get(key);
276
+ if (cached) {
277
+ return cached;
278
+ }
279
+ const font = await pdf.embedFont(key);
280
+ fontCache.set(key, font);
281
+ return font;
282
+ };
283
+ const pageCount = pdf.getPageCount();
284
+ for (const highlight of highlights) {
285
+ if (highlight.pageNumber < 1 || highlight.pageNumber > pageCount) {
286
+ continue;
287
+ }
288
+ drawHighlight(pdf.getPage(highlight.pageNumber - 1), highlight);
289
+ }
290
+ for (const annotation of annotations) {
291
+ if (annotation.pageNumber < 1 || annotation.pageNumber > pageCount) {
292
+ continue;
293
+ }
294
+ const page = pdf.getPage(annotation.pageNumber - 1);
295
+ const fontKey = resolveStandardFont(
296
+ annotation.fontFamily,
297
+ annotation.fontWeight,
298
+ annotation.fontStyle
299
+ );
300
+ const font = await embedFont(fontKey);
301
+ drawAnnotation(page, annotation, font);
302
+ }
303
+ for (const stroke of drawings) {
304
+ if (stroke.pageNumber < 1 || stroke.pageNumber > pageCount) {
305
+ continue;
306
+ }
307
+ const page = pdf.getPage(stroke.pageNumber - 1);
308
+ drawStroke(page, stroke);
309
+ }
310
+ const imageCache = /* @__PURE__ */ new Map();
311
+ const embedPlacedImage = async (src) => {
312
+ const cached = imageCache.get(src);
313
+ if (cached) {
314
+ return cached;
315
+ }
316
+ const bytes = dataUrlToBytes(src);
317
+ const image = dataUrlKind(src) === "jpg" ? await pdf.embedJpg(bytes) : await pdf.embedPng(bytes);
318
+ imageCache.set(src, image);
319
+ return image;
320
+ };
321
+ for (const signature of signatures) {
322
+ if (signature.pageNumber < 1 || signature.pageNumber > pageCount) {
323
+ continue;
324
+ }
325
+ const image = await embedPlacedImage(signature.src);
326
+ drawPlacedImage(pdf.getPage(signature.pageNumber - 1), signature, image);
327
+ }
328
+ for (const placed of images) {
329
+ if (placed.pageNumber < 1 || placed.pageNumber > pageCount) {
330
+ continue;
331
+ }
332
+ const image = await embedPlacedImage(placed.src);
333
+ drawPlacedImage(pdf.getPage(placed.pageNumber - 1), placed, image);
334
+ }
335
+ const saved = await pdf.save({ useObjectStreams: true });
336
+ return saved instanceof Uint8Array ? saved : new Uint8Array(saved);
337
+ }
338
+
339
+ export { exportPdfBytes };
340
+ //# sourceMappingURL=exportPdf-USRSK72H.js.map
341
+ //# sourceMappingURL=exportPdf-USRSK72H.js.map