fabricjs-document-engine 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -10
- package/README.zh-CN.md +181 -10
- package/dist/assets/asset-manifest.d.cts +3 -0
- package/dist/assets/asset-manifest.d.ts +3 -0
- package/dist/assets/asset-pipeline.cjs +22 -10
- package/dist/assets/asset-pipeline.d.cts +5 -1
- package/dist/assets/asset-pipeline.d.ts +5 -1
- package/dist/assets/asset-pipeline.js +22 -10
- package/dist/assets/font-check.cjs +9 -1
- package/dist/assets/font-check.js +9 -1
- package/dist/assets/image-check.cjs +88 -6
- package/dist/assets/image-check.d.cts +17 -0
- package/dist/assets/image-check.d.ts +17 -0
- package/dist/assets/image-check.js +88 -7
- package/dist/commands/clipboard.cjs +136 -0
- package/dist/commands/clipboard.d.cts +47 -0
- package/dist/commands/clipboard.d.ts +47 -0
- package/dist/commands/clipboard.js +135 -0
- package/dist/commands/layers.cjs +97 -0
- package/dist/commands/layers.d.cts +39 -0
- package/dist/commands/layers.d.ts +39 -0
- package/dist/commands/layers.js +92 -0
- package/dist/engine/create-document-engine.cjs +85 -14
- package/dist/engine/create-document-engine.d.cts +20 -1
- package/dist/engine/create-document-engine.d.ts +20 -1
- package/dist/engine/create-document-engine.js +86 -15
- package/dist/engine/errors.d.cts +1 -1
- package/dist/engine/errors.d.ts +1 -1
- package/dist/export/batch-render.cjs +172 -0
- package/dist/export/batch-render.d.cts +43 -0
- package/dist/export/batch-render.d.ts +43 -0
- package/dist/export/batch-render.js +171 -0
- package/dist/export/export-options.cjs +18 -1
- package/dist/export/export-options.d.cts +23 -0
- package/dist/export/export-options.d.ts +23 -0
- package/dist/export/export-options.js +18 -2
- package/dist/export/preflight-export.cjs +11 -2
- package/dist/export/preflight-export.d.cts +1 -1
- package/dist/export/preflight-export.d.ts +1 -1
- package/dist/export/preflight-export.js +11 -2
- package/dist/export/render-export.cjs +18 -3
- package/dist/export/render-export.js +18 -4
- package/dist/export/svg/embed-assets.cjs +249 -0
- package/dist/export/svg/embed-assets.js +249 -0
- package/dist/export/svg/overrides.cjs +32 -0
- package/dist/export/svg/overrides.js +32 -0
- package/dist/export/svg/text-on-path.cjs +252 -0
- package/dist/export/svg/text-on-path.js +249 -0
- package/dist/fabric/fabric-adapter.cjs +46 -5
- package/dist/fabric/fabric-adapter.js +46 -5
- package/dist/fabric/object-registry.cjs +1 -1
- package/dist/fabric/object-registry.js +1 -1
- package/dist/import/svg-import.cjs +256 -0
- package/dist/import/svg-import.d.cts +50 -0
- package/dist/import/svg-import.d.ts +50 -0
- package/dist/import/svg-import.js +256 -0
- package/dist/index.cjs +12 -0
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -1
- package/dist/pdf/export-pdf.cjs +440 -0
- package/dist/pdf/export-pdf.d.cts +73 -0
- package/dist/pdf/export-pdf.d.ts +73 -0
- package/dist/pdf/export-pdf.js +440 -0
- package/dist/pdf/fonts.cjs +115 -0
- package/dist/pdf/fonts.d.cts +12 -0
- package/dist/pdf/fonts.d.ts +12 -0
- package/dist/pdf/fonts.js +112 -0
- package/dist/pdf/page-layout.cjs +79 -0
- package/dist/pdf/page-layout.d.cts +51 -0
- package/dist/pdf/page-layout.d.ts +51 -0
- package/dist/pdf/page-layout.js +76 -0
- package/dist/pdf/text-decorations.cjs +108 -0
- package/dist/pdf/text-decorations.js +107 -0
- package/dist/pdf.cjs +7 -0
- package/dist/pdf.d.cts +4 -0
- package/dist/pdf.d.ts +4 -0
- package/dist/pdf.js +3 -0
- package/dist/react/use-layers.cjs +53 -0
- package/dist/react/use-layers.d.cts +10 -0
- package/dist/react/use-layers.d.ts +10 -0
- package/dist/react/use-layers.js +53 -0
- package/dist/react.cjs +2 -0
- package/dist/react.d.cts +3 -1
- package/dist/react.d.ts +3 -1
- package/dist/react.js +2 -1
- package/dist/util/concurrency.cjs +28 -0
- package/dist/util/concurrency.js +27 -0
- package/package.json +30 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { CURRENT_SCHEMA_VERSION, DocumentCanvas, DocumentInfo, FabricDocument, SerializedFabricObject } from "./document/document-format.js";
|
|
2
|
+
import { ImageFailureReason, ImageLoadFailure } from "./assets/image-check.js";
|
|
2
3
|
import { AssetManifest, FontAsset, ImageAsset } from "./assets/asset-manifest.js";
|
|
3
4
|
import { FontLoader } from "./assets/font-check.js";
|
|
4
5
|
import { AssetOptions, AssetReport, AssetWarning, AssetWarningCode, UploadRequest } from "./assets/asset-pipeline.js";
|
|
5
|
-
import { ExportArea, ExportBackground, ExportFormat, ExportOptions, ExportRect } from "./export/export-options.js";
|
|
6
|
+
import { ExportArea, ExportBackground, ExportFormat, ExportOptions, ExportRect, FontSource, SvgExportOptions } from "./export/export-options.js";
|
|
6
7
|
import { ExportPreflight, ExportProblem, ExportProblemCode } from "./export/preflight-export.js";
|
|
8
|
+
import { ContentLimits, isSafeImageUrl, refuseUnsafeImageUrls, secureDocument } from "./security/content-limits.js";
|
|
9
|
+
import { SvgImportOptions, SvgImportResult, SvgImportWarning, SvgImportWarningCode } from "./import/svg-import.js";
|
|
7
10
|
import { NewDocumentOptions } from "./document/create-document.js";
|
|
8
11
|
import { CustomObjectDefinition } from "./fabric/object-registry.js";
|
|
9
12
|
import { HistoryOptions, HistoryState } from "./history/create-history.js";
|
|
10
|
-
import { ContentLimits, isSafeImageUrl, refuseUnsafeImageUrls, secureDocument } from "./security/content-limits.js";
|
|
11
13
|
import { DocumentVersion, VersionKind, VersionOptions, VersionStorage, VersionSummary } from "./versions/document-version.js";
|
|
12
14
|
import { RecoveryStore } from "./recovery/recovery-store.js";
|
|
13
15
|
import { InterruptedLoad, RecoveryOptions, RecoveryRecord } from "./recovery/recovery-controller.js";
|
|
@@ -17,11 +19,14 @@ import { DocumentEngineError, DocumentEngineErrorDetails, DocumentErrorCode, Doc
|
|
|
17
19
|
import { DocumentStorage, SaveContext, SaveResult } from "./storage/storage-contract.js";
|
|
18
20
|
import { SaveOptions, SaveRetryEvent, SaveState, SaveStatus } from "./save/save-controller.js";
|
|
19
21
|
import { Unsubscribe } from "./engine/event-emitter.js";
|
|
20
|
-
import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, NewDocumentRequest, createDocumentEngine } from "./engine/create-document-engine.js";
|
|
22
|
+
import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, LoadProgress, LoadStage, NewDocumentRequest, createDocumentEngine } from "./engine/create-document-engine.js";
|
|
21
23
|
import { validateDocument } from "./document/validate-document.js";
|
|
22
24
|
import { KeyboardShortcutOptions, UndoRedoTarget, bindKeyboardShortcuts } from "./history/keyboard-shortcuts.js";
|
|
23
25
|
import { UnsavedChangesSource, bindUnsavedChangesWarning } from "./save/unsaved-changes-warning.js";
|
|
24
26
|
import { DownloadableExport, downloadExport } from "./export/download-export.js";
|
|
27
|
+
import { RenderDocumentsOptions, RenderedDocument, renderDocuments } from "./export/batch-render.js";
|
|
25
28
|
import { Migration, MigrationContext, MigrationResult, detectSchemaVersion, migrateDocument } from "./migrations/migrate-document.js";
|
|
26
29
|
import { DocumentState, DocumentStateStore, createDocumentStateStore } from "./state/document-state-store.js";
|
|
27
|
-
|
|
30
|
+
import { CLIPBOARD_FORMAT, Clipboard, ClipboardContent, ClipboardOptions, PasteOptions, createClipboard } from "./commands/clipboard.js";
|
|
31
|
+
import { LayerInfo, LayerOptions, LayerPin, bringForward, bringToFront, getLayers, moveToIndex, sendBackward, sendToBack } from "./commands/layers.js";
|
|
32
|
+
export { type AssetManifest, type AssetOptions, type AssetReport, type AssetWarning, type AssetWarningCode, type AutosaveOptions, CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, type Clipboard, type ClipboardContent, type ClipboardOptions, type ContentLimits, type CustomObjectDefinition, type DocumentCanvas, type DocumentEngine, DocumentEngineError, type DocumentEngineErrorDetails, type DocumentEngineEvents, type DocumentEngineOptions, type DocumentErrorCode, type DocumentInfo, type DocumentIssue, type DocumentState, type DocumentStateStore, type DocumentStorage, type DocumentVersion, type DownloadableExport, type ExportArea, type ExportBackground, type ExportFormat, type ExportOptions, type ExportPreflight, type ExportProblem, type ExportProblemCode, type ExportRect, type ExportResult, type FabricDocument, type FontAsset, type FontLoader, type FontSource, type HistoryOptions, type HistoryState, type ImageAsset, type ImageFailureReason, type ImageLoadFailure, type ImportOptions, type InterruptedLoad, type KeyboardShortcutOptions, type LayerInfo, type LayerOptions, type LayerPin, type LoadOptions, type LoadProgress, type LoadStage, type Migration, type MigrationContext, type MigrationResult, type NewDocumentOptions, type NewDocumentRequest, type PasteOptions, type RecoveryOptions, type RecoveryRecord, type RecoveryStore, type RenderDocumentsOptions, type RenderedDocument, type RetryOptions, type SaveContext, type SaveOptions, type SaveResult, type SaveRetryEvent, type SaveState, type SaveStatus, type SerializedFabricObject, type SvgExportOptions, type SvgImportOptions, type SvgImportResult, type SvgImportWarning, type SvgImportWarningCode, type UndoRedoTarget, type UnsavedChangesSource, type Unsubscribe, type UploadRequest, type VersionKind, type VersionOptions, type VersionStorage, type VersionSummary, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, refuseUnsafeImageUrls, renderDocuments, secureDocument, sendBackward, sendToBack, validateDocument };
|
package/dist/index.js
CHANGED
|
@@ -7,5 +7,8 @@ import { createDocumentEngine } from "./engine/create-document-engine.js";
|
|
|
7
7
|
import { bindKeyboardShortcuts } from "./history/keyboard-shortcuts.js";
|
|
8
8
|
import { bindUnsavedChangesWarning } from "./save/unsaved-changes-warning.js";
|
|
9
9
|
import { downloadExport } from "./export/download-export.js";
|
|
10
|
+
import { renderDocuments } from "./export/batch-render.js";
|
|
10
11
|
import { createDocumentStateStore } from "./state/document-state-store.js";
|
|
11
|
-
|
|
12
|
+
import { CLIPBOARD_FORMAT, createClipboard } from "./commands/clipboard.js";
|
|
13
|
+
import { bringForward, bringToFront, getLayers, moveToIndex, sendBackward, sendToBack } from "./commands/layers.js";
|
|
14
|
+
export { CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, DocumentEngineError, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, refuseUnsafeImageUrls, renderDocuments, secureDocument, sendBackward, sendToBack, validateDocument };
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
const require_errors = require("../engine/errors.cjs");
|
|
2
|
+
const require_object_ids = require("../fabric/object-ids.cjs");
|
|
3
|
+
const require_walk_objects = require("../fabric/walk-objects.cjs");
|
|
4
|
+
const require_overrides = require("../export/svg/overrides.cjs");
|
|
5
|
+
const require_text_on_path = require("../export/svg/text-on-path.cjs");
|
|
6
|
+
const require_render_export = require("../export/render-export.cjs");
|
|
7
|
+
const require_embed_assets = require("../export/svg/embed-assets.cjs");
|
|
8
|
+
const require_batch_render = require("../export/batch-render.cjs");
|
|
9
|
+
const require_fonts = require("./fonts.cjs");
|
|
10
|
+
const require_page_layout = require("./page-layout.cjs");
|
|
11
|
+
const require_text_decorations = require("./text-decorations.cjs");
|
|
12
|
+
//#region src/pdf/export-pdf.ts
|
|
13
|
+
const RASTER_REASONS = {
|
|
14
|
+
shadow: "it has a shadow, which PDF vectors cannot draw",
|
|
15
|
+
blend: "it uses a blend mode, which PDF vectors cannot draw",
|
|
16
|
+
gradientStroke: "its outline is a gradient or pattern",
|
|
17
|
+
uniformStroke: "it keeps its outline width while scaled (strokeUniform)",
|
|
18
|
+
font: "its font has no TrueType file in fonts",
|
|
19
|
+
characters: "it uses characters the built-in PDF fonts do not have; add a TrueType font that has them"
|
|
20
|
+
};
|
|
21
|
+
function stop(signal) {
|
|
22
|
+
if (signal?.aborted) throw new require_errors.DocumentEngineError("EXPORT_ABORTED", "The PDF export was cancelled");
|
|
23
|
+
}
|
|
24
|
+
async function loadPeers(needsSvg) {
|
|
25
|
+
let jsPDF;
|
|
26
|
+
try {
|
|
27
|
+
jsPDF = (await import("jspdf")).jsPDF;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw new require_errors.DocumentEngineError("PDF_UNAVAILABLE", "PDF export needs the jspdf package. Install it with: npm install jspdf svg2pdf.js", { cause: error });
|
|
30
|
+
}
|
|
31
|
+
if (needsSvg) try {
|
|
32
|
+
await import("svg2pdf.js");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new require_errors.DocumentEngineError("PDF_UNAVAILABLE", "Vector and hybrid PDF export need the svg2pdf.js package. Install it with: npm install svg2pdf.js, or use mode: \"raster\".", { cause: error });
|
|
35
|
+
}
|
|
36
|
+
return jsPDF;
|
|
37
|
+
}
|
|
38
|
+
function isEngine(source) {
|
|
39
|
+
return typeof source.toDocument === "function" && "canvas" in source;
|
|
40
|
+
}
|
|
41
|
+
function isCanvas(source) {
|
|
42
|
+
const candidate = source;
|
|
43
|
+
return typeof candidate.getObjects === "function" && typeof candidate.toCanvasElement === "function";
|
|
44
|
+
}
|
|
45
|
+
function idsOf(object) {
|
|
46
|
+
const ids = [];
|
|
47
|
+
require_walk_objects.walkObjects([object], (child) => {
|
|
48
|
+
const id = require_object_ids.readObjectId(child);
|
|
49
|
+
if (id !== void 0) ids.push(id);
|
|
50
|
+
});
|
|
51
|
+
return ids.slice(0, 1);
|
|
52
|
+
}
|
|
53
|
+
function familiesOf(object) {
|
|
54
|
+
const text = object;
|
|
55
|
+
const families = /* @__PURE__ */ new Set();
|
|
56
|
+
if (typeof text.fontFamily === "string") families.add(text.fontFamily);
|
|
57
|
+
for (const line of Object.values(text.styles ?? {})) for (const style of Object.values(line ?? {})) if (typeof style?.fontFamily === "string") families.add(style.fontFamily);
|
|
58
|
+
return [...families];
|
|
59
|
+
}
|
|
60
|
+
function resolvesTo(family, registered) {
|
|
61
|
+
const names = family.split(",").map((name) => name.trim().replace(/^['"]|['"]$/g, ""));
|
|
62
|
+
if (names.some((name) => registered.families.has(name.toLowerCase()))) return {
|
|
63
|
+
registered: true,
|
|
64
|
+
standard: false
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
registered: false,
|
|
68
|
+
standard: names.some((name) => require_fonts.standardFamily(name) !== void 0)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Why an object cannot be drawn as PDF vectors, or undefined when it can. */
|
|
72
|
+
function rasterReason(object, registered, missingFonts) {
|
|
73
|
+
let reason;
|
|
74
|
+
require_walk_objects.walkObjects([object], (child) => {
|
|
75
|
+
if (reason) return;
|
|
76
|
+
if (child.shadow) reason = "shadow";
|
|
77
|
+
else if (child.globalCompositeOperation && child.globalCompositeOperation !== "source-over") reason = "blend";
|
|
78
|
+
else if (typeof child.stroke === "object" && child.stroke !== null && child.strokeWidth > 0) reason = "gradientStroke";
|
|
79
|
+
else if (child.strokeUniform && child.stroke && child.strokeWidth > 0) {
|
|
80
|
+
const { x: scaleX, y: scaleY } = child.getObjectScaling();
|
|
81
|
+
if (Math.abs(scaleX - 1) > 1e-6 || Math.abs(scaleY - 1) > 1e-6) reason = "uniformStroke";
|
|
82
|
+
}
|
|
83
|
+
const text = child.text;
|
|
84
|
+
if (!reason && typeof text === "string") {
|
|
85
|
+
const families = familiesOf(child).map((family) => resolvesTo(family, registered));
|
|
86
|
+
const allRegistered = families.every((family) => family.registered);
|
|
87
|
+
if (!allRegistered && /[^\u0000-ÿ]/.test(text)) reason = "characters";
|
|
88
|
+
else if (!allRegistered && missingFonts === "rasterize" && families.some((family) => !family.registered && !family.standard)) reason = "font";
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return reason;
|
|
92
|
+
}
|
|
93
|
+
function shadowPadding(object) {
|
|
94
|
+
let padding = 0;
|
|
95
|
+
require_walk_objects.walkObjects([object], (child) => {
|
|
96
|
+
const shadow = child.shadow;
|
|
97
|
+
if (shadow) padding = Math.max(padding, shadow.blur + Math.max(Math.abs(shadow.offsetX), Math.abs(shadow.offsetY)));
|
|
98
|
+
});
|
|
99
|
+
return padding + 2;
|
|
100
|
+
}
|
|
101
|
+
function usesBlendMode(object) {
|
|
102
|
+
let blends = false;
|
|
103
|
+
require_walk_objects.walkObjects([object], (child) => {
|
|
104
|
+
if (child.globalCompositeOperation && child.globalCompositeOperation !== "source-over") blends = true;
|
|
105
|
+
});
|
|
106
|
+
return blends;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* An object as a picture placed where it sits on the canvas. Usually the
|
|
110
|
+
* object alone, so the vectors underneath show through. An object with a
|
|
111
|
+
* blend mode mixes with what lies below it, so its picture includes
|
|
112
|
+
* everything below it within its bounds, which covers those vectors exactly.
|
|
113
|
+
*/
|
|
114
|
+
function rasterMarkup(canvas, object, multiplier) {
|
|
115
|
+
object.setCoords();
|
|
116
|
+
const bounds = object.getBoundingRect();
|
|
117
|
+
const padding = shadowPadding(object);
|
|
118
|
+
const left = Math.max(0, Math.floor(bounds.left - padding));
|
|
119
|
+
const top = Math.max(0, Math.floor(bounds.top - padding));
|
|
120
|
+
const right = Math.min(canvas.getWidth(), Math.ceil(bounds.left + bounds.width + padding));
|
|
121
|
+
const bottom = Math.min(canvas.getHeight(), Math.ceil(bounds.top + bounds.height + padding));
|
|
122
|
+
if (right <= left || bottom <= top) return "";
|
|
123
|
+
const blends = usesBlendMode(object);
|
|
124
|
+
const stack = canvas.getObjects();
|
|
125
|
+
const position = stack.indexOf(object);
|
|
126
|
+
const saved = {
|
|
127
|
+
backgroundColor: canvas.backgroundColor,
|
|
128
|
+
backgroundImage: canvas.backgroundImage,
|
|
129
|
+
overlayColor: canvas.overlayColor,
|
|
130
|
+
overlayImage: canvas.overlayImage
|
|
131
|
+
};
|
|
132
|
+
if (!blends) {
|
|
133
|
+
canvas.backgroundColor = "";
|
|
134
|
+
canvas.backgroundImage = void 0;
|
|
135
|
+
}
|
|
136
|
+
canvas.overlayColor = "";
|
|
137
|
+
canvas.overlayImage = void 0;
|
|
138
|
+
let element;
|
|
139
|
+
try {
|
|
140
|
+
const filter = (candidate) => blends ? stack.indexOf(candidate) <= position : candidate === object;
|
|
141
|
+
element = canvas.toCanvasElement(multiplier, {
|
|
142
|
+
left,
|
|
143
|
+
top,
|
|
144
|
+
width: right - left,
|
|
145
|
+
height: bottom - top,
|
|
146
|
+
filter
|
|
147
|
+
});
|
|
148
|
+
} finally {
|
|
149
|
+
Object.assign(canvas, saved);
|
|
150
|
+
}
|
|
151
|
+
const url = element.toDataURL("image/png");
|
|
152
|
+
element.width = 0;
|
|
153
|
+
element.height = 0;
|
|
154
|
+
return `<image x="${left}" y="${top}" width="${right - left}" height="${bottom - top}" preserveAspectRatio="none" xlink:href="${url}" />\n`;
|
|
155
|
+
}
|
|
156
|
+
function quoteFamily(name) {
|
|
157
|
+
return /^[a-z-]+$/i.test(name) ? name : `"${name.replace(/"/g, "")}"`;
|
|
158
|
+
}
|
|
159
|
+
function resolveFamily(list, registered) {
|
|
160
|
+
const names = list.split(",").map((name) => name.trim().replace(/^['"]|['"]$/g, ""));
|
|
161
|
+
for (const name of names) {
|
|
162
|
+
const own = registered.families.get(name.toLowerCase());
|
|
163
|
+
if (own) return quoteFamily(own);
|
|
164
|
+
}
|
|
165
|
+
for (const name of names) {
|
|
166
|
+
const standard = require_fonts.standardFamily(name);
|
|
167
|
+
if (standard) return standard;
|
|
168
|
+
}
|
|
169
|
+
return "helvetica";
|
|
170
|
+
}
|
|
171
|
+
function weightOf(value) {
|
|
172
|
+
const number = Number(value);
|
|
173
|
+
return value === "bold" || value === "bolder" || Number.isFinite(number) && number >= 600 ? "bold" : "normal";
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Points every font at a font jsPDF has, and rounds weights to normal or
|
|
177
|
+
* bold. svg2pdf matches family names exactly and otherwise falls back to
|
|
178
|
+
* Times, and it looks for weights such as 500 as styles no font has.
|
|
179
|
+
*/
|
|
180
|
+
function normalizeFonts(root, registered) {
|
|
181
|
+
for (const element of [root, ...Array.from(root.getElementsByTagName("*"))]) {
|
|
182
|
+
const family = element.getAttribute("font-family");
|
|
183
|
+
if (family) element.setAttribute("font-family", resolveFamily(family, registered));
|
|
184
|
+
const weight = element.getAttribute("font-weight");
|
|
185
|
+
if (weight) element.setAttribute("font-weight", weightOf(weight));
|
|
186
|
+
const style = element.getAttribute("style");
|
|
187
|
+
if (style && /font-(family|weight)/.test(style)) element.setAttribute("style", style.replace(/font-family:\s*([^;]+)/g, (_, value) => `font-family: ${resolveFamily(value, registered)}`).replace(/font-weight:\s*([^;]+)/g, (_, value) => `font-weight: ${weightOf(value.trim())}`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Warns once for each family and style the canvas uses that has no file of its own. */
|
|
191
|
+
function warnSubstitutedStyles(canvas, registered, page, warnings, warned) {
|
|
192
|
+
if (registered.substituted.length === 0) return;
|
|
193
|
+
const missing = new Set(registered.substituted.map(({ family, style }) => `${family.toLowerCase()}|${style}`));
|
|
194
|
+
require_walk_objects.walkObjects(canvas.getObjects(), (object) => {
|
|
195
|
+
const text = object;
|
|
196
|
+
if (typeof text.text !== "string") return;
|
|
197
|
+
const uses = [{
|
|
198
|
+
family: text.fontFamily,
|
|
199
|
+
weight: text.fontWeight,
|
|
200
|
+
style: text.fontStyle
|
|
201
|
+
}];
|
|
202
|
+
for (const line of Object.values(text.styles ?? {})) for (const style of Object.values(line ?? {})) uses.push({
|
|
203
|
+
family: style?.fontFamily ?? text.fontFamily,
|
|
204
|
+
weight: style?.fontWeight ?? text.fontWeight,
|
|
205
|
+
style: style?.fontStyle ?? text.fontStyle
|
|
206
|
+
});
|
|
207
|
+
for (const use of uses) {
|
|
208
|
+
const family = registered.families.get(String(use.family ?? "").toLowerCase());
|
|
209
|
+
if (!family) continue;
|
|
210
|
+
const style = require_fonts.jsPdfStyle(use.weight, use.style);
|
|
211
|
+
const key = `${family.toLowerCase()}|${style}`;
|
|
212
|
+
if (!missing.has(key) || warned.has(key)) continue;
|
|
213
|
+
warned.add(key);
|
|
214
|
+
warnings.push({
|
|
215
|
+
code: "PDF_FONT_SUBSTITUTED",
|
|
216
|
+
message: `No ${style} file was given for "${family}", so its ${style} text uses another file of the same family`,
|
|
217
|
+
page,
|
|
218
|
+
objectIds: idsOf(object),
|
|
219
|
+
family
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function clipTo(context, draw) {
|
|
225
|
+
const clip = context.layout.clip;
|
|
226
|
+
if (!clip) return draw();
|
|
227
|
+
const { document } = context;
|
|
228
|
+
document.saveGraphicsState();
|
|
229
|
+
document.rect(clip.x, clip.y, clip.width, clip.height, null);
|
|
230
|
+
document.clip();
|
|
231
|
+
document.discardPath();
|
|
232
|
+
const finish = () => {
|
|
233
|
+
document.restoreGraphicsState();
|
|
234
|
+
};
|
|
235
|
+
const drawn = draw();
|
|
236
|
+
if (drawn instanceof Promise) return drawn.finally(finish);
|
|
237
|
+
finish();
|
|
238
|
+
}
|
|
239
|
+
async function drawRasterPage(canvas, context) {
|
|
240
|
+
const { layout, options } = context;
|
|
241
|
+
const multiplier = layout.scale * (options.dpi ?? 300) / 72;
|
|
242
|
+
const element = require_render_export.withExportView(canvas, options.background ?? "keep", "png", () => canvas.toCanvasElement(multiplier));
|
|
243
|
+
try {
|
|
244
|
+
await clipTo(context, () => {
|
|
245
|
+
context.document.addImage(element, "PNG", layout.x, layout.y, layout.width, layout.height, void 0, "FAST");
|
|
246
|
+
});
|
|
247
|
+
} finally {
|
|
248
|
+
element.width = 0;
|
|
249
|
+
element.height = 0;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function drawVectorPage(canvas, context) {
|
|
253
|
+
const { layout, options, page, warnings, registered } = context;
|
|
254
|
+
const mode = options.mode ?? "hybrid";
|
|
255
|
+
const missingFonts = options.missingFonts ?? (mode === "hybrid" ? "rasterize" : "substitute");
|
|
256
|
+
const multiplier = layout.scale * (options.dpi ?? 300) / 72;
|
|
257
|
+
const width = canvas.getWidth();
|
|
258
|
+
const height = canvas.getHeight();
|
|
259
|
+
const svg = require_render_export.withExportView(canvas, options.background ?? "keep", "svg", () => {
|
|
260
|
+
const rasters = /* @__PURE__ */ new Map();
|
|
261
|
+
for (const object of canvas.getObjects()) {
|
|
262
|
+
const reason = rasterReason(object, registered, missingFonts);
|
|
263
|
+
if (!reason) continue;
|
|
264
|
+
if (mode === "hybrid") {
|
|
265
|
+
rasters.set(object, rasterMarkup(canvas, object, multiplier));
|
|
266
|
+
warnings.push({
|
|
267
|
+
code: "PDF_RASTERIZED",
|
|
268
|
+
message: `An object was drawn as a picture at ${options.dpi ?? 300} dpi because ${RASTER_REASONS[reason]}`,
|
|
269
|
+
page,
|
|
270
|
+
objectIds: idsOf(object)
|
|
271
|
+
});
|
|
272
|
+
} else warnings.push({
|
|
273
|
+
code: reason === "font" || reason === "characters" ? "PDF_FONT_SUBSTITUTED" : "PDF_UNSUPPORTED",
|
|
274
|
+
message: `An object may look different in the PDF because ${RASTER_REASONS[reason]}`,
|
|
275
|
+
page,
|
|
276
|
+
objectIds: idsOf(object)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const writerFor = (object) => {
|
|
280
|
+
const raster = rasters.get(object);
|
|
281
|
+
if (raster !== void 0) return () => raster;
|
|
282
|
+
if (require_text_on_path.isTextOnPath(object)) return (reviver) => require_text_on_path.textOnPathToSVG(object, reviver);
|
|
283
|
+
if (require_text_decorations.hasStraightDecorations(object)) return (reviver) => require_text_decorations.decoratedTextToSVG(object, reviver);
|
|
284
|
+
};
|
|
285
|
+
return require_overrides.withSvgOverrides(canvas, writerFor, () => canvas.toSVG({
|
|
286
|
+
viewBox: {
|
|
287
|
+
x: 0,
|
|
288
|
+
y: 0,
|
|
289
|
+
width,
|
|
290
|
+
height
|
|
291
|
+
},
|
|
292
|
+
width: String(width),
|
|
293
|
+
height: String(height)
|
|
294
|
+
})).result;
|
|
295
|
+
});
|
|
296
|
+
const embedded = await require_embed_assets.embedSvgAssets(require_render_export.repairFabricSvg(svg), canvas, {
|
|
297
|
+
textOnPath: "vector",
|
|
298
|
+
embedImages: true,
|
|
299
|
+
maxEmbeddedImageBytes: Number.MAX_SAFE_INTEGER,
|
|
300
|
+
embedFonts: {}
|
|
301
|
+
}, options.signal);
|
|
302
|
+
stop(options.signal);
|
|
303
|
+
for (const warning of embedded.warnings) if (warning.code === "IMAGE_NOT_EMBEDDED") warnings.push({
|
|
304
|
+
code: "IMAGE_NOT_EMBEDDED",
|
|
305
|
+
message: warning.message,
|
|
306
|
+
page,
|
|
307
|
+
objectIds: warning.objectIds,
|
|
308
|
+
url: warning.url
|
|
309
|
+
});
|
|
310
|
+
const root = new DOMParser().parseFromString(embedded.svg, "image/svg+xml").documentElement;
|
|
311
|
+
normalizeFonts(root, registered);
|
|
312
|
+
await clipTo(context, async () => {
|
|
313
|
+
await context.document.svg(root, {
|
|
314
|
+
x: layout.x,
|
|
315
|
+
y: layout.y,
|
|
316
|
+
width: layout.width,
|
|
317
|
+
height: layout.height
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Exports one or more pages as a PDF. Each source becomes one page: an
|
|
323
|
+
* engine's canvas, a Fabric canvas, or a saved document, which is drawn on
|
|
324
|
+
* an off-screen canvas that is freed after its page.
|
|
325
|
+
*/
|
|
326
|
+
async function exportPdf(sources, options = {}) {
|
|
327
|
+
const list = Array.isArray(sources) ? [...sources] : [sources];
|
|
328
|
+
if (list.length === 0) throw new require_errors.DocumentEngineError("INVALID_EXPORT_OPTIONS", "exportPdf needs at least one page");
|
|
329
|
+
const dpi = options.dpi ?? 300;
|
|
330
|
+
if (!(Number.isFinite(dpi) && dpi > 0 && dpi <= 1200)) throw new require_errors.DocumentEngineError("INVALID_EXPORT_OPTIONS", "dpi must be between 1 and 1200");
|
|
331
|
+
const mode = options.mode ?? "hybrid";
|
|
332
|
+
if (![
|
|
333
|
+
"vector",
|
|
334
|
+
"raster",
|
|
335
|
+
"hybrid"
|
|
336
|
+
].includes(mode)) throw new require_errors.DocumentEngineError("INVALID_EXPORT_OPTIONS", "mode must be \"vector\", \"raster\" or \"hybrid\"");
|
|
337
|
+
if (typeof document === "undefined") throw new require_errors.DocumentEngineError("PDF_UNAVAILABLE", "PDF export needs a browser DOM");
|
|
338
|
+
stop(options.signal);
|
|
339
|
+
const jsPDF = await loadPeers(mode !== "raster");
|
|
340
|
+
const fonts = await require_fonts.loadFonts(options.fonts ?? [], options.signal);
|
|
341
|
+
stop(options.signal);
|
|
342
|
+
let pdf;
|
|
343
|
+
let registered = {
|
|
344
|
+
families: /* @__PURE__ */ new Map(),
|
|
345
|
+
substituted: []
|
|
346
|
+
};
|
|
347
|
+
const warnings = [];
|
|
348
|
+
const warnedStyles = /* @__PURE__ */ new Set();
|
|
349
|
+
let renderer;
|
|
350
|
+
try {
|
|
351
|
+
for (let index = 0; index < list.length; index += 1) {
|
|
352
|
+
stop(options.signal);
|
|
353
|
+
const source = list[index];
|
|
354
|
+
let canvas;
|
|
355
|
+
if (isEngine(source)) canvas = source.canvas;
|
|
356
|
+
else if (isCanvas(source)) canvas = source;
|
|
357
|
+
else {
|
|
358
|
+
renderer ?? (renderer = await createRenderer(options));
|
|
359
|
+
await renderer.engine.loadDocument(source, {
|
|
360
|
+
signal: options.signal,
|
|
361
|
+
discardUnsavedChanges: true
|
|
362
|
+
});
|
|
363
|
+
canvas = renderer.canvas;
|
|
364
|
+
}
|
|
365
|
+
const layout = require_page_layout.layoutPage({
|
|
366
|
+
width: canvas.getWidth(),
|
|
367
|
+
height: canvas.getHeight()
|
|
368
|
+
}, options);
|
|
369
|
+
const format = [layout.pageWidth, layout.pageHeight];
|
|
370
|
+
if (!pdf) {
|
|
371
|
+
pdf = new jsPDF({
|
|
372
|
+
unit: "pt",
|
|
373
|
+
format,
|
|
374
|
+
orientation: layout.orientation,
|
|
375
|
+
compress: true,
|
|
376
|
+
putOnlyUsedFonts: true
|
|
377
|
+
});
|
|
378
|
+
registered = require_fonts.registerFonts(pdf, fonts);
|
|
379
|
+
} else pdf.addPage(format, layout.orientation);
|
|
380
|
+
warnSubstitutedStyles(canvas, registered, index + 1, warnings, warnedStyles);
|
|
381
|
+
const context = {
|
|
382
|
+
document: pdf,
|
|
383
|
+
layout,
|
|
384
|
+
options,
|
|
385
|
+
registered,
|
|
386
|
+
page: index + 1,
|
|
387
|
+
warnings
|
|
388
|
+
};
|
|
389
|
+
if (mode === "raster") await drawRasterPage(canvas, context);
|
|
390
|
+
else await drawVectorPage(canvas, context);
|
|
391
|
+
if (renderer && canvas === renderer.canvas) require_batch_render.disposeObjects(renderer.canvas);
|
|
392
|
+
}
|
|
393
|
+
stop(options.signal);
|
|
394
|
+
const { metadata } = options;
|
|
395
|
+
pdf.setProperties({
|
|
396
|
+
creator: metadata?.creator ?? "fabricjs-document-engine",
|
|
397
|
+
...metadata
|
|
398
|
+
});
|
|
399
|
+
return {
|
|
400
|
+
blob: pdf.output("blob"),
|
|
401
|
+
pageCount: list.length,
|
|
402
|
+
warnings
|
|
403
|
+
};
|
|
404
|
+
} catch (error) {
|
|
405
|
+
if (require_errors.isDocumentEngineError(error)) throw error;
|
|
406
|
+
if (options.signal?.aborted) throw new require_errors.DocumentEngineError("EXPORT_ABORTED", "The PDF export was cancelled", { cause: error });
|
|
407
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
408
|
+
throw new require_errors.DocumentEngineError("PDF_FAILED", `The PDF could not be made: ${reason}`, { cause: error });
|
|
409
|
+
} finally {
|
|
410
|
+
await renderer?.release();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async function createRenderer(options) {
|
|
414
|
+
const [{ StaticCanvas }, { createDocumentEngine }] = await Promise.all([import("fabric"), Promise.resolve().then(() => require("../engine/create-document-engine.cjs"))]);
|
|
415
|
+
const element = document.createElement("canvas");
|
|
416
|
+
const canvas = new StaticCanvas(element, {
|
|
417
|
+
renderOnAddRemove: false,
|
|
418
|
+
enableRetinaScaling: false
|
|
419
|
+
});
|
|
420
|
+
const engine = createDocumentEngine({
|
|
421
|
+
canvas,
|
|
422
|
+
customObjects: options.customObjects,
|
|
423
|
+
assets: options.assets,
|
|
424
|
+
limits: options.limits,
|
|
425
|
+
history: { limit: 1 }
|
|
426
|
+
});
|
|
427
|
+
return {
|
|
428
|
+
canvas,
|
|
429
|
+
engine,
|
|
430
|
+
release: async () => {
|
|
431
|
+
require_batch_render.disposeObjects(canvas);
|
|
432
|
+
engine.destroy();
|
|
433
|
+
await canvas.dispose();
|
|
434
|
+
element.width = 0;
|
|
435
|
+
element.height = 0;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
//#endregion
|
|
440
|
+
exports.exportPdf = exportPdf;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { FabricDocument } from "../document/document-format.cjs";
|
|
2
|
+
import { AssetOptions } from "../assets/asset-pipeline.cjs";
|
|
3
|
+
import { ExportBackground } from "../export/export-options.cjs";
|
|
4
|
+
import { ContentLimits } from "../security/content-limits.cjs";
|
|
5
|
+
import { CustomObjectDefinition } from "../fabric/object-registry.cjs";
|
|
6
|
+
import { DocumentEngine } from "../engine/create-document-engine.cjs";
|
|
7
|
+
import { PdfFont } from "./fonts.cjs";
|
|
8
|
+
import { PageLayoutOptions } from "./page-layout.cjs";
|
|
9
|
+
import { StaticCanvas } from "fabric";
|
|
10
|
+
//#region src/pdf/export-pdf.d.ts
|
|
11
|
+
/**
|
|
12
|
+
* Exports canvases and documents as PDF (fabric.js #5906), with jsPDF and
|
|
13
|
+
* svg2pdf.js as optional peer dependencies.
|
|
14
|
+
*
|
|
15
|
+
* - `vector` draws every object as PDF vectors and text, so text can be
|
|
16
|
+
* selected and the file prints sharply at any size.
|
|
17
|
+
* - `raster` draws each page as one picture at `dpi`.
|
|
18
|
+
* - `hybrid` (the default) draws everything as vectors except what svg2pdf
|
|
19
|
+
* cannot draw faithfully (shadows, blend modes, gradient outlines,
|
|
20
|
+
* non-scaling outlines on scaled objects, and text in a font with no file),
|
|
21
|
+
* which becomes a picture of just that object, in its place.
|
|
22
|
+
*/
|
|
23
|
+
export type PdfMode = "vector" | "raster" | "hybrid";
|
|
24
|
+
/** An engine, a Fabric canvas, or a saved document or plain Fabric JSON. */
|
|
25
|
+
export type PdfSource = DocumentEngine | StaticCanvas | FabricDocument | Record<string, unknown>;
|
|
26
|
+
export interface PdfExportOptions extends PageLayoutOptions {
|
|
27
|
+
mode?: PdfMode;
|
|
28
|
+
/** Resolution of everything drawn as a picture. Default 300. */
|
|
29
|
+
dpi?: number;
|
|
30
|
+
/** TrueType files for the fonts the canvas uses. */
|
|
31
|
+
fonts?: PdfFont[];
|
|
32
|
+
/**
|
|
33
|
+
* Text in a font with no file in `fonts`. `rasterize` (the default in
|
|
34
|
+
* hybrid mode) draws it as a picture so it looks right; `substitute` keeps
|
|
35
|
+
* it as text in the closest built-in PDF font.
|
|
36
|
+
*/
|
|
37
|
+
missingFonts?: "rasterize" | "substitute";
|
|
38
|
+
background?: ExportBackground;
|
|
39
|
+
metadata?: {
|
|
40
|
+
title?: string;
|
|
41
|
+
author?: string;
|
|
42
|
+
subject?: string;
|
|
43
|
+
keywords?: string;
|
|
44
|
+
creator?: string;
|
|
45
|
+
};
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
/** For documents: custom object classes, asset options and limits, as for the engine. */
|
|
48
|
+
customObjects?: CustomObjectDefinition[];
|
|
49
|
+
assets?: AssetOptions;
|
|
50
|
+
limits?: ContentLimits;
|
|
51
|
+
}
|
|
52
|
+
export type PdfWarningCode = "PDF_RASTERIZED" | "PDF_UNSUPPORTED" | "PDF_FONT_SUBSTITUTED" | "IMAGE_NOT_EMBEDDED";
|
|
53
|
+
export interface PdfWarning {
|
|
54
|
+
code: PdfWarningCode;
|
|
55
|
+
message: string;
|
|
56
|
+
/** The page, counted from 1. */
|
|
57
|
+
page: number;
|
|
58
|
+
objectIds: string[];
|
|
59
|
+
family?: string;
|
|
60
|
+
url?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface PdfExportResult {
|
|
63
|
+
blob: Blob;
|
|
64
|
+
pageCount: number;
|
|
65
|
+
warnings: PdfWarning[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Exports one or more pages as a PDF. Each source becomes one page: an
|
|
69
|
+
* engine's canvas, a Fabric canvas, or a saved document, which is drawn on
|
|
70
|
+
* an off-screen canvas that is freed after its page.
|
|
71
|
+
*/
|
|
72
|
+
export declare function exportPdf(sources: PdfSource | readonly PdfSource[], options?: PdfExportOptions): Promise<PdfExportResult>;
|
|
73
|
+
//#endregion
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { FabricDocument } from "../document/document-format.js";
|
|
2
|
+
import { AssetOptions } from "../assets/asset-pipeline.js";
|
|
3
|
+
import { ExportBackground } from "../export/export-options.js";
|
|
4
|
+
import { ContentLimits } from "../security/content-limits.js";
|
|
5
|
+
import { CustomObjectDefinition } from "../fabric/object-registry.js";
|
|
6
|
+
import { DocumentEngine } from "../engine/create-document-engine.js";
|
|
7
|
+
import { PdfFont } from "./fonts.js";
|
|
8
|
+
import { PageLayoutOptions } from "./page-layout.js";
|
|
9
|
+
import { StaticCanvas } from "fabric";
|
|
10
|
+
//#region src/pdf/export-pdf.d.ts
|
|
11
|
+
/**
|
|
12
|
+
* Exports canvases and documents as PDF (fabric.js #5906), with jsPDF and
|
|
13
|
+
* svg2pdf.js as optional peer dependencies.
|
|
14
|
+
*
|
|
15
|
+
* - `vector` draws every object as PDF vectors and text, so text can be
|
|
16
|
+
* selected and the file prints sharply at any size.
|
|
17
|
+
* - `raster` draws each page as one picture at `dpi`.
|
|
18
|
+
* - `hybrid` (the default) draws everything as vectors except what svg2pdf
|
|
19
|
+
* cannot draw faithfully (shadows, blend modes, gradient outlines,
|
|
20
|
+
* non-scaling outlines on scaled objects, and text in a font with no file),
|
|
21
|
+
* which becomes a picture of just that object, in its place.
|
|
22
|
+
*/
|
|
23
|
+
export type PdfMode = "vector" | "raster" | "hybrid";
|
|
24
|
+
/** An engine, a Fabric canvas, or a saved document or plain Fabric JSON. */
|
|
25
|
+
export type PdfSource = DocumentEngine | StaticCanvas | FabricDocument | Record<string, unknown>;
|
|
26
|
+
export interface PdfExportOptions extends PageLayoutOptions {
|
|
27
|
+
mode?: PdfMode;
|
|
28
|
+
/** Resolution of everything drawn as a picture. Default 300. */
|
|
29
|
+
dpi?: number;
|
|
30
|
+
/** TrueType files for the fonts the canvas uses. */
|
|
31
|
+
fonts?: PdfFont[];
|
|
32
|
+
/**
|
|
33
|
+
* Text in a font with no file in `fonts`. `rasterize` (the default in
|
|
34
|
+
* hybrid mode) draws it as a picture so it looks right; `substitute` keeps
|
|
35
|
+
* it as text in the closest built-in PDF font.
|
|
36
|
+
*/
|
|
37
|
+
missingFonts?: "rasterize" | "substitute";
|
|
38
|
+
background?: ExportBackground;
|
|
39
|
+
metadata?: {
|
|
40
|
+
title?: string;
|
|
41
|
+
author?: string;
|
|
42
|
+
subject?: string;
|
|
43
|
+
keywords?: string;
|
|
44
|
+
creator?: string;
|
|
45
|
+
};
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
/** For documents: custom object classes, asset options and limits, as for the engine. */
|
|
48
|
+
customObjects?: CustomObjectDefinition[];
|
|
49
|
+
assets?: AssetOptions;
|
|
50
|
+
limits?: ContentLimits;
|
|
51
|
+
}
|
|
52
|
+
export type PdfWarningCode = "PDF_RASTERIZED" | "PDF_UNSUPPORTED" | "PDF_FONT_SUBSTITUTED" | "IMAGE_NOT_EMBEDDED";
|
|
53
|
+
export interface PdfWarning {
|
|
54
|
+
code: PdfWarningCode;
|
|
55
|
+
message: string;
|
|
56
|
+
/** The page, counted from 1. */
|
|
57
|
+
page: number;
|
|
58
|
+
objectIds: string[];
|
|
59
|
+
family?: string;
|
|
60
|
+
url?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface PdfExportResult {
|
|
63
|
+
blob: Blob;
|
|
64
|
+
pageCount: number;
|
|
65
|
+
warnings: PdfWarning[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Exports one or more pages as a PDF. Each source becomes one page: an
|
|
69
|
+
* engine's canvas, a Fabric canvas, or a saved document, which is drawn on
|
|
70
|
+
* an off-screen canvas that is freed after its page.
|
|
71
|
+
*/
|
|
72
|
+
export declare function exportPdf(sources: PdfSource | readonly PdfSource[], options?: PdfExportOptions): Promise<PdfExportResult>;
|
|
73
|
+
//#endregion
|