@myoc/element 0.19.532 → 0.19.534
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/dev/index.js +816 -16
- package/dist/dev/index.js.map +4 -4
- package/dist/prod/index.js +15 -15
- package/dist/types/common/src/constants.d.ts +1 -0
- package/dist/types/element/src/gif.d.ts +29 -0
- package/dist/types/element/src/image.d.ts +6 -1
- package/dist/types/element/src/index.d.ts +2 -0
- package/dist/types/element/src/newElement.d.ts +1 -0
- package/dist/types/element/src/renderGif.d.ts +5 -0
- package/dist/types/element/src/types.d.ts +12 -0
- package/dist/types/excalidraw/actions/actionBoundText.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionCanvas.d.ts +6 -6
- package/dist/types/excalidraw/actions/actionClipboard.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionCropEditor.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +3 -3
- package/dist/types/excalidraw/actions/actionDeselect.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionElementLock.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionExport.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionFrame.d.ts +4 -3
- package/dist/types/excalidraw/actions/actionGroup.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +2 -1
- package/dist/types/excalidraw/actions/actionLink.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionProperties.d.ts +2 -2
- package/dist/types/excalidraw/actions/actionSelectAll.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionStyles.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleStats.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +1 -1
- package/dist/types/excalidraw/components/App.d.ts +8 -1
- package/dist/types/excalidraw/components/App.gif.d.ts +18 -0
- package/dist/types/excalidraw/components/GifPlaybackControls.d.ts +10 -0
- package/dist/types/excalidraw/components/icons.d.ts +4 -0
- package/dist/types/excalidraw/data/blob.d.ts +2 -2
- package/dist/types/excalidraw/data/json.d.ts +1 -1
- package/dist/types/excalidraw/data/restoreGif.d.ts +4 -0
- package/dist/types/excalidraw/scene/Renderer.d.ts +1 -0
- package/dist/types/excalidraw/scene/types.d.ts +2 -1
- package/dist/types/excalidraw/types.d.ts +12 -2
- package/dist/types/excalidraw/viewport.d.ts +1 -1
- package/package.json +5 -4
package/dist/dev/index.js
CHANGED
|
@@ -14535,7 +14535,11 @@ var determineCustomLinearAngle = (pivotPoint, draggedPoint) => Math.atan2(dragge
|
|
|
14535
14535
|
|
|
14536
14536
|
// src/image.ts
|
|
14537
14537
|
init_define_import_meta_env();
|
|
14538
|
-
import {
|
|
14538
|
+
import {
|
|
14539
|
+
DEFAULT_GIF_AUTO_DECODE_MAX_FILE_SIZE_BYTES,
|
|
14540
|
+
MIME_TYPES,
|
|
14541
|
+
SVG_NS
|
|
14542
|
+
} from "@excalidraw/common";
|
|
14539
14543
|
|
|
14540
14544
|
// ../../node_modules/thumbhash/thumbhash.js
|
|
14541
14545
|
init_define_import_meta_env();
|
|
@@ -14689,6 +14693,647 @@ function thumbHashToApproximateAspectRatio(hash) {
|
|
|
14689
14693
|
return lx / ly;
|
|
14690
14694
|
}
|
|
14691
14695
|
|
|
14696
|
+
// src/gif.ts
|
|
14697
|
+
init_define_import_meta_env();
|
|
14698
|
+
|
|
14699
|
+
// ../../node_modules/modern-gif/dist/index.mjs
|
|
14700
|
+
init_define_import_meta_env();
|
|
14701
|
+
var SIGNATURE = "GIF";
|
|
14702
|
+
var VERSIONS = ["87a", "89a"];
|
|
14703
|
+
var IMAGE_DESCRIPTOR = 44;
|
|
14704
|
+
var EXTENSION = 33;
|
|
14705
|
+
var EXTENSION_APPLICATION = 255;
|
|
14706
|
+
var EXTENSION_APPLICATION_BLOCK_SIZE = 11;
|
|
14707
|
+
var EXTENSION_COMMENT = 254;
|
|
14708
|
+
var EXTENSION_GRAPHIC_CONTROL = 249;
|
|
14709
|
+
var EXTENSION_GRAPHIC_CONTROL_BLOCK_SIZE = 4;
|
|
14710
|
+
var EXTENSION_PLAIN_TEXT = 1;
|
|
14711
|
+
var EXTENSION_PLAIN_TEXT_BLOCK_SIZE = 1;
|
|
14712
|
+
var TRAILER = 59;
|
|
14713
|
+
function mergeBuffers(buffers) {
|
|
14714
|
+
const container = new Uint8Array(
|
|
14715
|
+
buffers.reduce((total, array) => total + array.byteLength, 0)
|
|
14716
|
+
);
|
|
14717
|
+
buffers.reduce((offset, array) => {
|
|
14718
|
+
container.set(array, offset);
|
|
14719
|
+
return offset + array.byteLength;
|
|
14720
|
+
}, 0);
|
|
14721
|
+
return container;
|
|
14722
|
+
}
|
|
14723
|
+
function resovleSource(source, output, options) {
|
|
14724
|
+
let buffer;
|
|
14725
|
+
if (ArrayBuffer.isView(source)) {
|
|
14726
|
+
buffer = source.buffer;
|
|
14727
|
+
} else if (source instanceof ArrayBuffer) {
|
|
14728
|
+
buffer = source;
|
|
14729
|
+
} else {
|
|
14730
|
+
const canvas = document.createElement("canvas");
|
|
14731
|
+
const { width, height } = options || {};
|
|
14732
|
+
const context2d = canvas.getContext("2d");
|
|
14733
|
+
if (!context2d) {
|
|
14734
|
+
throw new Error("Failed to create canvas context2d");
|
|
14735
|
+
}
|
|
14736
|
+
canvas.width = width ?? ("width" in source ? typeof source.width === "number" ? source.width : source.width.baseVal.value : 0);
|
|
14737
|
+
canvas.height = height ?? ("height" in source ? typeof source.height === "number" ? source.height : source.height.baseVal.value : 0);
|
|
14738
|
+
context2d.drawImage(source, 0, 0, canvas.width, canvas.height);
|
|
14739
|
+
buffer = context2d.getImageData(0, 0, canvas.width, canvas.height).data.buffer;
|
|
14740
|
+
}
|
|
14741
|
+
switch (output) {
|
|
14742
|
+
case "uint8Array":
|
|
14743
|
+
return new Uint8Array(buffer);
|
|
14744
|
+
case "uint8ClampedArray":
|
|
14745
|
+
return new Uint8ClampedArray(buffer);
|
|
14746
|
+
case "dataView":
|
|
14747
|
+
return new DataView(buffer);
|
|
14748
|
+
default:
|
|
14749
|
+
throw new Error("Unsupported output format");
|
|
14750
|
+
}
|
|
14751
|
+
}
|
|
14752
|
+
var Reader = class {
|
|
14753
|
+
_view;
|
|
14754
|
+
offset = 0;
|
|
14755
|
+
constructor(source) {
|
|
14756
|
+
this._view = resovleSource(source, "dataView");
|
|
14757
|
+
}
|
|
14758
|
+
readByte() {
|
|
14759
|
+
return this._view.getUint8(this.offset++);
|
|
14760
|
+
}
|
|
14761
|
+
readBytes(length) {
|
|
14762
|
+
return Array.from({ length }).map(() => this.readByte());
|
|
14763
|
+
}
|
|
14764
|
+
readString(length) {
|
|
14765
|
+
return String.fromCharCode(...this.readBytes(length));
|
|
14766
|
+
}
|
|
14767
|
+
readUnsigned() {
|
|
14768
|
+
return [this._view.getUint16(this.offset, true), this.offset += 2][0];
|
|
14769
|
+
}
|
|
14770
|
+
readBits() {
|
|
14771
|
+
return this._view.getUint8(this.offset++).toString(2).padStart(8, "0").split("").map(Number);
|
|
14772
|
+
}
|
|
14773
|
+
readColorTable(length) {
|
|
14774
|
+
return Array.from({ length }, () => Array.from(this.readBytes(3)));
|
|
14775
|
+
}
|
|
14776
|
+
readSubBlock() {
|
|
14777
|
+
const block = [];
|
|
14778
|
+
while (true) {
|
|
14779
|
+
const val = this.readByte();
|
|
14780
|
+
if (val === 0 && this._view.getUint8(this.offset) !== 0)
|
|
14781
|
+
break;
|
|
14782
|
+
block.push(val);
|
|
14783
|
+
}
|
|
14784
|
+
return block;
|
|
14785
|
+
}
|
|
14786
|
+
};
|
|
14787
|
+
function decode(source) {
|
|
14788
|
+
const gif = {};
|
|
14789
|
+
const reader = new Reader(source);
|
|
14790
|
+
const createFrame = () => ({ index: 0, delay: 100, disposal: 0 });
|
|
14791
|
+
const signature = reader.readString(3);
|
|
14792
|
+
const version = reader.readString(3);
|
|
14793
|
+
if (signature !== SIGNATURE || !VERSIONS.includes(version)) {
|
|
14794
|
+
throw new Error("This is not a 87a/89a GIF data.");
|
|
14795
|
+
}
|
|
14796
|
+
gif.version = version;
|
|
14797
|
+
gif.width = reader.readUnsigned();
|
|
14798
|
+
gif.height = reader.readUnsigned();
|
|
14799
|
+
const bits = reader.readBits();
|
|
14800
|
+
gif.globalColorTable = Boolean(bits[0]);
|
|
14801
|
+
gif.colorResoluTion = Number.parseInt(bits.slice(1, 4).join(""), 2) + 1;
|
|
14802
|
+
gif.colorTableSorted = Boolean(bits[4]);
|
|
14803
|
+
const colorTableSize = Number.parseInt(bits.slice(5, 8).join(""), 2);
|
|
14804
|
+
gif.colorTableSize = 2 ** (colorTableSize + 1);
|
|
14805
|
+
gif.backgroundColorIndex = reader.readByte();
|
|
14806
|
+
gif.pixelAspectRatio = reader.readByte();
|
|
14807
|
+
if (gif.globalColorTable) {
|
|
14808
|
+
if (gif.colorTableSize) {
|
|
14809
|
+
gif.colorTable = reader.readColorTable(gif.colorTableSize);
|
|
14810
|
+
} else {
|
|
14811
|
+
reader.readSubBlock();
|
|
14812
|
+
}
|
|
14813
|
+
}
|
|
14814
|
+
gif.frames = [];
|
|
14815
|
+
let frame = createFrame();
|
|
14816
|
+
const flags = [];
|
|
14817
|
+
const extensionFlags = [];
|
|
14818
|
+
while (true) {
|
|
14819
|
+
const flag = reader.readByte();
|
|
14820
|
+
flags.push(flag);
|
|
14821
|
+
if (flag === IMAGE_DESCRIPTOR) {
|
|
14822
|
+
frame.left = reader.readUnsigned();
|
|
14823
|
+
frame.top = reader.readUnsigned();
|
|
14824
|
+
frame.width = reader.readUnsigned();
|
|
14825
|
+
frame.height = reader.readUnsigned();
|
|
14826
|
+
const bits2 = reader.readBits();
|
|
14827
|
+
frame.localColorTable = Boolean(bits2[0]);
|
|
14828
|
+
frame.interlaced = Boolean(bits2[1]);
|
|
14829
|
+
frame.colorTableSorted = Boolean(bits2[2]);
|
|
14830
|
+
frame.reserved = Number.parseInt(bits2.slice(3, 5).join(""), 2);
|
|
14831
|
+
const colorTableSize2 = Number.parseInt(bits2.slice(5, 8).join(""), 2);
|
|
14832
|
+
frame.colorTableSize = 2 ** (colorTableSize2 + 1);
|
|
14833
|
+
if (frame.localColorTable) {
|
|
14834
|
+
frame.colorTable = reader.readColorTable(frame.colorTableSize);
|
|
14835
|
+
}
|
|
14836
|
+
frame.lzwMinCodeSize = reader.readByte();
|
|
14837
|
+
frame.dataPositions = [];
|
|
14838
|
+
while (true) {
|
|
14839
|
+
const length = reader.readByte();
|
|
14840
|
+
if (length === 0)
|
|
14841
|
+
break;
|
|
14842
|
+
const offset = reader.offset;
|
|
14843
|
+
frame.dataPositions.push([offset, length]);
|
|
14844
|
+
reader.offset = offset + length;
|
|
14845
|
+
}
|
|
14846
|
+
gif.frames.push(frame);
|
|
14847
|
+
frame = createFrame();
|
|
14848
|
+
frame.index = gif.frames.length;
|
|
14849
|
+
continue;
|
|
14850
|
+
}
|
|
14851
|
+
if (flag === EXTENSION) {
|
|
14852
|
+
const extensionFlag = reader.readByte();
|
|
14853
|
+
extensionFlags.push(extensionFlag);
|
|
14854
|
+
if (extensionFlag === EXTENSION_APPLICATION) {
|
|
14855
|
+
if (reader.readByte() !== EXTENSION_APPLICATION_BLOCK_SIZE)
|
|
14856
|
+
continue;
|
|
14857
|
+
const application = {
|
|
14858
|
+
identifier: reader.readString(8),
|
|
14859
|
+
code: reader.readString(3),
|
|
14860
|
+
data: []
|
|
14861
|
+
};
|
|
14862
|
+
if (`${application.identifier}${application.code}` === "NETSCAPE2.0") {
|
|
14863
|
+
if (reader.readByte() === 3) {
|
|
14864
|
+
gif.looped = Boolean(reader.readByte());
|
|
14865
|
+
gif.loopCount = reader.readUnsigned();
|
|
14866
|
+
}
|
|
14867
|
+
}
|
|
14868
|
+
application.data = reader.readSubBlock();
|
|
14869
|
+
frame.application = application;
|
|
14870
|
+
continue;
|
|
14871
|
+
}
|
|
14872
|
+
if (extensionFlag === EXTENSION_COMMENT) {
|
|
14873
|
+
frame.comment = reader.readSubBlock().map((val) => String.fromCharCode(val)).join("");
|
|
14874
|
+
continue;
|
|
14875
|
+
}
|
|
14876
|
+
if (extensionFlag === EXTENSION_GRAPHIC_CONTROL) {
|
|
14877
|
+
if (reader.readByte() !== EXTENSION_GRAPHIC_CONTROL_BLOCK_SIZE)
|
|
14878
|
+
continue;
|
|
14879
|
+
const bits2 = reader.readBits();
|
|
14880
|
+
const graphicControl = {
|
|
14881
|
+
// ↓ <Packed Fields>
|
|
14882
|
+
reserved: Number.parseInt(bits2.slice(0, 3).join(""), 2),
|
|
14883
|
+
disposal: Number.parseInt(bits2.slice(3, 6).join(""), 2),
|
|
14884
|
+
userInput: Boolean(bits2[6]),
|
|
14885
|
+
transparent: Boolean(bits2[7]),
|
|
14886
|
+
// ↑ <Packed Fields>
|
|
14887
|
+
delayTime: reader.readUnsigned(),
|
|
14888
|
+
transparentIndex: reader.readByte()
|
|
14889
|
+
};
|
|
14890
|
+
reader.readSubBlock();
|
|
14891
|
+
frame.graphicControl = graphicControl;
|
|
14892
|
+
frame.disposal = graphicControl.disposal;
|
|
14893
|
+
frame.delay = (graphicControl.delayTime || 10) * 10;
|
|
14894
|
+
continue;
|
|
14895
|
+
}
|
|
14896
|
+
if (extensionFlag === EXTENSION_PLAIN_TEXT) {
|
|
14897
|
+
if (reader.readByte() !== EXTENSION_PLAIN_TEXT_BLOCK_SIZE)
|
|
14898
|
+
continue;
|
|
14899
|
+
frame.plainText = {
|
|
14900
|
+
left: reader.readUnsigned(),
|
|
14901
|
+
top: reader.readUnsigned(),
|
|
14902
|
+
width: reader.readUnsigned(),
|
|
14903
|
+
height: reader.readUnsigned(),
|
|
14904
|
+
cellWidth: reader.readByte(),
|
|
14905
|
+
cellHeight: reader.readByte(),
|
|
14906
|
+
colorIndex: reader.readByte(),
|
|
14907
|
+
backgroundColorIndex: reader.readByte(),
|
|
14908
|
+
data: reader.readSubBlock()
|
|
14909
|
+
};
|
|
14910
|
+
continue;
|
|
14911
|
+
}
|
|
14912
|
+
console.warn(
|
|
14913
|
+
`Unknown extension block: 0x${extensionFlag.toString(16)}`,
|
|
14914
|
+
flags.slice(0, flags.length - 1).map((val) => `0x${val.toString(16)}`),
|
|
14915
|
+
extensionFlags.slice(0, extensionFlags.length - 1).map((val) => `0x${val.toString(16)}`)
|
|
14916
|
+
);
|
|
14917
|
+
continue;
|
|
14918
|
+
}
|
|
14919
|
+
if (flag === TRAILER)
|
|
14920
|
+
break;
|
|
14921
|
+
console.warn(
|
|
14922
|
+
`Unknown block: 0x${flag.toString(16)}`,
|
|
14923
|
+
flags.slice(0, flags.length - 1).map((val) => `0x${val.toString(16)}`),
|
|
14924
|
+
extensionFlags.slice(0, extensionFlags.length - 1).map((val) => `0x${val.toString(16)}`)
|
|
14925
|
+
);
|
|
14926
|
+
}
|
|
14927
|
+
return gif;
|
|
14928
|
+
}
|
|
14929
|
+
function createWorker(options) {
|
|
14930
|
+
const callbacks = /* @__PURE__ */ new Map();
|
|
14931
|
+
const { workerUrl } = options;
|
|
14932
|
+
let { workerNumber = 1 } = options;
|
|
14933
|
+
const workers = [...Array.from({ length: workerUrl ? workerNumber : 0 })].map(() => {
|
|
14934
|
+
try {
|
|
14935
|
+
const worker = new Worker(workerUrl);
|
|
14936
|
+
worker.onmessage = onMessage;
|
|
14937
|
+
return worker;
|
|
14938
|
+
} catch (err) {
|
|
14939
|
+
console.warn(err);
|
|
14940
|
+
return null;
|
|
14941
|
+
}
|
|
14942
|
+
}).filter(Boolean);
|
|
14943
|
+
workerNumber = workers.length;
|
|
14944
|
+
function onMessage(event) {
|
|
14945
|
+
const { id, data } = event.data;
|
|
14946
|
+
callbacks.get(id)?.(data);
|
|
14947
|
+
callbacks.delete(id);
|
|
14948
|
+
}
|
|
14949
|
+
const getWorker = /* @__PURE__ */ function() {
|
|
14950
|
+
let id = 0;
|
|
14951
|
+
return (index) => workers[(index ?? id++) % workerNumber];
|
|
14952
|
+
}();
|
|
14953
|
+
const call = /* @__PURE__ */ function() {
|
|
14954
|
+
let id = 0;
|
|
14955
|
+
return (type, data, transfer, index) => {
|
|
14956
|
+
return new Promise((resolve) => {
|
|
14957
|
+
const worker = getWorker(index);
|
|
14958
|
+
if (!worker)
|
|
14959
|
+
return resolve(void 0);
|
|
14960
|
+
callbacks.set(id, resolve);
|
|
14961
|
+
worker.postMessage({ id: id++, type, data }, { transfer });
|
|
14962
|
+
});
|
|
14963
|
+
};
|
|
14964
|
+
}();
|
|
14965
|
+
return {
|
|
14966
|
+
call
|
|
14967
|
+
};
|
|
14968
|
+
}
|
|
14969
|
+
function deinterlace(pixels, width) {
|
|
14970
|
+
const newPixels = Array.from({ length: pixels.length });
|
|
14971
|
+
const rows = pixels.length / width;
|
|
14972
|
+
const offsets = [0, 4, 2, 1];
|
|
14973
|
+
const steps = [8, 8, 4, 2];
|
|
14974
|
+
let fromRow = 0;
|
|
14975
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
14976
|
+
for (let toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
|
|
14977
|
+
newPixels.splice.apply(
|
|
14978
|
+
newPixels,
|
|
14979
|
+
[toRow * width, width].concat(
|
|
14980
|
+
pixels.slice(fromRow * width, (fromRow + 1) * width)
|
|
14981
|
+
)
|
|
14982
|
+
);
|
|
14983
|
+
fromRow++;
|
|
14984
|
+
}
|
|
14985
|
+
}
|
|
14986
|
+
return newPixels;
|
|
14987
|
+
}
|
|
14988
|
+
function lzwDecode(minCodeSize, data, pixelCount) {
|
|
14989
|
+
const MAX_STACK_SIZE = 4096;
|
|
14990
|
+
const nullCode = -1;
|
|
14991
|
+
const npix = pixelCount;
|
|
14992
|
+
let available, codeMask, codeSize, inCode, oldCode, code, i;
|
|
14993
|
+
const dstPixels = Array.from({ length: pixelCount });
|
|
14994
|
+
const prefix = Array.from({ length: MAX_STACK_SIZE });
|
|
14995
|
+
const suffix = Array.from({ length: MAX_STACK_SIZE });
|
|
14996
|
+
const pixelStack = Array.from({ length: MAX_STACK_SIZE + 1 });
|
|
14997
|
+
const dataSize = minCodeSize;
|
|
14998
|
+
const clear = 1 << dataSize;
|
|
14999
|
+
const endOfInformation = clear + 1;
|
|
15000
|
+
available = clear + 2;
|
|
15001
|
+
oldCode = nullCode;
|
|
15002
|
+
codeSize = dataSize + 1;
|
|
15003
|
+
codeMask = (1 << codeSize) - 1;
|
|
15004
|
+
for (code = 0; code < clear; code++) {
|
|
15005
|
+
prefix[code] = 0;
|
|
15006
|
+
suffix[code] = code;
|
|
15007
|
+
}
|
|
15008
|
+
let datum, bits, first, top, pi, bi;
|
|
15009
|
+
datum = bits = first = top = pi = bi = 0;
|
|
15010
|
+
for (i = 0; i < npix; ) {
|
|
15011
|
+
if (top === 0) {
|
|
15012
|
+
if (bits < codeSize) {
|
|
15013
|
+
datum += data[bi] << bits;
|
|
15014
|
+
bits += 8;
|
|
15015
|
+
bi++;
|
|
15016
|
+
continue;
|
|
15017
|
+
}
|
|
15018
|
+
code = datum & codeMask;
|
|
15019
|
+
datum >>= codeSize;
|
|
15020
|
+
bits -= codeSize;
|
|
15021
|
+
if (code > available || code === endOfInformation) {
|
|
15022
|
+
break;
|
|
15023
|
+
}
|
|
15024
|
+
if (code === clear) {
|
|
15025
|
+
codeSize = dataSize + 1;
|
|
15026
|
+
codeMask = (1 << codeSize) - 1;
|
|
15027
|
+
available = clear + 2;
|
|
15028
|
+
oldCode = nullCode;
|
|
15029
|
+
continue;
|
|
15030
|
+
}
|
|
15031
|
+
if (oldCode === nullCode) {
|
|
15032
|
+
pixelStack[top++] = suffix[code];
|
|
15033
|
+
oldCode = code;
|
|
15034
|
+
first = code;
|
|
15035
|
+
continue;
|
|
15036
|
+
}
|
|
15037
|
+
inCode = code;
|
|
15038
|
+
if (code === available) {
|
|
15039
|
+
pixelStack[top++] = first;
|
|
15040
|
+
code = oldCode;
|
|
15041
|
+
}
|
|
15042
|
+
while (code > clear) {
|
|
15043
|
+
pixelStack[top++] = suffix[code];
|
|
15044
|
+
code = prefix[code];
|
|
15045
|
+
}
|
|
15046
|
+
first = suffix[code] & 255;
|
|
15047
|
+
pixelStack[top++] = first;
|
|
15048
|
+
if (available < MAX_STACK_SIZE) {
|
|
15049
|
+
prefix[available] = oldCode;
|
|
15050
|
+
suffix[available] = first;
|
|
15051
|
+
available++;
|
|
15052
|
+
if ((available & codeMask) === 0 && available < MAX_STACK_SIZE) {
|
|
15053
|
+
codeSize++;
|
|
15054
|
+
codeMask += available;
|
|
15055
|
+
}
|
|
15056
|
+
}
|
|
15057
|
+
oldCode = inCode;
|
|
15058
|
+
}
|
|
15059
|
+
top--;
|
|
15060
|
+
dstPixels[pi++] = pixelStack[top];
|
|
15061
|
+
i++;
|
|
15062
|
+
}
|
|
15063
|
+
for (i = pi; i < npix; i++) {
|
|
15064
|
+
dstPixels[i] = 0;
|
|
15065
|
+
}
|
|
15066
|
+
return dstPixels;
|
|
15067
|
+
}
|
|
15068
|
+
function decodeFrames(source, options) {
|
|
15069
|
+
const array = resovleSource(source, "uint8Array");
|
|
15070
|
+
if (options?.workerUrl) {
|
|
15071
|
+
return createWorker({ workerUrl: options.workerUrl }).call(
|
|
15072
|
+
"frames:decode",
|
|
15073
|
+
array,
|
|
15074
|
+
[array.buffer]
|
|
15075
|
+
);
|
|
15076
|
+
}
|
|
15077
|
+
const {
|
|
15078
|
+
gif = decode(source),
|
|
15079
|
+
range
|
|
15080
|
+
} = options ?? {};
|
|
15081
|
+
const {
|
|
15082
|
+
width: globalWidth,
|
|
15083
|
+
height: globalHeight,
|
|
15084
|
+
colorTable: globalColorTable,
|
|
15085
|
+
frames: globalFrames
|
|
15086
|
+
} = gif;
|
|
15087
|
+
const frames2 = range ? globalFrames.slice(range[0], range[1] + 1) : globalFrames;
|
|
15088
|
+
const hasDisposal3 = frames2.some((frame) => frame.disposal === 3);
|
|
15089
|
+
let pixels = new Uint8ClampedArray(globalWidth * globalHeight * 4);
|
|
15090
|
+
let previousFrame;
|
|
15091
|
+
let previousPixels = pixels.slice();
|
|
15092
|
+
return frames2.map((frame) => {
|
|
15093
|
+
const {
|
|
15094
|
+
left,
|
|
15095
|
+
top,
|
|
15096
|
+
width,
|
|
15097
|
+
height,
|
|
15098
|
+
interlaced,
|
|
15099
|
+
localColorTable,
|
|
15100
|
+
colorTable,
|
|
15101
|
+
lzwMinCodeSize,
|
|
15102
|
+
dataPositions,
|
|
15103
|
+
graphicControl,
|
|
15104
|
+
delay,
|
|
15105
|
+
disposal
|
|
15106
|
+
} = frame;
|
|
15107
|
+
const previousDisposal = previousFrame?.disposal;
|
|
15108
|
+
const bottom = top + height;
|
|
15109
|
+
const {
|
|
15110
|
+
transparent,
|
|
15111
|
+
transparentIndex: localTransparentIndex
|
|
15112
|
+
} = graphicControl ?? {};
|
|
15113
|
+
const palette2 = localColorTable ? colorTable : globalColorTable;
|
|
15114
|
+
const transparentIndex = transparent ? localTransparentIndex : -1;
|
|
15115
|
+
const compressedData = mergeBuffers(
|
|
15116
|
+
dataPositions.map(
|
|
15117
|
+
([begin, length]) => array.subarray(begin, begin + length)
|
|
15118
|
+
)
|
|
15119
|
+
);
|
|
15120
|
+
let colorIndexes = lzwDecode(lzwMinCodeSize, compressedData, width * height);
|
|
15121
|
+
if (interlaced) {
|
|
15122
|
+
colorIndexes = deinterlace(colorIndexes, width);
|
|
15123
|
+
}
|
|
15124
|
+
if (previousDisposal === 3) {
|
|
15125
|
+
pixels = previousPixels.slice();
|
|
15126
|
+
} else if (previousDisposal === 2) {
|
|
15127
|
+
const { left: left2, top: top2, width: width2, height: height2 } = previousFrame;
|
|
15128
|
+
const bottom2 = top2 + height2;
|
|
15129
|
+
for (let y = top2; y < bottom2; y++) {
|
|
15130
|
+
const globalOffset = y * globalWidth + left2;
|
|
15131
|
+
for (let x = 0; x < width2; x++) {
|
|
15132
|
+
const index = (globalOffset + x) * 4;
|
|
15133
|
+
pixels[index] = pixels[index + 1] = pixels[index + 2] = pixels[index + 3] = 0;
|
|
15134
|
+
}
|
|
15135
|
+
}
|
|
15136
|
+
}
|
|
15137
|
+
for (let y = top; y < bottom; y++) {
|
|
15138
|
+
const globalOffset = y * globalWidth + left;
|
|
15139
|
+
const localOffset = (y - top) * width;
|
|
15140
|
+
for (let x = 0; x < width; x++) {
|
|
15141
|
+
const colorIndex = colorIndexes[localOffset + x];
|
|
15142
|
+
const index = (globalOffset + x) * 4;
|
|
15143
|
+
if (colorIndex !== transparentIndex) {
|
|
15144
|
+
const [r, g, b2] = palette2?.[colorIndex] ?? [0, 0, 0];
|
|
15145
|
+
pixels[index] = r;
|
|
15146
|
+
pixels[index + 1] = g;
|
|
15147
|
+
pixels[index + 2] = b2;
|
|
15148
|
+
pixels[index + 3] = 255;
|
|
15149
|
+
}
|
|
15150
|
+
}
|
|
15151
|
+
}
|
|
15152
|
+
if (hasDisposal3 && disposal !== 1 && disposal !== 3) {
|
|
15153
|
+
previousPixels = pixels.slice();
|
|
15154
|
+
}
|
|
15155
|
+
previousFrame = frame;
|
|
15156
|
+
return {
|
|
15157
|
+
width: globalWidth,
|
|
15158
|
+
height: globalHeight,
|
|
15159
|
+
delay,
|
|
15160
|
+
data: pixels.slice()
|
|
15161
|
+
};
|
|
15162
|
+
});
|
|
15163
|
+
}
|
|
15164
|
+
var ditherKernels = {
|
|
15165
|
+
"floyd-steinberg": [
|
|
15166
|
+
[7 / 16, 1, 0],
|
|
15167
|
+
[3 / 16, -1, 1],
|
|
15168
|
+
[5 / 16, 0, 1],
|
|
15169
|
+
[1 / 16, 1, 1]
|
|
15170
|
+
],
|
|
15171
|
+
"atkinson": [
|
|
15172
|
+
[1 / 8, 1, 0],
|
|
15173
|
+
[1 / 8, 2, 0],
|
|
15174
|
+
[1 / 8, -1, 1],
|
|
15175
|
+
[1 / 8, 0, 1],
|
|
15176
|
+
[1 / 8, 1, 1],
|
|
15177
|
+
[1 / 8, 0, 2]
|
|
15178
|
+
],
|
|
15179
|
+
"stucki": [
|
|
15180
|
+
[8 / 42, 1, 0],
|
|
15181
|
+
[4 / 42, 2, 0],
|
|
15182
|
+
[2 / 42, -2, 1],
|
|
15183
|
+
[4 / 42, -1, 1],
|
|
15184
|
+
[8 / 42, 0, 1],
|
|
15185
|
+
[4 / 42, 1, 1],
|
|
15186
|
+
[2 / 42, 2, 1],
|
|
15187
|
+
[1 / 42, -2, 2],
|
|
15188
|
+
[2 / 42, -1, 2],
|
|
15189
|
+
[4 / 42, 0, 2],
|
|
15190
|
+
[2 / 42, 1, 2],
|
|
15191
|
+
[1 / 42, 2, 2]
|
|
15192
|
+
]
|
|
15193
|
+
};
|
|
15194
|
+
|
|
15195
|
+
// src/gif.ts
|
|
15196
|
+
var MAX_CONCURRENT_GIF_DECODES = 5;
|
|
15197
|
+
var logGifDecodeMode = (mode, context) => {
|
|
15198
|
+
console.debug("[excalidraw][gif-decode]", {
|
|
15199
|
+
mode,
|
|
15200
|
+
...context
|
|
15201
|
+
});
|
|
15202
|
+
};
|
|
15203
|
+
var gifWorkerUrl;
|
|
15204
|
+
var configureGifWorkerUrl = (workerUrl) => {
|
|
15205
|
+
gifWorkerUrl = workerUrl;
|
|
15206
|
+
};
|
|
15207
|
+
var dataURLToArrayBuffer = (dataURL) => {
|
|
15208
|
+
const dataIndexStart = dataURL.indexOf(",");
|
|
15209
|
+
const byteString = atob(dataURL.slice(dataIndexStart + 1));
|
|
15210
|
+
const buffer = new ArrayBuffer(byteString.length);
|
|
15211
|
+
const bytes = new Uint8Array(buffer);
|
|
15212
|
+
for (let index = 0; index < byteString.length; index++) {
|
|
15213
|
+
bytes[index] = byteString.charCodeAt(index);
|
|
15214
|
+
}
|
|
15215
|
+
return buffer;
|
|
15216
|
+
};
|
|
15217
|
+
var isKnownModernGifWarning = (message) => typeof message === "string" && message.startsWith("Unknown block: 0x");
|
|
15218
|
+
var suppressKnownModernGifWarnings = async (task) => {
|
|
15219
|
+
const originalWarn = console.warn;
|
|
15220
|
+
console.warn = (...args) => {
|
|
15221
|
+
if (isKnownModernGifWarning(args[0])) {
|
|
15222
|
+
return;
|
|
15223
|
+
}
|
|
15224
|
+
originalWarn(...args);
|
|
15225
|
+
};
|
|
15226
|
+
try {
|
|
15227
|
+
return await task();
|
|
15228
|
+
} finally {
|
|
15229
|
+
console.warn = originalWarn;
|
|
15230
|
+
}
|
|
15231
|
+
};
|
|
15232
|
+
var decodeGifFrames = async (dataURL) => {
|
|
15233
|
+
const buffer = dataURLToArrayBuffer(dataURL);
|
|
15234
|
+
const decodeMode = gifWorkerUrl ? "worker" : "main-thread";
|
|
15235
|
+
logGifDecodeMode(decodeMode, {
|
|
15236
|
+
byteLength: buffer.byteLength,
|
|
15237
|
+
workerUrl: gifWorkerUrl
|
|
15238
|
+
});
|
|
15239
|
+
const { gif, decodedFrames } = await suppressKnownModernGifWarnings(
|
|
15240
|
+
async () => {
|
|
15241
|
+
const gif2 = decode(buffer);
|
|
15242
|
+
return {
|
|
15243
|
+
gif: gif2,
|
|
15244
|
+
decodedFrames: gifWorkerUrl ? await decodeFrames(buffer, { gif: gif2, workerUrl: gifWorkerUrl }) : await decodeFrames(buffer, { gif: gif2 })
|
|
15245
|
+
};
|
|
15246
|
+
}
|
|
15247
|
+
);
|
|
15248
|
+
const frames2 = decodedFrames.map((frame) => {
|
|
15249
|
+
const canvas = document.createElement("canvas");
|
|
15250
|
+
canvas.width = frame.width;
|
|
15251
|
+
canvas.height = frame.height;
|
|
15252
|
+
const context = canvas.getContext("2d");
|
|
15253
|
+
if (context) {
|
|
15254
|
+
const imageData = context.createImageData(frame.width, frame.height);
|
|
15255
|
+
imageData.data.set(frame.data);
|
|
15256
|
+
context.putImageData(imageData, 0, 0);
|
|
15257
|
+
}
|
|
15258
|
+
return canvas;
|
|
15259
|
+
});
|
|
15260
|
+
return {
|
|
15261
|
+
frames: frames2,
|
|
15262
|
+
delays: decodedFrames.map((frame) => Math.max(frame.delay, 16)),
|
|
15263
|
+
width: gif.width,
|
|
15264
|
+
height: gif.height
|
|
15265
|
+
};
|
|
15266
|
+
};
|
|
15267
|
+
var activeGifDecodeCount = 0;
|
|
15268
|
+
var gifDecodeSequence = 0;
|
|
15269
|
+
var gifDecodeSchedulePending = false;
|
|
15270
|
+
var gifDecodeQueue = [];
|
|
15271
|
+
var getDataURLByteLength = (dataURL) => {
|
|
15272
|
+
const dataIndexStart = dataURL.indexOf(",");
|
|
15273
|
+
const encoded = dataURL.slice(dataIndexStart + 1);
|
|
15274
|
+
const padding = encoded.endsWith("==") && 2 || encoded.endsWith("=") && 1 || 0;
|
|
15275
|
+
return Math.floor(encoded.length * 3 / 4) - padding;
|
|
15276
|
+
};
|
|
15277
|
+
var runGifDecodeTask = (task) => {
|
|
15278
|
+
activeGifDecodeCount++;
|
|
15279
|
+
decodeGifFrames(task.dataURL).then(task.resolve, task.reject).finally(() => {
|
|
15280
|
+
activeGifDecodeCount--;
|
|
15281
|
+
queueGifDecodeScheduler();
|
|
15282
|
+
});
|
|
15283
|
+
};
|
|
15284
|
+
var scheduleNextGifDecode = () => {
|
|
15285
|
+
gifDecodeSchedulePending = false;
|
|
15286
|
+
while (activeGifDecodeCount < MAX_CONCURRENT_GIF_DECODES && gifDecodeQueue.length) {
|
|
15287
|
+
runGifDecodeTask(gifDecodeQueue.shift());
|
|
15288
|
+
}
|
|
15289
|
+
};
|
|
15290
|
+
var queueGifDecodeScheduler = () => {
|
|
15291
|
+
if (gifDecodeSchedulePending) {
|
|
15292
|
+
return;
|
|
15293
|
+
}
|
|
15294
|
+
gifDecodeSchedulePending = true;
|
|
15295
|
+
queueMicrotask(scheduleNextGifDecode);
|
|
15296
|
+
};
|
|
15297
|
+
var decodeGifFramesQueued = (dataURL) => {
|
|
15298
|
+
return new Promise((resolve, reject) => {
|
|
15299
|
+
const task = {
|
|
15300
|
+
dataURL,
|
|
15301
|
+
priority: getDataURLByteLength(dataURL),
|
|
15302
|
+
sequence: gifDecodeSequence++,
|
|
15303
|
+
resolve,
|
|
15304
|
+
reject
|
|
15305
|
+
};
|
|
15306
|
+
const insertionIndex = gifDecodeQueue.findIndex(
|
|
15307
|
+
(queuedTask) => queuedTask.priority > task.priority || queuedTask.priority === task.priority && queuedTask.sequence > task.sequence
|
|
15308
|
+
);
|
|
15309
|
+
if (insertionIndex === -1) {
|
|
15310
|
+
gifDecodeQueue.push(task);
|
|
15311
|
+
} else {
|
|
15312
|
+
gifDecodeQueue.splice(insertionIndex, 0, task);
|
|
15313
|
+
}
|
|
15314
|
+
queueGifDecodeScheduler();
|
|
15315
|
+
});
|
|
15316
|
+
};
|
|
15317
|
+
var createGifPlaybackMetadata = (opts = {}) => ({
|
|
15318
|
+
frameIndex: 0,
|
|
15319
|
+
speed: 1,
|
|
15320
|
+
playing: opts.playing ?? false
|
|
15321
|
+
});
|
|
15322
|
+
var getGifRenderFrame = (element, cacheEntry, runtimeFrameIndex) => {
|
|
15323
|
+
const gifFrameIndex = element.gifPlayback?.playing ? runtimeFrameIndex ?? element.gifPlayback.frameIndex : element.gifPlayback?.frameIndex ?? 0;
|
|
15324
|
+
return cacheEntry?.gif?.frames[gifFrameIndex];
|
|
15325
|
+
};
|
|
15326
|
+
var hasActiveGifDecode = (visibleElements, imageCache) => visibleElements.some((element) => {
|
|
15327
|
+
if (!isInitializedImageElement(element)) {
|
|
15328
|
+
return false;
|
|
15329
|
+
}
|
|
15330
|
+
const cacheEntry = imageCache.get(element.fileId);
|
|
15331
|
+
return cacheEntry?.gifDecodeStatus === "pending" && !cacheEntry.gif?.frames.length;
|
|
15332
|
+
});
|
|
15333
|
+
var hasPlayableGif = (visibleElements, imageCache) => visibleElements.some(
|
|
15334
|
+
(element) => isInitializedImageElement(element) && element.gifPlayback?.playing && imageCache.get(element.fileId)?.gif?.frames.length
|
|
15335
|
+
);
|
|
15336
|
+
|
|
14692
15337
|
// src/image.ts
|
|
14693
15338
|
var THUMB_HASH_MAX_DIMENSION = 100;
|
|
14694
15339
|
var thumbHashCanvasCache = /* @__PURE__ */ new Map();
|
|
@@ -14774,7 +15419,10 @@ var loadHTMLImageElement = (dataURL) => {
|
|
|
14774
15419
|
var updateImageCache = async ({
|
|
14775
15420
|
fileIds,
|
|
14776
15421
|
files,
|
|
14777
|
-
imageCache
|
|
15422
|
+
imageCache,
|
|
15423
|
+
onImageCacheUpdate,
|
|
15424
|
+
gifAutoDecodeMaxFileSizeBytes = DEFAULT_GIF_AUTO_DECODE_MAX_FILE_SIZE_BYTES,
|
|
15425
|
+
forceGifDecode = false
|
|
14778
15426
|
}) => {
|
|
14779
15427
|
const updatedFiles = /* @__PURE__ */ new Map();
|
|
14780
15428
|
const erroredFiles = /* @__PURE__ */ new Map();
|
|
@@ -14793,20 +15441,72 @@ var updateImageCache = async ({
|
|
|
14793
15441
|
const imagePromise = loadHTMLImageElement(fileData.dataURL);
|
|
14794
15442
|
const data = {
|
|
14795
15443
|
image: imagePromise,
|
|
14796
|
-
mimeType: fileData.mimeType
|
|
15444
|
+
mimeType: fileData.mimeType,
|
|
15445
|
+
gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? "pending" : void 0
|
|
14797
15446
|
};
|
|
14798
15447
|
imageCache.set(fileId, data);
|
|
14799
|
-
|
|
15448
|
+
if (data.gifDecodeStatus === "pending") {
|
|
15449
|
+
onImageCacheUpdate?.(fileId);
|
|
15450
|
+
}
|
|
15451
|
+
let image = imagePromise;
|
|
15452
|
+
let gif;
|
|
15453
|
+
let gifDecodeStatus;
|
|
15454
|
+
try {
|
|
15455
|
+
image = await imagePromise;
|
|
15456
|
+
if (fileData.mimeType === MIME_TYPES.gif) {
|
|
15457
|
+
const decodingData = {
|
|
15458
|
+
...data,
|
|
15459
|
+
image,
|
|
15460
|
+
gifDecodeStatus: "pending"
|
|
15461
|
+
};
|
|
15462
|
+
imageCache.set(fileId, decodingData);
|
|
15463
|
+
onImageCacheUpdate?.(fileId);
|
|
15464
|
+
}
|
|
15465
|
+
if (fileData.mimeType === MIME_TYPES.gif && !forceGifDecode && getDataURLByteLength(fileData.dataURL) > gifAutoDecodeMaxFileSizeBytes) {
|
|
15466
|
+
gifDecodeStatus = "deferred";
|
|
15467
|
+
} else {
|
|
15468
|
+
gif = fileData.mimeType === MIME_TYPES.gif ? await decodeGifFramesQueued(fileData.dataURL) : void 0;
|
|
15469
|
+
if (fileData.mimeType === MIME_TYPES.gif) {
|
|
15470
|
+
gifDecodeStatus = "success";
|
|
15471
|
+
}
|
|
15472
|
+
}
|
|
15473
|
+
} catch (error) {
|
|
15474
|
+
erroredFiles.set(fileId, true);
|
|
15475
|
+
if (fileData.mimeType === MIME_TYPES.gif) {
|
|
15476
|
+
gifDecodeStatus = "error";
|
|
15477
|
+
}
|
|
15478
|
+
} finally {
|
|
15479
|
+
if (fileData.mimeType === MIME_TYPES.gif) {
|
|
15480
|
+
imageCache.set(fileId, {
|
|
15481
|
+
...data,
|
|
15482
|
+
image,
|
|
15483
|
+
gif,
|
|
15484
|
+
gifDecodeStatus: gifDecodeStatus ?? "error"
|
|
15485
|
+
});
|
|
15486
|
+
onImageCacheUpdate?.(fileId);
|
|
15487
|
+
}
|
|
15488
|
+
}
|
|
15489
|
+
if (erroredFiles.has(fileId)) {
|
|
15490
|
+
return;
|
|
15491
|
+
}
|
|
14800
15492
|
if (previousCacheEntry?.isPlaceholder) {
|
|
14801
15493
|
imageCache.set(fileId, {
|
|
14802
15494
|
...data,
|
|
14803
15495
|
image,
|
|
15496
|
+
gif,
|
|
15497
|
+
gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? gifDecodeStatus : void 0,
|
|
14804
15498
|
placeholderImage: await previousCacheEntry.image,
|
|
14805
15499
|
transitionStart: performance.now()
|
|
14806
15500
|
});
|
|
14807
15501
|
} else {
|
|
14808
|
-
imageCache.set(fileId, {
|
|
15502
|
+
imageCache.set(fileId, {
|
|
15503
|
+
...data,
|
|
15504
|
+
image,
|
|
15505
|
+
gif,
|
|
15506
|
+
gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? gifDecodeStatus : void 0
|
|
15507
|
+
});
|
|
14809
15508
|
}
|
|
15509
|
+
onImageCacheUpdate?.(fileId);
|
|
14810
15510
|
} catch (error) {
|
|
14811
15511
|
erroredFiles.set(fileId, true);
|
|
14812
15512
|
}
|
|
@@ -14870,6 +15570,52 @@ var normalizeSVG = (SVGString) => {
|
|
|
14870
15570
|
}
|
|
14871
15571
|
};
|
|
14872
15572
|
|
|
15573
|
+
// src/renderGif.ts
|
|
15574
|
+
init_define_import_meta_env();
|
|
15575
|
+
var drawGifDecodePlaceholder = (element, context, theme, drawImagePlaceholder2) => {
|
|
15576
|
+
drawImagePlaceholder2(element, context, theme);
|
|
15577
|
+
const pulse = 0.55 + Math.sin(performance.now() / 350) * 0.25;
|
|
15578
|
+
const text = "GIF Decoding";
|
|
15579
|
+
const fontFamily = "Assistant, system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif";
|
|
15580
|
+
const textX = element.width / 2;
|
|
15581
|
+
const textY = element.height / 2;
|
|
15582
|
+
context.save();
|
|
15583
|
+
context.globalAlpha *= pulse;
|
|
15584
|
+
context.textAlign = "center";
|
|
15585
|
+
context.textBaseline = "middle";
|
|
15586
|
+
context.font = `600 100px ${fontFamily}`;
|
|
15587
|
+
const targetTextWidth = element.width * 0.6;
|
|
15588
|
+
const measuredWidth = context.measureText(text).width;
|
|
15589
|
+
const widthFitFontSize = measuredWidth ? 100 * targetTextWidth / measuredWidth : 24;
|
|
15590
|
+
const fontSize = Math.max(
|
|
15591
|
+
12,
|
|
15592
|
+
Math.min(widthFitFontSize, element.height * 0.35)
|
|
15593
|
+
);
|
|
15594
|
+
context.font = `600 ${fontSize}px ${fontFamily}`;
|
|
15595
|
+
const finalFontSize = Number.parseFloat(
|
|
15596
|
+
context.font.match(/\d+(\.\d+)?px/)?.[0] ?? `${fontSize}`
|
|
15597
|
+
);
|
|
15598
|
+
const finalMeasuredWidth = context.measureText(text).width;
|
|
15599
|
+
const paddingX = Math.max(12, finalFontSize * 0.55);
|
|
15600
|
+
const paddingY = Math.max(8, finalFontSize * 0.35);
|
|
15601
|
+
const pillWidth = finalMeasuredWidth + paddingX * 2;
|
|
15602
|
+
const pillHeight = finalFontSize + paddingY * 2;
|
|
15603
|
+
const pillX = textX - pillWidth / 2;
|
|
15604
|
+
const pillY = textY - pillHeight / 2;
|
|
15605
|
+
const radius = Math.min(pillHeight / 2, finalFontSize * 0.25);
|
|
15606
|
+
context.fillStyle = "rgba(0, 0, 0, 0.62)";
|
|
15607
|
+
context.beginPath();
|
|
15608
|
+
if (context.roundRect) {
|
|
15609
|
+
context.roundRect(pillX, pillY, pillWidth, pillHeight, radius);
|
|
15610
|
+
} else {
|
|
15611
|
+
context.rect(pillX, pillY, pillWidth, pillHeight);
|
|
15612
|
+
}
|
|
15613
|
+
context.fill();
|
|
15614
|
+
context.fillStyle = "#fff";
|
|
15615
|
+
context.fillText(text, textX, textY);
|
|
15616
|
+
context.restore();
|
|
15617
|
+
};
|
|
15618
|
+
|
|
14873
15619
|
// src/renderElement.ts
|
|
14874
15620
|
var isPendingImageElement = (element, renderConfig) => isInitializedImageElement(element) && !renderConfig.imageCache.has(element.fileId);
|
|
14875
15621
|
var getCanvasPadding = (element) => {
|
|
@@ -15039,7 +15785,14 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
|
|
|
15039
15785
|
context.save();
|
|
15040
15786
|
const cacheEntry = element.fileId !== null ? renderConfig.imageCache.get(element.fileId) : null;
|
|
15041
15787
|
const img = isInitializedImageElement(element) ? cacheEntry?.image : void 0;
|
|
15042
|
-
if (
|
|
15788
|
+
if (cacheEntry?.gifDecodeStatus === "pending" && !cacheEntry.gif?.frames.length) {
|
|
15789
|
+
drawGifDecodePlaceholder(
|
|
15790
|
+
element,
|
|
15791
|
+
context,
|
|
15792
|
+
renderConfig.theme,
|
|
15793
|
+
drawImagePlaceholder
|
|
15794
|
+
);
|
|
15795
|
+
} else if (img != null && !(img instanceof Promise)) {
|
|
15043
15796
|
if (element.roundness && context.roundRect) {
|
|
15044
15797
|
context.beginPath();
|
|
15045
15798
|
context.roundRect(
|
|
@@ -15080,11 +15833,17 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
|
|
|
15080
15833
|
delete cacheEntry.transitionStart;
|
|
15081
15834
|
}
|
|
15082
15835
|
}
|
|
15836
|
+
const gifFrame = getGifRenderFrame(
|
|
15837
|
+
element,
|
|
15838
|
+
cacheEntry,
|
|
15839
|
+
renderConfig.getGifFrameIndex?.(element)
|
|
15840
|
+
);
|
|
15841
|
+
const imageForRender = gifFrame ?? img;
|
|
15083
15842
|
const { x, y, width, height } = element.crop ? element.crop : {
|
|
15084
15843
|
x: 0,
|
|
15085
15844
|
y: 0,
|
|
15086
|
-
width:
|
|
15087
|
-
height:
|
|
15845
|
+
width: imageForRender instanceof HTMLCanvasElement ? imageForRender.width : imageForRender.naturalWidth,
|
|
15846
|
+
height: imageForRender instanceof HTMLCanvasElement ? imageForRender.height : imageForRender.naturalHeight
|
|
15088
15847
|
};
|
|
15089
15848
|
const shouldInvertImage = renderConfig.theme === THEME.DARK && cacheEntry?.mimeType === MIME_TYPES2.svg;
|
|
15090
15849
|
if (shouldInvertImage && isSafari) {
|
|
@@ -15096,7 +15855,7 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
|
|
|
15096
15855
|
if (tempContext) {
|
|
15097
15856
|
tempContext.scale(devicePixelRatio, devicePixelRatio);
|
|
15098
15857
|
tempContext.drawImage(
|
|
15099
|
-
|
|
15858
|
+
imageForRender,
|
|
15100
15859
|
x,
|
|
15101
15860
|
y,
|
|
15102
15861
|
width,
|
|
@@ -15136,7 +15895,7 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
|
|
|
15136
15895
|
context.filter = DARK_THEME_FILTER;
|
|
15137
15896
|
}
|
|
15138
15897
|
context.drawImage(
|
|
15139
|
-
|
|
15898
|
+
imageForRender,
|
|
15140
15899
|
x,
|
|
15141
15900
|
y,
|
|
15142
15901
|
width,
|
|
@@ -18496,7 +19255,8 @@ var newImageElement = (opts) => {
|
|
|
18496
19255
|
fileName: opts.fileName ?? null,
|
|
18497
19256
|
thumbHash: opts.thumbHash ?? null,
|
|
18498
19257
|
scale: opts.scale ?? [1, 1],
|
|
18499
|
-
crop: opts.crop ?? null
|
|
19258
|
+
crop: opts.crop ?? null,
|
|
19259
|
+
gifPlayback: opts.gifPlayback ?? null
|
|
18500
19260
|
};
|
|
18501
19261
|
};
|
|
18502
19262
|
|
|
@@ -22336,10 +23096,10 @@ var dragSelectedElements = (pointerDownState, _selectedElements, offset, scene,
|
|
|
22336
23096
|
const elementsToUpdate = new Set(
|
|
22337
23097
|
selectedElements
|
|
22338
23098
|
);
|
|
22339
|
-
const
|
|
22340
|
-
if (
|
|
23099
|
+
const frames2 = selectedElements.filter((e) => isFrameLikeElement(e)).map((f) => f.id);
|
|
23100
|
+
if (frames2.length > 0) {
|
|
22341
23101
|
for (const element of scene.getNonDeletedElements()) {
|
|
22342
|
-
if (element.frameId !== null &&
|
|
23102
|
+
if (element.frameId !== null && frames2.includes(element.frameId)) {
|
|
22343
23103
|
elementsToUpdate.add(element);
|
|
22344
23104
|
}
|
|
22345
23105
|
}
|
|
@@ -25521,6 +26281,10 @@ var PlusIcon = createIcon(
|
|
|
25521
26281
|
] }),
|
|
25522
26282
|
tablerIconProps
|
|
25523
26283
|
);
|
|
26284
|
+
var CirclePauseIcon = createIcon(
|
|
26285
|
+
"M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM288 248C288 234.7 277.3 224 264 224C250.7 224 240 234.7 240 248L240 392C240 405.3 250.7 416 264 416C277.3 416 288 405.3 288 392L288 248zM400 248C400 234.7 389.3 224 376 224C362.7 224 352 234.7 352 248L352 392C352 405.3 362.7 416 376 416C389.3 416 400 405.3 400 392L400 248z",
|
|
26286
|
+
640
|
|
26287
|
+
);
|
|
25524
26288
|
var DotsIcon = createIcon(
|
|
25525
26289
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { strokeWidth: "1.5", children: [
|
|
25526
26290
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
|
|
@@ -27364,6 +28128,33 @@ var playerStopFilledIcon = createIcon(
|
|
|
27364
28128
|
] }),
|
|
27365
28129
|
tablerIconProps
|
|
27366
28130
|
);
|
|
28131
|
+
var prevFrame = createIcon(
|
|
28132
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
28133
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 5v14" }),
|
|
28134
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 6l-9 6l9 6z" })
|
|
28135
|
+
] }),
|
|
28136
|
+
tablerIconProps
|
|
28137
|
+
);
|
|
28138
|
+
var nextFrame = createIcon(
|
|
28139
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
28140
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 5v14" }),
|
|
28141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 6l9 6l-9 6z" })
|
|
28142
|
+
] }),
|
|
28143
|
+
tablerIconProps
|
|
28144
|
+
);
|
|
28145
|
+
var frames = createIcon(
|
|
28146
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { strokeWidth: 1.25, children: [
|
|
28147
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
|
|
28148
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6h16a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10a1 1 0 0 1 1 -1z" }),
|
|
28149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 6v12" }),
|
|
28150
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 6v12" }),
|
|
28151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 10h4" }),
|
|
28152
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 14h4" }),
|
|
28153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 10h4" }),
|
|
28154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 14h4" })
|
|
28155
|
+
] }),
|
|
28156
|
+
tablerIconProps
|
|
28157
|
+
);
|
|
27367
28158
|
var tablerCheckIcon = createIcon(
|
|
27368
28159
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
27369
28160
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
|
|
@@ -28947,7 +29738,7 @@ var recognizeShape = (points, previousElement, zoom = 1) => {
|
|
|
28947
29738
|
const type = previousElement?.type === "arrow" && recognized !== "arrow" ? "freedraw" : recognized;
|
|
28948
29739
|
return { type, points, boundingBox };
|
|
28949
29740
|
};
|
|
28950
|
-
var convertToShape = (points, appState, elementsMap, previousElement,
|
|
29741
|
+
var convertToShape = (points, appState, elementsMap, previousElement, frames2) => {
|
|
28951
29742
|
const recognizedShape = recognizeShape(
|
|
28952
29743
|
points,
|
|
28953
29744
|
previousElement,
|
|
@@ -28955,7 +29746,7 @@ var convertToShape = (points, appState, elementsMap, previousElement, frames) =>
|
|
|
28955
29746
|
);
|
|
28956
29747
|
const boundingBox = recognizedShape.boundingBox;
|
|
28957
29748
|
const [minX, minY, maxX, maxY] = boundingBox;
|
|
28958
|
-
const frameLikeElements =
|
|
29749
|
+
const frameLikeElements = frames2 ?? getFrameLikeElements([...elementsMap.values()]);
|
|
28959
29750
|
const frameId = frameLikeElements.find((frame) => {
|
|
28960
29751
|
const [fx1, fy1, fx2, fy2] = getElementAbsoluteCoords3(frame, elementsMap);
|
|
28961
29752
|
return fx1 <= minX && fy1 <= minY && fx2 >= maxX && fy2 >= maxY;
|
|
@@ -29252,13 +30043,17 @@ export {
|
|
|
29252
30043
|
computeBoundTextPosition,
|
|
29253
30044
|
computeBucketFillPolygon,
|
|
29254
30045
|
computeContainerDimensionForBoundText,
|
|
30046
|
+
configureGifWorkerUrl,
|
|
29255
30047
|
containsCJK,
|
|
29256
30048
|
convertToExcalidrawElements,
|
|
29257
30049
|
convertToShape,
|
|
29258
30050
|
convertToShapeHandlePointerMoveFromPointerDown,
|
|
30051
|
+
createGifPlaybackMetadata,
|
|
29259
30052
|
createPlaceholderEmbeddableLabel,
|
|
29260
30053
|
createSrcDoc,
|
|
29261
30054
|
cropElement,
|
|
30055
|
+
decodeGifFrames,
|
|
30056
|
+
decodeGifFramesQueued,
|
|
29262
30057
|
deconstructDiamondElement,
|
|
29263
30058
|
deconstructLinearOrFreeDrawElement,
|
|
29264
30059
|
deconstructRectanguloidElement,
|
|
@@ -29271,6 +30066,7 @@ export {
|
|
|
29271
30066
|
dragNewElement,
|
|
29272
30067
|
dragNewTextElement,
|
|
29273
30068
|
dragSelectedElements,
|
|
30069
|
+
drawGifDecodePlaceholder,
|
|
29274
30070
|
duplicateElement,
|
|
29275
30071
|
duplicateElements,
|
|
29276
30072
|
editGroupForSelectedElement,
|
|
@@ -29321,6 +30117,7 @@ export {
|
|
|
29321
30117
|
getCornerRadius,
|
|
29322
30118
|
getCubicBezierCurveBound,
|
|
29323
30119
|
getCursorForResizingElement,
|
|
30120
|
+
getDataURLByteLength,
|
|
29324
30121
|
getDefaultFrameName,
|
|
29325
30122
|
getDefaultRoundnessTypeForElement,
|
|
29326
30123
|
getDiamondBaseCorners,
|
|
@@ -29350,6 +30147,7 @@ export {
|
|
|
29350
30147
|
getFreedrawOutlineAsSegments,
|
|
29351
30148
|
getFreedrawOutlinePoints,
|
|
29352
30149
|
getFreedrawStrokeCenterPoints,
|
|
30150
|
+
getGifRenderFrame,
|
|
29353
30151
|
getGlobalFixedPointForBindableElement,
|
|
29354
30152
|
getGlobalFixedPoints,
|
|
29355
30153
|
getHeadingForElbowArrowSnap,
|
|
@@ -29416,10 +30214,12 @@ export {
|
|
|
29416
30214
|
handleFocusPointHover,
|
|
29417
30215
|
handleFocusPointPointerDown,
|
|
29418
30216
|
handleFocusPointPointerUp,
|
|
30217
|
+
hasActiveGifDecode,
|
|
29419
30218
|
hasBackground,
|
|
29420
30219
|
hasBoundTextElement,
|
|
29421
30220
|
hasBoundingBox,
|
|
29422
30221
|
hasFreedrawMode,
|
|
30222
|
+
hasPlayableGif,
|
|
29423
30223
|
hasStrokeColor,
|
|
29424
30224
|
hasStrokeStyle,
|
|
29425
30225
|
hasStrokeWidth,
|