@reekon-tools/boldr-utils 1.23.0 → 1.24.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/dist/annotation/canvas/pdfCanvasPages.d.ts +25 -0
- package/dist/annotation/canvas/pdfCanvasPages.js +255 -0
- package/dist/annotation/data/AnnotationDataProvider.d.ts +6 -0
- package/dist/annotation/data/InMemoryAnnotationProvider.d.ts +6 -0
- package/dist/annotation/data/InMemoryAnnotationProvider.js +25 -0
- package/dist/annotation/data/hooks/usePdfCanvasDoc.d.ts +29 -0
- package/dist/annotation/data/hooks/usePdfCanvasDoc.js +344 -0
- package/dist/export/pdf/index.d.ts +2 -2
- package/dist/export/pdf/index.js +1 -1
- package/dist/export/pdf/renderCanvasToPdf.d.ts +9 -1
- package/dist/export/pdf/renderCanvasToPdf.js +209 -113
- package/dist/export/pdf/types.d.ts +13 -0
- package/dist/exports.d.ts +3 -0
- package/dist/exports.js +3 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2 -0
- package/dist/types/firestore.d.ts +6 -0
- package/dist/types/firestore.js +5 -0
- package/dist/types/pdfCanvas.d.ts +38 -0
- package/dist/types/pdfCanvas.js +16 -0
- package/package.json +1 -1
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { applyPatch, createEmptyCanvasState, } from '../../../types/annotation.js';
|
|
3
|
+
import { canvasStateToPageState, pageStateToCanvasState, pdfCanvasKnobsEqual, pdfCanvasKnobsOf, pdfPageDisplaySize, rotatePageState, rotatePdfCanvasPage, } from '../../canvas/pdfCanvasPages.js';
|
|
4
|
+
import { useAnnotationData } from '../AnnotationDataContext.js';
|
|
5
|
+
import { annotationScopeKey, } from '../AnnotationDataProvider.js';
|
|
6
|
+
import { createCoalescedRunner } from '../coalescedRunner.js';
|
|
7
|
+
import { useAnnotationDoc } from './useAnnotationDoc.js';
|
|
8
|
+
const makeClientId = () => `${Date.now().toString(36)}-${Math.floor(Math.random() * 0x100000000).toString(36)}`;
|
|
9
|
+
const hasContent = (canvas) => canvas.strokes.length > 0 ||
|
|
10
|
+
canvas.shapes.length > 0 ||
|
|
11
|
+
canvas.placedMeasurements.length > 0 ||
|
|
12
|
+
(canvas.planes?.length ?? 0) > 0;
|
|
13
|
+
// Drop undefined keys (Firestore — RN in particular — rejects them) and detach
|
|
14
|
+
// the persisted payload from the working state's object identities.
|
|
15
|
+
const jsonClone = (value) => JSON.parse(JSON.stringify(value));
|
|
16
|
+
// Load + explicit-save orchestration for ONE page of a PdfCanvas file. The
|
|
17
|
+
// canvas engine is page-agnostic: this hook hands it the page's state as an
|
|
18
|
+
// ordinary AnnotationCanvasState (pageStateToCanvasState) and persists it back
|
|
19
|
+
// as a page doc. Mirrors useAnnotationCanvasDoc's echo suppression (a `rev`
|
|
20
|
+
// stamped with this session's clientId) and single-flight flushing.
|
|
21
|
+
export const usePdfCanvasDoc = (options) => {
|
|
22
|
+
const { scope, fileId, pageIndex, onSaveError, captureThumbnail, debugLogging = false, } = options;
|
|
23
|
+
const provider = useAnnotationData();
|
|
24
|
+
const { data: file, loading: fileLoading, error: fileError, } = useAnnotationDoc(scope, fileId);
|
|
25
|
+
const pdfCanvas = file?.fileData.pdfCanvas ?? null;
|
|
26
|
+
const [pageDoc, setPageDoc] = useState(null);
|
|
27
|
+
const [pageLoading, setPageLoading] = useState(true);
|
|
28
|
+
const [pageError, setPageError] = useState(null);
|
|
29
|
+
const [working, setWorking] = useState(null);
|
|
30
|
+
const [saveStatus, setSaveStatus] = useState('idle');
|
|
31
|
+
const workingRef = useRef(null);
|
|
32
|
+
const pdfCanvasRef = useRef(null);
|
|
33
|
+
const pageDocRef = useRef(null);
|
|
34
|
+
const statusRef = useRef('idle');
|
|
35
|
+
const pageIndexRef = useRef(pageIndex);
|
|
36
|
+
const scopeRef = useRef(scope);
|
|
37
|
+
const fileIdRef = useRef(fileId);
|
|
38
|
+
const onSaveErrorRef = useRef(onSaveError);
|
|
39
|
+
const captureThumbnailRef = useRef(captureThumbnail);
|
|
40
|
+
const debugRef = useRef(debugLogging);
|
|
41
|
+
const clientIdRef = useRef(null);
|
|
42
|
+
if (clientIdRef.current === null)
|
|
43
|
+
clientIdRef.current = makeClientId();
|
|
44
|
+
const writeSeqRef = useRef(0);
|
|
45
|
+
const editSeqRef = useRef(0);
|
|
46
|
+
const thumbnailSavingRef = useRef(false);
|
|
47
|
+
const thumbnailRequestedRef = useRef(false);
|
|
48
|
+
const thumbnailPromiseRef = useRef(undefined);
|
|
49
|
+
// A page whose edits must be persisted although it is no longer the current
|
|
50
|
+
// page (the user turned the page with unsaved edits).
|
|
51
|
+
const outgoingRef = useRef(null);
|
|
52
|
+
workingRef.current = working;
|
|
53
|
+
pdfCanvasRef.current = pdfCanvas;
|
|
54
|
+
pageDocRef.current = pageDoc;
|
|
55
|
+
statusRef.current = saveStatus;
|
|
56
|
+
scopeRef.current = scope;
|
|
57
|
+
fileIdRef.current = fileId;
|
|
58
|
+
onSaveErrorRef.current = onSaveError;
|
|
59
|
+
captureThumbnailRef.current = captureThumbnail;
|
|
60
|
+
debugRef.current = debugLogging;
|
|
61
|
+
const setStatus = useCallback((next) => {
|
|
62
|
+
statusRef.current = next;
|
|
63
|
+
setSaveStatus(next);
|
|
64
|
+
}, []);
|
|
65
|
+
// Subscribe to the current page's doc.
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (!scope || !fileId) {
|
|
68
|
+
setPageDoc(null);
|
|
69
|
+
setPageLoading(false);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
setPageLoading(true);
|
|
73
|
+
setPageError(null);
|
|
74
|
+
const unsubscribe = provider.subscribePage(scope, fileId, pageIndex, (doc) => {
|
|
75
|
+
setPageDoc(doc);
|
|
76
|
+
setPageLoading(false);
|
|
77
|
+
}, (err) => {
|
|
78
|
+
setPageError(err);
|
|
79
|
+
setPageLoading(false);
|
|
80
|
+
});
|
|
81
|
+
return unsubscribe;
|
|
82
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
|
+
}, [provider, annotationScopeKey(scope), fileId, pageIndex]);
|
|
84
|
+
// Persist one page: the page doc, then whatever file-level fields it moved
|
|
85
|
+
// (first-annotation marker, tile knobs). Returns normally on failure after
|
|
86
|
+
// reporting it — callers read the status, not a rejection.
|
|
87
|
+
const persist = useCallback(async (target) => {
|
|
88
|
+
const currentScope = scopeRef.current;
|
|
89
|
+
const currentFileId = fileIdRef.current;
|
|
90
|
+
if (!currentScope || !currentFileId)
|
|
91
|
+
return false;
|
|
92
|
+
const rev = {
|
|
93
|
+
clientId: clientIdRef.current,
|
|
94
|
+
seq: ++writeSeqRef.current,
|
|
95
|
+
};
|
|
96
|
+
const state = jsonClone(canvasStateToPageState(target.canvas, target.pageIndex, {
|
|
97
|
+
updatedAt: Date.now(),
|
|
98
|
+
rev,
|
|
99
|
+
}));
|
|
100
|
+
if (debugRef.current) {
|
|
101
|
+
console.log('[usePdfCanvasDoc] save attempt', {
|
|
102
|
+
fileId: currentFileId,
|
|
103
|
+
pageIndex: target.pageIndex,
|
|
104
|
+
strokes: state.strokes.length,
|
|
105
|
+
shapes: state.shapes.length,
|
|
106
|
+
measurements: state.placedMeasurements.length,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
await provider.writePage(currentScope, currentFileId, target.pageIndex, state);
|
|
111
|
+
const patch = {};
|
|
112
|
+
if (!target.pdfCanvas.annotatedPages.includes(target.pageIndex)) {
|
|
113
|
+
patch['fileData.pdfCanvas.annotatedPages'] = {
|
|
114
|
+
kind: 'arrayUnion',
|
|
115
|
+
values: [target.pageIndex],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const knobs = pdfCanvasKnobsOf(target.canvas);
|
|
119
|
+
if (!pdfCanvasKnobsEqual(knobs, pdfCanvasKnobsOf(target.pdfCanvas))) {
|
|
120
|
+
for (const [key, value] of Object.entries(knobs)) {
|
|
121
|
+
patch[`fileData.pdfCanvas.${key}`] = value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (Object.keys(patch).length > 0) {
|
|
125
|
+
await provider.update(currentScope, currentFileId, patch);
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
console.error('[usePdfCanvasDoc] save failed', { fileId: currentFileId, pageIndex: target.pageIndex }, e);
|
|
131
|
+
onSaveErrorRef.current?.(e);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}, [provider]);
|
|
135
|
+
const saveThumbnail = useCallback(async (targetFileId) => {
|
|
136
|
+
const capture = captureThumbnailRef.current;
|
|
137
|
+
const currentScope = scopeRef.current;
|
|
138
|
+
if (!capture || !currentScope || thumbnailSavingRef.current)
|
|
139
|
+
return;
|
|
140
|
+
thumbnailSavingRef.current = true;
|
|
141
|
+
try {
|
|
142
|
+
const blob = await capture();
|
|
143
|
+
if (blob) {
|
|
144
|
+
await provider.uploadImage(currentScope, targetFileId, 'thumbnail', blob);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
console.warn('[usePdfCanvasDoc] thumbnail save failed', e);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
thumbnailSavingRef.current = false;
|
|
152
|
+
}
|
|
153
|
+
}, [provider]);
|
|
154
|
+
// One flush pass: an outgoing page first (if a page turn left one behind),
|
|
155
|
+
// then the current page when it is dirty.
|
|
156
|
+
const runFlush = useCallback(async () => {
|
|
157
|
+
const outgoing = outgoingRef.current;
|
|
158
|
+
if (outgoing) {
|
|
159
|
+
outgoingRef.current = null;
|
|
160
|
+
await persist(outgoing);
|
|
161
|
+
}
|
|
162
|
+
const canvas = workingRef.current;
|
|
163
|
+
const data = pdfCanvasRef.current;
|
|
164
|
+
if (!canvas ||
|
|
165
|
+
!data ||
|
|
166
|
+
(statusRef.current !== 'dirty' && statusRef.current !== 'error')) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const editSeqAtFlush = editSeqRef.current;
|
|
170
|
+
const wantThumbnail = thumbnailRequestedRef.current;
|
|
171
|
+
thumbnailRequestedRef.current = false;
|
|
172
|
+
const targetPage = pageIndexRef.current;
|
|
173
|
+
setStatus('saving');
|
|
174
|
+
const ok = await persist({
|
|
175
|
+
pageIndex: targetPage,
|
|
176
|
+
canvas,
|
|
177
|
+
pdfCanvas: data,
|
|
178
|
+
});
|
|
179
|
+
if (!ok) {
|
|
180
|
+
setStatus('error');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const currentFileId = fileIdRef.current;
|
|
184
|
+
if (wantThumbnail && targetPage === 0 && currentFileId) {
|
|
185
|
+
thumbnailPromiseRef.current = saveThumbnail(currentFileId);
|
|
186
|
+
}
|
|
187
|
+
setStatus(editSeqRef.current !== editSeqAtFlush ? 'dirty' : 'saved');
|
|
188
|
+
}, [persist, saveThumbnail, setStatus]);
|
|
189
|
+
const runFlushRef = useRef(runFlush);
|
|
190
|
+
runFlushRef.current = runFlush;
|
|
191
|
+
const flushRunner = useMemo(() => createCoalescedRunner(() => runFlushRef.current()), []);
|
|
192
|
+
const flush = useCallback(() => flushRunner(), [flushRunner]);
|
|
193
|
+
// Page turn: hand the outgoing page to the flusher if it has unsaved edits,
|
|
194
|
+
// then drop the working state so the next snapshot hydrates the new page.
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
if (pageIndexRef.current === pageIndex)
|
|
197
|
+
return;
|
|
198
|
+
const previous = workingRef.current;
|
|
199
|
+
const data = pdfCanvasRef.current;
|
|
200
|
+
if (previous &&
|
|
201
|
+
data &&
|
|
202
|
+
(statusRef.current === 'dirty' || statusRef.current === 'error')) {
|
|
203
|
+
outgoingRef.current = {
|
|
204
|
+
pageIndex: pageIndexRef.current,
|
|
205
|
+
canvas: previous,
|
|
206
|
+
pdfCanvas: data,
|
|
207
|
+
};
|
|
208
|
+
void flush();
|
|
209
|
+
}
|
|
210
|
+
pageIndexRef.current = pageIndex;
|
|
211
|
+
workingRef.current = null;
|
|
212
|
+
setWorking(null);
|
|
213
|
+
setStatus('idle');
|
|
214
|
+
}, [pageIndex, flush, setStatus]);
|
|
215
|
+
// Reset on a different file.
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
workingRef.current = null;
|
|
218
|
+
setWorking(null);
|
|
219
|
+
setStatus('idle');
|
|
220
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
221
|
+
}, [annotationScopeKey(scope), fileId]);
|
|
222
|
+
// Hydrate / reconcile from the persisted docs.
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (!pdfCanvas || pageLoading)
|
|
225
|
+
return;
|
|
226
|
+
if (pageIndex >= pdfCanvas.document.pages.length)
|
|
227
|
+
return;
|
|
228
|
+
if (workingRef.current === null) {
|
|
229
|
+
const next = pageStateToCanvasState(pdfCanvas, pageDoc, pageIndex);
|
|
230
|
+
workingRef.current = next;
|
|
231
|
+
setWorking(next);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// Local edits pending or a write in flight: never clobber them.
|
|
235
|
+
if (statusRef.current === 'saving' || statusRef.current === 'dirty')
|
|
236
|
+
return;
|
|
237
|
+
// The echo of this session's own write carries our clientId.
|
|
238
|
+
if (pageDoc?.rev?.clientId === clientIdRef.current)
|
|
239
|
+
return;
|
|
240
|
+
const next = pageStateToCanvasState(pdfCanvas, pageDoc, pageIndex);
|
|
241
|
+
workingRef.current = next;
|
|
242
|
+
setWorking(next);
|
|
243
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
244
|
+
}, [pdfCanvas, pageDoc, pageLoading, pageIndex]);
|
|
245
|
+
const onCommit = useCallback((patch) => {
|
|
246
|
+
editSeqRef.current += 1;
|
|
247
|
+
setWorking((prev) => {
|
|
248
|
+
if (!prev)
|
|
249
|
+
return prev;
|
|
250
|
+
const next = applyPatch(prev, patch);
|
|
251
|
+
workingRef.current = next;
|
|
252
|
+
return next;
|
|
253
|
+
});
|
|
254
|
+
setStatus('dirty');
|
|
255
|
+
}, [setStatus]);
|
|
256
|
+
const save = useCallback(async () => {
|
|
257
|
+
thumbnailRequestedRef.current = true;
|
|
258
|
+
await flush();
|
|
259
|
+
await thumbnailPromiseRef.current;
|
|
260
|
+
}, [flush]);
|
|
261
|
+
const refreshThumbnail = useCallback(async () => {
|
|
262
|
+
const currentFileId = fileIdRef.current;
|
|
263
|
+
if (!currentFileId)
|
|
264
|
+
return;
|
|
265
|
+
await saveThumbnail(currentFileId);
|
|
266
|
+
}, [saveThumbnail]);
|
|
267
|
+
const rotatePage = useCallback(async (delta) => {
|
|
268
|
+
const currentScope = scopeRef.current;
|
|
269
|
+
const currentFileId = fileIdRef.current;
|
|
270
|
+
// Pending edits first, so the rewrite below starts from persisted truth.
|
|
271
|
+
await flush();
|
|
272
|
+
const data = pdfCanvasRef.current;
|
|
273
|
+
const canvas = workingRef.current;
|
|
274
|
+
const index = pageIndexRef.current;
|
|
275
|
+
if (!currentScope || !currentFileId || !data || !canvas)
|
|
276
|
+
return;
|
|
277
|
+
const page = data.document.pages[index];
|
|
278
|
+
if (!page)
|
|
279
|
+
return;
|
|
280
|
+
const size = pdfPageDisplaySize(page);
|
|
281
|
+
const turnedPage = rotatePdfCanvasPage(page, delta);
|
|
282
|
+
const pages = data.document.pages.map((p, i) => i === index ? turnedPage : p);
|
|
283
|
+
// Knobs the flush just wrote may not have echoed back yet; carry them.
|
|
284
|
+
const nextData = {
|
|
285
|
+
...data,
|
|
286
|
+
...pdfCanvasKnobsOf(canvas),
|
|
287
|
+
document: { ...data.document, pages },
|
|
288
|
+
};
|
|
289
|
+
setStatus('saving');
|
|
290
|
+
try {
|
|
291
|
+
const patch = {
|
|
292
|
+
'fileData.pdfCanvas.document.pages': pages,
|
|
293
|
+
};
|
|
294
|
+
let turnedState = null;
|
|
295
|
+
if (hasContent(canvas)) {
|
|
296
|
+
const rev = {
|
|
297
|
+
clientId: clientIdRef.current,
|
|
298
|
+
seq: ++writeSeqRef.current,
|
|
299
|
+
};
|
|
300
|
+
turnedState = jsonClone(rotatePageState(canvasStateToPageState(canvas, index, {
|
|
301
|
+
updatedAt: Date.now(),
|
|
302
|
+
rev,
|
|
303
|
+
}), size, delta));
|
|
304
|
+
await provider.writePage(currentScope, currentFileId, index, turnedState);
|
|
305
|
+
if (!data.annotatedPages.includes(index)) {
|
|
306
|
+
patch['fileData.pdfCanvas.annotatedPages'] = {
|
|
307
|
+
kind: 'arrayUnion',
|
|
308
|
+
values: [index],
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
await provider.update(currentScope, currentFileId, patch);
|
|
313
|
+
const next = pageStateToCanvasState(nextData, turnedState, index);
|
|
314
|
+
workingRef.current = next;
|
|
315
|
+
setWorking(next);
|
|
316
|
+
setStatus('saved');
|
|
317
|
+
}
|
|
318
|
+
catch (e) {
|
|
319
|
+
console.error('[usePdfCanvasDoc] rotate failed', { fileId: currentFileId, pageIndex: index, delta }, e);
|
|
320
|
+
onSaveErrorRef.current?.(e);
|
|
321
|
+
setStatus('error');
|
|
322
|
+
}
|
|
323
|
+
}, [flush, provider, setStatus]);
|
|
324
|
+
const page = pdfCanvas?.document.pages[pageIndex] ?? null;
|
|
325
|
+
const canvas = useMemo(() => working ??
|
|
326
|
+
(page
|
|
327
|
+
? createEmptyCanvasState(pdfPageDisplaySize(page))
|
|
328
|
+
: createEmptyCanvasState()), [working, page]);
|
|
329
|
+
return {
|
|
330
|
+
file,
|
|
331
|
+
pdfCanvas,
|
|
332
|
+
pageCount: pdfCanvas?.document.pageCount ?? 0,
|
|
333
|
+
page,
|
|
334
|
+
canvas,
|
|
335
|
+
onCommit,
|
|
336
|
+
loading: fileLoading || pageLoading || working === null,
|
|
337
|
+
error: fileError ?? pageError,
|
|
338
|
+
saveStatus,
|
|
339
|
+
hasUnsavedChanges: saveStatus === 'dirty' || saveStatus === 'error',
|
|
340
|
+
save,
|
|
341
|
+
rotatePage,
|
|
342
|
+
refreshThumbnail,
|
|
343
|
+
};
|
|
344
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { renderCanvasToPdf } from './renderCanvasToPdf.js';
|
|
1
|
+
export { renderCanvasToPdf, renderPdfCanvasToPdf, } from './renderCanvasToPdf.js';
|
|
2
2
|
export { stripPdfEncryption, type StripPdfEncryptionOptions, type StripPdfEncryptionResult, } from './decrypt.js';
|
|
3
3
|
export { docToPageMatrix, pageRectsOf, normalizeRotation, rotatedBoxSize, applyMatrix, type AffineMatrix, type PageRotation, type PdfBox, } from './pageMapping.js';
|
|
4
4
|
export { resolveTileContent, measurementTileFillFor, FORMULA_COLUMN_TILE_FILL, PLANE_COMPUTED_TILE_FILL, type TileFileInfo, type TileResolutionContext, } from './tileContent.js';
|
|
5
5
|
export { tileFootprint, type TileFootprint } from './tiles.js';
|
|
6
6
|
export { annotationCount } from './annots.js';
|
|
7
|
-
export { PdfExportError, type EmbeddedImage, type PdfExportCalibration, type RenderCanvasToPdfInput, type RenderCanvasToPdfResult, type ResolvedTileContent, type MeasurementTileContent, type LiteralTileContent, type EmptyTileContent, type HeaderTileContent, type ObjectTileContent, type PlaneDimensionTileContent, type InstructionsTileContent, type SkippedItem, } from './types.js';
|
|
7
|
+
export { PdfExportError, type EmbeddedImage, type PdfExportCalibration, type RenderCanvasToPdfInput, type RenderPdfCanvasToPdfInput, type RenderCanvasToPdfResult, type ResolvedTileContent, type MeasurementTileContent, type LiteralTileContent, type EmptyTileContent, type HeaderTileContent, type ObjectTileContent, type PlaneDimensionTileContent, type InstructionsTileContent, type SkippedItem, } from './types.js';
|
package/dist/export/pdf/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { renderCanvasToPdf } from './renderCanvasToPdf.js';
|
|
1
|
+
export { renderCanvasToPdf, renderPdfCanvasToPdf, } from './renderCanvasToPdf.js';
|
|
2
2
|
export { stripPdfEncryption, } from './decrypt.js';
|
|
3
3
|
export { docToPageMatrix, pageRectsOf, normalizeRotation, rotatedBoxSize, applyMatrix, } from './pageMapping.js';
|
|
4
4
|
export { resolveTileContent, measurementTileFillFor, FORMULA_COLUMN_TILE_FILL, PLANE_COMPUTED_TILE_FILL, } from './tileContent.js';
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
import { type RenderCanvasToPdfInput, type RenderCanvasToPdfResult } from './types.js';
|
|
1
|
+
import { type RenderCanvasToPdfInput, type RenderCanvasToPdfResult, type RenderPdfCanvasToPdfInput } from './types.js';
|
|
2
2
|
export declare const renderCanvasToPdf: (input: RenderCanvasToPdfInput) => Promise<RenderCanvasToPdfResult>;
|
|
3
|
+
/**
|
|
4
|
+
* Export a PdfCanvas file. Each page's state is drawn in that page's own doc
|
|
5
|
+
* space (the DISPLAYED page: rotated extents, origin top-left). A user
|
|
6
|
+
* rotation is written into the page's /Rotate — so the recipient sees the
|
|
7
|
+
* page as the user did — and the page matrix undoes the combined rotation.
|
|
8
|
+
* Pages without a state are still rotated.
|
|
9
|
+
*/
|
|
10
|
+
export declare const renderPdfCanvasToPdf: (input: RenderPdfCanvasToPdfInput) => Promise<RenderCanvasToPdfResult>;
|