@tldraw/editor 3.8.0-canary.61db77736050 → 3.8.0-canary.80294e641ad6

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.
Files changed (56) hide show
  1. package/dist-cjs/index.d.ts +11 -104
  2. package/dist-cjs/index.js +1 -5
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -1
  5. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  6. package/dist-cjs/lib/config/createTLStore.js +1 -1
  7. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  8. package/dist-cjs/lib/editor/Editor.js +4 -57
  9. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  10. package/dist-cjs/lib/editor/types/SvgExportContext.js.map +2 -2
  11. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  12. package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
  13. package/dist-cjs/lib/exports/getSvgJsx.js +3 -16
  14. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  15. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +1 -3
  16. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  17. package/dist-cjs/version.js +3 -3
  18. package/dist-cjs/version.js.map +1 -1
  19. package/dist-esm/index.d.mts +11 -104
  20. package/dist-esm/index.mjs +1 -5
  21. package/dist-esm/index.mjs.map +2 -2
  22. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +4 -1
  23. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  24. package/dist-esm/lib/config/createTLStore.mjs +1 -1
  25. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  26. package/dist-esm/lib/editor/Editor.mjs +4 -57
  27. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  28. package/dist-esm/lib/editor/types/SvgExportContext.mjs.map +2 -2
  29. package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
  30. package/dist-esm/lib/exports/getSvgJsx.mjs +3 -16
  31. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  32. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +1 -3
  33. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  34. package/dist-esm/version.mjs +3 -3
  35. package/dist-esm/version.mjs.map +1 -1
  36. package/package.json +7 -9
  37. package/src/index.ts +0 -4
  38. package/src/lib/components/default-components/DefaultCanvas.tsx +4 -1
  39. package/src/lib/config/createTLStore.ts +1 -1
  40. package/src/lib/editor/Editor.ts +9 -68
  41. package/src/lib/editor/types/SvgExportContext.tsx +0 -21
  42. package/src/lib/editor/types/misc-types.ts +2 -55
  43. package/src/lib/exports/exportToSvg.tsx +2 -2
  44. package/src/lib/exports/getSvgJsx.tsx +2 -17
  45. package/src/lib/utils/sync/TLLocalSyncClient.ts +1 -3
  46. package/src/version.ts +3 -3
  47. package/dist-cjs/lib/exports/getSvgAsImage.js +0 -83
  48. package/dist-cjs/lib/exports/getSvgAsImage.js.map +0 -7
  49. package/dist-cjs/lib/utils/browserCanvasMaxSize.js +0 -75
  50. package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +0 -7
  51. package/dist-esm/lib/exports/getSvgAsImage.mjs +0 -63
  52. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +0 -7
  53. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +0 -45
  54. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +0 -7
  55. package/src/lib/exports/getSvgAsImage.ts +0 -92
  56. package/src/lib/utils/browserCanvasMaxSize.ts +0 -65
@@ -8,70 +8,17 @@ export type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T,
8
8
  export type OptionalKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
9
9
 
10
10
  /** @public */
11
- export type TLExportType = 'svg' | 'png' | 'jpeg' | 'webp'
12
-
13
- /** @public */
14
- export interface TLSvgExportOptions {
15
- /**
16
- * The bounding box, in page coordinates, of the area being exported.
17
- */
11
+ export interface TLImageExportOptions {
18
12
  bounds?: Box
19
- /**
20
- * The logical scale of the export. This scales the resulting size of the SVG being generated.
21
- */
22
13
  scale?: number
23
- /**
24
- * When exporting an SVG, the expected pixel ratio of the export will be passed in to
25
- * {@link @tldraw/tlschema#TLAssetStore.resolve} as the `dpr` property, so that assets can be
26
- * downscaled to the appropriate resolution.
27
- *
28
- * When exporting to a bitmap image format, the size of the resulting image will be multiplied
29
- * by this number.
30
- *
31
- * For SVG exports, this defaults to undefined - which means we'll request original-quality
32
- * assets. For bitmap exports, this defaults to 2.
33
- */
14
+ quality?: number
34
15
  pixelRatio?: number
35
-
36
- /**
37
- * Should the background color be included in the export? If false, the generated image will be
38
- * transparent (if exporting to a format that supports transparency).
39
- */
40
16
  background?: boolean
41
-
42
- /**
43
- * How much padding to include around the bounds of exports? Defaults to 32px.
44
- */
45
17
  padding?: number
46
-
47
- /**
48
- * Should the export be rendered in dark mode (true) or light mode (false)? Defaults to the
49
- * current instance's dark mode setting.
50
- */
51
18
  darkMode?: boolean
52
-
53
- /**
54
- * The
55
- * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio | `preserveAspectRatio` }
56
- * attribute of the SVG element.
57
- */
58
19
  preserveAspectRatio?: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio']
59
20
  }
60
21
 
61
- /** @public */
62
- export interface TLImageExportOptions extends TLSvgExportOptions {
63
- /**
64
- * If the export is being converted to a lossy bitmap format (e.g. jpeg), this is the quality of
65
- * the export. This is a number between 0 and 1.
66
- */
67
- quality?: number
68
-
69
- /**
70
- * The format to export as. Defaults to 'png'.
71
- */
72
- format?: TLExportType
73
- }
74
-
75
22
  /**
76
23
  * @public
77
24
  * @deprecated use {@link TLImageExportOptions} instead
@@ -3,7 +3,7 @@ import { assert } from '@tldraw/utils'
3
3
  import { flushSync } from 'react-dom'
4
4
  import { createRoot } from 'react-dom/client'
5
5
  import { Editor } from '../editor/Editor'
6
- import { TLSvgExportOptions } from '../editor/types/misc-types'
6
+ import { TLImageExportOptions } from '../editor/types/misc-types'
7
7
  import { StyleEmbedder } from './StyleEmbedder'
8
8
  import { embedMedia } from './embedMedia'
9
9
  import { getSvgJsx } from './getSvgJsx'
@@ -13,7 +13,7 @@ let idCounter = 1
13
13
  export async function exportToSvg(
14
14
  editor: Editor,
15
15
  shapeIds: TLShapeId[],
16
- opts: TLSvgExportOptions = {}
16
+ opts: TLImageExportOptions = {}
17
17
  ) {
18
18
  // when rendering to SVG, we start by creating a JSX representation of the SVG that we can
19
19
  // render with react. Hopefully elements will have a `toSvg` method that renders them to SVG,
@@ -41,7 +41,7 @@ export function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportO
41
41
  const {
42
42
  scale = 1,
43
43
  // should we include the background in the export? or is it transparent?
44
- background = editor.getInstanceState().exportBackground,
44
+ background = false,
45
45
  padding = editor.options.defaultSvgPadding,
46
46
  preserveAspectRatio,
47
47
  } = opts
@@ -102,7 +102,6 @@ export function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportO
102
102
  editor={editor}
103
103
  preserveAspectRatio={preserveAspectRatio}
104
104
  scale={scale}
105
- pixelRatio={opts.pixelRatio ?? null}
106
105
  bbox={bbox}
107
106
  background={background}
108
107
  singleFrameShapeId={singleFrameShapeId}
@@ -122,7 +121,6 @@ function SvgExport({
122
121
  editor,
123
122
  preserveAspectRatio,
124
123
  scale,
125
- pixelRatio,
126
124
  bbox,
127
125
  background,
128
126
  singleFrameShapeId,
@@ -134,7 +132,6 @@ function SvgExport({
134
132
  editor: Editor
135
133
  preserveAspectRatio?: string
136
134
  scale: number
137
- pixelRatio: number | null
138
135
  bbox: Box
139
136
  background: boolean
140
137
  singleFrameShapeId: TLShapeId | null
@@ -180,20 +177,8 @@ function SvgExport({
180
177
  isDarkMode,
181
178
  waitUntil,
182
179
  addExportDef,
183
- scale,
184
- pixelRatio,
185
- async resolveAssetUrl(assetId, width) {
186
- const asset = editor.getAsset(assetId)
187
- if (!asset || (asset.type !== 'image' && asset.type !== 'video')) return null
188
-
189
- return await editor.resolveAssetUrl(assetId, {
190
- screenScale: scale * (width / asset.props.w),
191
- shouldResolveToOriginal: pixelRatio === null,
192
- dpr: pixelRatio ?? undefined,
193
- })
194
- },
195
180
  }),
196
- [isDarkMode, waitUntil, addExportDef, scale, pixelRatio, editor]
181
+ [isDarkMode, waitUntil, addExportDef]
197
182
  )
198
183
 
199
184
  const didRenderRef = useRef(false)
@@ -196,9 +196,7 @@ export class TLLocalSyncClient {
196
196
  }
197
197
 
198
198
  if (sessionStateSnapshot) {
199
- loadSessionStateSnapshotIntoStore(this.store, sessionStateSnapshot, {
200
- forceOverwrite: true,
201
- })
199
+ loadSessionStateSnapshotIntoStore(this.store, sessionStateSnapshot)
202
200
  }
203
201
  }
204
202
 
package/src/version.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '3.8.0-canary.61db77736050'
4
+ export const version = '3.8.0-canary.80294e641ad6'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-01-21T09:06:10.847Z',
8
- patch: '2025-01-21T09:06:10.847Z',
7
+ minor: '2025-01-20T09:29:17.935Z',
8
+ patch: '2025-01-20T09:29:17.935Z',
9
9
  }
@@ -1,83 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var getSvgAsImage_exports = {};
20
- __export(getSvgAsImage_exports, {
21
- getSvgAsImage: () => getSvgAsImage
22
- });
23
- module.exports = __toCommonJS(getSvgAsImage_exports);
24
- var import_utils = require("@tldraw/utils");
25
- var import_environment = require("../globals/environment");
26
- var import_browserCanvasMaxSize = require("../utils/browserCanvasMaxSize");
27
- var import_debug_flags = require("../utils/debug-flags");
28
- async function getSvgAsImage(svgString, options) {
29
- const { type, width, height, quality = 1, pixelRatio = 2 } = options;
30
- let [clampedWidth, clampedHeight] = await (0, import_browserCanvasMaxSize.clampToBrowserMaxCanvasSize)(
31
- width * pixelRatio,
32
- height * pixelRatio
33
- );
34
- clampedWidth = Math.floor(clampedWidth);
35
- clampedHeight = Math.floor(clampedHeight);
36
- const effectiveScale = clampedWidth / width;
37
- const svgUrl = await import_utils.FileHelpers.blobToDataUrl(new Blob([svgString], { type: "image/svg+xml" }));
38
- const canvas = await new Promise((resolve) => {
39
- const image = (0, import_utils.Image)();
40
- image.crossOrigin = "anonymous";
41
- image.onload = async () => {
42
- if (import_environment.tlenv.isSafari) {
43
- await (0, import_utils.sleep)(250);
44
- }
45
- const canvas2 = document.createElement("canvas");
46
- const ctx = canvas2.getContext("2d");
47
- canvas2.width = clampedWidth;
48
- canvas2.height = clampedHeight;
49
- ctx.imageSmoothingEnabled = true;
50
- ctx.imageSmoothingQuality = "high";
51
- ctx.drawImage(image, 0, 0, clampedWidth, clampedHeight);
52
- URL.revokeObjectURL(svgUrl);
53
- resolve(canvas2);
54
- };
55
- image.onerror = () => {
56
- resolve(null);
57
- };
58
- image.src = svgUrl;
59
- });
60
- if (!canvas) return null;
61
- const blob = await new Promise(
62
- (resolve) => canvas.toBlob(
63
- (blob2) => {
64
- if (!blob2 || import_debug_flags.debugFlags.throwToBlob.get()) {
65
- resolve(null);
66
- }
67
- resolve(blob2);
68
- },
69
- "image/" + type,
70
- quality
71
- )
72
- );
73
- if (!blob) return null;
74
- if (type === "png") {
75
- const view = new DataView(await blob.arrayBuffer());
76
- return import_utils.PngHelpers.setPhysChunk(view, effectiveScale, {
77
- type: "image/" + type
78
- });
79
- } else {
80
- return blob;
81
- }
82
- }
83
- //# sourceMappingURL=getSvgAsImage.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/lib/exports/getSvgAsImage.ts"],
4
- "sourcesContent": ["import { FileHelpers, Image, PngHelpers, sleep } from '@tldraw/utils'\nimport { tlenv } from '../globals/environment'\nimport { clampToBrowserMaxCanvasSize } from '../utils/browserCanvasMaxSize'\nimport { debugFlags } from '../utils/debug-flags'\n\n/** @public */\nexport async function getSvgAsImage(\n\tsvgString: string,\n\toptions: {\n\t\ttype: 'png' | 'jpeg' | 'webp'\n\t\twidth: number\n\t\theight: number\n\t\tquality?: number\n\t\tpixelRatio?: number\n\t}\n) {\n\tconst { type, width, height, quality = 1, pixelRatio = 2 } = options\n\n\tlet [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(\n\t\twidth * pixelRatio,\n\t\theight * pixelRatio\n\t)\n\tclampedWidth = Math.floor(clampedWidth)\n\tclampedHeight = Math.floor(clampedHeight)\n\tconst effectiveScale = clampedWidth / width\n\n\t// usually we would use `URL.createObjectURL` here, but chrome has a bug where `blob:` URLs of\n\t// SVGs that use <foreignObject> mark the canvas as tainted, where data: ones do not.\n\t// https://issues.chromium.org/issues/41054640\n\tconst svgUrl = await FileHelpers.blobToDataUrl(new Blob([svgString], { type: 'image/svg+xml' }))\n\n\tconst canvas = await new Promise<HTMLCanvasElement | null>((resolve) => {\n\t\tconst image = Image()\n\t\timage.crossOrigin = 'anonymous'\n\n\t\timage.onload = async () => {\n\t\t\t// safari will fire `onLoad` before the fonts in the SVG are\n\t\t\t// actually loaded. just waiting around a while is brittle, but\n\t\t\t// there doesn't seem to be any better solution for now :( see\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=219770\n\t\t\tif (tlenv.isSafari) {\n\t\t\t\tawait sleep(250)\n\t\t\t}\n\n\t\t\tconst canvas = document.createElement('canvas') as HTMLCanvasElement\n\t\t\tconst ctx = canvas.getContext('2d')!\n\n\t\t\tcanvas.width = clampedWidth\n\t\t\tcanvas.height = clampedHeight\n\n\t\t\tctx.imageSmoothingEnabled = true\n\t\t\tctx.imageSmoothingQuality = 'high'\n\t\t\tctx.drawImage(image, 0, 0, clampedWidth, clampedHeight)\n\n\t\t\tURL.revokeObjectURL(svgUrl)\n\n\t\t\tresolve(canvas)\n\t\t}\n\n\t\timage.onerror = () => {\n\t\t\tresolve(null)\n\t\t}\n\n\t\timage.src = svgUrl\n\t})\n\n\tif (!canvas) return null\n\n\tconst blob = await new Promise<Blob | null>((resolve) =>\n\t\tcanvas.toBlob(\n\t\t\t(blob) => {\n\t\t\t\tif (!blob || debugFlags.throwToBlob.get()) {\n\t\t\t\t\tresolve(null)\n\t\t\t\t}\n\t\t\t\tresolve(blob)\n\t\t\t},\n\t\t\t'image/' + type,\n\t\t\tquality\n\t\t)\n\t)\n\n\tif (!blob) return null\n\n\tif (type === 'png') {\n\t\tconst view = new DataView(await blob.arrayBuffer())\n\t\treturn PngHelpers.setPhysChunk(view, effectiveScale, {\n\t\t\ttype: 'image/' + type,\n\t\t})\n\t} else {\n\t\treturn blob\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsD;AACtD,yBAAsB;AACtB,kCAA4C;AAC5C,yBAA2B;AAG3B,eAAsB,cACrB,WACA,SAOC;AACD,QAAM,EAAE,MAAM,OAAO,QAAQ,UAAU,GAAG,aAAa,EAAE,IAAI;AAE7D,MAAI,CAAC,cAAc,aAAa,IAAI,UAAM;AAAA,IACzC,QAAQ;AAAA,IACR,SAAS;AAAA,EACV;AACA,iBAAe,KAAK,MAAM,YAAY;AACtC,kBAAgB,KAAK,MAAM,aAAa;AACxC,QAAM,iBAAiB,eAAe;AAKtC,QAAM,SAAS,MAAM,yBAAY,cAAc,IAAI,KAAK,CAAC,SAAS,GAAG,EAAE,MAAM,gBAAgB,CAAC,CAAC;AAE/F,QAAM,SAAS,MAAM,IAAI,QAAkC,CAAC,YAAY;AACvE,UAAM,YAAQ,oBAAM;AACpB,UAAM,cAAc;AAEpB,UAAM,SAAS,YAAY;AAK1B,UAAI,yBAAM,UAAU;AACnB,kBAAM,oBAAM,GAAG;AAAA,MAChB;AAEA,YAAMA,UAAS,SAAS,cAAc,QAAQ;AAC9C,YAAM,MAAMA,QAAO,WAAW,IAAI;AAElC,MAAAA,QAAO,QAAQ;AACf,MAAAA,QAAO,SAAS;AAEhB,UAAI,wBAAwB;AAC5B,UAAI,wBAAwB;AAC5B,UAAI,UAAU,OAAO,GAAG,GAAG,cAAc,aAAa;AAEtD,UAAI,gBAAgB,MAAM;AAE1B,cAAQA,OAAM;AAAA,IACf;AAEA,UAAM,UAAU,MAAM;AACrB,cAAQ,IAAI;AAAA,IACb;AAEA,UAAM,MAAM;AAAA,EACb,CAAC;AAED,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,OAAO,MAAM,IAAI;AAAA,IAAqB,CAAC,YAC5C,OAAO;AAAA,MACN,CAACC,UAAS;AACT,YAAI,CAACA,SAAQ,8BAAW,YAAY,IAAI,GAAG;AAC1C,kBAAQ,IAAI;AAAA,QACb;AACA,gBAAQA,KAAI;AAAA,MACb;AAAA,MACA,WAAW;AAAA,MACX;AAAA,IACD;AAAA,EACD;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,SAAS,OAAO;AACnB,UAAM,OAAO,IAAI,SAAS,MAAM,KAAK,YAAY,CAAC;AAClD,WAAO,wBAAW,aAAa,MAAM,gBAAgB;AAAA,MACpD,MAAM,WAAW;AAAA,IAClB,CAAC;AAAA,EACF,OAAO;AACN,WAAO;AAAA,EACR;AACD;",
6
- "names": ["canvas", "blob"]
7
- }
@@ -1,75 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var browserCanvasMaxSize_exports = {};
30
- __export(browserCanvasMaxSize_exports, {
31
- clampToBrowserMaxCanvasSize: () => clampToBrowserMaxCanvasSize
32
- });
33
- module.exports = __toCommonJS(browserCanvasMaxSize_exports);
34
- var import_canvas_size = __toESM(require("canvas-size"));
35
- let maxSizePromise = null;
36
- function getBrowserCanvasMaxSize() {
37
- if (!maxSizePromise) {
38
- maxSizePromise = calculateBrowserCanvasMaxSize();
39
- }
40
- return maxSizePromise;
41
- }
42
- async function calculateBrowserCanvasMaxSize() {
43
- const maxWidth = await import_canvas_size.default.maxWidth({ usePromise: true });
44
- const maxHeight = await import_canvas_size.default.maxHeight({ usePromise: true });
45
- const maxArea = await import_canvas_size.default.maxArea({ usePromise: true });
46
- return {
47
- maxWidth: maxWidth.width,
48
- maxHeight: maxHeight.height,
49
- maxArea: maxArea.width * maxArea.height
50
- };
51
- }
52
- const MAX_SAFE_CANVAS_DIMENSION = 8192;
53
- const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
54
- async function clampToBrowserMaxCanvasSize(width, height) {
55
- if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
56
- return [width, height];
57
- }
58
- const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize();
59
- const aspectRatio = width / height;
60
- if (width > maxWidth) {
61
- width = maxWidth;
62
- height = width / aspectRatio;
63
- }
64
- if (height > maxHeight) {
65
- height = maxHeight;
66
- width = height * aspectRatio;
67
- }
68
- if (width * height > maxArea) {
69
- const ratio = Math.sqrt(maxArea / (width * height));
70
- width *= ratio;
71
- height *= ratio;
72
- }
73
- return [width, height];
74
- }
75
- //# sourceMappingURL=browserCanvasMaxSize.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
4
- "sourcesContent": ["import canvasSize from 'canvas-size'\n\n/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\nlet maxSizePromise: Promise<CanvasMaxSize> | null = null\n\nfunction getBrowserCanvasMaxSize() {\n\tif (!maxSizePromise) {\n\t\tmaxSizePromise = calculateBrowserCanvasMaxSize()\n\t}\n\n\treturn maxSizePromise\n}\n\nasync function calculateBrowserCanvasMaxSize(): Promise<CanvasMaxSize> {\n\tconst maxWidth = await canvasSize.maxWidth({ usePromise: true })\n\tconst maxHeight = await canvasSize.maxHeight({ usePromise: true })\n\tconst maxArea = await canvasSize.maxArea({ usePromise: true })\n\treturn {\n\t\tmaxWidth: maxWidth.width,\n\t\tmaxHeight: maxHeight.height,\n\t\tmaxArea: maxArea.width * maxArea.height,\n\t}\n}\n\n// https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results\nconst MAX_SAFE_CANVAS_DIMENSION = 8192\nconst MAX_SAFE_CANVAS_AREA = 4096 * 4096\n\n/** @internal */\nexport async function clampToBrowserMaxCanvasSize(width: number, height: number) {\n\tif (\n\t\twidth <= MAX_SAFE_CANVAS_DIMENSION &&\n\t\theight <= MAX_SAFE_CANVAS_DIMENSION &&\n\t\twidth * height <= MAX_SAFE_CANVAS_AREA\n\t) {\n\t\treturn [width, height]\n\t}\n\n\tconst { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize()\n\tconst aspectRatio = width / height\n\n\tif (width > maxWidth) {\n\t\twidth = maxWidth\n\t\theight = width / aspectRatio\n\t}\n\n\tif (height > maxHeight) {\n\t\theight = maxHeight\n\t\twidth = height * aspectRatio\n\t}\n\n\tif (width * height > maxArea) {\n\t\tconst ratio = Math.sqrt(maxArea / (width * height))\n\t\twidth *= ratio\n\t\theight *= ratio\n\t}\n\n\treturn [width, height]\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAuB;AASvB,IAAI,iBAAgD;AAEpD,SAAS,0BAA0B;AAClC,MAAI,CAAC,gBAAgB;AACpB,qBAAiB,8BAA8B;AAAA,EAChD;AAEA,SAAO;AACR;AAEA,eAAe,gCAAwD;AACtE,QAAM,WAAW,MAAM,mBAAAA,QAAW,SAAS,EAAE,YAAY,KAAK,CAAC;AAC/D,QAAM,YAAY,MAAM,mBAAAA,QAAW,UAAU,EAAE,YAAY,KAAK,CAAC;AACjE,QAAM,UAAU,MAAM,mBAAAA,QAAW,QAAQ,EAAE,YAAY,KAAK,CAAC;AAC7D,SAAO;AAAA,IACN,UAAU,SAAS;AAAA,IACnB,WAAW,UAAU;AAAA,IACrB,SAAS,QAAQ,QAAQ,QAAQ;AAAA,EAClC;AACD;AAGA,MAAM,4BAA4B;AAClC,MAAM,uBAAuB,OAAO;AAGpC,eAAsB,4BAA4B,OAAe,QAAgB;AAChF,MACC,SAAS,6BACT,UAAU,6BACV,QAAQ,UAAU,sBACjB;AACD,WAAO,CAAC,OAAO,MAAM;AAAA,EACtB;AAEA,QAAM,EAAE,UAAU,WAAW,QAAQ,IAAI,MAAM,wBAAwB;AACvE,QAAM,cAAc,QAAQ;AAE5B,MAAI,QAAQ,UAAU;AACrB,YAAQ;AACR,aAAS,QAAQ;AAAA,EAClB;AAEA,MAAI,SAAS,WAAW;AACvB,aAAS;AACT,YAAQ,SAAS;AAAA,EAClB;AAEA,MAAI,QAAQ,SAAS,SAAS;AAC7B,UAAM,QAAQ,KAAK,KAAK,WAAW,QAAQ,OAAO;AAClD,aAAS;AACT,cAAU;AAAA,EACX;AAEA,SAAO,CAAC,OAAO,MAAM;AACtB;",
6
- "names": ["canvasSize"]
7
- }
@@ -1,63 +0,0 @@
1
- import { FileHelpers, Image, PngHelpers, sleep } from "@tldraw/utils";
2
- import { tlenv } from "../globals/environment.mjs";
3
- import { clampToBrowserMaxCanvasSize } from "../utils/browserCanvasMaxSize.mjs";
4
- import { debugFlags } from "../utils/debug-flags.mjs";
5
- async function getSvgAsImage(svgString, options) {
6
- const { type, width, height, quality = 1, pixelRatio = 2 } = options;
7
- let [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(
8
- width * pixelRatio,
9
- height * pixelRatio
10
- );
11
- clampedWidth = Math.floor(clampedWidth);
12
- clampedHeight = Math.floor(clampedHeight);
13
- const effectiveScale = clampedWidth / width;
14
- const svgUrl = await FileHelpers.blobToDataUrl(new Blob([svgString], { type: "image/svg+xml" }));
15
- const canvas = await new Promise((resolve) => {
16
- const image = Image();
17
- image.crossOrigin = "anonymous";
18
- image.onload = async () => {
19
- if (tlenv.isSafari) {
20
- await sleep(250);
21
- }
22
- const canvas2 = document.createElement("canvas");
23
- const ctx = canvas2.getContext("2d");
24
- canvas2.width = clampedWidth;
25
- canvas2.height = clampedHeight;
26
- ctx.imageSmoothingEnabled = true;
27
- ctx.imageSmoothingQuality = "high";
28
- ctx.drawImage(image, 0, 0, clampedWidth, clampedHeight);
29
- URL.revokeObjectURL(svgUrl);
30
- resolve(canvas2);
31
- };
32
- image.onerror = () => {
33
- resolve(null);
34
- };
35
- image.src = svgUrl;
36
- });
37
- if (!canvas) return null;
38
- const blob = await new Promise(
39
- (resolve) => canvas.toBlob(
40
- (blob2) => {
41
- if (!blob2 || debugFlags.throwToBlob.get()) {
42
- resolve(null);
43
- }
44
- resolve(blob2);
45
- },
46
- "image/" + type,
47
- quality
48
- )
49
- );
50
- if (!blob) return null;
51
- if (type === "png") {
52
- const view = new DataView(await blob.arrayBuffer());
53
- return PngHelpers.setPhysChunk(view, effectiveScale, {
54
- type: "image/" + type
55
- });
56
- } else {
57
- return blob;
58
- }
59
- }
60
- export {
61
- getSvgAsImage
62
- };
63
- //# sourceMappingURL=getSvgAsImage.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/lib/exports/getSvgAsImage.ts"],
4
- "sourcesContent": ["import { FileHelpers, Image, PngHelpers, sleep } from '@tldraw/utils'\nimport { tlenv } from '../globals/environment'\nimport { clampToBrowserMaxCanvasSize } from '../utils/browserCanvasMaxSize'\nimport { debugFlags } from '../utils/debug-flags'\n\n/** @public */\nexport async function getSvgAsImage(\n\tsvgString: string,\n\toptions: {\n\t\ttype: 'png' | 'jpeg' | 'webp'\n\t\twidth: number\n\t\theight: number\n\t\tquality?: number\n\t\tpixelRatio?: number\n\t}\n) {\n\tconst { type, width, height, quality = 1, pixelRatio = 2 } = options\n\n\tlet [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(\n\t\twidth * pixelRatio,\n\t\theight * pixelRatio\n\t)\n\tclampedWidth = Math.floor(clampedWidth)\n\tclampedHeight = Math.floor(clampedHeight)\n\tconst effectiveScale = clampedWidth / width\n\n\t// usually we would use `URL.createObjectURL` here, but chrome has a bug where `blob:` URLs of\n\t// SVGs that use <foreignObject> mark the canvas as tainted, where data: ones do not.\n\t// https://issues.chromium.org/issues/41054640\n\tconst svgUrl = await FileHelpers.blobToDataUrl(new Blob([svgString], { type: 'image/svg+xml' }))\n\n\tconst canvas = await new Promise<HTMLCanvasElement | null>((resolve) => {\n\t\tconst image = Image()\n\t\timage.crossOrigin = 'anonymous'\n\n\t\timage.onload = async () => {\n\t\t\t// safari will fire `onLoad` before the fonts in the SVG are\n\t\t\t// actually loaded. just waiting around a while is brittle, but\n\t\t\t// there doesn't seem to be any better solution for now :( see\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=219770\n\t\t\tif (tlenv.isSafari) {\n\t\t\t\tawait sleep(250)\n\t\t\t}\n\n\t\t\tconst canvas = document.createElement('canvas') as HTMLCanvasElement\n\t\t\tconst ctx = canvas.getContext('2d')!\n\n\t\t\tcanvas.width = clampedWidth\n\t\t\tcanvas.height = clampedHeight\n\n\t\t\tctx.imageSmoothingEnabled = true\n\t\t\tctx.imageSmoothingQuality = 'high'\n\t\t\tctx.drawImage(image, 0, 0, clampedWidth, clampedHeight)\n\n\t\t\tURL.revokeObjectURL(svgUrl)\n\n\t\t\tresolve(canvas)\n\t\t}\n\n\t\timage.onerror = () => {\n\t\t\tresolve(null)\n\t\t}\n\n\t\timage.src = svgUrl\n\t})\n\n\tif (!canvas) return null\n\n\tconst blob = await new Promise<Blob | null>((resolve) =>\n\t\tcanvas.toBlob(\n\t\t\t(blob) => {\n\t\t\t\tif (!blob || debugFlags.throwToBlob.get()) {\n\t\t\t\t\tresolve(null)\n\t\t\t\t}\n\t\t\t\tresolve(blob)\n\t\t\t},\n\t\t\t'image/' + type,\n\t\t\tquality\n\t\t)\n\t)\n\n\tif (!blob) return null\n\n\tif (type === 'png') {\n\t\tconst view = new DataView(await blob.arrayBuffer())\n\t\treturn PngHelpers.setPhysChunk(view, effectiveScale, {\n\t\t\ttype: 'image/' + type,\n\t\t})\n\t} else {\n\t\treturn blob\n\t}\n}\n"],
5
- "mappings": "AAAA,SAAS,aAAa,OAAO,YAAY,aAAa;AACtD,SAAS,aAAa;AACtB,SAAS,mCAAmC;AAC5C,SAAS,kBAAkB;AAG3B,eAAsB,cACrB,WACA,SAOC;AACD,QAAM,EAAE,MAAM,OAAO,QAAQ,UAAU,GAAG,aAAa,EAAE,IAAI;AAE7D,MAAI,CAAC,cAAc,aAAa,IAAI,MAAM;AAAA,IACzC,QAAQ;AAAA,IACR,SAAS;AAAA,EACV;AACA,iBAAe,KAAK,MAAM,YAAY;AACtC,kBAAgB,KAAK,MAAM,aAAa;AACxC,QAAM,iBAAiB,eAAe;AAKtC,QAAM,SAAS,MAAM,YAAY,cAAc,IAAI,KAAK,CAAC,SAAS,GAAG,EAAE,MAAM,gBAAgB,CAAC,CAAC;AAE/F,QAAM,SAAS,MAAM,IAAI,QAAkC,CAAC,YAAY;AACvE,UAAM,QAAQ,MAAM;AACpB,UAAM,cAAc;AAEpB,UAAM,SAAS,YAAY;AAK1B,UAAI,MAAM,UAAU;AACnB,cAAM,MAAM,GAAG;AAAA,MAChB;AAEA,YAAMA,UAAS,SAAS,cAAc,QAAQ;AAC9C,YAAM,MAAMA,QAAO,WAAW,IAAI;AAElC,MAAAA,QAAO,QAAQ;AACf,MAAAA,QAAO,SAAS;AAEhB,UAAI,wBAAwB;AAC5B,UAAI,wBAAwB;AAC5B,UAAI,UAAU,OAAO,GAAG,GAAG,cAAc,aAAa;AAEtD,UAAI,gBAAgB,MAAM;AAE1B,cAAQA,OAAM;AAAA,IACf;AAEA,UAAM,UAAU,MAAM;AACrB,cAAQ,IAAI;AAAA,IACb;AAEA,UAAM,MAAM;AAAA,EACb,CAAC;AAED,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,OAAO,MAAM,IAAI;AAAA,IAAqB,CAAC,YAC5C,OAAO;AAAA,MACN,CAACC,UAAS;AACT,YAAI,CAACA,SAAQ,WAAW,YAAY,IAAI,GAAG;AAC1C,kBAAQ,IAAI;AAAA,QACb;AACA,gBAAQA,KAAI;AAAA,MACb;AAAA,MACA,WAAW;AAAA,MACX;AAAA,IACD;AAAA,EACD;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,SAAS,OAAO;AACnB,UAAM,OAAO,IAAI,SAAS,MAAM,KAAK,YAAY,CAAC;AAClD,WAAO,WAAW,aAAa,MAAM,gBAAgB;AAAA,MACpD,MAAM,WAAW;AAAA,IAClB,CAAC;AAAA,EACF,OAAO;AACN,WAAO;AAAA,EACR;AACD;",
6
- "names": ["canvas", "blob"]
7
- }
@@ -1,45 +0,0 @@
1
- import canvasSize from "canvas-size";
2
- let maxSizePromise = null;
3
- function getBrowserCanvasMaxSize() {
4
- if (!maxSizePromise) {
5
- maxSizePromise = calculateBrowserCanvasMaxSize();
6
- }
7
- return maxSizePromise;
8
- }
9
- async function calculateBrowserCanvasMaxSize() {
10
- const maxWidth = await canvasSize.maxWidth({ usePromise: true });
11
- const maxHeight = await canvasSize.maxHeight({ usePromise: true });
12
- const maxArea = await canvasSize.maxArea({ usePromise: true });
13
- return {
14
- maxWidth: maxWidth.width,
15
- maxHeight: maxHeight.height,
16
- maxArea: maxArea.width * maxArea.height
17
- };
18
- }
19
- const MAX_SAFE_CANVAS_DIMENSION = 8192;
20
- const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
21
- async function clampToBrowserMaxCanvasSize(width, height) {
22
- if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
23
- return [width, height];
24
- }
25
- const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize();
26
- const aspectRatio = width / height;
27
- if (width > maxWidth) {
28
- width = maxWidth;
29
- height = width / aspectRatio;
30
- }
31
- if (height > maxHeight) {
32
- height = maxHeight;
33
- width = height * aspectRatio;
34
- }
35
- if (width * height > maxArea) {
36
- const ratio = Math.sqrt(maxArea / (width * height));
37
- width *= ratio;
38
- height *= ratio;
39
- }
40
- return [width, height];
41
- }
42
- export {
43
- clampToBrowserMaxCanvasSize
44
- };
45
- //# sourceMappingURL=browserCanvasMaxSize.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
4
- "sourcesContent": ["import canvasSize from 'canvas-size'\n\n/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\nlet maxSizePromise: Promise<CanvasMaxSize> | null = null\n\nfunction getBrowserCanvasMaxSize() {\n\tif (!maxSizePromise) {\n\t\tmaxSizePromise = calculateBrowserCanvasMaxSize()\n\t}\n\n\treturn maxSizePromise\n}\n\nasync function calculateBrowserCanvasMaxSize(): Promise<CanvasMaxSize> {\n\tconst maxWidth = await canvasSize.maxWidth({ usePromise: true })\n\tconst maxHeight = await canvasSize.maxHeight({ usePromise: true })\n\tconst maxArea = await canvasSize.maxArea({ usePromise: true })\n\treturn {\n\t\tmaxWidth: maxWidth.width,\n\t\tmaxHeight: maxHeight.height,\n\t\tmaxArea: maxArea.width * maxArea.height,\n\t}\n}\n\n// https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results\nconst MAX_SAFE_CANVAS_DIMENSION = 8192\nconst MAX_SAFE_CANVAS_AREA = 4096 * 4096\n\n/** @internal */\nexport async function clampToBrowserMaxCanvasSize(width: number, height: number) {\n\tif (\n\t\twidth <= MAX_SAFE_CANVAS_DIMENSION &&\n\t\theight <= MAX_SAFE_CANVAS_DIMENSION &&\n\t\twidth * height <= MAX_SAFE_CANVAS_AREA\n\t) {\n\t\treturn [width, height]\n\t}\n\n\tconst { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize()\n\tconst aspectRatio = width / height\n\n\tif (width > maxWidth) {\n\t\twidth = maxWidth\n\t\theight = width / aspectRatio\n\t}\n\n\tif (height > maxHeight) {\n\t\theight = maxHeight\n\t\twidth = height * aspectRatio\n\t}\n\n\tif (width * height > maxArea) {\n\t\tconst ratio = Math.sqrt(maxArea / (width * height))\n\t\twidth *= ratio\n\t\theight *= ratio\n\t}\n\n\treturn [width, height]\n}\n"],
5
- "mappings": "AAAA,OAAO,gBAAgB;AASvB,IAAI,iBAAgD;AAEpD,SAAS,0BAA0B;AAClC,MAAI,CAAC,gBAAgB;AACpB,qBAAiB,8BAA8B;AAAA,EAChD;AAEA,SAAO;AACR;AAEA,eAAe,gCAAwD;AACtE,QAAM,WAAW,MAAM,WAAW,SAAS,EAAE,YAAY,KAAK,CAAC;AAC/D,QAAM,YAAY,MAAM,WAAW,UAAU,EAAE,YAAY,KAAK,CAAC;AACjE,QAAM,UAAU,MAAM,WAAW,QAAQ,EAAE,YAAY,KAAK,CAAC;AAC7D,SAAO;AAAA,IACN,UAAU,SAAS;AAAA,IACnB,WAAW,UAAU;AAAA,IACrB,SAAS,QAAQ,QAAQ,QAAQ;AAAA,EAClC;AACD;AAGA,MAAM,4BAA4B;AAClC,MAAM,uBAAuB,OAAO;AAGpC,eAAsB,4BAA4B,OAAe,QAAgB;AAChF,MACC,SAAS,6BACT,UAAU,6BACV,QAAQ,UAAU,sBACjB;AACD,WAAO,CAAC,OAAO,MAAM;AAAA,EACtB;AAEA,QAAM,EAAE,UAAU,WAAW,QAAQ,IAAI,MAAM,wBAAwB;AACvE,QAAM,cAAc,QAAQ;AAE5B,MAAI,QAAQ,UAAU;AACrB,YAAQ;AACR,aAAS,QAAQ;AAAA,EAClB;AAEA,MAAI,SAAS,WAAW;AACvB,aAAS;AACT,YAAQ,SAAS;AAAA,EAClB;AAEA,MAAI,QAAQ,SAAS,SAAS;AAC7B,UAAM,QAAQ,KAAK,KAAK,WAAW,QAAQ,OAAO;AAClD,aAAS;AACT,cAAU;AAAA,EACX;AAEA,SAAO,CAAC,OAAO,MAAM;AACtB;",
6
- "names": []
7
- }
@@ -1,92 +0,0 @@
1
- import { FileHelpers, Image, PngHelpers, sleep } from '@tldraw/utils'
2
- import { tlenv } from '../globals/environment'
3
- import { clampToBrowserMaxCanvasSize } from '../utils/browserCanvasMaxSize'
4
- import { debugFlags } from '../utils/debug-flags'
5
-
6
- /** @public */
7
- export async function getSvgAsImage(
8
- svgString: string,
9
- options: {
10
- type: 'png' | 'jpeg' | 'webp'
11
- width: number
12
- height: number
13
- quality?: number
14
- pixelRatio?: number
15
- }
16
- ) {
17
- const { type, width, height, quality = 1, pixelRatio = 2 } = options
18
-
19
- let [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(
20
- width * pixelRatio,
21
- height * pixelRatio
22
- )
23
- clampedWidth = Math.floor(clampedWidth)
24
- clampedHeight = Math.floor(clampedHeight)
25
- const effectiveScale = clampedWidth / width
26
-
27
- // usually we would use `URL.createObjectURL` here, but chrome has a bug where `blob:` URLs of
28
- // SVGs that use <foreignObject> mark the canvas as tainted, where data: ones do not.
29
- // https://issues.chromium.org/issues/41054640
30
- const svgUrl = await FileHelpers.blobToDataUrl(new Blob([svgString], { type: 'image/svg+xml' }))
31
-
32
- const canvas = await new Promise<HTMLCanvasElement | null>((resolve) => {
33
- const image = Image()
34
- image.crossOrigin = 'anonymous'
35
-
36
- image.onload = async () => {
37
- // safari will fire `onLoad` before the fonts in the SVG are
38
- // actually loaded. just waiting around a while is brittle, but
39
- // there doesn't seem to be any better solution for now :( see
40
- // https://bugs.webkit.org/show_bug.cgi?id=219770
41
- if (tlenv.isSafari) {
42
- await sleep(250)
43
- }
44
-
45
- const canvas = document.createElement('canvas') as HTMLCanvasElement
46
- const ctx = canvas.getContext('2d')!
47
-
48
- canvas.width = clampedWidth
49
- canvas.height = clampedHeight
50
-
51
- ctx.imageSmoothingEnabled = true
52
- ctx.imageSmoothingQuality = 'high'
53
- ctx.drawImage(image, 0, 0, clampedWidth, clampedHeight)
54
-
55
- URL.revokeObjectURL(svgUrl)
56
-
57
- resolve(canvas)
58
- }
59
-
60
- image.onerror = () => {
61
- resolve(null)
62
- }
63
-
64
- image.src = svgUrl
65
- })
66
-
67
- if (!canvas) return null
68
-
69
- const blob = await new Promise<Blob | null>((resolve) =>
70
- canvas.toBlob(
71
- (blob) => {
72
- if (!blob || debugFlags.throwToBlob.get()) {
73
- resolve(null)
74
- }
75
- resolve(blob)
76
- },
77
- 'image/' + type,
78
- quality
79
- )
80
- )
81
-
82
- if (!blob) return null
83
-
84
- if (type === 'png') {
85
- const view = new DataView(await blob.arrayBuffer())
86
- return PngHelpers.setPhysChunk(view, effectiveScale, {
87
- type: 'image/' + type,
88
- })
89
- } else {
90
- return blob
91
- }
92
- }
@@ -1,65 +0,0 @@
1
- import canvasSize from 'canvas-size'
2
-
3
- /** @internal */
4
- export interface CanvasMaxSize {
5
- maxWidth: number
6
- maxHeight: number
7
- maxArea: number
8
- }
9
-
10
- let maxSizePromise: Promise<CanvasMaxSize> | null = null
11
-
12
- function getBrowserCanvasMaxSize() {
13
- if (!maxSizePromise) {
14
- maxSizePromise = calculateBrowserCanvasMaxSize()
15
- }
16
-
17
- return maxSizePromise
18
- }
19
-
20
- async function calculateBrowserCanvasMaxSize(): Promise<CanvasMaxSize> {
21
- const maxWidth = await canvasSize.maxWidth({ usePromise: true })
22
- const maxHeight = await canvasSize.maxHeight({ usePromise: true })
23
- const maxArea = await canvasSize.maxArea({ usePromise: true })
24
- return {
25
- maxWidth: maxWidth.width,
26
- maxHeight: maxHeight.height,
27
- maxArea: maxArea.width * maxArea.height,
28
- }
29
- }
30
-
31
- // https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results
32
- const MAX_SAFE_CANVAS_DIMENSION = 8192
33
- const MAX_SAFE_CANVAS_AREA = 4096 * 4096
34
-
35
- /** @internal */
36
- export async function clampToBrowserMaxCanvasSize(width: number, height: number) {
37
- if (
38
- width <= MAX_SAFE_CANVAS_DIMENSION &&
39
- height <= MAX_SAFE_CANVAS_DIMENSION &&
40
- width * height <= MAX_SAFE_CANVAS_AREA
41
- ) {
42
- return [width, height]
43
- }
44
-
45
- const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize()
46
- const aspectRatio = width / height
47
-
48
- if (width > maxWidth) {
49
- width = maxWidth
50
- height = width / aspectRatio
51
- }
52
-
53
- if (height > maxHeight) {
54
- height = maxHeight
55
- width = height * aspectRatio
56
- }
57
-
58
- if (width * height > maxArea) {
59
- const ratio = Math.sqrt(maxArea / (width * height))
60
- width *= ratio
61
- height *= ratio
62
- }
63
-
64
- return [width, height]
65
- }