@tldraw/editor 3.9.0-canary.811b8881d508 → 3.9.0-canary.81717556ec3d
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 +2 -0
- 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 +3 -1
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js +104 -28
- 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 +2 -0
- 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 +3 -1
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +104 -18
- 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 +7 -9
- package/src/lib/exports/getSvgAsImage.ts +1 -1
- package/src/lib/globals/environment.ts +3 -0
- package/src/lib/utils/browserCanvasMaxSize.ts +121 -21
- package/src/version.ts +3 -3
package/dist-cjs/index.d.ts
CHANGED
|
@@ -1047,6 +1047,7 @@ export declare class Editor extends EventEmitter<TLEventMap> {
|
|
|
1047
1047
|
* @public
|
|
1048
1048
|
*/
|
|
1049
1049
|
readonly environment: {
|
|
1050
|
+
hasCanvasSupport: boolean;
|
|
1050
1051
|
isAndroid: boolean;
|
|
1051
1052
|
isChromeForIos: boolean;
|
|
1052
1053
|
isDarwin: boolean;
|
|
@@ -6154,6 +6155,7 @@ export declare type TLEnterEventHandler = (info: any, from: string) => void;
|
|
|
6154
6155
|
* @public
|
|
6155
6156
|
*/
|
|
6156
6157
|
export declare const tlenv: {
|
|
6158
|
+
hasCanvasSupport: boolean;
|
|
6157
6159
|
isAndroid: boolean;
|
|
6158
6160
|
isChromeForIos: boolean;
|
|
6159
6161
|
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] =
|
|
30
|
+
let [clampedWidth, clampedHeight] = (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] =
|
|
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] = 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,QAAI;AAAA,IACnC,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,7 +28,8 @@ const tlenv = {
|
|
|
28
28
|
isFirefox: false,
|
|
29
29
|
isAndroid: false,
|
|
30
30
|
isWebview: false,
|
|
31
|
-
isDarwin: false
|
|
31
|
+
isDarwin: false,
|
|
32
|
+
hasCanvasSupport: false
|
|
32
33
|
};
|
|
33
34
|
if (typeof window !== "undefined" && "navigator" in window) {
|
|
34
35
|
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
@@ -37,5 +38,6 @@ if (typeof window !== "undefined" && "navigator" in window) {
|
|
|
37
38
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent);
|
|
38
39
|
tlenv.isAndroid = /android/i.test(navigator.userAgent);
|
|
39
40
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf("mac") > -1;
|
|
41
|
+
tlenv.hasCanvasSupport = typeof window !== "undefined" && "Promise" in window && "HTMLCanvasElement" in window;
|
|
40
42
|
}
|
|
41
43
|
//# 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}\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;
|
|
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\thasCanvasSupport: 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\ttlenv.hasCanvasSupport =\n\t\ttypeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window\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;AAAA,EACV,kBAAkB;AACnB;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;AAC3E,QAAM,mBACL,OAAO,WAAW,eAAe,aAAa,UAAU,uBAAuB;AACjF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,45 +15,123 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
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
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var browserCanvasMaxSize_exports = {};
|
|
30
20
|
__export(browserCanvasMaxSize_exports, {
|
|
31
|
-
clampToBrowserMaxCanvasSize: () => clampToBrowserMaxCanvasSize
|
|
21
|
+
clampToBrowserMaxCanvasSize: () => clampToBrowserMaxCanvasSize,
|
|
22
|
+
getCanvasSize: () => getCanvasSize
|
|
32
23
|
});
|
|
33
24
|
module.exports = __toCommonJS(browserCanvasMaxSize_exports);
|
|
34
|
-
|
|
35
|
-
let maxSizePromise = null;
|
|
25
|
+
let maxCanvasSizes = null;
|
|
36
26
|
function getBrowserCanvasMaxSize() {
|
|
37
|
-
if (!
|
|
38
|
-
|
|
27
|
+
if (!maxCanvasSizes) {
|
|
28
|
+
maxCanvasSizes = {
|
|
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
|
+
};
|
|
39
36
|
}
|
|
40
|
-
return
|
|
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
|
-
};
|
|
37
|
+
return maxCanvasSizes;
|
|
51
38
|
}
|
|
52
39
|
const MAX_SAFE_CANVAS_DIMENSION = 8192;
|
|
53
40
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
|
|
54
|
-
|
|
41
|
+
const TEST_SIZES = {
|
|
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) {
|
|
55
131
|
if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
|
|
56
132
|
return [width, height];
|
|
57
133
|
}
|
|
58
|
-
const { maxWidth, maxHeight, maxArea } =
|
|
134
|
+
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize();
|
|
59
135
|
const aspectRatio = width / height;
|
|
60
136
|
if (width > maxWidth) {
|
|
61
137
|
width = maxWidth;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\n// Cache this, only want to do this once per browser session\nlet maxCanvasSizes: CanvasMaxSize | null = null\n\nfunction getBrowserCanvasMaxSize(): CanvasMaxSize {\n\tif (!maxCanvasSizes) {\n\t\tmaxCanvasSizes = {\n\t\t\tmaxWidth: getCanvasSize('width'), // test very wide but 1 pixel tall canvases\n\t\t\tmaxHeight: getCanvasSize('height'), // test very tall but 1 pixel wide canvases\n\t\t\tmaxArea: getCanvasSize('area'), // test square canvases\n\t\t}\n\t}\n\treturn maxCanvasSizes\n}\n\n// Extracted from https://github.com/jhildenbiddle/canvas-size\n// MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE\n// Copyright (c) John Hildenbiddle\n\nconst MAX_SAFE_CANVAS_DIMENSION = 8192\nconst MAX_SAFE_CANVAS_AREA = 4096 * 4096\n\nconst TEST_SIZES = {\n\tarea: [\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4)\n\t\t// Edge 17 (Win)\n\t\t// Safari 7-12 (Mac)\n\t\t16384,\n\t\t// Chrome 68 (Android 7.1-9)\n\t\t14188,\n\t\t// Chrome 68 (Android 5)\n\t\t11402,\n\t\t// Firefox 63 (Mac, Win)\n\t\t11180,\n\t\t// Chrome 68 (Android 6)\n\t\t10836,\n\t\t// IE 9-11 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t// Safari (iOS 9 - 12)\n\t\t4096,\n\t],\n\theight: [\n\t\t// Safari 7-12 (Mac)\n\t\t// Safari (iOS 9-12)\n\t\t8388607,\n\t\t// Chrome 83 (Mac, Win)\n\t\t65535,\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4-9)\n\t\t// Firefox 63 (Mac, Win)\n\t\t32767,\n\t\t// Edge 17 (Win)\n\t\t// IE11 (Win)\n\t\t16384,\n\t\t// IE 9-10 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t4096,\n\t],\n\twidth: [\n\t\t// Safari 7-12 (Mac)\n\t\t// Safari (iOS 9-12)\n\t\t4194303,\n\t\t// Chrome 83 (Mac, Win)\n\t\t65535,\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4-9)\n\t\t// Firefox 63 (Mac, Win)\n\t\t32767,\n\t\t// Edge 17 (Win)\n\t\t// IE11 (Win)\n\t\t16384,\n\t\t// IE 9-10 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t4096,\n\t],\n} as const\n\n/**\n * Tests ability to read pixel data from canvas elements of various dimensions\n * by decreasing canvas height and/or width until a test succeeds.\n */\nexport function getCanvasSize(dimension: 'width' | 'height' | 'area') {\n\tconst cropCvs = document.createElement('canvas')\n\tcropCvs.width = 1\n\tcropCvs.height = 1\n\tconst cropCtx = cropCvs.getContext('2d')!\n\n\tfor (const size of TEST_SIZES[dimension]) {\n\t\tconst w = dimension === 'height' ? 1 : size\n\t\tconst h = dimension === 'width' ? 1 : size\n\n\t\tconst testCvs = document.createElement('canvas')\n\t\ttestCvs.width = w\n\t\ttestCvs.height = h\n\t\tconst testCtx = testCvs.getContext('2d')!\n\n\t\ttestCtx.fillRect(w - 1, h - 1, 1, 1)\n\t\tcropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1)\n\n\t\tconst isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0\n\t\t// release memory\n\t\ttestCvs.width = 0\n\t\ttestCvs.height = 0\n\n\t\tif (isTestPassed) {\n\t\t\t// release memory\n\t\t\tcropCvs.width = 0\n\t\t\tcropCvs.height = 0\n\n\t\t\tif (dimension === 'area') {\n\t\t\t\treturn size * size\n\t\t\t} else {\n\t\t\t\treturn size\n\t\t\t}\n\t\t}\n\t}\n\n\t// didn't find a good size, release memory and error\n\tcropCvs.width = 0\n\tcropCvs.height = 0\n\n\tthrow Error('Failed to determine maximum canvas dimension')\n}\n\n/** @internal */\nexport 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 } = 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;AAQA,IAAI,iBAAuC;AAE3C,SAAS,0BAAyC;AACjD,MAAI,CAAC,gBAAgB;AACpB,qBAAiB;AAAA,MAChB,UAAU,cAAc,OAAO;AAAA;AAAA,MAC/B,WAAW,cAAc,QAAQ;AAAA;AAAA,MACjC,SAAS,cAAc,MAAM;AAAA;AAAA,IAC9B;AAAA,EACD;AACA,SAAO;AACR;AAMA,MAAM,4BAA4B;AAClC,MAAM,uBAAuB,OAAO;AAEpC,MAAM,aAAa;AAAA,EAClB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA,IAGA;AAAA,EACD;AAAA,EACA,QAAQ;AAAA;AAAA;AAAA,IAGP;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA;AAAA;AAAA,IAGA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAAA;AAAA,IAGN;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA;AAAA;AAAA,IAGA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACD;AACD;AAMO,SAAS,cAAc,WAAwC;AACrE,QAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,UAAQ,QAAQ;AAChB,UAAQ,SAAS;AACjB,QAAM,UAAU,QAAQ,WAAW,IAAI;AAEvC,aAAW,QAAQ,WAAW,SAAS,GAAG;AACzC,UAAM,IAAI,cAAc,WAAW,IAAI;AACvC,UAAM,IAAI,cAAc,UAAU,IAAI;AAEtC,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,QAAQ;AAChB,YAAQ,SAAS;AACjB,UAAM,UAAU,QAAQ,WAAW,IAAI;AAEvC,YAAQ,SAAS,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AACnC,YAAQ,UAAU,SAAS,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzD,UAAM,eAAe,QAAQ,aAAa,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM;AAElE,YAAQ,QAAQ;AAChB,YAAQ,SAAS;AAEjB,QAAI,cAAc;AAEjB,cAAQ,QAAQ;AAChB,cAAQ,SAAS;AAEjB,UAAI,cAAc,QAAQ;AACzB,eAAO,OAAO;AAAA,MACf,OAAO;AACN,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAGA,UAAQ,QAAQ;AAChB,UAAQ,SAAS;AAEjB,QAAM,MAAM,8CAA8C;AAC3D;AAGO,SAAS,4BAA4B,OAAe,QAAgB;AAC1E,MACC,SAAS,6BACT,UAAU,6BACV,QAAQ,UAAU,sBACjB;AACD,WAAO,CAAC,OAAO,MAAM;AAAA,EACtB;AAEA,QAAM,EAAE,UAAU,WAAW,QAAQ,IAAI,wBAAwB;AACjE,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
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.81717556ec3d";
|
|
26
26
|
const publishDates = {
|
|
27
27
|
major: "2024-09-13T14:36:29.063Z",
|
|
28
|
-
minor: "2025-02-
|
|
29
|
-
patch: "2025-02-
|
|
28
|
+
minor: "2025-02-25T13:46:50.082Z",
|
|
29
|
+
patch: "2025-02-25T13:46:50.082Z"
|
|
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.81717556ec3d'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-02-25T13:46:50.082Z',\n\tpatch: '2025-02-25T13:46:50.082Z',\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,6 +1047,7 @@ export declare class Editor extends EventEmitter<TLEventMap> {
|
|
|
1047
1047
|
* @public
|
|
1048
1048
|
*/
|
|
1049
1049
|
readonly environment: {
|
|
1050
|
+
hasCanvasSupport: boolean;
|
|
1050
1051
|
isAndroid: boolean;
|
|
1051
1052
|
isChromeForIos: boolean;
|
|
1052
1053
|
isDarwin: boolean;
|
|
@@ -6154,6 +6155,7 @@ export declare type TLEnterEventHandler = (info: any, from: string) => void;
|
|
|
6154
6155
|
* @public
|
|
6155
6156
|
*/
|
|
6156
6157
|
export declare const tlenv: {
|
|
6158
|
+
hasCanvasSupport: boolean;
|
|
6157
6159
|
isAndroid: boolean;
|
|
6158
6160
|
isChromeForIos: boolean;
|
|
6159
6161
|
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] =
|
|
7
|
+
let [clampedWidth, clampedHeight] = 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] =
|
|
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
|
|
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,IACnC,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,7 +5,8 @@ const tlenv = {
|
|
|
5
5
|
isFirefox: false,
|
|
6
6
|
isAndroid: false,
|
|
7
7
|
isWebview: false,
|
|
8
|
-
isDarwin: false
|
|
8
|
+
isDarwin: false,
|
|
9
|
+
hasCanvasSupport: false
|
|
9
10
|
};
|
|
10
11
|
if (typeof window !== "undefined" && "navigator" in window) {
|
|
11
12
|
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
@@ -14,6 +15,7 @@ if (typeof window !== "undefined" && "navigator" in window) {
|
|
|
14
15
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent);
|
|
15
16
|
tlenv.isAndroid = /android/i.test(navigator.userAgent);
|
|
16
17
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf("mac") > -1;
|
|
18
|
+
tlenv.hasCanvasSupport = typeof window !== "undefined" && "Promise" in window && "HTMLCanvasElement" in window;
|
|
17
19
|
}
|
|
18
20
|
export {
|
|
19
21
|
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}\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;
|
|
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\thasCanvasSupport: 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\ttlenv.hasCanvasSupport =\n\t\ttypeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window\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;AAAA,EACV,kBAAkB;AACnB;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;AAC3E,QAAM,mBACL,OAAO,WAAW,eAAe,aAAa,UAAU,uBAAuB;AACjF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,28 +1,113 @@
|
|
|
1
|
-
|
|
2
|
-
let maxSizePromise = null;
|
|
1
|
+
let maxCanvasSizes = null;
|
|
3
2
|
function getBrowserCanvasMaxSize() {
|
|
4
|
-
if (!
|
|
5
|
-
|
|
3
|
+
if (!maxCanvasSizes) {
|
|
4
|
+
maxCanvasSizes = {
|
|
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
|
+
};
|
|
6
12
|
}
|
|
7
|
-
return
|
|
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
|
-
};
|
|
13
|
+
return maxCanvasSizes;
|
|
18
14
|
}
|
|
19
15
|
const MAX_SAFE_CANVAS_DIMENSION = 8192;
|
|
20
16
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096;
|
|
21
|
-
|
|
17
|
+
const TEST_SIZES = {
|
|
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) {
|
|
22
107
|
if (width <= MAX_SAFE_CANVAS_DIMENSION && height <= MAX_SAFE_CANVAS_DIMENSION && width * height <= MAX_SAFE_CANVAS_AREA) {
|
|
23
108
|
return [width, height];
|
|
24
109
|
}
|
|
25
|
-
const { maxWidth, maxHeight, maxArea } =
|
|
110
|
+
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize();
|
|
26
111
|
const aspectRatio = width / height;
|
|
27
112
|
if (width > maxWidth) {
|
|
28
113
|
width = maxWidth;
|
|
@@ -40,6 +125,7 @@ async function clampToBrowserMaxCanvasSize(width, height) {
|
|
|
40
125
|
return [width, height];
|
|
41
126
|
}
|
|
42
127
|
export {
|
|
43
|
-
clampToBrowserMaxCanvasSize
|
|
128
|
+
clampToBrowserMaxCanvasSize,
|
|
129
|
+
getCanvasSize
|
|
44
130
|
};
|
|
45
131
|
//# sourceMappingURL=browserCanvasMaxSize.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/browserCanvasMaxSize.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/** @internal */\nexport interface CanvasMaxSize {\n\tmaxWidth: number\n\tmaxHeight: number\n\tmaxArea: number\n}\n\n// Cache this, only want to do this once per browser session\nlet maxCanvasSizes: CanvasMaxSize | null = null\n\nfunction getBrowserCanvasMaxSize(): CanvasMaxSize {\n\tif (!maxCanvasSizes) {\n\t\tmaxCanvasSizes = {\n\t\t\tmaxWidth: getCanvasSize('width'), // test very wide but 1 pixel tall canvases\n\t\t\tmaxHeight: getCanvasSize('height'), // test very tall but 1 pixel wide canvases\n\t\t\tmaxArea: getCanvasSize('area'), // test square canvases\n\t\t}\n\t}\n\treturn maxCanvasSizes\n}\n\n// Extracted from https://github.com/jhildenbiddle/canvas-size\n// MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE\n// Copyright (c) John Hildenbiddle\n\nconst MAX_SAFE_CANVAS_DIMENSION = 8192\nconst MAX_SAFE_CANVAS_AREA = 4096 * 4096\n\nconst TEST_SIZES = {\n\tarea: [\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4)\n\t\t// Edge 17 (Win)\n\t\t// Safari 7-12 (Mac)\n\t\t16384,\n\t\t// Chrome 68 (Android 7.1-9)\n\t\t14188,\n\t\t// Chrome 68 (Android 5)\n\t\t11402,\n\t\t// Firefox 63 (Mac, Win)\n\t\t11180,\n\t\t// Chrome 68 (Android 6)\n\t\t10836,\n\t\t// IE 9-11 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t// Safari (iOS 9 - 12)\n\t\t4096,\n\t],\n\theight: [\n\t\t// Safari 7-12 (Mac)\n\t\t// Safari (iOS 9-12)\n\t\t8388607,\n\t\t// Chrome 83 (Mac, Win)\n\t\t65535,\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4-9)\n\t\t// Firefox 63 (Mac, Win)\n\t\t32767,\n\t\t// Edge 17 (Win)\n\t\t// IE11 (Win)\n\t\t16384,\n\t\t// IE 9-10 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t4096,\n\t],\n\twidth: [\n\t\t// Safari 7-12 (Mac)\n\t\t// Safari (iOS 9-12)\n\t\t4194303,\n\t\t// Chrome 83 (Mac, Win)\n\t\t65535,\n\t\t// Chrome 70 (Mac, Win)\n\t\t// Chrome 68 (Android 4.4-9)\n\t\t// Firefox 63 (Mac, Win)\n\t\t32767,\n\t\t// Edge 17 (Win)\n\t\t// IE11 (Win)\n\t\t16384,\n\t\t// IE 9-10 (Win)\n\t\t8192,\n\t\t// IE Mobile (Windows Phone 8.x)\n\t\t4096,\n\t],\n} as const\n\n/**\n * Tests ability to read pixel data from canvas elements of various dimensions\n * by decreasing canvas height and/or width until a test succeeds.\n */\nexport function getCanvasSize(dimension: 'width' | 'height' | 'area') {\n\tconst cropCvs = document.createElement('canvas')\n\tcropCvs.width = 1\n\tcropCvs.height = 1\n\tconst cropCtx = cropCvs.getContext('2d')!\n\n\tfor (const size of TEST_SIZES[dimension]) {\n\t\tconst w = dimension === 'height' ? 1 : size\n\t\tconst h = dimension === 'width' ? 1 : size\n\n\t\tconst testCvs = document.createElement('canvas')\n\t\ttestCvs.width = w\n\t\ttestCvs.height = h\n\t\tconst testCtx = testCvs.getContext('2d')!\n\n\t\ttestCtx.fillRect(w - 1, h - 1, 1, 1)\n\t\tcropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1)\n\n\t\tconst isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0\n\t\t// release memory\n\t\ttestCvs.width = 0\n\t\ttestCvs.height = 0\n\n\t\tif (isTestPassed) {\n\t\t\t// release memory\n\t\t\tcropCvs.width = 0\n\t\t\tcropCvs.height = 0\n\n\t\t\tif (dimension === 'area') {\n\t\t\t\treturn size * size\n\t\t\t} else {\n\t\t\t\treturn size\n\t\t\t}\n\t\t}\n\t}\n\n\t// didn't find a good size, release memory and error\n\tcropCvs.width = 0\n\tcropCvs.height = 0\n\n\tthrow Error('Failed to determine maximum canvas dimension')\n}\n\n/** @internal */\nexport 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 } = 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": "AAQA,IAAI,iBAAuC;AAE3C,SAAS,0BAAyC;AACjD,MAAI,CAAC,gBAAgB;AACpB,qBAAiB;AAAA,MAChB,UAAU,cAAc,OAAO;AAAA;AAAA,MAC/B,WAAW,cAAc,QAAQ;AAAA;AAAA,MACjC,SAAS,cAAc,MAAM;AAAA;AAAA,IAC9B;AAAA,EACD;AACA,SAAO;AACR;AAMA,MAAM,4BAA4B;AAClC,MAAM,uBAAuB,OAAO;AAEpC,MAAM,aAAa;AAAA,EAClB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA,IAGA;AAAA,EACD;AAAA,EACA,QAAQ;AAAA;AAAA;AAAA,IAGP;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA;AAAA;AAAA,IAGA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAAA;AAAA,IAGN;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA;AAAA;AAAA,IAGA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACD;AACD;AAMO,SAAS,cAAc,WAAwC;AACrE,QAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,UAAQ,QAAQ;AAChB,UAAQ,SAAS;AACjB,QAAM,UAAU,QAAQ,WAAW,IAAI;AAEvC,aAAW,QAAQ,WAAW,SAAS,GAAG;AACzC,UAAM,IAAI,cAAc,WAAW,IAAI;AACvC,UAAM,IAAI,cAAc,UAAU,IAAI;AAEtC,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,QAAQ;AAChB,YAAQ,SAAS;AACjB,UAAM,UAAU,QAAQ,WAAW,IAAI;AAEvC,YAAQ,SAAS,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AACnC,YAAQ,UAAU,SAAS,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzD,UAAM,eAAe,QAAQ,aAAa,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM;AAElE,YAAQ,QAAQ;AAChB,YAAQ,SAAS;AAEjB,QAAI,cAAc;AAEjB,cAAQ,QAAQ;AAChB,cAAQ,SAAS;AAEjB,UAAI,cAAc,QAAQ;AACzB,eAAO,OAAO;AAAA,MACf,OAAO;AACN,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAGA,UAAQ,QAAQ;AAChB,UAAQ,SAAS;AAEjB,QAAM,MAAM,8CAA8C;AAC3D;AAGO,SAAS,4BAA4B,OAAe,QAAgB;AAC1E,MACC,SAAS,6BACT,UAAU,6BACV,QAAQ,UAAU,sBACjB;AACD,WAAO,CAAC,OAAO,MAAM;AAAA,EACtB;AAEA,QAAM,EAAE,UAAU,WAAW,QAAQ,IAAI,wBAAwB;AACjE,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.81717556ec3d";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-02-
|
|
5
|
-
patch: "2025-02-
|
|
4
|
+
minor: "2025-02-25T13:46:50.082Z",
|
|
5
|
+
patch: "2025-02-25T13:46:50.082Z"
|
|
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.81717556ec3d'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-02-25T13:46:50.082Z',\n\tpatch: '2025-02-25T13:46:50.082Z',\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.81717556ec3d",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -45,15 +45,14 @@
|
|
|
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.81717556ec3d",
|
|
49
|
+
"@tldraw/state-react": "3.9.0-canary.81717556ec3d",
|
|
50
|
+
"@tldraw/store": "3.9.0-canary.81717556ec3d",
|
|
51
|
+
"@tldraw/tlschema": "3.9.0-canary.81717556ec3d",
|
|
52
|
+
"@tldraw/utils": "3.9.0-canary.81717556ec3d",
|
|
53
|
+
"@tldraw/validate": "3.9.0-canary.81717556ec3d",
|
|
54
54
|
"@types/core-js": "^2.5.8",
|
|
55
55
|
"@use-gesture/react": "^10.3.1",
|
|
56
|
-
"canvas-size": "~2.0.0",
|
|
57
56
|
"classnames": "^2.5.1",
|
|
58
57
|
"core-js": "^3.40.0",
|
|
59
58
|
"eventemitter3": "^4.0.7",
|
|
@@ -70,7 +69,6 @@
|
|
|
70
69
|
"@testing-library/jest-dom": "^5.17.0",
|
|
71
70
|
"@testing-library/react": "^15.0.7",
|
|
72
71
|
"@types/benchmark": "^2.1.5",
|
|
73
|
-
"@types/canvas-size": "^1.2.2",
|
|
74
72
|
"@types/wicg-file-system-access": "^2020.9.8",
|
|
75
73
|
"benchmark": "^2.1.4",
|
|
76
74
|
"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] =
|
|
19
|
+
let [clampedWidth, clampedHeight] = clampToBrowserMaxCanvasSize(
|
|
20
20
|
width * pixelRatio,
|
|
21
21
|
height * pixelRatio
|
|
22
22
|
)
|
|
@@ -11,6 +11,7 @@ const tlenv = {
|
|
|
11
11
|
isAndroid: false,
|
|
12
12
|
isWebview: false,
|
|
13
13
|
isDarwin: false,
|
|
14
|
+
hasCanvasSupport: false,
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
@@ -20,6 +21,8 @@ if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
|
20
21
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
21
22
|
tlenv.isAndroid = /android/i.test(navigator.userAgent)
|
|
22
23
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
24
|
+
tlenv.hasCanvasSupport =
|
|
25
|
+
typeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export { tlenv }
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import canvasSize from 'canvas-size'
|
|
2
|
-
|
|
3
1
|
/** @internal */
|
|
4
2
|
export interface CanvasMaxSize {
|
|
5
3
|
maxWidth: number
|
|
@@ -7,33 +5,135 @@ export interface CanvasMaxSize {
|
|
|
7
5
|
maxArea: number
|
|
8
6
|
}
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
// Cache this, only want to do this once per browser session
|
|
9
|
+
let maxCanvasSizes: CanvasMaxSize | null = null
|
|
11
10
|
|
|
12
|
-
function getBrowserCanvasMaxSize() {
|
|
13
|
-
if (!
|
|
14
|
-
|
|
11
|
+
function getBrowserCanvasMaxSize(): CanvasMaxSize {
|
|
12
|
+
if (!maxCanvasSizes) {
|
|
13
|
+
maxCanvasSizes = {
|
|
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
|
+
}
|
|
15
18
|
}
|
|
16
|
-
|
|
17
|
-
return maxSizePromise
|
|
19
|
+
return maxCanvasSizes
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
}
|
|
22
|
+
// Extracted from https://github.com/jhildenbiddle/canvas-size
|
|
23
|
+
// MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE
|
|
24
|
+
// Copyright (c) John Hildenbiddle
|
|
30
25
|
|
|
31
|
-
// https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results
|
|
32
26
|
const MAX_SAFE_CANVAS_DIMENSION = 8192
|
|
33
27
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096
|
|
34
28
|
|
|
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
|
+
|
|
35
135
|
/** @internal */
|
|
36
|
-
export
|
|
136
|
+
export function clampToBrowserMaxCanvasSize(width: number, height: number) {
|
|
37
137
|
if (
|
|
38
138
|
width <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
39
139
|
height <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
@@ -42,7 +142,7 @@ export async function clampToBrowserMaxCanvasSize(width: number, height: number)
|
|
|
42
142
|
return [width, height]
|
|
43
143
|
}
|
|
44
144
|
|
|
45
|
-
const { maxWidth, maxHeight, maxArea } =
|
|
145
|
+
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize()
|
|
46
146
|
const aspectRatio = width / height
|
|
47
147
|
|
|
48
148
|
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.81717556ec3d'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-02-
|
|
8
|
-
patch: '2025-02-
|
|
7
|
+
minor: '2025-02-25T13:46:50.082Z',
|
|
8
|
+
patch: '2025-02-25T13:46:50.082Z',
|
|
9
9
|
}
|