@tldraw/editor 3.9.0-canary.81717556ec3d → 3.9.0-canary.a3bcb05e47b6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +0 -2
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/exports/getSvgAsImage.js +1 -1
- package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +1 -3
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js +28 -104
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +3 -3
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +0 -2
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/exports/getSvgAsImage.mjs +1 -1
- package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +1 -3
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +18 -104
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +9 -7
- package/src/lib/exports/getSvgAsImage.ts +1 -1
- package/src/lib/globals/environment.ts +0 -3
- package/src/lib/utils/browserCanvasMaxSize.ts +21 -121
- package/src/version.ts +3 -3
package/dist-cjs/index.d.ts
CHANGED
|
@@ -1047,7 +1047,6 @@ export declare class Editor extends EventEmitter<TLEventMap> {
|
|
|
1047
1047
|
* @public
|
|
1048
1048
|
*/
|
|
1049
1049
|
readonly environment: {
|
|
1050
|
-
hasCanvasSupport: boolean;
|
|
1051
1050
|
isAndroid: boolean;
|
|
1052
1051
|
isChromeForIos: boolean;
|
|
1053
1052
|
isDarwin: boolean;
|
|
@@ -6155,7 +6154,6 @@ export declare type TLEnterEventHandler = (info: any, from: string) => void;
|
|
|
6155
6154
|
* @public
|
|
6156
6155
|
*/
|
|
6157
6156
|
export declare const tlenv: {
|
|
6158
|
-
hasCanvasSupport: boolean;
|
|
6159
6157
|
isAndroid: boolean;
|
|
6160
6158
|
isChromeForIos: boolean;
|
|
6161
6159
|
isDarwin: boolean;
|
package/dist-cjs/index.js
CHANGED
|
@@ -27,7 +27,7 @@ var import_browserCanvasMaxSize = require("../utils/browserCanvasMaxSize");
|
|
|
27
27
|
var import_debug_flags = require("../utils/debug-flags");
|
|
28
28
|
async function getSvgAsImage(svgString, options) {
|
|
29
29
|
const { type, width, height, quality = 1, pixelRatio = 2 } = options;
|
|
30
|
-
let [clampedWidth, clampedHeight] = (0, import_browserCanvasMaxSize.clampToBrowserMaxCanvasSize)(
|
|
30
|
+
let [clampedWidth, clampedHeight] = await (0, import_browserCanvasMaxSize.clampToBrowserMaxCanvasSize)(
|
|
31
31
|
width * pixelRatio,
|
|
32
32
|
height * pixelRatio
|
|
33
33
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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] = 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,
|
|
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
6
|
"names": ["canvas", "blob"]
|
|
7
7
|
}
|
|
@@ -28,8 +28,7 @@ const tlenv = {
|
|
|
28
28
|
isFirefox: false,
|
|
29
29
|
isAndroid: false,
|
|
30
30
|
isWebview: false,
|
|
31
|
-
isDarwin: false
|
|
32
|
-
hasCanvasSupport: false
|
|
31
|
+
isDarwin: false
|
|
33
32
|
};
|
|
34
33
|
if (typeof window !== "undefined" && "navigator" in window) {
|
|
35
34
|
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
@@ -38,6 +37,5 @@ if (typeof window !== "undefined" && "navigator" in window) {
|
|
|
38
37
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent);
|
|
39
38
|
tlenv.isAndroid = /android/i.test(navigator.userAgent);
|
|
40
39
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf("mac") > -1;
|
|
41
|
-
tlenv.hasCanvasSupport = typeof window !== "undefined" && "Promise" in window && "HTMLCanvasElement" in window;
|
|
42
40
|
}
|
|
43
41
|
//# sourceMappingURL=environment.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/globals/environment.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * An object that contains information about the current device and environment.\n *\n * @public\n */\nconst tlenv = {\n\tisSafari: false,\n\tisIos: false,\n\tisChromeForIos: false,\n\tisFirefox: false,\n\tisAndroid: false,\n\tisWebview: false,\n\tisDarwin: false,\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,MAAM,QAAQ;AAAA,EACb,UAAU;AAAA,EACV,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;
|
|
4
|
+
"sourcesContent": ["/**\n * An object that contains information about the current device and environment.\n *\n * @public\n */\nconst tlenv = {\n\tisSafari: false,\n\tisIos: false,\n\tisChromeForIos: false,\n\tisFirefox: false,\n\tisAndroid: false,\n\tisWebview: false,\n\tisDarwin: false,\n}\n\nif (typeof window !== 'undefined' && 'navigator' in window) {\n\ttlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)\n\ttlenv.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)\n\ttlenv.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)\n\ttlenv.isFirefox = /firefox/i.test(navigator.userAgent)\n\ttlenv.isAndroid = /android/i.test(navigator.userAgent)\n\ttlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1\n}\n\nexport { tlenv }\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,MAAM,QAAQ;AAAA,EACb,UAAU;AAAA,EACV,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AACX;AAEA,IAAI,OAAO,WAAW,eAAe,eAAe,QAAQ;AAC3D,QAAM,WAAW,iCAAiC,KAAK,UAAU,SAAS;AAC1E,QAAM,QAAQ,CAAC,CAAC,UAAU,UAAU,MAAM,OAAO,KAAK,CAAC,CAAC,UAAU,UAAU,MAAM,SAAS;AAC3F,QAAM,iBAAiB,iBAAiB,KAAK,UAAU,SAAS;AAChE,QAAM,YAAY,WAAW,KAAK,UAAU,SAAS;AACrD,QAAM,YAAY,WAAW,KAAK,UAAU,SAAS;AACrD,QAAM,WAAW,OAAO,UAAU,UAAU,YAAY,EAAE,QAAQ,KAAK,IAAI;AAC5E;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,123 +17,45 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
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
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var browserCanvasMaxSize_exports = {};
|
|
20
30
|
__export(browserCanvasMaxSize_exports, {
|
|
21
|
-
clampToBrowserMaxCanvasSize: () => clampToBrowserMaxCanvasSize
|
|
22
|
-
getCanvasSize: () => getCanvasSize
|
|
31
|
+
clampToBrowserMaxCanvasSize: () => clampToBrowserMaxCanvasSize
|
|
23
32
|
});
|
|
24
33
|
module.exports = __toCommonJS(browserCanvasMaxSize_exports);
|
|
25
|
-
|
|
34
|
+
var import_canvas_size = __toESM(require("canvas-size"));
|
|
35
|
+
let maxSizePromise = null;
|
|
26
36
|
function getBrowserCanvasMaxSize() {
|
|
27
|
-
if (!
|
|
28
|
-
|
|
29
|
-
maxWidth: getCanvasSize("width"),
|
|
30
|
-
// test very wide but 1 pixel tall canvases
|
|
31
|
-
maxHeight: getCanvasSize("height"),
|
|
32
|
-
// test very tall but 1 pixel wide canvases
|
|
33
|
-
maxArea: getCanvasSize("area")
|
|
34
|
-
// test square canvases
|
|
35
|
-
};
|
|
37
|
+
if (!maxSizePromise) {
|
|
38
|
+
maxSizePromise = calculateBrowserCanvasMaxSize();
|
|
36
39
|
}
|
|
37
|
-
return
|
|
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
|
+
};
|
|
38
51
|
}
|
|
39
52
|
const MAX_SAFE_CANVAS_DIMENSION = 8192;
|
|
40
53
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
|
|
41
|
-
|
|
42
|
-
area: [
|
|
43
|
-
// Chrome 70 (Mac, Win)
|
|
44
|
-
// Chrome 68 (Android 4.4)
|
|
45
|
-
// Edge 17 (Win)
|
|
46
|
-
// Safari 7-12 (Mac)
|
|
47
|
-
16384,
|
|
48
|
-
// Chrome 68 (Android 7.1-9)
|
|
49
|
-
14188,
|
|
50
|
-
// Chrome 68 (Android 5)
|
|
51
|
-
11402,
|
|
52
|
-
// Firefox 63 (Mac, Win)
|
|
53
|
-
11180,
|
|
54
|
-
// Chrome 68 (Android 6)
|
|
55
|
-
10836,
|
|
56
|
-
// IE 9-11 (Win)
|
|
57
|
-
8192,
|
|
58
|
-
// IE Mobile (Windows Phone 8.x)
|
|
59
|
-
// Safari (iOS 9 - 12)
|
|
60
|
-
4096
|
|
61
|
-
],
|
|
62
|
-
height: [
|
|
63
|
-
// Safari 7-12 (Mac)
|
|
64
|
-
// Safari (iOS 9-12)
|
|
65
|
-
8388607,
|
|
66
|
-
// Chrome 83 (Mac, Win)
|
|
67
|
-
65535,
|
|
68
|
-
// Chrome 70 (Mac, Win)
|
|
69
|
-
// Chrome 68 (Android 4.4-9)
|
|
70
|
-
// Firefox 63 (Mac, Win)
|
|
71
|
-
32767,
|
|
72
|
-
// Edge 17 (Win)
|
|
73
|
-
// IE11 (Win)
|
|
74
|
-
16384,
|
|
75
|
-
// IE 9-10 (Win)
|
|
76
|
-
8192,
|
|
77
|
-
// IE Mobile (Windows Phone 8.x)
|
|
78
|
-
4096
|
|
79
|
-
],
|
|
80
|
-
width: [
|
|
81
|
-
// Safari 7-12 (Mac)
|
|
82
|
-
// Safari (iOS 9-12)
|
|
83
|
-
4194303,
|
|
84
|
-
// Chrome 83 (Mac, Win)
|
|
85
|
-
65535,
|
|
86
|
-
// Chrome 70 (Mac, Win)
|
|
87
|
-
// Chrome 68 (Android 4.4-9)
|
|
88
|
-
// Firefox 63 (Mac, Win)
|
|
89
|
-
32767,
|
|
90
|
-
// Edge 17 (Win)
|
|
91
|
-
// IE11 (Win)
|
|
92
|
-
16384,
|
|
93
|
-
// IE 9-10 (Win)
|
|
94
|
-
8192,
|
|
95
|
-
// IE Mobile (Windows Phone 8.x)
|
|
96
|
-
4096
|
|
97
|
-
]
|
|
98
|
-
};
|
|
99
|
-
function getCanvasSize(dimension) {
|
|
100
|
-
const cropCvs = document.createElement("canvas");
|
|
101
|
-
cropCvs.width = 1;
|
|
102
|
-
cropCvs.height = 1;
|
|
103
|
-
const cropCtx = cropCvs.getContext("2d");
|
|
104
|
-
for (const size of TEST_SIZES[dimension]) {
|
|
105
|
-
const w = dimension === "height" ? 1 : size;
|
|
106
|
-
const h = dimension === "width" ? 1 : size;
|
|
107
|
-
const testCvs = document.createElement("canvas");
|
|
108
|
-
testCvs.width = w;
|
|
109
|
-
testCvs.height = h;
|
|
110
|
-
const testCtx = testCvs.getContext("2d");
|
|
111
|
-
testCtx.fillRect(w - 1, h - 1, 1, 1);
|
|
112
|
-
cropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1);
|
|
113
|
-
const isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;
|
|
114
|
-
testCvs.width = 0;
|
|
115
|
-
testCvs.height = 0;
|
|
116
|
-
if (isTestPassed) {
|
|
117
|
-
cropCvs.width = 0;
|
|
118
|
-
cropCvs.height = 0;
|
|
119
|
-
if (dimension === "area") {
|
|
120
|
-
return size * size;
|
|
121
|
-
} else {
|
|
122
|
-
return size;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
cropCvs.width = 0;
|
|
127
|
-
cropCvs.height = 0;
|
|
128
|
-
throw Error("Failed to determine maximum canvas dimension");
|
|
129
|
-
}
|
|
130
|
-
function clampToBrowserMaxCanvasSize(width, height) {
|
|
54
|
+
async function clampToBrowserMaxCanvasSize(width, height) {
|
|
131
55
|
if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
|
|
132
56
|
return [width, height];
|
|
133
57
|
}
|
|
134
|
-
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize();
|
|
58
|
+
const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize();
|
|
135
59
|
const aspectRatio = width / height;
|
|
136
60
|
if (width > maxWidth) {
|
|
137
61
|
width = maxWidth;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
|
|
4
|
-
"sourcesContent": ["/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
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
7
|
}
|
package/dist-cjs/version.js
CHANGED
|
@@ -22,10 +22,10 @@ __export(version_exports, {
|
|
|
22
22
|
version: () => version
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(version_exports);
|
|
25
|
-
const version = "3.9.0-canary.
|
|
25
|
+
const version = "3.9.0-canary.a3bcb05e47b6";
|
|
26
26
|
const publishDates = {
|
|
27
27
|
major: "2024-09-13T14:36:29.063Z",
|
|
28
|
-
minor: "2025-02-25T13:
|
|
29
|
-
patch: "2025-02-25T13:
|
|
28
|
+
minor: "2025-02-25T13:27:39.366Z",
|
|
29
|
+
patch: "2025-02-25T13:27:39.366Z"
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=version.js.map
|
package/dist-cjs/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.9.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.9.0-canary.a3bcb05e47b6'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-02-25T13:27:39.366Z',\n\tpatch: '2025-02-25T13:27:39.366Z',\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.d.mts
CHANGED
|
@@ -1047,7 +1047,6 @@ export declare class Editor extends EventEmitter<TLEventMap> {
|
|
|
1047
1047
|
* @public
|
|
1048
1048
|
*/
|
|
1049
1049
|
readonly environment: {
|
|
1050
|
-
hasCanvasSupport: boolean;
|
|
1051
1050
|
isAndroid: boolean;
|
|
1052
1051
|
isChromeForIos: boolean;
|
|
1053
1052
|
isDarwin: boolean;
|
|
@@ -6155,7 +6154,6 @@ export declare type TLEnterEventHandler = (info: any, from: string) => void;
|
|
|
6155
6154
|
* @public
|
|
6156
6155
|
*/
|
|
6157
6156
|
export declare const tlenv: {
|
|
6158
|
-
hasCanvasSupport: boolean;
|
|
6159
6157
|
isAndroid: boolean;
|
|
6160
6158
|
isChromeForIos: boolean;
|
|
6161
6159
|
isDarwin: boolean;
|
package/dist-esm/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { clampToBrowserMaxCanvasSize } from "../utils/browserCanvasMaxSize.mjs";
|
|
|
4
4
|
import { debugFlags } from "../utils/debug-flags.mjs";
|
|
5
5
|
async function getSvgAsImage(svgString, options) {
|
|
6
6
|
const { type, width, height, quality = 1, pixelRatio = 2 } = options;
|
|
7
|
-
let [clampedWidth, clampedHeight] = clampToBrowserMaxCanvasSize(
|
|
7
|
+
let [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(
|
|
8
8
|
width * pixelRatio,
|
|
9
9
|
height * pixelRatio
|
|
10
10
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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] = 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;AAAA,
|
|
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
6
|
"names": ["canvas", "blob"]
|
|
7
7
|
}
|
|
@@ -5,8 +5,7 @@ const tlenv = {
|
|
|
5
5
|
isFirefox: false,
|
|
6
6
|
isAndroid: false,
|
|
7
7
|
isWebview: false,
|
|
8
|
-
isDarwin: false
|
|
9
|
-
hasCanvasSupport: false
|
|
8
|
+
isDarwin: false
|
|
10
9
|
};
|
|
11
10
|
if (typeof window !== "undefined" && "navigator" in window) {
|
|
12
11
|
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
@@ -15,7 +14,6 @@ if (typeof window !== "undefined" && "navigator" in window) {
|
|
|
15
14
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent);
|
|
16
15
|
tlenv.isAndroid = /android/i.test(navigator.userAgent);
|
|
17
16
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf("mac") > -1;
|
|
18
|
-
tlenv.hasCanvasSupport = typeof window !== "undefined" && "Promise" in window && "HTMLCanvasElement" in window;
|
|
19
17
|
}
|
|
20
18
|
export {
|
|
21
19
|
tlenv
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/globals/environment.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * An object that contains information about the current device and environment.\n *\n * @public\n */\nconst tlenv = {\n\tisSafari: false,\n\tisIos: false,\n\tisChromeForIos: false,\n\tisFirefox: false,\n\tisAndroid: false,\n\tisWebview: false,\n\tisDarwin: false,\n
|
|
5
|
-
"mappings": "AAKA,MAAM,QAAQ;AAAA,EACb,UAAU;AAAA,EACV,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;
|
|
4
|
+
"sourcesContent": ["/**\n * An object that contains information about the current device and environment.\n *\n * @public\n */\nconst tlenv = {\n\tisSafari: false,\n\tisIos: false,\n\tisChromeForIos: false,\n\tisFirefox: false,\n\tisAndroid: false,\n\tisWebview: false,\n\tisDarwin: false,\n}\n\nif (typeof window !== 'undefined' && 'navigator' in window) {\n\ttlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)\n\ttlenv.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)\n\ttlenv.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)\n\ttlenv.isFirefox = /firefox/i.test(navigator.userAgent)\n\ttlenv.isAndroid = /android/i.test(navigator.userAgent)\n\ttlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1\n}\n\nexport { tlenv }\n"],
|
|
5
|
+
"mappings": "AAKA,MAAM,QAAQ;AAAA,EACb,UAAU;AAAA,EACV,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AACX;AAEA,IAAI,OAAO,WAAW,eAAe,eAAe,QAAQ;AAC3D,QAAM,WAAW,iCAAiC,KAAK,UAAU,SAAS;AAC1E,QAAM,QAAQ,CAAC,CAAC,UAAU,UAAU,MAAM,OAAO,KAAK,CAAC,CAAC,UAAU,UAAU,MAAM,SAAS;AAC3F,QAAM,iBAAiB,iBAAiB,KAAK,UAAU,SAAS;AAChE,QAAM,YAAY,WAAW,KAAK,UAAU,SAAS;AACrD,QAAM,YAAY,WAAW,KAAK,UAAU,SAAS;AACrD,QAAM,WAAW,OAAO,UAAU,UAAU,YAAY,EAAE,QAAQ,KAAK,IAAI;AAC5E;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,113 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import canvasSize from "canvas-size";
|
|
2
|
+
let maxSizePromise = null;
|
|
2
3
|
function getBrowserCanvasMaxSize() {
|
|
3
|
-
if (!
|
|
4
|
-
|
|
5
|
-
maxWidth: getCanvasSize("width"),
|
|
6
|
-
// test very wide but 1 pixel tall canvases
|
|
7
|
-
maxHeight: getCanvasSize("height"),
|
|
8
|
-
// test very tall but 1 pixel wide canvases
|
|
9
|
-
maxArea: getCanvasSize("area")
|
|
10
|
-
// test square canvases
|
|
11
|
-
};
|
|
4
|
+
if (!maxSizePromise) {
|
|
5
|
+
maxSizePromise = calculateBrowserCanvasMaxSize();
|
|
12
6
|
}
|
|
13
|
-
return
|
|
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
|
+
};
|
|
14
18
|
}
|
|
15
19
|
const MAX_SAFE_CANVAS_DIMENSION = 8192;
|
|
16
20
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
|
|
17
|
-
|
|
18
|
-
area: [
|
|
19
|
-
// Chrome 70 (Mac, Win)
|
|
20
|
-
// Chrome 68 (Android 4.4)
|
|
21
|
-
// Edge 17 (Win)
|
|
22
|
-
// Safari 7-12 (Mac)
|
|
23
|
-
16384,
|
|
24
|
-
// Chrome 68 (Android 7.1-9)
|
|
25
|
-
14188,
|
|
26
|
-
// Chrome 68 (Android 5)
|
|
27
|
-
11402,
|
|
28
|
-
// Firefox 63 (Mac, Win)
|
|
29
|
-
11180,
|
|
30
|
-
// Chrome 68 (Android 6)
|
|
31
|
-
10836,
|
|
32
|
-
// IE 9-11 (Win)
|
|
33
|
-
8192,
|
|
34
|
-
// IE Mobile (Windows Phone 8.x)
|
|
35
|
-
// Safari (iOS 9 - 12)
|
|
36
|
-
4096
|
|
37
|
-
],
|
|
38
|
-
height: [
|
|
39
|
-
// Safari 7-12 (Mac)
|
|
40
|
-
// Safari (iOS 9-12)
|
|
41
|
-
8388607,
|
|
42
|
-
// Chrome 83 (Mac, Win)
|
|
43
|
-
65535,
|
|
44
|
-
// Chrome 70 (Mac, Win)
|
|
45
|
-
// Chrome 68 (Android 4.4-9)
|
|
46
|
-
// Firefox 63 (Mac, Win)
|
|
47
|
-
32767,
|
|
48
|
-
// Edge 17 (Win)
|
|
49
|
-
// IE11 (Win)
|
|
50
|
-
16384,
|
|
51
|
-
// IE 9-10 (Win)
|
|
52
|
-
8192,
|
|
53
|
-
// IE Mobile (Windows Phone 8.x)
|
|
54
|
-
4096
|
|
55
|
-
],
|
|
56
|
-
width: [
|
|
57
|
-
// Safari 7-12 (Mac)
|
|
58
|
-
// Safari (iOS 9-12)
|
|
59
|
-
4194303,
|
|
60
|
-
// Chrome 83 (Mac, Win)
|
|
61
|
-
65535,
|
|
62
|
-
// Chrome 70 (Mac, Win)
|
|
63
|
-
// Chrome 68 (Android 4.4-9)
|
|
64
|
-
// Firefox 63 (Mac, Win)
|
|
65
|
-
32767,
|
|
66
|
-
// Edge 17 (Win)
|
|
67
|
-
// IE11 (Win)
|
|
68
|
-
16384,
|
|
69
|
-
// IE 9-10 (Win)
|
|
70
|
-
8192,
|
|
71
|
-
// IE Mobile (Windows Phone 8.x)
|
|
72
|
-
4096
|
|
73
|
-
]
|
|
74
|
-
};
|
|
75
|
-
function getCanvasSize(dimension) {
|
|
76
|
-
const cropCvs = document.createElement("canvas");
|
|
77
|
-
cropCvs.width = 1;
|
|
78
|
-
cropCvs.height = 1;
|
|
79
|
-
const cropCtx = cropCvs.getContext("2d");
|
|
80
|
-
for (const size of TEST_SIZES[dimension]) {
|
|
81
|
-
const w = dimension === "height" ? 1 : size;
|
|
82
|
-
const h = dimension === "width" ? 1 : size;
|
|
83
|
-
const testCvs = document.createElement("canvas");
|
|
84
|
-
testCvs.width = w;
|
|
85
|
-
testCvs.height = h;
|
|
86
|
-
const testCtx = testCvs.getContext("2d");
|
|
87
|
-
testCtx.fillRect(w - 1, h - 1, 1, 1);
|
|
88
|
-
cropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1);
|
|
89
|
-
const isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;
|
|
90
|
-
testCvs.width = 0;
|
|
91
|
-
testCvs.height = 0;
|
|
92
|
-
if (isTestPassed) {
|
|
93
|
-
cropCvs.width = 0;
|
|
94
|
-
cropCvs.height = 0;
|
|
95
|
-
if (dimension === "area") {
|
|
96
|
-
return size * size;
|
|
97
|
-
} else {
|
|
98
|
-
return size;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
cropCvs.width = 0;
|
|
103
|
-
cropCvs.height = 0;
|
|
104
|
-
throw Error("Failed to determine maximum canvas dimension");
|
|
105
|
-
}
|
|
106
|
-
function clampToBrowserMaxCanvasSize(width, height) {
|
|
21
|
+
async function clampToBrowserMaxCanvasSize(width, height) {
|
|
107
22
|
if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
|
|
108
23
|
return [width, height];
|
|
109
24
|
}
|
|
110
|
-
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize();
|
|
25
|
+
const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize();
|
|
111
26
|
const aspectRatio = width / height;
|
|
112
27
|
if (width > maxWidth) {
|
|
113
28
|
width = maxWidth;
|
|
@@ -125,7 +40,6 @@ function clampToBrowserMaxCanvasSize(width, height) {
|
|
|
125
40
|
return [width, height];
|
|
126
41
|
}
|
|
127
42
|
export {
|
|
128
|
-
clampToBrowserMaxCanvasSize
|
|
129
|
-
getCanvasSize
|
|
43
|
+
clampToBrowserMaxCanvasSize
|
|
130
44
|
};
|
|
131
45
|
//# sourceMappingURL=browserCanvasMaxSize.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
|
|
4
|
-
"sourcesContent": ["/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\
|
|
5
|
-
"mappings": "
|
|
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
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.9.0-canary.
|
|
1
|
+
const version = "3.9.0-canary.a3bcb05e47b6";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-02-25T13:
|
|
5
|
-
patch: "2025-02-25T13:
|
|
4
|
+
minor: "2025-02-25T13:27:39.366Z",
|
|
5
|
+
patch: "2025-02-25T13:27:39.366Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.9.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.9.0-canary.a3bcb05e47b6'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-02-25T13:27:39.366Z',\n\tpatch: '2025-02-25T13:27:39.366Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "A tiny little drawing app (editor).",
|
|
4
|
-
"version": "3.9.0-canary.
|
|
4
|
+
"version": "3.9.0-canary.a3bcb05e47b6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -45,14 +45,15 @@
|
|
|
45
45
|
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@tldraw/state": "3.9.0-canary.
|
|
49
|
-
"@tldraw/state-react": "3.9.0-canary.
|
|
50
|
-
"@tldraw/store": "3.9.0-canary.
|
|
51
|
-
"@tldraw/tlschema": "3.9.0-canary.
|
|
52
|
-
"@tldraw/utils": "3.9.0-canary.
|
|
53
|
-
"@tldraw/validate": "3.9.0-canary.
|
|
48
|
+
"@tldraw/state": "3.9.0-canary.a3bcb05e47b6",
|
|
49
|
+
"@tldraw/state-react": "3.9.0-canary.a3bcb05e47b6",
|
|
50
|
+
"@tldraw/store": "3.9.0-canary.a3bcb05e47b6",
|
|
51
|
+
"@tldraw/tlschema": "3.9.0-canary.a3bcb05e47b6",
|
|
52
|
+
"@tldraw/utils": "3.9.0-canary.a3bcb05e47b6",
|
|
53
|
+
"@tldraw/validate": "3.9.0-canary.a3bcb05e47b6",
|
|
54
54
|
"@types/core-js": "^2.5.8",
|
|
55
55
|
"@use-gesture/react": "^10.3.1",
|
|
56
|
+
"canvas-size": "~2.0.0",
|
|
56
57
|
"classnames": "^2.5.1",
|
|
57
58
|
"core-js": "^3.40.0",
|
|
58
59
|
"eventemitter3": "^4.0.7",
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
"@testing-library/jest-dom": "^5.17.0",
|
|
70
71
|
"@testing-library/react": "^15.0.7",
|
|
71
72
|
"@types/benchmark": "^2.1.5",
|
|
73
|
+
"@types/canvas-size": "^1.2.2",
|
|
72
74
|
"@types/wicg-file-system-access": "^2020.9.8",
|
|
73
75
|
"benchmark": "^2.1.4",
|
|
74
76
|
"fake-indexeddb": "^4.0.2",
|
|
@@ -16,7 +16,7 @@ export async function getSvgAsImage(
|
|
|
16
16
|
) {
|
|
17
17
|
const { type, width, height, quality = 1, pixelRatio = 2 } = options
|
|
18
18
|
|
|
19
|
-
let [clampedWidth, clampedHeight] = clampToBrowserMaxCanvasSize(
|
|
19
|
+
let [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize(
|
|
20
20
|
width * pixelRatio,
|
|
21
21
|
height * pixelRatio
|
|
22
22
|
)
|
|
@@ -11,7 +11,6 @@ const tlenv = {
|
|
|
11
11
|
isAndroid: false,
|
|
12
12
|
isWebview: false,
|
|
13
13
|
isDarwin: false,
|
|
14
|
-
hasCanvasSupport: false,
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
@@ -21,8 +20,6 @@ if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
|
21
20
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
22
21
|
tlenv.isAndroid = /android/i.test(navigator.userAgent)
|
|
23
22
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
24
|
-
tlenv.hasCanvasSupport =
|
|
25
|
-
typeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
export { tlenv }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import canvasSize from 'canvas-size'
|
|
2
|
+
|
|
1
3
|
/** @internal */
|
|
2
4
|
export interface CanvasMaxSize {
|
|
3
5
|
maxWidth: number
|
|
@@ -5,135 +7,33 @@ export interface CanvasMaxSize {
|
|
|
5
7
|
maxArea: number
|
|
6
8
|
}
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
let maxCanvasSizes: CanvasMaxSize | null = null
|
|
10
|
+
let maxSizePromise: Promise<CanvasMaxSize> | null = null
|
|
10
11
|
|
|
11
|
-
function getBrowserCanvasMaxSize()
|
|
12
|
-
if (!
|
|
13
|
-
|
|
14
|
-
maxWidth: getCanvasSize('width'), // test very wide but 1 pixel tall canvases
|
|
15
|
-
maxHeight: getCanvasSize('height'), // test very tall but 1 pixel wide canvases
|
|
16
|
-
maxArea: getCanvasSize('area'), // test square canvases
|
|
17
|
-
}
|
|
12
|
+
function getBrowserCanvasMaxSize() {
|
|
13
|
+
if (!maxSizePromise) {
|
|
14
|
+
maxSizePromise = calculateBrowserCanvasMaxSize()
|
|
18
15
|
}
|
|
19
|
-
|
|
16
|
+
|
|
17
|
+
return maxSizePromise
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
}
|
|
25
30
|
|
|
31
|
+
// https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results
|
|
26
32
|
const MAX_SAFE_CANVAS_DIMENSION = 8192
|
|
27
33
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096
|
|
28
34
|
|
|
29
|
-
const TEST_SIZES = {
|
|
30
|
-
area: [
|
|
31
|
-
// Chrome 70 (Mac, Win)
|
|
32
|
-
// Chrome 68 (Android 4.4)
|
|
33
|
-
// Edge 17 (Win)
|
|
34
|
-
// Safari 7-12 (Mac)
|
|
35
|
-
16384,
|
|
36
|
-
// Chrome 68 (Android 7.1-9)
|
|
37
|
-
14188,
|
|
38
|
-
// Chrome 68 (Android 5)
|
|
39
|
-
11402,
|
|
40
|
-
// Firefox 63 (Mac, Win)
|
|
41
|
-
11180,
|
|
42
|
-
// Chrome 68 (Android 6)
|
|
43
|
-
10836,
|
|
44
|
-
// IE 9-11 (Win)
|
|
45
|
-
8192,
|
|
46
|
-
// IE Mobile (Windows Phone 8.x)
|
|
47
|
-
// Safari (iOS 9 - 12)
|
|
48
|
-
4096,
|
|
49
|
-
],
|
|
50
|
-
height: [
|
|
51
|
-
// Safari 7-12 (Mac)
|
|
52
|
-
// Safari (iOS 9-12)
|
|
53
|
-
8388607,
|
|
54
|
-
// Chrome 83 (Mac, Win)
|
|
55
|
-
65535,
|
|
56
|
-
// Chrome 70 (Mac, Win)
|
|
57
|
-
// Chrome 68 (Android 4.4-9)
|
|
58
|
-
// Firefox 63 (Mac, Win)
|
|
59
|
-
32767,
|
|
60
|
-
// Edge 17 (Win)
|
|
61
|
-
// IE11 (Win)
|
|
62
|
-
16384,
|
|
63
|
-
// IE 9-10 (Win)
|
|
64
|
-
8192,
|
|
65
|
-
// IE Mobile (Windows Phone 8.x)
|
|
66
|
-
4096,
|
|
67
|
-
],
|
|
68
|
-
width: [
|
|
69
|
-
// Safari 7-12 (Mac)
|
|
70
|
-
// Safari (iOS 9-12)
|
|
71
|
-
4194303,
|
|
72
|
-
// Chrome 83 (Mac, Win)
|
|
73
|
-
65535,
|
|
74
|
-
// Chrome 70 (Mac, Win)
|
|
75
|
-
// Chrome 68 (Android 4.4-9)
|
|
76
|
-
// Firefox 63 (Mac, Win)
|
|
77
|
-
32767,
|
|
78
|
-
// Edge 17 (Win)
|
|
79
|
-
// IE11 (Win)
|
|
80
|
-
16384,
|
|
81
|
-
// IE 9-10 (Win)
|
|
82
|
-
8192,
|
|
83
|
-
// IE Mobile (Windows Phone 8.x)
|
|
84
|
-
4096,
|
|
85
|
-
],
|
|
86
|
-
} as const
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Tests ability to read pixel data from canvas elements of various dimensions
|
|
90
|
-
* by decreasing canvas height and/or width until a test succeeds.
|
|
91
|
-
*/
|
|
92
|
-
export function getCanvasSize(dimension: 'width' | 'height' | 'area') {
|
|
93
|
-
const cropCvs = document.createElement('canvas')
|
|
94
|
-
cropCvs.width = 1
|
|
95
|
-
cropCvs.height = 1
|
|
96
|
-
const cropCtx = cropCvs.getContext('2d')!
|
|
97
|
-
|
|
98
|
-
for (const size of TEST_SIZES[dimension]) {
|
|
99
|
-
const w = dimension === 'height' ? 1 : size
|
|
100
|
-
const h = dimension === 'width' ? 1 : size
|
|
101
|
-
|
|
102
|
-
const testCvs = document.createElement('canvas')
|
|
103
|
-
testCvs.width = w
|
|
104
|
-
testCvs.height = h
|
|
105
|
-
const testCtx = testCvs.getContext('2d')!
|
|
106
|
-
|
|
107
|
-
testCtx.fillRect(w - 1, h - 1, 1, 1)
|
|
108
|
-
cropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1)
|
|
109
|
-
|
|
110
|
-
const isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0
|
|
111
|
-
// release memory
|
|
112
|
-
testCvs.width = 0
|
|
113
|
-
testCvs.height = 0
|
|
114
|
-
|
|
115
|
-
if (isTestPassed) {
|
|
116
|
-
// release memory
|
|
117
|
-
cropCvs.width = 0
|
|
118
|
-
cropCvs.height = 0
|
|
119
|
-
|
|
120
|
-
if (dimension === 'area') {
|
|
121
|
-
return size * size
|
|
122
|
-
} else {
|
|
123
|
-
return size
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// didn't find a good size, release memory and error
|
|
129
|
-
cropCvs.width = 0
|
|
130
|
-
cropCvs.height = 0
|
|
131
|
-
|
|
132
|
-
throw Error('Failed to determine maximum canvas dimension')
|
|
133
|
-
}
|
|
134
|
-
|
|
135
35
|
/** @internal */
|
|
136
|
-
export function clampToBrowserMaxCanvasSize(width: number, height: number) {
|
|
36
|
+
export async function clampToBrowserMaxCanvasSize(width: number, height: number) {
|
|
137
37
|
if (
|
|
138
38
|
width <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
139
39
|
height <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
@@ -142,7 +42,7 @@ export function clampToBrowserMaxCanvasSize(width: number, height: number) {
|
|
|
142
42
|
return [width, height]
|
|
143
43
|
}
|
|
144
44
|
|
|
145
|
-
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize()
|
|
45
|
+
const { maxWidth, maxHeight, maxArea } = await getBrowserCanvasMaxSize()
|
|
146
46
|
const aspectRatio = width / height
|
|
147
47
|
|
|
148
48
|
if (width > maxWidth) {
|
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.9.0-canary.
|
|
4
|
+
export const version = '3.9.0-canary.a3bcb05e47b6'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-02-25T13:
|
|
8
|
-
patch: '2025-02-25T13:
|
|
7
|
+
minor: '2025-02-25T13:27:39.366Z',
|
|
8
|
+
patch: '2025-02-25T13:27:39.366Z',
|
|
9
9
|
}
|