fabricjs-document-engine 1.1.0 → 1.3.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 +70 -1
- package/README.zh-CN.md +71 -1
- package/dist/assets/asset-pipeline.cjs +10 -8
- package/dist/assets/asset-pipeline.d.cts +1 -1
- package/dist/assets/asset-pipeline.d.ts +1 -1
- package/dist/assets/asset-pipeline.js +10 -8
- package/dist/assets/image-check.cjs +4 -3
- package/dist/assets/image-check.d.cts +1 -1
- package/dist/assets/image-check.d.ts +1 -1
- package/dist/assets/image-check.js +4 -3
- package/dist/commands/clipboard.cjs +5 -0
- package/dist/commands/clipboard.js +5 -0
- package/dist/commands/text-edit.cjs +223 -0
- package/dist/commands/text-edit.d.cts +23 -0
- package/dist/commands/text-edit.d.ts +23 -0
- package/dist/commands/text-edit.js +218 -0
- package/dist/document/document-format.d.cts +15 -0
- package/dist/document/document-format.d.ts +15 -0
- package/dist/document/validate-document.cjs +8 -0
- package/dist/document/validate-document.js +8 -0
- package/dist/engine/create-document-engine.cjs +115 -21
- package/dist/engine/create-document-engine.d.cts +24 -6
- package/dist/engine/create-document-engine.d.ts +24 -6
- package/dist/engine/create-document-engine.js +116 -22
- package/dist/engine/errors.d.cts +1 -1
- package/dist/engine/errors.d.ts +1 -1
- package/dist/export/export-options.cjs +3 -0
- package/dist/export/export-options.d.cts +6 -0
- package/dist/export/export-options.d.ts +6 -0
- package/dist/export/export-options.js +3 -0
- package/dist/export/preflight-export.d.cts +1 -1
- package/dist/export/preflight-export.d.ts +1 -1
- package/dist/export/render-export.cjs +42 -4
- package/dist/export/render-export.js +43 -5
- package/dist/export/svg/clip-masks.cjs +39 -0
- package/dist/export/svg/clip-masks.js +37 -0
- package/dist/export/svg/embed-assets.cjs +1 -0
- package/dist/export/svg/embed-assets.js +1 -0
- package/dist/export/svg/raster-object.cjs +82 -0
- package/dist/export/svg/raster-object.js +81 -0
- package/dist/{pdf → export/svg}/text-decorations.cjs +3 -3
- package/dist/{pdf → export/svg}/text-decorations.js +3 -3
- package/dist/export/svg/text-on-path.cjs +0 -10
- package/dist/export/svg/text-on-path.js +1 -10
- package/dist/fabric/fabric-adapter.cjs +5 -3
- package/dist/fabric/fabric-adapter.js +5 -3
- package/dist/fabric/object-registry.cjs +7 -1
- package/dist/fabric/object-registry.js +7 -1
- package/dist/fabric/page-state.cjs +69 -0
- package/dist/fabric/page-state.js +64 -0
- package/dist/filters/filter-worker.cjs +281 -0
- package/dist/filters/filter-worker.d.cts +26 -0
- package/dist/filters/filter-worker.d.ts +26 -0
- package/dist/filters/filter-worker.js +281 -0
- package/dist/filters/pipeline.cjs +91 -0
- package/dist/filters/pipeline.d.cts +35 -0
- package/dist/filters/pipeline.d.ts +35 -0
- package/dist/filters/pipeline.js +87 -0
- package/dist/filters/worker-entry.cjs +78 -0
- package/dist/filters/worker-entry.d.cts +29 -0
- package/dist/filters/worker-entry.d.ts +29 -0
- package/dist/filters/worker-entry.js +78 -0
- package/dist/filters.cjs +9 -0
- package/dist/filters.d.cts +3 -0
- package/dist/filters.d.ts +3 -0
- package/dist/filters.js +3 -0
- package/dist/history/apply-state.cjs +19 -2
- package/dist/history/apply-state.js +19 -2
- package/dist/history/create-history.cjs +53 -13
- package/dist/history/create-history.d.cts +8 -0
- package/dist/history/create-history.d.ts +8 -0
- package/dist/history/create-history.js +53 -13
- package/dist/history/snapshot.cjs +10 -1
- package/dist/history/snapshot.js +10 -2
- package/dist/import/svg-import.cjs +102 -0
- package/dist/import/svg-import.d.cts +1 -0
- package/dist/import/svg-import.d.ts +1 -0
- package/dist/import/svg-import.js +103 -1
- package/dist/index.cjs +7 -0
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/migrations/migrate-document.cjs +2 -1
- package/dist/migrations/migrate-document.js +2 -1
- package/dist/pdf/export-pdf.cjs +8 -67
- package/dist/pdf/export-pdf.js +8 -67
- package/dist/performance/batch.cjs +31 -0
- package/dist/performance/batch.d.cts +4 -0
- package/dist/performance/batch.d.ts +4 -0
- package/dist/performance/batch.js +31 -0
- package/dist/performance/dirty-regions.cjs +378 -0
- package/dist/performance/dirty-regions.d.cts +23 -0
- package/dist/performance/dirty-regions.d.ts +23 -0
- package/dist/performance/dirty-regions.js +378 -0
- package/dist/performance/monitor.cjs +60 -0
- package/dist/performance/monitor.d.cts +20 -0
- package/dist/performance/monitor.d.ts +20 -0
- package/dist/performance/monitor.js +60 -0
- package/dist/performance/spatial-index.cjs +78 -0
- package/dist/performance/spatial-index.d.cts +21 -0
- package/dist/performance/spatial-index.d.ts +21 -0
- package/dist/performance/spatial-index.js +78 -0
- package/dist/performance.cjs +9 -0
- package/dist/performance.d.cts +5 -0
- package/dist/performance.d.ts +5 -0
- package/dist/performance.js +5 -0
- package/dist/recovery/recovery-controller.cjs +148 -29
- package/dist/recovery/recovery-controller.d.cts +8 -0
- package/dist/recovery/recovery-controller.d.ts +8 -0
- package/dist/recovery/recovery-controller.js +148 -29
- package/dist/security/content-limits.cjs +43 -3
- package/dist/security/content-limits.d.cts +8 -0
- package/dist/security/content-limits.d.ts +8 -0
- package/dist/security/content-limits.js +39 -4
- package/dist/text/bounded-textbox.cjs +306 -0
- package/dist/text/bounded-textbox.d.cts +53 -0
- package/dist/text/bounded-textbox.d.ts +53 -0
- package/dist/text/bounded-textbox.js +306 -0
- package/dist/text/mobile-input.cjs +146 -0
- package/dist/text/mobile-input.d.cts +19 -0
- package/dist/text/mobile-input.d.ts +19 -0
- package/dist/text/mobile-input.js +145 -0
- package/dist/text/register.cjs +17 -0
- package/dist/text/register.d.cts +5 -0
- package/dist/text/register.d.ts +5 -0
- package/dist/text/register.js +16 -0
- package/dist/text/shaping.cjs +125 -0
- package/dist/text/shaping.d.cts +28 -0
- package/dist/text/shaping.d.ts +28 -0
- package/dist/text/shaping.js +121 -0
- package/dist/text/vertical-orientation.cjs +192 -0
- package/dist/text/vertical-orientation.d.cts +10 -0
- package/dist/text/vertical-orientation.d.ts +10 -0
- package/dist/text/vertical-orientation.js +190 -0
- package/dist/text/vertical-text.cjs +336 -0
- package/dist/text/vertical-text.d.cts +54 -0
- package/dist/text/vertical-text.d.ts +54 -0
- package/dist/text/vertical-text.js +336 -0
- package/dist/text.cjs +21 -0
- package/dist/text.d.cts +7 -0
- package/dist/text.d.ts +7 -0
- package/dist/text.js +7 -0
- package/dist/util/concurrency.cjs +16 -3
- package/dist/util/concurrency.js +16 -3
- package/package.json +31 -1
- package/schema/document-v1.schema.json +5 -1
package/dist/pdf/export-pdf.cjs
CHANGED
|
@@ -3,12 +3,13 @@ const require_object_ids = require("../fabric/object-ids.cjs");
|
|
|
3
3
|
const require_walk_objects = require("../fabric/walk-objects.cjs");
|
|
4
4
|
const require_overrides = require("../export/svg/overrides.cjs");
|
|
5
5
|
const require_text_on_path = require("../export/svg/text-on-path.cjs");
|
|
6
|
+
const require_raster_object = require("../export/svg/raster-object.cjs");
|
|
7
|
+
const require_text_decorations = require("../export/svg/text-decorations.cjs");
|
|
6
8
|
const require_render_export = require("../export/render-export.cjs");
|
|
7
9
|
const require_embed_assets = require("../export/svg/embed-assets.cjs");
|
|
8
10
|
const require_batch_render = require("../export/batch-render.cjs");
|
|
9
11
|
const require_fonts = require("./fonts.cjs");
|
|
10
12
|
const require_page_layout = require("./page-layout.cjs");
|
|
11
|
-
const require_text_decorations = require("./text-decorations.cjs");
|
|
12
13
|
//#region src/pdf/export-pdf.ts
|
|
13
14
|
const RASTER_REASONS = {
|
|
14
15
|
shadow: "it has a shadow, which PDF vectors cannot draw",
|
|
@@ -16,7 +17,8 @@ const RASTER_REASONS = {
|
|
|
16
17
|
gradientStroke: "its outline is a gradient or pattern",
|
|
17
18
|
uniformStroke: "it keeps its outline width while scaled (strokeUniform)",
|
|
18
19
|
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
|
+
characters: "it uses characters the built-in PDF fonts do not have; add a TrueType font that has them",
|
|
21
|
+
mask: "it uses an inverted or nested clip path, which PDF vectors cannot draw"
|
|
20
22
|
};
|
|
21
23
|
function stop(signal) {
|
|
22
24
|
if (signal?.aborted) throw new require_errors.DocumentEngineError("EXPORT_ABORTED", "The PDF export was cancelled");
|
|
@@ -74,6 +76,7 @@ function rasterReason(object, registered, missingFonts) {
|
|
|
74
76
|
require_walk_objects.walkObjects([object], (child) => {
|
|
75
77
|
if (reason) return;
|
|
76
78
|
if (child.shadow) reason = "shadow";
|
|
79
|
+
else if (child.clipPath?.inverted || child.clipPath?.clipPath) reason = "mask";
|
|
77
80
|
else if (child.globalCompositeOperation && child.globalCompositeOperation !== "source-over") reason = "blend";
|
|
78
81
|
else if (typeof child.stroke === "object" && child.stroke !== null && child.strokeWidth > 0) reason = "gradientStroke";
|
|
79
82
|
else if (child.strokeUniform && child.stroke && child.strokeWidth > 0) {
|
|
@@ -90,69 +93,6 @@ function rasterReason(object, registered, missingFonts) {
|
|
|
90
93
|
});
|
|
91
94
|
return reason;
|
|
92
95
|
}
|
|
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
96
|
function quoteFamily(name) {
|
|
157
97
|
return /^[a-z-]+$/i.test(name) ? name : `"${name.replace(/"/g, "")}"`;
|
|
158
98
|
}
|
|
@@ -238,7 +178,7 @@ function clipTo(context, draw) {
|
|
|
238
178
|
}
|
|
239
179
|
async function drawRasterPage(canvas, context) {
|
|
240
180
|
const { layout, options } = context;
|
|
241
|
-
const multiplier = layout.scale * (options.dpi ?? 300) / 72;
|
|
181
|
+
const multiplier = require_raster_object.safeMultiplier(layout.scale * (options.dpi ?? 300) / 72, canvas.getWidth(), canvas.getHeight(), options.limits);
|
|
242
182
|
const element = require_render_export.withExportView(canvas, options.background ?? "keep", "png", () => canvas.toCanvasElement(multiplier));
|
|
243
183
|
try {
|
|
244
184
|
await clipTo(context, () => {
|
|
@@ -262,7 +202,7 @@ async function drawVectorPage(canvas, context) {
|
|
|
262
202
|
const reason = rasterReason(object, registered, missingFonts);
|
|
263
203
|
if (!reason) continue;
|
|
264
204
|
if (mode === "hybrid") {
|
|
265
|
-
rasters.set(object, rasterMarkup(canvas, object, multiplier));
|
|
205
|
+
rasters.set(object, require_raster_object.rasterMarkup(canvas, object, multiplier, options.limits));
|
|
266
206
|
warnings.push({
|
|
267
207
|
code: "PDF_RASTERIZED",
|
|
268
208
|
message: `An object was drawn as a picture at ${options.dpi ?? 300} dpi because ${RASTER_REASONS[reason]}`,
|
|
@@ -295,6 +235,7 @@ async function drawVectorPage(canvas, context) {
|
|
|
295
235
|
});
|
|
296
236
|
const embedded = await require_embed_assets.embedSvgAssets(require_render_export.repairFabricSvg(svg), canvas, {
|
|
297
237
|
textOnPath: "vector",
|
|
238
|
+
textDecorations: "shapes",
|
|
298
239
|
embedImages: true,
|
|
299
240
|
maxEmbeddedImageBytes: Number.MAX_SAFE_INTEGER,
|
|
300
241
|
embedFonts: {}
|
package/dist/pdf/export-pdf.js
CHANGED
|
@@ -3,12 +3,13 @@ import { readObjectId } from "../fabric/object-ids.js";
|
|
|
3
3
|
import { walkObjects } from "../fabric/walk-objects.js";
|
|
4
4
|
import { withSvgOverrides } from "../export/svg/overrides.js";
|
|
5
5
|
import { isTextOnPath, textOnPathToSVG } from "../export/svg/text-on-path.js";
|
|
6
|
+
import { rasterMarkup, safeMultiplier } from "../export/svg/raster-object.js";
|
|
7
|
+
import { decoratedTextToSVG, hasStraightDecorations } from "../export/svg/text-decorations.js";
|
|
6
8
|
import { repairFabricSvg, withExportView } from "../export/render-export.js";
|
|
7
9
|
import { embedSvgAssets } from "../export/svg/embed-assets.js";
|
|
8
10
|
import { disposeObjects } from "../export/batch-render.js";
|
|
9
11
|
import { jsPdfStyle, loadFonts, registerFonts, standardFamily } from "./fonts.js";
|
|
10
12
|
import { layoutPage } from "./page-layout.js";
|
|
11
|
-
import { decoratedTextToSVG, hasStraightDecorations } from "./text-decorations.js";
|
|
12
13
|
//#region src/pdf/export-pdf.ts
|
|
13
14
|
const RASTER_REASONS = {
|
|
14
15
|
shadow: "it has a shadow, which PDF vectors cannot draw",
|
|
@@ -16,7 +17,8 @@ const RASTER_REASONS = {
|
|
|
16
17
|
gradientStroke: "its outline is a gradient or pattern",
|
|
17
18
|
uniformStroke: "it keeps its outline width while scaled (strokeUniform)",
|
|
18
19
|
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
|
+
characters: "it uses characters the built-in PDF fonts do not have; add a TrueType font that has them",
|
|
21
|
+
mask: "it uses an inverted or nested clip path, which PDF vectors cannot draw"
|
|
20
22
|
};
|
|
21
23
|
function stop(signal) {
|
|
22
24
|
if (signal?.aborted) throw new DocumentEngineError("EXPORT_ABORTED", "The PDF export was cancelled");
|
|
@@ -74,6 +76,7 @@ function rasterReason(object, registered, missingFonts) {
|
|
|
74
76
|
walkObjects([object], (child) => {
|
|
75
77
|
if (reason) return;
|
|
76
78
|
if (child.shadow) reason = "shadow";
|
|
79
|
+
else if (child.clipPath?.inverted || child.clipPath?.clipPath) reason = "mask";
|
|
77
80
|
else if (child.globalCompositeOperation && child.globalCompositeOperation !== "source-over") reason = "blend";
|
|
78
81
|
else if (typeof child.stroke === "object" && child.stroke !== null && child.strokeWidth > 0) reason = "gradientStroke";
|
|
79
82
|
else if (child.strokeUniform && child.stroke && child.strokeWidth > 0) {
|
|
@@ -90,69 +93,6 @@ function rasterReason(object, registered, missingFonts) {
|
|
|
90
93
|
});
|
|
91
94
|
return reason;
|
|
92
95
|
}
|
|
93
|
-
function shadowPadding(object) {
|
|
94
|
-
let padding = 0;
|
|
95
|
-
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
|
-
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
96
|
function quoteFamily(name) {
|
|
157
97
|
return /^[a-z-]+$/i.test(name) ? name : `"${name.replace(/"/g, "")}"`;
|
|
158
98
|
}
|
|
@@ -238,7 +178,7 @@ function clipTo(context, draw) {
|
|
|
238
178
|
}
|
|
239
179
|
async function drawRasterPage(canvas, context) {
|
|
240
180
|
const { layout, options } = context;
|
|
241
|
-
const multiplier = layout.scale * (options.dpi ?? 300) / 72;
|
|
181
|
+
const multiplier = safeMultiplier(layout.scale * (options.dpi ?? 300) / 72, canvas.getWidth(), canvas.getHeight(), options.limits);
|
|
242
182
|
const element = withExportView(canvas, options.background ?? "keep", "png", () => canvas.toCanvasElement(multiplier));
|
|
243
183
|
try {
|
|
244
184
|
await clipTo(context, () => {
|
|
@@ -262,7 +202,7 @@ async function drawVectorPage(canvas, context) {
|
|
|
262
202
|
const reason = rasterReason(object, registered, missingFonts);
|
|
263
203
|
if (!reason) continue;
|
|
264
204
|
if (mode === "hybrid") {
|
|
265
|
-
rasters.set(object, rasterMarkup(canvas, object, multiplier));
|
|
205
|
+
rasters.set(object, rasterMarkup(canvas, object, multiplier, options.limits));
|
|
266
206
|
warnings.push({
|
|
267
207
|
code: "PDF_RASTERIZED",
|
|
268
208
|
message: `An object was drawn as a picture at ${options.dpi ?? 300} dpi because ${RASTER_REASONS[reason]}`,
|
|
@@ -295,6 +235,7 @@ async function drawVectorPage(canvas, context) {
|
|
|
295
235
|
});
|
|
296
236
|
const embedded = await embedSvgAssets(repairFabricSvg(svg), canvas, {
|
|
297
237
|
textOnPath: "vector",
|
|
238
|
+
textDecorations: "shapes",
|
|
298
239
|
embedImages: true,
|
|
299
240
|
maxEmbeddedImageBytes: Number.MAX_SAFE_INTEGER,
|
|
300
241
|
embedFonts: {}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/performance/batch.ts
|
|
2
|
+
const depths = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function batchCanvasUpdates(canvas, work) {
|
|
4
|
+
const state = depths.get(canvas) ?? {
|
|
5
|
+
depth: 0,
|
|
6
|
+
renderOnAddRemove: canvas.renderOnAddRemove
|
|
7
|
+
};
|
|
8
|
+
if (state.depth === 0) state.renderOnAddRemove = canvas.renderOnAddRemove;
|
|
9
|
+
state.depth += 1;
|
|
10
|
+
depths.set(canvas, state);
|
|
11
|
+
canvas.renderOnAddRemove = false;
|
|
12
|
+
const finish = () => {
|
|
13
|
+
state.depth -= 1;
|
|
14
|
+
if (state.depth > 0) return;
|
|
15
|
+
depths.delete(canvas);
|
|
16
|
+
canvas.renderOnAddRemove = state.renderOnAddRemove;
|
|
17
|
+
canvas.requestRenderAll();
|
|
18
|
+
};
|
|
19
|
+
let result;
|
|
20
|
+
try {
|
|
21
|
+
result = work();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
finish();
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
if (result instanceof Promise) return result.finally(finish);
|
|
27
|
+
finish();
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
exports.batchCanvasUpdates = batchCanvasUpdates;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/performance/batch.ts
|
|
2
|
+
const depths = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function batchCanvasUpdates(canvas, work) {
|
|
4
|
+
const state = depths.get(canvas) ?? {
|
|
5
|
+
depth: 0,
|
|
6
|
+
renderOnAddRemove: canvas.renderOnAddRemove
|
|
7
|
+
};
|
|
8
|
+
if (state.depth === 0) state.renderOnAddRemove = canvas.renderOnAddRemove;
|
|
9
|
+
state.depth += 1;
|
|
10
|
+
depths.set(canvas, state);
|
|
11
|
+
canvas.renderOnAddRemove = false;
|
|
12
|
+
const finish = () => {
|
|
13
|
+
state.depth -= 1;
|
|
14
|
+
if (state.depth > 0) return;
|
|
15
|
+
depths.delete(canvas);
|
|
16
|
+
canvas.renderOnAddRemove = state.renderOnAddRemove;
|
|
17
|
+
canvas.requestRenderAll();
|
|
18
|
+
};
|
|
19
|
+
let result;
|
|
20
|
+
try {
|
|
21
|
+
result = work();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
finish();
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
if (result instanceof Promise) return result.finally(finish);
|
|
27
|
+
finish();
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { batchCanvasUpdates };
|