@loaders.gl/video 4.0.0-beta.2 → 4.0.0-beta.4
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/dist.dev.js +2113 -0
- package/dist/{esm/gif-builder.js → gif-builder.js} +2 -2
- package/dist/gif-builder.js.map +1 -0
- package/dist/index.cjs +2180 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/gifshot/gifshot-loader.js.map +1 -0
- package/dist/{esm/lib → lib}/gifshot/gifshot.js +11 -11
- package/dist/lib/gifshot/gifshot.js.map +1 -0
- package/dist/lib/parsers/parse-video.js.map +1 -0
- package/dist/lib/utils/assert.js.map +1 -0
- package/dist/{esm/video-loader.js → video-loader.js} +2 -2
- package/dist/video-loader.js.map +1 -0
- package/package.json +16 -8
- package/dist/bundle.d.ts +0 -2
- package/dist/bundle.d.ts.map +0 -1
- package/dist/dist.min.js +0 -2147
- package/dist/es5/bundle.js +0 -6
- package/dist/es5/bundle.js.map +0 -1
- package/dist/es5/gif-builder.js +0 -200
- package/dist/es5/gif-builder.js.map +0 -1
- package/dist/es5/index.js +0 -21
- package/dist/es5/index.js.map +0 -1
- package/dist/es5/lib/gifshot/gifshot-loader.js +0 -67
- package/dist/es5/lib/gifshot/gifshot-loader.js.map +0 -1
- package/dist/es5/lib/gifshot/gifshot.js +0 -1924
- package/dist/es5/lib/gifshot/gifshot.js.map +0 -1
- package/dist/es5/lib/parsers/parse-video.js +0 -31
- package/dist/es5/lib/parsers/parse-video.js.map +0 -1
- package/dist/es5/lib/utils/assert.js +0 -12
- package/dist/es5/lib/utils/assert.js.map +0 -1
- package/dist/es5/video-loader.js +0 -26
- package/dist/es5/video-loader.js.map +0 -1
- package/dist/esm/bundle.js +0 -4
- package/dist/esm/bundle.js.map +0 -1
- package/dist/esm/gif-builder.js.map +0 -1
- package/dist/esm/index.js +0 -3
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/lib/gifshot/gifshot-loader.js.map +0 -1
- package/dist/esm/lib/gifshot/gifshot.js.map +0 -1
- package/dist/esm/lib/parsers/parse-video.js.map +0 -1
- package/dist/esm/lib/utils/assert.js.map +0 -1
- package/dist/esm/video-loader.js.map +0 -1
- package/src/bundle.ts +0 -4
- /package/dist/{esm/lib → lib}/gifshot/gifshot-loader.js +0 -0
- /package/dist/{esm/lib → lib}/parsers/parse-video.js +0 -0
- /package/dist/{esm/lib → lib}/utils/assert.js +0 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
GIFBuilder: () => GIFBuilder,
|
|
24
|
+
VideoLoader: () => VideoLoader
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(src_exports);
|
|
27
|
+
|
|
28
|
+
// src/lib/parsers/parse-video.ts
|
|
29
|
+
async function parseVideo(arrayBuffer) {
|
|
30
|
+
const blob2 = new Blob([arrayBuffer]);
|
|
31
|
+
const video = document.createElement("video");
|
|
32
|
+
video.src = URL.createObjectURL(blob2);
|
|
33
|
+
return video;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/video-loader.ts
|
|
37
|
+
var VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
|
|
38
|
+
var EXTENSIONS = ["mp4"];
|
|
39
|
+
var MIME_TYPES = ["video/mp4"];
|
|
40
|
+
var DEFAULT_LOADER_OPTIONS = {
|
|
41
|
+
video: {}
|
|
42
|
+
};
|
|
43
|
+
var VideoLoader = {
|
|
44
|
+
name: "Video",
|
|
45
|
+
id: "video",
|
|
46
|
+
module: "video",
|
|
47
|
+
version: VERSION,
|
|
48
|
+
extensions: EXTENSIONS,
|
|
49
|
+
mimeTypes: MIME_TYPES,
|
|
50
|
+
parse: parseVideo,
|
|
51
|
+
// tests: arrayBuffer => Boolean(getBinaryImageMetadata(new DataView(arrayBuffer))),
|
|
52
|
+
options: DEFAULT_LOADER_OPTIONS
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/lib/utils/assert.ts
|
|
56
|
+
function assert(condition, message) {
|
|
57
|
+
if (!condition) {
|
|
58
|
+
throw new Error(message);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/lib/gifshot/gifshot.ts
|
|
63
|
+
var utils = {
|
|
64
|
+
URL: globalThis.URL || globalThis.webkitURL || globalThis.mozURL || globalThis.msURL,
|
|
65
|
+
getUserMedia: function() {
|
|
66
|
+
if (!globalThis.navigator)
|
|
67
|
+
return globalThis.navigator;
|
|
68
|
+
const getUserMedia = globalThis.navigator.getUserMedia || globalThis.navigator.webkitGetUserMedia || globalThis.navigator.mozGetUserMedia || globalThis.navigator.msGetUserMedia;
|
|
69
|
+
return getUserMedia ? getUserMedia.bind(globalThis.navigator) : getUserMedia;
|
|
70
|
+
}(),
|
|
71
|
+
requestAnimFrame: globalThis.requestAnimationFrame || globalThis.webkitRequestAnimationFrame || globalThis.mozRequestAnimationFrame || globalThis.oRequestAnimationFrame || globalThis.msRequestAnimationFrame,
|
|
72
|
+
requestTimeout: function requestTimeout(callback, delay) {
|
|
73
|
+
callback = callback || utils.noop;
|
|
74
|
+
delay = delay || 0;
|
|
75
|
+
if (!utils.requestAnimFrame) {
|
|
76
|
+
return setTimeout(callback, delay);
|
|
77
|
+
}
|
|
78
|
+
const start = new Date().getTime();
|
|
79
|
+
const handle = new Object();
|
|
80
|
+
const requestAnimFrame = utils.requestAnimFrame;
|
|
81
|
+
const loop = function loop2() {
|
|
82
|
+
const current = new Date().getTime();
|
|
83
|
+
const delta = current - start;
|
|
84
|
+
delta >= delay ? callback.call() : handle.value = requestAnimFrame(loop2);
|
|
85
|
+
};
|
|
86
|
+
handle.value = requestAnimFrame(loop);
|
|
87
|
+
return handle;
|
|
88
|
+
},
|
|
89
|
+
Blob: globalThis.Blob || globalThis.BlobBuilder || globalThis.WebKitBlobBuilder || globalThis.MozBlobBuilder || globalThis.MSBlobBuilder,
|
|
90
|
+
btoa: function() {
|
|
91
|
+
const btoa = globalThis.btoa || function(input) {
|
|
92
|
+
let output = "";
|
|
93
|
+
let i = 0;
|
|
94
|
+
const l = input.length;
|
|
95
|
+
const key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
96
|
+
let chr1 = void 0;
|
|
97
|
+
let chr2 = void 0;
|
|
98
|
+
let chr3 = void 0;
|
|
99
|
+
let enc1 = void 0;
|
|
100
|
+
let enc2 = void 0;
|
|
101
|
+
let enc3 = void 0;
|
|
102
|
+
let enc4 = void 0;
|
|
103
|
+
while (i < l) {
|
|
104
|
+
chr1 = input.charCodeAt(i++);
|
|
105
|
+
chr2 = input.charCodeAt(i++);
|
|
106
|
+
chr3 = input.charCodeAt(i++);
|
|
107
|
+
enc1 = chr1 >> 2;
|
|
108
|
+
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
|
|
109
|
+
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
|
|
110
|
+
enc4 = chr3 & 63;
|
|
111
|
+
if (isNaN(chr2)) {
|
|
112
|
+
enc3 = enc4 = 64;
|
|
113
|
+
} else if (isNaN(chr3)) {
|
|
114
|
+
enc4 = 64;
|
|
115
|
+
}
|
|
116
|
+
output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4);
|
|
117
|
+
}
|
|
118
|
+
return output;
|
|
119
|
+
};
|
|
120
|
+
return btoa ? btoa.bind(globalThis) : utils.noop;
|
|
121
|
+
}(),
|
|
122
|
+
isObject: function isObject(obj) {
|
|
123
|
+
return obj && Object.prototype.toString.call(obj) === "[object Object]";
|
|
124
|
+
},
|
|
125
|
+
isEmptyObject: function isEmptyObject(obj) {
|
|
126
|
+
return utils.isObject(obj) && !Object.keys(obj).length;
|
|
127
|
+
},
|
|
128
|
+
isArray: function isArray(arr) {
|
|
129
|
+
return arr && Array.isArray(arr);
|
|
130
|
+
},
|
|
131
|
+
isFunction: function isFunction(func) {
|
|
132
|
+
return func && typeof func === "function";
|
|
133
|
+
},
|
|
134
|
+
isElement: function isElement(elem) {
|
|
135
|
+
return elem && elem.nodeType === 1;
|
|
136
|
+
},
|
|
137
|
+
isString: function isString(value) {
|
|
138
|
+
return typeof value === "string" || Object.prototype.toString.call(value) === "[object String]";
|
|
139
|
+
},
|
|
140
|
+
isSupported: {
|
|
141
|
+
canvas: function canvas() {
|
|
142
|
+
const el = document.createElement("canvas");
|
|
143
|
+
return el && el.getContext && el.getContext("2d");
|
|
144
|
+
},
|
|
145
|
+
webworkers: function webworkers() {
|
|
146
|
+
return globalThis.Worker;
|
|
147
|
+
},
|
|
148
|
+
blob: function blob() {
|
|
149
|
+
return utils.Blob;
|
|
150
|
+
},
|
|
151
|
+
Uint8Array: function Uint8Array2() {
|
|
152
|
+
return globalThis.Uint8Array;
|
|
153
|
+
},
|
|
154
|
+
Uint32Array: function Uint32Array2() {
|
|
155
|
+
return globalThis.Uint32Array;
|
|
156
|
+
},
|
|
157
|
+
videoCodecs: function() {
|
|
158
|
+
const testEl = document.createElement("video");
|
|
159
|
+
const supportObj = {
|
|
160
|
+
mp4: false,
|
|
161
|
+
h264: false,
|
|
162
|
+
ogv: false,
|
|
163
|
+
ogg: false,
|
|
164
|
+
webm: false
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
if (testEl && testEl.canPlayType) {
|
|
168
|
+
supportObj.mp4 = testEl.canPlayType('video/mp4; codecs="mp4v.20.8"') !== "";
|
|
169
|
+
supportObj.h264 = (testEl.canPlayType('video/mp4; codecs="avc1.42E01E"') || testEl.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')) !== "";
|
|
170
|
+
supportObj.ogv = testEl.canPlayType('video/ogg; codecs="theora"') !== "";
|
|
171
|
+
supportObj.ogg = testEl.canPlayType('video/ogg; codecs="theora"') !== "";
|
|
172
|
+
supportObj.webm = testEl.canPlayType('video/webm; codecs="vp8, vorbis"') !== -1;
|
|
173
|
+
}
|
|
174
|
+
} catch (e) {
|
|
175
|
+
}
|
|
176
|
+
return supportObj;
|
|
177
|
+
}()
|
|
178
|
+
},
|
|
179
|
+
noop: function noop() {
|
|
180
|
+
},
|
|
181
|
+
each: function each(collection, callback) {
|
|
182
|
+
let x = void 0;
|
|
183
|
+
let len = void 0;
|
|
184
|
+
if (utils.isArray(collection)) {
|
|
185
|
+
x = -1;
|
|
186
|
+
len = collection.length;
|
|
187
|
+
while (++x < len) {
|
|
188
|
+
if (callback(x, collection[x]) === false) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} else if (utils.isObject(collection)) {
|
|
193
|
+
for (x in collection) {
|
|
194
|
+
if (collection.hasOwnProperty(x)) {
|
|
195
|
+
if (callback(x, collection[x]) === false) {
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
normalizeOptions: function normalizeOptions(defaultOptions2, userOptions) {
|
|
203
|
+
if (!utils.isObject(defaultOptions2) || !utils.isObject(userOptions) || !Object.keys) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const newObj = {};
|
|
207
|
+
utils.each(defaultOptions2, function(key, val) {
|
|
208
|
+
newObj[key] = defaultOptions2[key];
|
|
209
|
+
});
|
|
210
|
+
utils.each(userOptions, function(key, val) {
|
|
211
|
+
const currentUserOption = userOptions[key];
|
|
212
|
+
if (!utils.isObject(currentUserOption)) {
|
|
213
|
+
newObj[key] = currentUserOption;
|
|
214
|
+
} else if (!defaultOptions2[key]) {
|
|
215
|
+
newObj[key] = currentUserOption;
|
|
216
|
+
} else {
|
|
217
|
+
newObj[key] = utils.normalizeOptions(defaultOptions2[key], currentUserOption);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return newObj;
|
|
221
|
+
},
|
|
222
|
+
setCSSAttr: function setCSSAttr(elem, attr, val) {
|
|
223
|
+
if (!utils.isElement(elem)) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (utils.isString(attr) && utils.isString(val)) {
|
|
227
|
+
elem.style[attr] = val;
|
|
228
|
+
} else if (utils.isObject(attr)) {
|
|
229
|
+
utils.each(attr, function(key, val2) {
|
|
230
|
+
elem.style[key] = val2;
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
removeElement: function removeElement(node) {
|
|
235
|
+
if (!utils.isElement(node)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (node.parentNode) {
|
|
239
|
+
node.parentNode.removeChild(node);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
createWebWorker: function createWebWorker(content) {
|
|
243
|
+
if (!utils.isString(content)) {
|
|
244
|
+
return {};
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const blob2 = new utils.Blob([content], {
|
|
248
|
+
type: "text/javascript"
|
|
249
|
+
});
|
|
250
|
+
const objectUrl = utils.URL.createObjectURL(blob2);
|
|
251
|
+
const worker = new Worker(objectUrl);
|
|
252
|
+
return {
|
|
253
|
+
objectUrl,
|
|
254
|
+
worker
|
|
255
|
+
};
|
|
256
|
+
} catch (e) {
|
|
257
|
+
return `${e}`;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
getExtension: function getExtension(src) {
|
|
261
|
+
return src.substr(src.lastIndexOf(".") + 1, src.length);
|
|
262
|
+
},
|
|
263
|
+
getFontSize: function getFontSize() {
|
|
264
|
+
const options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
265
|
+
if (!document.body || options.resizeFont === false) {
|
|
266
|
+
return options.fontSize;
|
|
267
|
+
}
|
|
268
|
+
const text = options.text;
|
|
269
|
+
const containerWidth = options.gifWidth;
|
|
270
|
+
let fontSize = parseInt(options.fontSize, 10);
|
|
271
|
+
const minFontSize = parseInt(options.minFontSize, 10);
|
|
272
|
+
const div = document.createElement("div");
|
|
273
|
+
const span = document.createElement("span");
|
|
274
|
+
div.setAttribute("width", containerWidth);
|
|
275
|
+
div.appendChild(span);
|
|
276
|
+
span.innerHTML = text;
|
|
277
|
+
span.style.fontSize = `${fontSize}px`;
|
|
278
|
+
span.style.textIndent = "-9999px";
|
|
279
|
+
span.style.visibility = "hidden";
|
|
280
|
+
document.body.appendChild(span);
|
|
281
|
+
while (span.offsetWidth > containerWidth && fontSize >= minFontSize) {
|
|
282
|
+
span.style.fontSize = `${--fontSize}px`;
|
|
283
|
+
}
|
|
284
|
+
document.body.removeChild(span);
|
|
285
|
+
return `${fontSize}px`;
|
|
286
|
+
},
|
|
287
|
+
webWorkerError: false
|
|
288
|
+
};
|
|
289
|
+
var utils$2 = Object.freeze({
|
|
290
|
+
default: utils
|
|
291
|
+
});
|
|
292
|
+
var error = {
|
|
293
|
+
validate: function validate(skipObj) {
|
|
294
|
+
skipObj = utils.isObject(skipObj) ? skipObj : {};
|
|
295
|
+
let errorObj = {};
|
|
296
|
+
utils.each(error.validators, function(indece, currentValidator) {
|
|
297
|
+
const errorCode = currentValidator.errorCode;
|
|
298
|
+
if (!skipObj[errorCode] && !currentValidator.condition) {
|
|
299
|
+
errorObj = currentValidator;
|
|
300
|
+
errorObj.error = true;
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
delete errorObj.condition;
|
|
305
|
+
return errorObj;
|
|
306
|
+
},
|
|
307
|
+
isValid: function isValid(skipObj) {
|
|
308
|
+
const errorObj = error.validate(skipObj);
|
|
309
|
+
const isValid2 = errorObj.error !== true;
|
|
310
|
+
return isValid2;
|
|
311
|
+
},
|
|
312
|
+
validators: [
|
|
313
|
+
{
|
|
314
|
+
condition: utils.isFunction(utils.getUserMedia),
|
|
315
|
+
errorCode: "getUserMedia",
|
|
316
|
+
errorMsg: "The getUserMedia API is not supported in your browser"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
condition: utils.isSupported.canvas(),
|
|
320
|
+
errorCode: "canvas",
|
|
321
|
+
errorMsg: "Canvas elements are not supported in your browser"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
condition: utils.isSupported.webworkers(),
|
|
325
|
+
errorCode: "webworkers",
|
|
326
|
+
errorMsg: "The Web Workers API is not supported in your browser"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
condition: utils.isFunction(utils.URL),
|
|
330
|
+
errorCode: "globalThis.URL",
|
|
331
|
+
errorMsg: "The globalThis.URL API is not supported in your browser"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
condition: utils.isSupported.blob(),
|
|
335
|
+
errorCode: "globalThis.Blob",
|
|
336
|
+
errorMsg: "The globalThis.Blob File API is not supported in your browser"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
condition: utils.isSupported.Uint8Array(),
|
|
340
|
+
errorCode: "globalThis.Uint8Array",
|
|
341
|
+
errorMsg: "The globalThis.Uint8Array function constructor is not supported in your browser"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
condition: utils.isSupported.Uint32Array(),
|
|
345
|
+
errorCode: "globalThis.Uint32Array",
|
|
346
|
+
errorMsg: "The globalThis.Uint32Array function constructor is not supported in your browser"
|
|
347
|
+
}
|
|
348
|
+
],
|
|
349
|
+
messages: {
|
|
350
|
+
videoCodecs: {
|
|
351
|
+
errorCode: "videocodec",
|
|
352
|
+
errorMsg: "The video codec you are trying to use is not supported in your browser"
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
var error$2 = Object.freeze({
|
|
357
|
+
default: error
|
|
358
|
+
});
|
|
359
|
+
var noop2 = function noop3() {
|
|
360
|
+
};
|
|
361
|
+
var defaultOptions = {
|
|
362
|
+
sampleInterval: 10,
|
|
363
|
+
numWorkers: 2,
|
|
364
|
+
filter: "",
|
|
365
|
+
gifWidth: 200,
|
|
366
|
+
gifHeight: 200,
|
|
367
|
+
interval: 0.1,
|
|
368
|
+
numFrames: 10,
|
|
369
|
+
frameDuration: 1,
|
|
370
|
+
keepCameraOn: false,
|
|
371
|
+
images: [],
|
|
372
|
+
video: null,
|
|
373
|
+
webcamVideoElement: null,
|
|
374
|
+
cameraStream: null,
|
|
375
|
+
text: "",
|
|
376
|
+
fontWeight: "normal",
|
|
377
|
+
fontSize: "16px",
|
|
378
|
+
minFontSize: "10px",
|
|
379
|
+
resizeFont: false,
|
|
380
|
+
fontFamily: "sans-serif",
|
|
381
|
+
fontColor: "#ffffff",
|
|
382
|
+
textAlign: "center",
|
|
383
|
+
textBaseline: "bottom",
|
|
384
|
+
textXCoordinate: null,
|
|
385
|
+
textYCoordinate: null,
|
|
386
|
+
progressCallback: noop2,
|
|
387
|
+
completeCallback: noop2,
|
|
388
|
+
saveRenderingContexts: false,
|
|
389
|
+
savedRenderingContexts: [],
|
|
390
|
+
crossOrigin: "Anonymous"
|
|
391
|
+
};
|
|
392
|
+
var defaultOptions$2 = Object.freeze({
|
|
393
|
+
default: defaultOptions
|
|
394
|
+
});
|
|
395
|
+
function isSupported() {
|
|
396
|
+
return error.isValid();
|
|
397
|
+
}
|
|
398
|
+
function isWebCamGIFSupported() {
|
|
399
|
+
return error.isValid();
|
|
400
|
+
}
|
|
401
|
+
function isSupported$1() {
|
|
402
|
+
const options = {
|
|
403
|
+
getUserMedia: true
|
|
404
|
+
};
|
|
405
|
+
return error.isValid(options);
|
|
406
|
+
}
|
|
407
|
+
function isExistingVideoGIFSupported(codecs) {
|
|
408
|
+
let hasValidCodec = false;
|
|
409
|
+
if (utils.isArray(codecs) && codecs.length) {
|
|
410
|
+
utils.each(codecs, function(indece, currentCodec) {
|
|
411
|
+
if (utils.isSupported.videoCodecs[currentCodec]) {
|
|
412
|
+
hasValidCodec = true;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
if (!hasValidCodec) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
} else if (utils.isString(codecs) && codecs.length) {
|
|
419
|
+
if (!utils.isSupported.videoCodecs[codecs]) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return error.isValid({
|
|
424
|
+
getUserMedia: true
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function NeuQuant() {
|
|
428
|
+
const netsize = 256;
|
|
429
|
+
const prime1 = 499;
|
|
430
|
+
const prime2 = 491;
|
|
431
|
+
const prime3 = 487;
|
|
432
|
+
const prime4 = 503;
|
|
433
|
+
const minpicturebytes = 3 * prime4;
|
|
434
|
+
const maxnetpos = netsize - 1;
|
|
435
|
+
const netbiasshift = 4;
|
|
436
|
+
const ncycles = 100;
|
|
437
|
+
const intbiasshift = 16;
|
|
438
|
+
const intbias = 1 << intbiasshift;
|
|
439
|
+
const gammashift = 10;
|
|
440
|
+
const gamma = 1 << gammashift;
|
|
441
|
+
const betashift = 10;
|
|
442
|
+
const beta = intbias >> betashift;
|
|
443
|
+
const betagamma = intbias << gammashift - betashift;
|
|
444
|
+
const initrad = netsize >> 3;
|
|
445
|
+
const radiusbiasshift = 6;
|
|
446
|
+
const radiusbias = 1 << radiusbiasshift;
|
|
447
|
+
const initradius = initrad * radiusbias;
|
|
448
|
+
const radiusdec = 30;
|
|
449
|
+
const alphabiasshift = 10;
|
|
450
|
+
const initalpha = 1 << alphabiasshift;
|
|
451
|
+
let alphadec;
|
|
452
|
+
const radbiasshift = 8;
|
|
453
|
+
const radbias = 1 << radbiasshift;
|
|
454
|
+
const alpharadbshift = alphabiasshift + radbiasshift;
|
|
455
|
+
const alpharadbias = 1 << alpharadbshift;
|
|
456
|
+
let thepicture;
|
|
457
|
+
let lengthcount;
|
|
458
|
+
let samplefac;
|
|
459
|
+
let network;
|
|
460
|
+
const netindex = [];
|
|
461
|
+
const bias = [];
|
|
462
|
+
const freq = [];
|
|
463
|
+
const radpower = [];
|
|
464
|
+
function NeuQuantConstructor(thepic, len, sample) {
|
|
465
|
+
let i;
|
|
466
|
+
let p;
|
|
467
|
+
thepicture = thepic;
|
|
468
|
+
lengthcount = len;
|
|
469
|
+
samplefac = sample;
|
|
470
|
+
network = new Array(netsize);
|
|
471
|
+
for (i = 0; i < netsize; i++) {
|
|
472
|
+
network[i] = new Array(4);
|
|
473
|
+
p = network[i];
|
|
474
|
+
p[0] = p[1] = p[2] = (i << netbiasshift + 8) / netsize | 0;
|
|
475
|
+
freq[i] = intbias / netsize | 0;
|
|
476
|
+
bias[i] = 0;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function colorMap() {
|
|
480
|
+
const map2 = [];
|
|
481
|
+
const index = new Array(netsize);
|
|
482
|
+
for (let i = 0; i < netsize; i++) {
|
|
483
|
+
index[network[i][3]] = i;
|
|
484
|
+
}
|
|
485
|
+
let k = 0;
|
|
486
|
+
for (let l = 0; l < netsize; l++) {
|
|
487
|
+
const j = index[l];
|
|
488
|
+
map2[k++] = network[j][0];
|
|
489
|
+
map2[k++] = network[j][1];
|
|
490
|
+
map2[k++] = network[j][2];
|
|
491
|
+
}
|
|
492
|
+
return map2;
|
|
493
|
+
}
|
|
494
|
+
function inxbuild() {
|
|
495
|
+
let i;
|
|
496
|
+
let j;
|
|
497
|
+
let smallpos;
|
|
498
|
+
let smallval;
|
|
499
|
+
let p;
|
|
500
|
+
let q;
|
|
501
|
+
let previouscol;
|
|
502
|
+
let startpos;
|
|
503
|
+
previouscol = 0;
|
|
504
|
+
startpos = 0;
|
|
505
|
+
for (i = 0; i < netsize; i++) {
|
|
506
|
+
p = network[i];
|
|
507
|
+
smallpos = i;
|
|
508
|
+
smallval = p[1];
|
|
509
|
+
for (j = i + 1; j < netsize; j++) {
|
|
510
|
+
q = network[j];
|
|
511
|
+
if (q[1] < smallval) {
|
|
512
|
+
smallpos = j;
|
|
513
|
+
smallval = q[1];
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
q = network[smallpos];
|
|
517
|
+
if (i != smallpos) {
|
|
518
|
+
j = q[0];
|
|
519
|
+
q[0] = p[0];
|
|
520
|
+
p[0] = j;
|
|
521
|
+
j = q[1];
|
|
522
|
+
q[1] = p[1];
|
|
523
|
+
p[1] = j;
|
|
524
|
+
j = q[2];
|
|
525
|
+
q[2] = p[2];
|
|
526
|
+
p[2] = j;
|
|
527
|
+
j = q[3];
|
|
528
|
+
q[3] = p[3];
|
|
529
|
+
p[3] = j;
|
|
530
|
+
}
|
|
531
|
+
if (smallval != previouscol) {
|
|
532
|
+
netindex[previouscol] = startpos + i >> 1;
|
|
533
|
+
for (j = previouscol + 1; j < smallval; j++) {
|
|
534
|
+
netindex[j] = i;
|
|
535
|
+
}
|
|
536
|
+
previouscol = smallval;
|
|
537
|
+
startpos = i;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
netindex[previouscol] = startpos + maxnetpos >> 1;
|
|
541
|
+
for (j = previouscol + 1; j < 256; j++) {
|
|
542
|
+
netindex[j] = maxnetpos;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
function learn() {
|
|
546
|
+
let i;
|
|
547
|
+
let j;
|
|
548
|
+
let b;
|
|
549
|
+
let g;
|
|
550
|
+
let r;
|
|
551
|
+
let radius;
|
|
552
|
+
let rad;
|
|
553
|
+
let alpha;
|
|
554
|
+
let step;
|
|
555
|
+
let delta;
|
|
556
|
+
let samplepixels;
|
|
557
|
+
let p;
|
|
558
|
+
let pix;
|
|
559
|
+
let lim;
|
|
560
|
+
if (lengthcount < minpicturebytes) {
|
|
561
|
+
samplefac = 1;
|
|
562
|
+
}
|
|
563
|
+
alphadec = 30 + (samplefac - 1) / 3;
|
|
564
|
+
p = thepicture;
|
|
565
|
+
pix = 0;
|
|
566
|
+
lim = lengthcount;
|
|
567
|
+
samplepixels = lengthcount / (3 * samplefac);
|
|
568
|
+
delta = samplepixels / ncycles | 0;
|
|
569
|
+
alpha = initalpha;
|
|
570
|
+
radius = initradius;
|
|
571
|
+
rad = radius >> radiusbiasshift;
|
|
572
|
+
if (rad <= 1) {
|
|
573
|
+
rad = 0;
|
|
574
|
+
}
|
|
575
|
+
for (i = 0; i < rad; i++) {
|
|
576
|
+
radpower[i] = alpha * ((rad * rad - i * i) * radbias / (rad * rad));
|
|
577
|
+
}
|
|
578
|
+
if (lengthcount < minpicturebytes) {
|
|
579
|
+
step = 3;
|
|
580
|
+
} else if (lengthcount % prime1 !== 0) {
|
|
581
|
+
step = 3 * prime1;
|
|
582
|
+
} else if (lengthcount % prime2 !== 0) {
|
|
583
|
+
step = 3 * prime2;
|
|
584
|
+
} else if (lengthcount % prime3 !== 0) {
|
|
585
|
+
step = 3 * prime3;
|
|
586
|
+
} else {
|
|
587
|
+
step = 3 * prime4;
|
|
588
|
+
}
|
|
589
|
+
i = 0;
|
|
590
|
+
while (i < samplepixels) {
|
|
591
|
+
b = (p[pix + 0] & 255) << netbiasshift;
|
|
592
|
+
g = (p[pix + 1] & 255) << netbiasshift;
|
|
593
|
+
r = (p[pix + 2] & 255) << netbiasshift;
|
|
594
|
+
j = contest(b, g, r);
|
|
595
|
+
altersingle(alpha, j, b, g, r);
|
|
596
|
+
if (rad !== 0) {
|
|
597
|
+
alterneigh(rad, j, b, g, r);
|
|
598
|
+
}
|
|
599
|
+
pix += step;
|
|
600
|
+
if (pix >= lim) {
|
|
601
|
+
pix -= lengthcount;
|
|
602
|
+
}
|
|
603
|
+
i++;
|
|
604
|
+
if (delta === 0) {
|
|
605
|
+
delta = 1;
|
|
606
|
+
}
|
|
607
|
+
if (i % delta === 0) {
|
|
608
|
+
alpha -= alpha / alphadec;
|
|
609
|
+
radius -= radius / radiusdec;
|
|
610
|
+
rad = radius >> radiusbiasshift;
|
|
611
|
+
if (rad <= 1) {
|
|
612
|
+
rad = 0;
|
|
613
|
+
}
|
|
614
|
+
for (j = 0; j < rad; j++) {
|
|
615
|
+
radpower[j] = alpha * ((rad * rad - j * j) * radbias / (rad * rad));
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
function map(b, g, r) {
|
|
621
|
+
let i;
|
|
622
|
+
let j;
|
|
623
|
+
let dist;
|
|
624
|
+
let a;
|
|
625
|
+
let bestd;
|
|
626
|
+
let p;
|
|
627
|
+
let best;
|
|
628
|
+
bestd = 1e3;
|
|
629
|
+
best = -1;
|
|
630
|
+
i = netindex[g];
|
|
631
|
+
j = i - 1;
|
|
632
|
+
while (i < netsize || j >= 0) {
|
|
633
|
+
if (i < netsize) {
|
|
634
|
+
p = network[i];
|
|
635
|
+
dist = p[1] - g;
|
|
636
|
+
if (dist >= bestd) {
|
|
637
|
+
i = netsize;
|
|
638
|
+
} else {
|
|
639
|
+
i++;
|
|
640
|
+
if (dist < 0) {
|
|
641
|
+
dist = -dist;
|
|
642
|
+
}
|
|
643
|
+
a = p[0] - b;
|
|
644
|
+
if (a < 0) {
|
|
645
|
+
a = -a;
|
|
646
|
+
}
|
|
647
|
+
dist += a;
|
|
648
|
+
if (dist < bestd) {
|
|
649
|
+
a = p[2] - r;
|
|
650
|
+
if (a < 0) {
|
|
651
|
+
a = -a;
|
|
652
|
+
}
|
|
653
|
+
dist += a;
|
|
654
|
+
if (dist < bestd) {
|
|
655
|
+
bestd = dist;
|
|
656
|
+
best = p[3];
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (j >= 0) {
|
|
662
|
+
p = network[j];
|
|
663
|
+
dist = g - p[1];
|
|
664
|
+
if (dist >= bestd) {
|
|
665
|
+
j = -1;
|
|
666
|
+
} else {
|
|
667
|
+
j--;
|
|
668
|
+
if (dist < 0) {
|
|
669
|
+
dist = -dist;
|
|
670
|
+
}
|
|
671
|
+
a = p[0] - b;
|
|
672
|
+
if (a < 0) {
|
|
673
|
+
a = -a;
|
|
674
|
+
}
|
|
675
|
+
dist += a;
|
|
676
|
+
if (dist < bestd) {
|
|
677
|
+
a = p[2] - r;
|
|
678
|
+
if (a < 0) {
|
|
679
|
+
a = -a;
|
|
680
|
+
}
|
|
681
|
+
dist += a;
|
|
682
|
+
if (dist < bestd) {
|
|
683
|
+
bestd = dist;
|
|
684
|
+
best = p[3];
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return best;
|
|
691
|
+
}
|
|
692
|
+
function process() {
|
|
693
|
+
learn();
|
|
694
|
+
unbiasnet();
|
|
695
|
+
inxbuild();
|
|
696
|
+
return colorMap();
|
|
697
|
+
}
|
|
698
|
+
function unbiasnet() {
|
|
699
|
+
let i;
|
|
700
|
+
let j;
|
|
701
|
+
for (i = 0; i < netsize; i++) {
|
|
702
|
+
network[i][0] >>= netbiasshift;
|
|
703
|
+
network[i][1] >>= netbiasshift;
|
|
704
|
+
network[i][2] >>= netbiasshift;
|
|
705
|
+
network[i][3] = i;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function alterneigh(rad, i, b, g, r) {
|
|
709
|
+
let j;
|
|
710
|
+
let k;
|
|
711
|
+
let lo;
|
|
712
|
+
let hi;
|
|
713
|
+
let a;
|
|
714
|
+
let m;
|
|
715
|
+
let p;
|
|
716
|
+
lo = i - rad;
|
|
717
|
+
if (lo < -1) {
|
|
718
|
+
lo = -1;
|
|
719
|
+
}
|
|
720
|
+
hi = i + rad;
|
|
721
|
+
if (hi > netsize) {
|
|
722
|
+
hi = netsize;
|
|
723
|
+
}
|
|
724
|
+
j = i + 1;
|
|
725
|
+
k = i - 1;
|
|
726
|
+
m = 1;
|
|
727
|
+
while (j < hi || k > lo) {
|
|
728
|
+
a = radpower[m++];
|
|
729
|
+
if (j < hi) {
|
|
730
|
+
p = network[j++];
|
|
731
|
+
try {
|
|
732
|
+
p[0] -= a * (p[0] - b) / alpharadbias | 0;
|
|
733
|
+
p[1] -= a * (p[1] - g) / alpharadbias | 0;
|
|
734
|
+
p[2] -= a * (p[2] - r) / alpharadbias | 0;
|
|
735
|
+
} catch (e) {
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (k > lo) {
|
|
739
|
+
p = network[k--];
|
|
740
|
+
try {
|
|
741
|
+
p[0] -= a * (p[0] - b) / alpharadbias | 0;
|
|
742
|
+
p[1] -= a * (p[1] - g) / alpharadbias | 0;
|
|
743
|
+
p[2] -= a * (p[2] - r) / alpharadbias | 0;
|
|
744
|
+
} catch (e) {
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function altersingle(alpha, i, b, g, r) {
|
|
750
|
+
const n = network[i];
|
|
751
|
+
const alphaMult = alpha / initalpha;
|
|
752
|
+
n[0] -= alphaMult * (n[0] - b) | 0;
|
|
753
|
+
n[1] -= alphaMult * (n[1] - g) | 0;
|
|
754
|
+
n[2] -= alphaMult * (n[2] - r) | 0;
|
|
755
|
+
}
|
|
756
|
+
function contest(b, g, r) {
|
|
757
|
+
let i;
|
|
758
|
+
let dist;
|
|
759
|
+
let a;
|
|
760
|
+
let biasdist;
|
|
761
|
+
let betafreq;
|
|
762
|
+
let bestpos;
|
|
763
|
+
let bestbiaspos;
|
|
764
|
+
let bestd;
|
|
765
|
+
let bestbiasd;
|
|
766
|
+
let n;
|
|
767
|
+
bestd = ~(1 << 31);
|
|
768
|
+
bestbiasd = bestd;
|
|
769
|
+
bestpos = -1;
|
|
770
|
+
bestbiaspos = bestpos;
|
|
771
|
+
for (i = 0; i < netsize; i++) {
|
|
772
|
+
n = network[i];
|
|
773
|
+
dist = n[0] - b;
|
|
774
|
+
if (dist < 0) {
|
|
775
|
+
dist = -dist;
|
|
776
|
+
}
|
|
777
|
+
a = n[1] - g;
|
|
778
|
+
if (a < 0) {
|
|
779
|
+
a = -a;
|
|
780
|
+
}
|
|
781
|
+
dist += a;
|
|
782
|
+
a = n[2] - r;
|
|
783
|
+
if (a < 0) {
|
|
784
|
+
a = -a;
|
|
785
|
+
}
|
|
786
|
+
dist += a;
|
|
787
|
+
if (dist < bestd) {
|
|
788
|
+
bestd = dist;
|
|
789
|
+
bestpos = i;
|
|
790
|
+
}
|
|
791
|
+
biasdist = dist - (bias[i] >> intbiasshift - netbiasshift);
|
|
792
|
+
if (biasdist < bestbiasd) {
|
|
793
|
+
bestbiasd = biasdist;
|
|
794
|
+
bestbiaspos = i;
|
|
795
|
+
}
|
|
796
|
+
betafreq = freq[i] >> betashift;
|
|
797
|
+
freq[i] -= betafreq;
|
|
798
|
+
bias[i] += betafreq << gammashift;
|
|
799
|
+
}
|
|
800
|
+
freq[bestpos] += beta;
|
|
801
|
+
bias[bestpos] -= betagamma;
|
|
802
|
+
return bestbiaspos;
|
|
803
|
+
}
|
|
804
|
+
NeuQuantConstructor.apply(this, arguments);
|
|
805
|
+
const exports = {};
|
|
806
|
+
exports.map = map;
|
|
807
|
+
exports.process = process;
|
|
808
|
+
return exports;
|
|
809
|
+
}
|
|
810
|
+
function workerCode() {
|
|
811
|
+
const self = this;
|
|
812
|
+
try {
|
|
813
|
+
globalThis.onmessage = function(ev) {
|
|
814
|
+
const data = ev.data || {};
|
|
815
|
+
let response;
|
|
816
|
+
if (data.gifshot) {
|
|
817
|
+
response = workerMethods.run(data);
|
|
818
|
+
postMessage(response);
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
} catch (e) {
|
|
822
|
+
}
|
|
823
|
+
var workerMethods = {
|
|
824
|
+
dataToRGB: function dataToRGB(data, width, height) {
|
|
825
|
+
const length = width * height * 4;
|
|
826
|
+
let i = 0;
|
|
827
|
+
const rgb = [];
|
|
828
|
+
while (i < length) {
|
|
829
|
+
rgb.push(data[i++]);
|
|
830
|
+
rgb.push(data[i++]);
|
|
831
|
+
rgb.push(data[i++]);
|
|
832
|
+
i++;
|
|
833
|
+
}
|
|
834
|
+
return rgb;
|
|
835
|
+
},
|
|
836
|
+
componentizedPaletteToArray: function componentizedPaletteToArray(paletteRGB) {
|
|
837
|
+
paletteRGB = paletteRGB || [];
|
|
838
|
+
const paletteArray = [];
|
|
839
|
+
for (let i = 0; i < paletteRGB.length; i += 3) {
|
|
840
|
+
const r = paletteRGB[i];
|
|
841
|
+
const g = paletteRGB[i + 1];
|
|
842
|
+
const b = paletteRGB[i + 2];
|
|
843
|
+
paletteArray.push(r << 16 | g << 8 | b);
|
|
844
|
+
}
|
|
845
|
+
return paletteArray;
|
|
846
|
+
},
|
|
847
|
+
// This is the "traditional" Animated_GIF style of going from RGBA to indexed color frames
|
|
848
|
+
processFrameWithQuantizer: function processFrameWithQuantizer(imageData, width, height, sampleInterval) {
|
|
849
|
+
const rgbComponents = this.dataToRGB(imageData, width, height);
|
|
850
|
+
const nq = new NeuQuant(rgbComponents, rgbComponents.length, sampleInterval);
|
|
851
|
+
const paletteRGB = nq.process();
|
|
852
|
+
const paletteArray = new Uint32Array(this.componentizedPaletteToArray(paletteRGB));
|
|
853
|
+
const numberPixels = width * height;
|
|
854
|
+
const indexedPixels = new Uint8Array(numberPixels);
|
|
855
|
+
let k = 0;
|
|
856
|
+
for (let i = 0; i < numberPixels; i++) {
|
|
857
|
+
const r = rgbComponents[k++];
|
|
858
|
+
const g = rgbComponents[k++];
|
|
859
|
+
const b = rgbComponents[k++];
|
|
860
|
+
indexedPixels[i] = nq.map(r, g, b);
|
|
861
|
+
}
|
|
862
|
+
return {
|
|
863
|
+
pixels: indexedPixels,
|
|
864
|
+
palette: paletteArray
|
|
865
|
+
};
|
|
866
|
+
},
|
|
867
|
+
run: function run(frame) {
|
|
868
|
+
frame = frame || {};
|
|
869
|
+
const _frame = frame;
|
|
870
|
+
const height = _frame.height;
|
|
871
|
+
const palette = _frame.palette;
|
|
872
|
+
const sampleInterval = _frame.sampleInterval;
|
|
873
|
+
const width = _frame.width;
|
|
874
|
+
const imageData = frame.data;
|
|
875
|
+
return this.processFrameWithQuantizer(imageData, width, height, sampleInterval);
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
return workerMethods;
|
|
879
|
+
}
|
|
880
|
+
function gifWriter(buf, width, height, gopts) {
|
|
881
|
+
let p = 0;
|
|
882
|
+
gopts = gopts === void 0 ? {} : gopts;
|
|
883
|
+
const loop_count = gopts.loop === void 0 ? null : gopts.loop;
|
|
884
|
+
const global_palette = gopts.palette === void 0 ? null : gopts.palette;
|
|
885
|
+
if (width <= 0 || height <= 0 || width > 65535 || height > 65535)
|
|
886
|
+
throw "Width/Height invalid.";
|
|
887
|
+
function check_palette_and_num_colors(palette) {
|
|
888
|
+
const num_colors = palette.length;
|
|
889
|
+
if (num_colors < 2 || num_colors > 256 || num_colors & num_colors - 1)
|
|
890
|
+
throw "Invalid code/color length, must be power of 2 and 2 .. 256.";
|
|
891
|
+
return num_colors;
|
|
892
|
+
}
|
|
893
|
+
buf[p++] = 71;
|
|
894
|
+
buf[p++] = 73;
|
|
895
|
+
buf[p++] = 70;
|
|
896
|
+
buf[p++] = 56;
|
|
897
|
+
buf[p++] = 57;
|
|
898
|
+
buf[p++] = 97;
|
|
899
|
+
const gp_num_colors_pow2 = 0;
|
|
900
|
+
const background = 0;
|
|
901
|
+
buf[p++] = width & 255;
|
|
902
|
+
buf[p++] = width >> 8 & 255;
|
|
903
|
+
buf[p++] = height & 255;
|
|
904
|
+
buf[p++] = height >> 8 & 255;
|
|
905
|
+
buf[p++] = (global_palette !== null ? 128 : 0) | // Global Color Table Flag.
|
|
906
|
+
gp_num_colors_pow2;
|
|
907
|
+
buf[p++] = background;
|
|
908
|
+
buf[p++] = 0;
|
|
909
|
+
if (loop_count !== null) {
|
|
910
|
+
if (loop_count < 0 || loop_count > 65535)
|
|
911
|
+
throw "Loop count invalid.";
|
|
912
|
+
buf[p++] = 33;
|
|
913
|
+
buf[p++] = 255;
|
|
914
|
+
buf[p++] = 11;
|
|
915
|
+
buf[p++] = 78;
|
|
916
|
+
buf[p++] = 69;
|
|
917
|
+
buf[p++] = 84;
|
|
918
|
+
buf[p++] = 83;
|
|
919
|
+
buf[p++] = 67;
|
|
920
|
+
buf[p++] = 65;
|
|
921
|
+
buf[p++] = 80;
|
|
922
|
+
buf[p++] = 69;
|
|
923
|
+
buf[p++] = 50;
|
|
924
|
+
buf[p++] = 46;
|
|
925
|
+
buf[p++] = 48;
|
|
926
|
+
buf[p++] = 3;
|
|
927
|
+
buf[p++] = 1;
|
|
928
|
+
buf[p++] = loop_count & 255;
|
|
929
|
+
buf[p++] = loop_count >> 8 & 255;
|
|
930
|
+
buf[p++] = 0;
|
|
931
|
+
}
|
|
932
|
+
let ended = false;
|
|
933
|
+
this.addFrame = function(x, y, w, h, indexed_pixels, opts) {
|
|
934
|
+
if (ended === true) {
|
|
935
|
+
--p;
|
|
936
|
+
ended = false;
|
|
937
|
+
}
|
|
938
|
+
opts = opts === void 0 ? {} : opts;
|
|
939
|
+
if (x < 0 || y < 0 || x > 65535 || y > 65535)
|
|
940
|
+
throw "x/y invalid.";
|
|
941
|
+
if (w <= 0 || h <= 0 || w > 65535 || h > 65535)
|
|
942
|
+
throw "Width/Height invalid.";
|
|
943
|
+
if (indexed_pixels.length < w * h)
|
|
944
|
+
throw "Not enough pixels for the frame size.";
|
|
945
|
+
let using_local_palette = true;
|
|
946
|
+
let palette = opts.palette;
|
|
947
|
+
if (palette === void 0 || palette === null) {
|
|
948
|
+
using_local_palette = false;
|
|
949
|
+
palette = global_palette;
|
|
950
|
+
}
|
|
951
|
+
if (palette === void 0 || palette === null)
|
|
952
|
+
throw "Must supply either a local or global palette.";
|
|
953
|
+
let num_colors = check_palette_and_num_colors(palette);
|
|
954
|
+
let min_code_size = 0;
|
|
955
|
+
while (num_colors >>= 1) {
|
|
956
|
+
++min_code_size;
|
|
957
|
+
}
|
|
958
|
+
num_colors = 1 << min_code_size;
|
|
959
|
+
const delay = opts.delay === void 0 ? 0 : opts.delay;
|
|
960
|
+
const disposal = opts.disposal === void 0 ? 0 : opts.disposal;
|
|
961
|
+
if (disposal < 0 || disposal > 3)
|
|
962
|
+
throw "Disposal out of range.";
|
|
963
|
+
let use_transparency = false;
|
|
964
|
+
let transparent_index = 0;
|
|
965
|
+
if (opts.transparent !== void 0 && opts.transparent !== null) {
|
|
966
|
+
use_transparency = true;
|
|
967
|
+
transparent_index = opts.transparent;
|
|
968
|
+
if (transparent_index < 0 || transparent_index >= num_colors)
|
|
969
|
+
throw "Transparent color index.";
|
|
970
|
+
}
|
|
971
|
+
if (disposal !== 0 || use_transparency || delay !== 0) {
|
|
972
|
+
buf[p++] = 33;
|
|
973
|
+
buf[p++] = 249;
|
|
974
|
+
buf[p++] = 4;
|
|
975
|
+
buf[p++] = disposal << 2 | (use_transparency === true ? 1 : 0);
|
|
976
|
+
buf[p++] = delay & 255;
|
|
977
|
+
buf[p++] = delay >> 8 & 255;
|
|
978
|
+
buf[p++] = transparent_index;
|
|
979
|
+
buf[p++] = 0;
|
|
980
|
+
}
|
|
981
|
+
buf[p++] = 44;
|
|
982
|
+
buf[p++] = x & 255;
|
|
983
|
+
buf[p++] = x >> 8 & 255;
|
|
984
|
+
buf[p++] = y & 255;
|
|
985
|
+
buf[p++] = y >> 8 & 255;
|
|
986
|
+
buf[p++] = w & 255;
|
|
987
|
+
buf[p++] = w >> 8 & 255;
|
|
988
|
+
buf[p++] = h & 255;
|
|
989
|
+
buf[p++] = h >> 8 & 255;
|
|
990
|
+
buf[p++] = using_local_palette === true ? 128 | min_code_size - 1 : 0;
|
|
991
|
+
if (using_local_palette === true) {
|
|
992
|
+
for (let i = 0, il = palette.length; i < il; ++i) {
|
|
993
|
+
const rgb = palette[i];
|
|
994
|
+
buf[p++] = rgb >> 16 & 255;
|
|
995
|
+
buf[p++] = rgb >> 8 & 255;
|
|
996
|
+
buf[p++] = rgb & 255;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
p = GifWriterOutputLZWCodeStream(buf, p, min_code_size < 2 ? 2 : min_code_size, indexed_pixels);
|
|
1000
|
+
};
|
|
1001
|
+
this.end = function() {
|
|
1002
|
+
if (ended === false) {
|
|
1003
|
+
buf[p++] = 59;
|
|
1004
|
+
ended = true;
|
|
1005
|
+
}
|
|
1006
|
+
return p;
|
|
1007
|
+
};
|
|
1008
|
+
function GifWriterOutputLZWCodeStream(buf2, p2, min_code_size, index_stream) {
|
|
1009
|
+
buf2[p2++] = min_code_size;
|
|
1010
|
+
let cur_subblock = p2++;
|
|
1011
|
+
const clear_code = 1 << min_code_size;
|
|
1012
|
+
const code_mask = clear_code - 1;
|
|
1013
|
+
const eoi_code = clear_code + 1;
|
|
1014
|
+
let next_code = eoi_code + 1;
|
|
1015
|
+
let cur_code_size = min_code_size + 1;
|
|
1016
|
+
let cur_shift = 0;
|
|
1017
|
+
let cur = 0;
|
|
1018
|
+
function emit_bytes_to_buffer(bit_block_size) {
|
|
1019
|
+
while (cur_shift >= bit_block_size) {
|
|
1020
|
+
buf2[p2++] = cur & 255;
|
|
1021
|
+
cur >>= 8;
|
|
1022
|
+
cur_shift -= 8;
|
|
1023
|
+
if (p2 === cur_subblock + 256) {
|
|
1024
|
+
buf2[cur_subblock] = 255;
|
|
1025
|
+
cur_subblock = p2++;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
function emit_code(c) {
|
|
1030
|
+
cur |= c << cur_shift;
|
|
1031
|
+
cur_shift += cur_code_size;
|
|
1032
|
+
emit_bytes_to_buffer(8);
|
|
1033
|
+
}
|
|
1034
|
+
let ib_code = index_stream[0] & code_mask;
|
|
1035
|
+
let code_table = {};
|
|
1036
|
+
emit_code(clear_code);
|
|
1037
|
+
for (let i = 1, il = index_stream.length; i < il; ++i) {
|
|
1038
|
+
const k = index_stream[i] & code_mask;
|
|
1039
|
+
const cur_key = ib_code << 8 | k;
|
|
1040
|
+
const cur_code = code_table[cur_key];
|
|
1041
|
+
if (cur_code === void 0) {
|
|
1042
|
+
cur |= ib_code << cur_shift;
|
|
1043
|
+
cur_shift += cur_code_size;
|
|
1044
|
+
while (cur_shift >= 8) {
|
|
1045
|
+
buf2[p2++] = cur & 255;
|
|
1046
|
+
cur >>= 8;
|
|
1047
|
+
cur_shift -= 8;
|
|
1048
|
+
if (p2 === cur_subblock + 256) {
|
|
1049
|
+
buf2[cur_subblock] = 255;
|
|
1050
|
+
cur_subblock = p2++;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (next_code === 4096) {
|
|
1054
|
+
emit_code(clear_code);
|
|
1055
|
+
next_code = eoi_code + 1;
|
|
1056
|
+
cur_code_size = min_code_size + 1;
|
|
1057
|
+
code_table = {};
|
|
1058
|
+
} else {
|
|
1059
|
+
if (next_code >= 1 << cur_code_size)
|
|
1060
|
+
++cur_code_size;
|
|
1061
|
+
code_table[cur_key] = next_code++;
|
|
1062
|
+
}
|
|
1063
|
+
ib_code = k;
|
|
1064
|
+
} else {
|
|
1065
|
+
ib_code = cur_code;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
emit_code(ib_code);
|
|
1069
|
+
emit_code(eoi_code);
|
|
1070
|
+
emit_bytes_to_buffer(1);
|
|
1071
|
+
if (cur_subblock + 1 === p2) {
|
|
1072
|
+
buf2[cur_subblock] = 0;
|
|
1073
|
+
} else {
|
|
1074
|
+
buf2[cur_subblock] = p2 - cur_subblock - 1;
|
|
1075
|
+
buf2[p2++] = 0;
|
|
1076
|
+
}
|
|
1077
|
+
return p2;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
var noop$2 = function noop4() {
|
|
1081
|
+
};
|
|
1082
|
+
var AnimatedGIF = function AnimatedGIF2(options) {
|
|
1083
|
+
this.canvas = null;
|
|
1084
|
+
this.ctx = null;
|
|
1085
|
+
this.repeat = 0;
|
|
1086
|
+
this.frames = [];
|
|
1087
|
+
this.numRenderedFrames = 0;
|
|
1088
|
+
this.onRenderCompleteCallback = noop$2;
|
|
1089
|
+
this.onRenderProgressCallback = noop$2;
|
|
1090
|
+
this.workers = [];
|
|
1091
|
+
this.availableWorkers = [];
|
|
1092
|
+
this.generatingGIF = false;
|
|
1093
|
+
this.options = options;
|
|
1094
|
+
this.initializeWebWorkers(options);
|
|
1095
|
+
};
|
|
1096
|
+
AnimatedGIF.prototype = {
|
|
1097
|
+
workerMethods: workerCode(),
|
|
1098
|
+
initializeWebWorkers: function initializeWebWorkers(options) {
|
|
1099
|
+
const self = this;
|
|
1100
|
+
const processFrameWorkerCode = `${NeuQuant.toString()}(${workerCode.toString()}());`;
|
|
1101
|
+
let webWorkerObj = void 0;
|
|
1102
|
+
let objectUrl = void 0;
|
|
1103
|
+
let webWorker = void 0;
|
|
1104
|
+
let numWorkers = void 0;
|
|
1105
|
+
let x = -1;
|
|
1106
|
+
let workerError = "";
|
|
1107
|
+
numWorkers = options.numWorkers;
|
|
1108
|
+
while (++x < numWorkers) {
|
|
1109
|
+
webWorkerObj = utils.createWebWorker(processFrameWorkerCode);
|
|
1110
|
+
if (utils.isObject(webWorkerObj)) {
|
|
1111
|
+
objectUrl = webWorkerObj.objectUrl;
|
|
1112
|
+
webWorker = webWorkerObj.worker;
|
|
1113
|
+
self.workers.push({
|
|
1114
|
+
worker: webWorker,
|
|
1115
|
+
objectUrl
|
|
1116
|
+
});
|
|
1117
|
+
self.availableWorkers.push(webWorker);
|
|
1118
|
+
} else {
|
|
1119
|
+
workerError = webWorkerObj;
|
|
1120
|
+
utils.webWorkerError = Boolean(webWorkerObj);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
this.workerError = workerError;
|
|
1124
|
+
this.canvas = document.createElement("canvas");
|
|
1125
|
+
this.canvas.width = options.gifWidth;
|
|
1126
|
+
this.canvas.height = options.gifHeight;
|
|
1127
|
+
this.ctx = this.canvas.getContext("2d");
|
|
1128
|
+
this.frames = [];
|
|
1129
|
+
},
|
|
1130
|
+
// Return a worker for processing a frame
|
|
1131
|
+
getWorker: function getWorker() {
|
|
1132
|
+
return this.availableWorkers.pop();
|
|
1133
|
+
},
|
|
1134
|
+
// Restores a worker to the pool
|
|
1135
|
+
freeWorker: function freeWorker(worker) {
|
|
1136
|
+
this.availableWorkers.push(worker);
|
|
1137
|
+
},
|
|
1138
|
+
byteMap: function() {
|
|
1139
|
+
const byteMap = [];
|
|
1140
|
+
for (let i = 0; i < 256; i++) {
|
|
1141
|
+
byteMap[i] = String.fromCharCode(i);
|
|
1142
|
+
}
|
|
1143
|
+
return byteMap;
|
|
1144
|
+
}(),
|
|
1145
|
+
bufferToString: function bufferToString(buffer) {
|
|
1146
|
+
const numberValues = buffer.length;
|
|
1147
|
+
let str = "";
|
|
1148
|
+
let x = -1;
|
|
1149
|
+
while (++x < numberValues) {
|
|
1150
|
+
str += this.byteMap[buffer[x]];
|
|
1151
|
+
}
|
|
1152
|
+
return str;
|
|
1153
|
+
},
|
|
1154
|
+
onFrameFinished: function onFrameFinished(progressCallback) {
|
|
1155
|
+
const self = this;
|
|
1156
|
+
const frames = self.frames;
|
|
1157
|
+
const options = self.options;
|
|
1158
|
+
const hasExistingImages = Boolean((options.images || []).length);
|
|
1159
|
+
const allDone = frames.every(function(frame) {
|
|
1160
|
+
return !frame.beingProcessed && frame.done;
|
|
1161
|
+
});
|
|
1162
|
+
self.numRenderedFrames++;
|
|
1163
|
+
if (hasExistingImages) {
|
|
1164
|
+
progressCallback(self.numRenderedFrames / frames.length);
|
|
1165
|
+
}
|
|
1166
|
+
self.onRenderProgressCallback(self.numRenderedFrames * 0.75 / frames.length);
|
|
1167
|
+
if (allDone) {
|
|
1168
|
+
if (!self.generatingGIF) {
|
|
1169
|
+
self.generateGIF(frames, self.onRenderCompleteCallback);
|
|
1170
|
+
}
|
|
1171
|
+
} else {
|
|
1172
|
+
utils.requestTimeout(function() {
|
|
1173
|
+
self.processNextFrame();
|
|
1174
|
+
}, 1);
|
|
1175
|
+
}
|
|
1176
|
+
},
|
|
1177
|
+
processFrame: function processFrame(position) {
|
|
1178
|
+
const AnimatedGifContext = this;
|
|
1179
|
+
const options = this.options;
|
|
1180
|
+
const _options = this.options;
|
|
1181
|
+
const progressCallback = _options.progressCallback;
|
|
1182
|
+
const sampleInterval = _options.sampleInterval;
|
|
1183
|
+
const frames = this.frames;
|
|
1184
|
+
let frame = void 0;
|
|
1185
|
+
let worker = void 0;
|
|
1186
|
+
const done = function done2() {
|
|
1187
|
+
const ev = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1188
|
+
const data = ev.data;
|
|
1189
|
+
delete frame.data;
|
|
1190
|
+
frame.pixels = Array.prototype.slice.call(data.pixels);
|
|
1191
|
+
frame.palette = Array.prototype.slice.call(data.palette);
|
|
1192
|
+
frame.done = true;
|
|
1193
|
+
frame.beingProcessed = false;
|
|
1194
|
+
AnimatedGifContext.freeWorker(worker);
|
|
1195
|
+
AnimatedGifContext.onFrameFinished(progressCallback);
|
|
1196
|
+
};
|
|
1197
|
+
frame = frames[position];
|
|
1198
|
+
if (frame.beingProcessed || frame.done) {
|
|
1199
|
+
this.onFrameFinished();
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
frame.sampleInterval = sampleInterval;
|
|
1203
|
+
frame.beingProcessed = true;
|
|
1204
|
+
frame.gifshot = true;
|
|
1205
|
+
worker = this.getWorker();
|
|
1206
|
+
if (worker) {
|
|
1207
|
+
worker.onmessage = done;
|
|
1208
|
+
worker.postMessage(frame);
|
|
1209
|
+
} else {
|
|
1210
|
+
done({
|
|
1211
|
+
data: AnimatedGifContext.workerMethods.run(frame)
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
},
|
|
1215
|
+
startRendering: function startRendering(completeCallback) {
|
|
1216
|
+
this.onRenderCompleteCallback = completeCallback;
|
|
1217
|
+
for (let i = 0; i < this.options.numWorkers && i < this.frames.length; i++) {
|
|
1218
|
+
this.processFrame(i);
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
processNextFrame: function processNextFrame() {
|
|
1222
|
+
let position = -1;
|
|
1223
|
+
for (let i = 0; i < this.frames.length; i++) {
|
|
1224
|
+
const frame = this.frames[i];
|
|
1225
|
+
if (!frame.done && !frame.beingProcessed) {
|
|
1226
|
+
position = i;
|
|
1227
|
+
break;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
if (position >= 0) {
|
|
1231
|
+
this.processFrame(position);
|
|
1232
|
+
}
|
|
1233
|
+
},
|
|
1234
|
+
// Takes the already processed data in frames and feeds it to a new
|
|
1235
|
+
// GifWriter instance in order to get the binary GIF file
|
|
1236
|
+
generateGIF: function generateGIF(frames, callback) {
|
|
1237
|
+
const buffer = [];
|
|
1238
|
+
const gifOptions = {
|
|
1239
|
+
loop: this.repeat
|
|
1240
|
+
};
|
|
1241
|
+
const options = this.options;
|
|
1242
|
+
const interval = options.interval;
|
|
1243
|
+
const frameDuration = options.frameDuration;
|
|
1244
|
+
const existingImages2 = options.images;
|
|
1245
|
+
const hasExistingImages = Boolean(existingImages2.length);
|
|
1246
|
+
const height = options.gifHeight;
|
|
1247
|
+
const width = options.gifWidth;
|
|
1248
|
+
const gifWriter$$1 = new gifWriter(buffer, width, height, gifOptions);
|
|
1249
|
+
const onRenderProgressCallback = this.onRenderProgressCallback;
|
|
1250
|
+
const delay = hasExistingImages ? interval * 100 : 0;
|
|
1251
|
+
let bufferToString2 = void 0;
|
|
1252
|
+
let gif = void 0;
|
|
1253
|
+
this.generatingGIF = true;
|
|
1254
|
+
utils.each(frames, function(iterator, frame) {
|
|
1255
|
+
const framePalette = frame.palette;
|
|
1256
|
+
onRenderProgressCallback(0.75 + 0.25 * frame.position * 1 / frames.length);
|
|
1257
|
+
for (let i = 0; i < frameDuration; i++) {
|
|
1258
|
+
gifWriter$$1.addFrame(0, 0, width, height, frame.pixels, {
|
|
1259
|
+
palette: framePalette,
|
|
1260
|
+
delay
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
gifWriter$$1.end();
|
|
1265
|
+
onRenderProgressCallback(1);
|
|
1266
|
+
this.frames = [];
|
|
1267
|
+
this.generatingGIF = false;
|
|
1268
|
+
if (utils.isFunction(callback)) {
|
|
1269
|
+
bufferToString2 = this.bufferToString(buffer);
|
|
1270
|
+
gif = `data:image/gif;base64,${utils.btoa(bufferToString2)}`;
|
|
1271
|
+
callback(gif);
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
// From GIF: 0 = loop forever, null = not looping, n > 0 = loop n times and stop
|
|
1275
|
+
setRepeat: function setRepeat(r) {
|
|
1276
|
+
this.repeat = r;
|
|
1277
|
+
},
|
|
1278
|
+
addFrame: function addFrame(element, gifshotOptions) {
|
|
1279
|
+
gifshotOptions = utils.isObject(gifshotOptions) ? gifshotOptions : {};
|
|
1280
|
+
const self = this;
|
|
1281
|
+
const ctx = self.ctx;
|
|
1282
|
+
const options = self.options;
|
|
1283
|
+
const width = options.gifWidth;
|
|
1284
|
+
const height = options.gifHeight;
|
|
1285
|
+
const fontSize = utils.getFontSize(gifshotOptions);
|
|
1286
|
+
const _gifshotOptions = gifshotOptions;
|
|
1287
|
+
const filter = _gifshotOptions.filter;
|
|
1288
|
+
const fontColor = _gifshotOptions.fontColor;
|
|
1289
|
+
const fontFamily = _gifshotOptions.fontFamily;
|
|
1290
|
+
const fontWeight = _gifshotOptions.fontWeight;
|
|
1291
|
+
const gifHeight = _gifshotOptions.gifHeight;
|
|
1292
|
+
const gifWidth = _gifshotOptions.gifWidth;
|
|
1293
|
+
const text = _gifshotOptions.text;
|
|
1294
|
+
const textAlign = _gifshotOptions.textAlign;
|
|
1295
|
+
const textBaseline = _gifshotOptions.textBaseline;
|
|
1296
|
+
const textXCoordinate = gifshotOptions.textXCoordinate ? gifshotOptions.textXCoordinate : textAlign === "left" ? 1 : textAlign === "right" ? width : width / 2;
|
|
1297
|
+
const textYCoordinate = gifshotOptions.textYCoordinate ? gifshotOptions.textYCoordinate : textBaseline === "top" ? 1 : textBaseline === "center" ? height / 2 : height;
|
|
1298
|
+
const font = `${fontWeight} ${fontSize} ${fontFamily}`;
|
|
1299
|
+
let imageData = void 0;
|
|
1300
|
+
try {
|
|
1301
|
+
ctx.filter = filter;
|
|
1302
|
+
ctx.drawImage(element, 0, 0, width, height);
|
|
1303
|
+
if (text) {
|
|
1304
|
+
ctx.font = font;
|
|
1305
|
+
ctx.fillStyle = fontColor;
|
|
1306
|
+
ctx.textAlign = textAlign;
|
|
1307
|
+
ctx.textBaseline = textBaseline;
|
|
1308
|
+
ctx.fillText(text, textXCoordinate, textYCoordinate);
|
|
1309
|
+
}
|
|
1310
|
+
imageData = ctx.getImageData(0, 0, width, height);
|
|
1311
|
+
self.addFrameImageData(imageData);
|
|
1312
|
+
} catch (e) {
|
|
1313
|
+
return `${e}`;
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
addFrameImageData: function addFrameImageData() {
|
|
1317
|
+
const imageData = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1318
|
+
const frames = this.frames;
|
|
1319
|
+
const imageDataArray = imageData.data;
|
|
1320
|
+
this.frames.push({
|
|
1321
|
+
data: imageDataArray,
|
|
1322
|
+
width: imageData.width,
|
|
1323
|
+
height: imageData.height,
|
|
1324
|
+
palette: null,
|
|
1325
|
+
dithering: null,
|
|
1326
|
+
done: false,
|
|
1327
|
+
beingProcessed: false,
|
|
1328
|
+
position: frames.length
|
|
1329
|
+
});
|
|
1330
|
+
},
|
|
1331
|
+
onRenderProgress: function onRenderProgress(callback) {
|
|
1332
|
+
this.onRenderProgressCallback = callback;
|
|
1333
|
+
},
|
|
1334
|
+
isRendering: function isRendering() {
|
|
1335
|
+
return this.generatingGIF;
|
|
1336
|
+
},
|
|
1337
|
+
getBase64GIF: function getBase64GIF(completeCallback) {
|
|
1338
|
+
const self = this;
|
|
1339
|
+
const onRenderComplete = function onRenderComplete2(gif) {
|
|
1340
|
+
self.destroyWorkers();
|
|
1341
|
+
utils.requestTimeout(function() {
|
|
1342
|
+
completeCallback(gif);
|
|
1343
|
+
}, 0);
|
|
1344
|
+
};
|
|
1345
|
+
self.startRendering(onRenderComplete);
|
|
1346
|
+
},
|
|
1347
|
+
destroyWorkers: function destroyWorkers() {
|
|
1348
|
+
if (this.workerError) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const workers = this.workers;
|
|
1352
|
+
utils.each(workers, function(iterator, workerObj) {
|
|
1353
|
+
const worker = workerObj.worker;
|
|
1354
|
+
const objectUrl = workerObj.objectUrl;
|
|
1355
|
+
worker.terminate();
|
|
1356
|
+
utils.URL.revokeObjectURL(objectUrl);
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
function getBase64GIF2(animatedGifInstance, callback) {
|
|
1361
|
+
animatedGifInstance.getBase64GIF(function(image) {
|
|
1362
|
+
callback({
|
|
1363
|
+
error: false,
|
|
1364
|
+
errorCode: "",
|
|
1365
|
+
errorMsg: "",
|
|
1366
|
+
image
|
|
1367
|
+
});
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
function existingImages() {
|
|
1371
|
+
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1372
|
+
const self = this;
|
|
1373
|
+
const callback = obj.callback;
|
|
1374
|
+
const images = obj.images;
|
|
1375
|
+
const options = obj.options;
|
|
1376
|
+
let imagesLength = obj.imagesLength;
|
|
1377
|
+
const skipObj = {
|
|
1378
|
+
getUserMedia: true,
|
|
1379
|
+
"globalThis.URL": true
|
|
1380
|
+
};
|
|
1381
|
+
const errorObj = error.validate(skipObj);
|
|
1382
|
+
const loadedImages = [];
|
|
1383
|
+
let loadedImagesLength = 0;
|
|
1384
|
+
let tempImage = void 0;
|
|
1385
|
+
let ag = void 0;
|
|
1386
|
+
if (errorObj.error) {
|
|
1387
|
+
return callback(errorObj);
|
|
1388
|
+
}
|
|
1389
|
+
ag = new AnimatedGIF(options);
|
|
1390
|
+
utils.each(images, function(index, image) {
|
|
1391
|
+
const currentImage = image;
|
|
1392
|
+
if (utils.isElement(currentImage)) {
|
|
1393
|
+
if (options.crossOrigin) {
|
|
1394
|
+
currentImage.crossOrigin = options.crossOrigin;
|
|
1395
|
+
}
|
|
1396
|
+
loadedImages[index] = currentImage;
|
|
1397
|
+
loadedImagesLength += 1;
|
|
1398
|
+
if (loadedImagesLength === imagesLength) {
|
|
1399
|
+
addLoadedImagesToGif();
|
|
1400
|
+
}
|
|
1401
|
+
} else if (utils.isString(currentImage)) {
|
|
1402
|
+
tempImage = new Image();
|
|
1403
|
+
if (options.crossOrigin) {
|
|
1404
|
+
tempImage.crossOrigin = options.crossOrigin;
|
|
1405
|
+
}
|
|
1406
|
+
(function(tempImage2) {
|
|
1407
|
+
if (image.text) {
|
|
1408
|
+
tempImage2.text = image.text;
|
|
1409
|
+
}
|
|
1410
|
+
tempImage2.onerror = function(e) {
|
|
1411
|
+
let obj2 = void 0;
|
|
1412
|
+
--imagesLength;
|
|
1413
|
+
if (imagesLength === 0) {
|
|
1414
|
+
obj2 = {};
|
|
1415
|
+
obj2.error = "None of the requested images was capable of being retrieved";
|
|
1416
|
+
return callback(obj2);
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
tempImage2.onload = function(e) {
|
|
1420
|
+
if (image.text) {
|
|
1421
|
+
loadedImages[index] = {
|
|
1422
|
+
img: tempImage2,
|
|
1423
|
+
text: tempImage2.text
|
|
1424
|
+
};
|
|
1425
|
+
} else {
|
|
1426
|
+
loadedImages[index] = tempImage2;
|
|
1427
|
+
}
|
|
1428
|
+
loadedImagesLength += 1;
|
|
1429
|
+
if (loadedImagesLength === imagesLength) {
|
|
1430
|
+
addLoadedImagesToGif();
|
|
1431
|
+
}
|
|
1432
|
+
utils.removeElement(tempImage2);
|
|
1433
|
+
};
|
|
1434
|
+
tempImage2.src = currentImage;
|
|
1435
|
+
})(tempImage);
|
|
1436
|
+
utils.setCSSAttr(tempImage, {
|
|
1437
|
+
position: "fixed",
|
|
1438
|
+
opacity: "0"
|
|
1439
|
+
});
|
|
1440
|
+
document.body.appendChild(tempImage);
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
function addLoadedImagesToGif() {
|
|
1444
|
+
utils.each(loadedImages, function(index, loadedImage) {
|
|
1445
|
+
if (loadedImage) {
|
|
1446
|
+
if (loadedImage.text) {
|
|
1447
|
+
ag.addFrame(loadedImage.img, options, loadedImage.text);
|
|
1448
|
+
} else {
|
|
1449
|
+
ag.addFrame(loadedImage, options);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
getBase64GIF2(ag, callback);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
var noop$3 = function noop5() {
|
|
1457
|
+
};
|
|
1458
|
+
var screenShot = {
|
|
1459
|
+
getGIF: function getGIF() {
|
|
1460
|
+
const options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1461
|
+
let callback = arguments[1];
|
|
1462
|
+
callback = utils.isFunction(callback) ? callback : noop$3;
|
|
1463
|
+
const canvas2 = document.createElement("canvas");
|
|
1464
|
+
let context = void 0;
|
|
1465
|
+
const existingImages2 = options.images;
|
|
1466
|
+
const hasExistingImages = Boolean(existingImages2.length);
|
|
1467
|
+
const cameraStream = options.cameraStream;
|
|
1468
|
+
const crop = options.crop;
|
|
1469
|
+
const filter = options.filter;
|
|
1470
|
+
const fontColor = options.fontColor;
|
|
1471
|
+
const fontFamily = options.fontFamily;
|
|
1472
|
+
const fontWeight = options.fontWeight;
|
|
1473
|
+
const keepCameraOn = options.keepCameraOn;
|
|
1474
|
+
const numWorkers = options.numWorkers;
|
|
1475
|
+
const progressCallback = options.progressCallback;
|
|
1476
|
+
const saveRenderingContexts = options.saveRenderingContexts;
|
|
1477
|
+
const savedRenderingContexts = options.savedRenderingContexts;
|
|
1478
|
+
const text = options.text;
|
|
1479
|
+
const textAlign = options.textAlign;
|
|
1480
|
+
const textBaseline = options.textBaseline;
|
|
1481
|
+
const videoElement = options.videoElement;
|
|
1482
|
+
const videoHeight = options.videoHeight;
|
|
1483
|
+
const videoWidth = options.videoWidth;
|
|
1484
|
+
const webcamVideoElement = options.webcamVideoElement;
|
|
1485
|
+
const gifWidth = Number(options.gifWidth);
|
|
1486
|
+
const gifHeight = Number(options.gifHeight);
|
|
1487
|
+
let interval = Number(options.interval);
|
|
1488
|
+
const sampleInterval = Number(options.sampleInterval);
|
|
1489
|
+
const waitBetweenFrames = hasExistingImages ? 0 : interval * 1e3;
|
|
1490
|
+
const renderingContextsToSave = [];
|
|
1491
|
+
let numFrames = savedRenderingContexts.length ? savedRenderingContexts.length : options.numFrames;
|
|
1492
|
+
let pendingFrames = numFrames;
|
|
1493
|
+
const ag = new AnimatedGIF(options);
|
|
1494
|
+
const fontSize = utils.getFontSize(options);
|
|
1495
|
+
const textXCoordinate = options.textXCoordinate ? options.textXCoordinate : textAlign === "left" ? 1 : textAlign === "right" ? gifWidth : gifWidth / 2;
|
|
1496
|
+
const textYCoordinate = options.textYCoordinate ? options.textYCoordinate : textBaseline === "top" ? 1 : textBaseline === "center" ? gifHeight / 2 : gifHeight;
|
|
1497
|
+
const font = `${fontWeight} ${fontSize} ${fontFamily}`;
|
|
1498
|
+
let sourceX = crop ? Math.floor(crop.scaledWidth / 2) : 0;
|
|
1499
|
+
let sourceWidth = crop ? videoWidth - crop.scaledWidth : 0;
|
|
1500
|
+
let sourceY = crop ? Math.floor(crop.scaledHeight / 2) : 0;
|
|
1501
|
+
let sourceHeight = crop ? videoHeight - crop.scaledHeight : 0;
|
|
1502
|
+
const captureFrames = function captureSingleFrame() {
|
|
1503
|
+
const framesLeft = pendingFrames - 1;
|
|
1504
|
+
if (savedRenderingContexts.length) {
|
|
1505
|
+
context.putImageData(savedRenderingContexts[numFrames - pendingFrames], 0, 0);
|
|
1506
|
+
finishCapture();
|
|
1507
|
+
} else {
|
|
1508
|
+
drawVideo();
|
|
1509
|
+
}
|
|
1510
|
+
function drawVideo() {
|
|
1511
|
+
try {
|
|
1512
|
+
if (sourceWidth > videoWidth) {
|
|
1513
|
+
sourceWidth = videoWidth;
|
|
1514
|
+
}
|
|
1515
|
+
if (sourceHeight > videoHeight) {
|
|
1516
|
+
sourceHeight = videoHeight;
|
|
1517
|
+
}
|
|
1518
|
+
if (sourceX < 0) {
|
|
1519
|
+
sourceX = 0;
|
|
1520
|
+
}
|
|
1521
|
+
if (sourceY < 0) {
|
|
1522
|
+
sourceY = 0;
|
|
1523
|
+
}
|
|
1524
|
+
context.filter = filter;
|
|
1525
|
+
context.drawImage(
|
|
1526
|
+
videoElement,
|
|
1527
|
+
sourceX,
|
|
1528
|
+
sourceY,
|
|
1529
|
+
sourceWidth,
|
|
1530
|
+
sourceHeight,
|
|
1531
|
+
0,
|
|
1532
|
+
0,
|
|
1533
|
+
gifWidth,
|
|
1534
|
+
gifHeight
|
|
1535
|
+
);
|
|
1536
|
+
finishCapture();
|
|
1537
|
+
} catch (e) {
|
|
1538
|
+
if (e.name === "NS_ERROR_NOT_AVAILABLE") {
|
|
1539
|
+
utils.requestTimeout(drawVideo, 100);
|
|
1540
|
+
} else {
|
|
1541
|
+
throw e;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function finishCapture() {
|
|
1546
|
+
let imageData = void 0;
|
|
1547
|
+
if (saveRenderingContexts) {
|
|
1548
|
+
renderingContextsToSave.push(context.getImageData(0, 0, gifWidth, gifHeight));
|
|
1549
|
+
}
|
|
1550
|
+
if (text) {
|
|
1551
|
+
context.font = font;
|
|
1552
|
+
context.fillStyle = fontColor;
|
|
1553
|
+
context.textAlign = textAlign;
|
|
1554
|
+
context.textBaseline = textBaseline;
|
|
1555
|
+
context.fillText(text, textXCoordinate, textYCoordinate);
|
|
1556
|
+
}
|
|
1557
|
+
imageData = context.getImageData(0, 0, gifWidth, gifHeight);
|
|
1558
|
+
ag.addFrameImageData(imageData);
|
|
1559
|
+
pendingFrames = framesLeft;
|
|
1560
|
+
progressCallback((numFrames - pendingFrames) / numFrames);
|
|
1561
|
+
if (framesLeft > 0) {
|
|
1562
|
+
utils.requestTimeout(captureSingleFrame, waitBetweenFrames);
|
|
1563
|
+
}
|
|
1564
|
+
if (!pendingFrames) {
|
|
1565
|
+
ag.getBase64GIF(function(image) {
|
|
1566
|
+
callback({
|
|
1567
|
+
error: false,
|
|
1568
|
+
errorCode: "",
|
|
1569
|
+
errorMsg: "",
|
|
1570
|
+
image,
|
|
1571
|
+
cameraStream,
|
|
1572
|
+
videoElement,
|
|
1573
|
+
webcamVideoElement,
|
|
1574
|
+
savedRenderingContexts: renderingContextsToSave,
|
|
1575
|
+
keepCameraOn
|
|
1576
|
+
});
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
numFrames = numFrames !== void 0 ? numFrames : 10;
|
|
1582
|
+
interval = interval !== void 0 ? interval : 0.1;
|
|
1583
|
+
canvas2.width = gifWidth;
|
|
1584
|
+
canvas2.height = gifHeight;
|
|
1585
|
+
context = canvas2.getContext("2d");
|
|
1586
|
+
(function capture() {
|
|
1587
|
+
if (!savedRenderingContexts.length && videoElement.currentTime === 0) {
|
|
1588
|
+
utils.requestTimeout(capture, 100);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
captureFrames();
|
|
1592
|
+
})();
|
|
1593
|
+
},
|
|
1594
|
+
getCropDimensions: function getCropDimensions() {
|
|
1595
|
+
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1596
|
+
const width = obj.videoWidth;
|
|
1597
|
+
const height = obj.videoHeight;
|
|
1598
|
+
const gifWidth = obj.gifWidth;
|
|
1599
|
+
const gifHeight = obj.gifHeight;
|
|
1600
|
+
const result = {
|
|
1601
|
+
width: 0,
|
|
1602
|
+
height: 0,
|
|
1603
|
+
scaledWidth: 0,
|
|
1604
|
+
scaledHeight: 0
|
|
1605
|
+
};
|
|
1606
|
+
if (width > height) {
|
|
1607
|
+
result.width = Math.round(width * (gifHeight / height)) - gifWidth;
|
|
1608
|
+
result.scaledWidth = Math.round(result.width * (height / gifHeight));
|
|
1609
|
+
} else {
|
|
1610
|
+
result.height = Math.round(height * (gifWidth / width)) - gifHeight;
|
|
1611
|
+
result.scaledHeight = Math.round(result.height * (width / gifWidth));
|
|
1612
|
+
}
|
|
1613
|
+
return result;
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
var videoStream = {
|
|
1617
|
+
loadedData: false,
|
|
1618
|
+
defaultVideoDimensions: {
|
|
1619
|
+
width: 640,
|
|
1620
|
+
height: 480
|
|
1621
|
+
},
|
|
1622
|
+
findVideoSize: function findVideoSizeMethod(obj) {
|
|
1623
|
+
findVideoSizeMethod.attempts = findVideoSizeMethod.attempts || 0;
|
|
1624
|
+
const cameraStream = obj.cameraStream;
|
|
1625
|
+
const completedCallback = obj.completedCallback;
|
|
1626
|
+
const videoElement = obj.videoElement;
|
|
1627
|
+
if (!videoElement) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (videoElement.videoWidth > 0 && videoElement.videoHeight > 0) {
|
|
1631
|
+
videoElement.removeEventListener("loadeddata", videoStream.findVideoSize);
|
|
1632
|
+
completedCallback({
|
|
1633
|
+
videoElement,
|
|
1634
|
+
cameraStream,
|
|
1635
|
+
videoWidth: videoElement.videoWidth,
|
|
1636
|
+
videoHeight: videoElement.videoHeight
|
|
1637
|
+
});
|
|
1638
|
+
} else if (findVideoSizeMethod.attempts < 10) {
|
|
1639
|
+
findVideoSizeMethod.attempts += 1;
|
|
1640
|
+
utils.requestTimeout(function() {
|
|
1641
|
+
videoStream.findVideoSize(obj);
|
|
1642
|
+
}, 400);
|
|
1643
|
+
} else {
|
|
1644
|
+
completedCallback({
|
|
1645
|
+
videoElement,
|
|
1646
|
+
cameraStream,
|
|
1647
|
+
videoWidth: videoStream.defaultVideoDimensions.width,
|
|
1648
|
+
videoHeight: videoStream.defaultVideoDimensions.height
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
onStreamingTimeout: function onStreamingTimeout(callback) {
|
|
1653
|
+
if (utils.isFunction(callback)) {
|
|
1654
|
+
callback({
|
|
1655
|
+
error: true,
|
|
1656
|
+
errorCode: "getUserMedia",
|
|
1657
|
+
errorMsg: "There was an issue with the getUserMedia API - Timed out while trying to start streaming",
|
|
1658
|
+
image: null,
|
|
1659
|
+
cameraStream: {}
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
stream: function stream(obj) {
|
|
1664
|
+
const existingVideo2 = utils.isArray(obj.existingVideo) ? obj.existingVideo[0] : obj.existingVideo;
|
|
1665
|
+
const cameraStream = obj.cameraStream;
|
|
1666
|
+
const completedCallback = obj.completedCallback;
|
|
1667
|
+
const streamedCallback = obj.streamedCallback;
|
|
1668
|
+
const videoElement = obj.videoElement;
|
|
1669
|
+
if (utils.isFunction(streamedCallback)) {
|
|
1670
|
+
streamedCallback();
|
|
1671
|
+
}
|
|
1672
|
+
if (existingVideo2) {
|
|
1673
|
+
if (utils.isString(existingVideo2)) {
|
|
1674
|
+
videoElement.src = existingVideo2;
|
|
1675
|
+
videoElement.innerHTML = `<source src="${existingVideo2}" type="video/${utils.getExtension(
|
|
1676
|
+
existingVideo2
|
|
1677
|
+
)}" />`;
|
|
1678
|
+
} else if (existingVideo2 instanceof Blob) {
|
|
1679
|
+
try {
|
|
1680
|
+
videoElement.src = utils.URL.createObjectURL(existingVideo2);
|
|
1681
|
+
} catch (e) {
|
|
1682
|
+
}
|
|
1683
|
+
videoElement.innerHTML = `<source src="${existingVideo2}" type="${existingVideo2.type}" />`;
|
|
1684
|
+
}
|
|
1685
|
+
} else if (videoElement.mozSrcObject) {
|
|
1686
|
+
videoElement.mozSrcObject = cameraStream;
|
|
1687
|
+
} else if (utils.URL) {
|
|
1688
|
+
try {
|
|
1689
|
+
videoElement.srcObject = cameraStream;
|
|
1690
|
+
videoElement.src = utils.URL.createObjectURL(cameraStream);
|
|
1691
|
+
} catch (e) {
|
|
1692
|
+
videoElement.srcObject = cameraStream;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
videoElement.play();
|
|
1696
|
+
utils.requestTimeout(function checkLoadedData() {
|
|
1697
|
+
checkLoadedData.count = checkLoadedData.count || 0;
|
|
1698
|
+
if (videoStream.loadedData === true) {
|
|
1699
|
+
videoStream.findVideoSize({
|
|
1700
|
+
videoElement,
|
|
1701
|
+
cameraStream,
|
|
1702
|
+
completedCallback
|
|
1703
|
+
});
|
|
1704
|
+
videoStream.loadedData = false;
|
|
1705
|
+
} else {
|
|
1706
|
+
checkLoadedData.count += 1;
|
|
1707
|
+
if (checkLoadedData.count > 10) {
|
|
1708
|
+
videoStream.findVideoSize({
|
|
1709
|
+
videoElement,
|
|
1710
|
+
cameraStream,
|
|
1711
|
+
completedCallback
|
|
1712
|
+
});
|
|
1713
|
+
} else {
|
|
1714
|
+
checkLoadedData();
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}, 0);
|
|
1718
|
+
},
|
|
1719
|
+
startStreaming: function startStreaming(obj) {
|
|
1720
|
+
const errorCallback = utils.isFunction(obj.error) ? obj.error : utils.noop;
|
|
1721
|
+
const streamedCallback = utils.isFunction(obj.streamed) ? obj.streamed : utils.noop;
|
|
1722
|
+
const completedCallback = utils.isFunction(obj.completed) ? obj.completed : utils.noop;
|
|
1723
|
+
const crossOrigin = obj.crossOrigin;
|
|
1724
|
+
const existingVideo2 = obj.existingVideo;
|
|
1725
|
+
const lastCameraStream = obj.lastCameraStream;
|
|
1726
|
+
const options = obj.options;
|
|
1727
|
+
const webcamVideoElement = obj.webcamVideoElement;
|
|
1728
|
+
const videoElement = utils.isElement(existingVideo2) ? existingVideo2 : webcamVideoElement ? webcamVideoElement : document.createElement("video");
|
|
1729
|
+
const cameraStream = void 0;
|
|
1730
|
+
if (crossOrigin) {
|
|
1731
|
+
videoElement.crossOrigin = options.crossOrigin;
|
|
1732
|
+
}
|
|
1733
|
+
videoElement.autoplay = true;
|
|
1734
|
+
videoElement.loop = true;
|
|
1735
|
+
videoElement.muted = true;
|
|
1736
|
+
videoElement.addEventListener("loadeddata", function(event) {
|
|
1737
|
+
videoStream.loadedData = true;
|
|
1738
|
+
if (options.offset) {
|
|
1739
|
+
videoElement.currentTime = options.offset;
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
if (existingVideo2) {
|
|
1743
|
+
videoStream.stream({
|
|
1744
|
+
videoElement,
|
|
1745
|
+
existingVideo: existingVideo2,
|
|
1746
|
+
completedCallback
|
|
1747
|
+
});
|
|
1748
|
+
} else if (lastCameraStream) {
|
|
1749
|
+
videoStream.stream({
|
|
1750
|
+
videoElement,
|
|
1751
|
+
cameraStream: lastCameraStream,
|
|
1752
|
+
streamedCallback,
|
|
1753
|
+
completedCallback
|
|
1754
|
+
});
|
|
1755
|
+
} else {
|
|
1756
|
+
utils.getUserMedia(
|
|
1757
|
+
{
|
|
1758
|
+
video: true
|
|
1759
|
+
},
|
|
1760
|
+
function(stream2) {
|
|
1761
|
+
videoStream.stream({
|
|
1762
|
+
videoElement,
|
|
1763
|
+
cameraStream: stream2,
|
|
1764
|
+
streamedCallback,
|
|
1765
|
+
completedCallback
|
|
1766
|
+
});
|
|
1767
|
+
},
|
|
1768
|
+
errorCallback
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
startVideoStreaming: function startVideoStreaming(callback) {
|
|
1773
|
+
const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
1774
|
+
const timeoutLength = options.timeout !== void 0 ? options.timeout : 0;
|
|
1775
|
+
const originalCallback = options.callback;
|
|
1776
|
+
const webcamVideoElement = options.webcamVideoElement;
|
|
1777
|
+
let noGetUserMediaSupportTimeout = void 0;
|
|
1778
|
+
if (timeoutLength > 0) {
|
|
1779
|
+
noGetUserMediaSupportTimeout = utils.requestTimeout(function() {
|
|
1780
|
+
videoStream.onStreamingTimeout(originalCallback);
|
|
1781
|
+
}, 1e4);
|
|
1782
|
+
}
|
|
1783
|
+
videoStream.startStreaming({
|
|
1784
|
+
error: function error2() {
|
|
1785
|
+
originalCallback({
|
|
1786
|
+
error: true,
|
|
1787
|
+
errorCode: "getUserMedia",
|
|
1788
|
+
errorMsg: "There was an issue with the getUserMedia API - the user probably denied permission",
|
|
1789
|
+
image: null,
|
|
1790
|
+
cameraStream: {}
|
|
1791
|
+
});
|
|
1792
|
+
},
|
|
1793
|
+
streamed: function streamed() {
|
|
1794
|
+
clearTimeout(noGetUserMediaSupportTimeout);
|
|
1795
|
+
},
|
|
1796
|
+
completed: function completed() {
|
|
1797
|
+
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1798
|
+
const cameraStream = obj.cameraStream;
|
|
1799
|
+
const videoElement = obj.videoElement;
|
|
1800
|
+
const videoHeight = obj.videoHeight;
|
|
1801
|
+
const videoWidth = obj.videoWidth;
|
|
1802
|
+
callback({
|
|
1803
|
+
cameraStream,
|
|
1804
|
+
videoElement,
|
|
1805
|
+
videoHeight,
|
|
1806
|
+
videoWidth
|
|
1807
|
+
});
|
|
1808
|
+
},
|
|
1809
|
+
lastCameraStream: options.lastCameraStream,
|
|
1810
|
+
webcamVideoElement,
|
|
1811
|
+
crossOrigin: options.crossOrigin,
|
|
1812
|
+
options
|
|
1813
|
+
});
|
|
1814
|
+
},
|
|
1815
|
+
stopVideoStreaming: function stopVideoStreaming(obj) {
|
|
1816
|
+
obj = utils.isObject(obj) ? obj : {};
|
|
1817
|
+
const _obj = obj;
|
|
1818
|
+
const keepCameraOn = _obj.keepCameraOn;
|
|
1819
|
+
const videoElement = _obj.videoElement;
|
|
1820
|
+
const webcamVideoElement = _obj.webcamVideoElement;
|
|
1821
|
+
const cameraStream = obj.cameraStream || {};
|
|
1822
|
+
const cameraStreamTracks = cameraStream.getTracks ? cameraStream.getTracks() || [] : [];
|
|
1823
|
+
const hasCameraStreamTracks = Boolean(cameraStreamTracks.length);
|
|
1824
|
+
const firstCameraStreamTrack = cameraStreamTracks[0];
|
|
1825
|
+
if (!keepCameraOn && hasCameraStreamTracks) {
|
|
1826
|
+
if (utils.isFunction(firstCameraStreamTrack.stop)) {
|
|
1827
|
+
firstCameraStreamTrack.stop();
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
if (utils.isElement(videoElement) && !webcamVideoElement) {
|
|
1831
|
+
videoElement.pause();
|
|
1832
|
+
if (utils.isFunction(utils.URL.revokeObjectURL) && !utils.webWorkerError) {
|
|
1833
|
+
if (videoElement.src) {
|
|
1834
|
+
utils.URL.revokeObjectURL(videoElement.src);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
utils.removeElement(videoElement);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1841
|
+
function stopVideoStreaming2(options) {
|
|
1842
|
+
options = utils.isObject(options) ? options : {};
|
|
1843
|
+
videoStream.stopVideoStreaming(options);
|
|
1844
|
+
}
|
|
1845
|
+
function createAndGetGIF(obj, callback) {
|
|
1846
|
+
const options = obj.options || {};
|
|
1847
|
+
const images = options.images;
|
|
1848
|
+
const video = options.video;
|
|
1849
|
+
const gifWidth = Number(options.gifWidth);
|
|
1850
|
+
const gifHeight = Number(options.gifHeight);
|
|
1851
|
+
const numFrames = Number(options.numFrames);
|
|
1852
|
+
const cameraStream = obj.cameraStream;
|
|
1853
|
+
const videoElement = obj.videoElement;
|
|
1854
|
+
const videoWidth = obj.videoWidth;
|
|
1855
|
+
const videoHeight = obj.videoHeight;
|
|
1856
|
+
const cropDimensions = screenShot.getCropDimensions({
|
|
1857
|
+
videoWidth,
|
|
1858
|
+
videoHeight,
|
|
1859
|
+
gifHeight,
|
|
1860
|
+
gifWidth
|
|
1861
|
+
});
|
|
1862
|
+
const completeCallback = callback;
|
|
1863
|
+
options.crop = cropDimensions;
|
|
1864
|
+
options.videoElement = videoElement;
|
|
1865
|
+
options.videoWidth = videoWidth;
|
|
1866
|
+
options.videoHeight = videoHeight;
|
|
1867
|
+
options.cameraStream = cameraStream;
|
|
1868
|
+
if (!utils.isElement(videoElement)) {
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
videoElement.width = gifWidth + cropDimensions.width;
|
|
1872
|
+
videoElement.height = gifHeight + cropDimensions.height;
|
|
1873
|
+
if (!options.webcamVideoElement) {
|
|
1874
|
+
utils.setCSSAttr(videoElement, {
|
|
1875
|
+
position: "fixed",
|
|
1876
|
+
opacity: "0"
|
|
1877
|
+
});
|
|
1878
|
+
document.body.appendChild(videoElement);
|
|
1879
|
+
}
|
|
1880
|
+
videoElement.play();
|
|
1881
|
+
screenShot.getGIF(options, function(obj2) {
|
|
1882
|
+
if ((!images || !images.length) && (!video || !video.length)) {
|
|
1883
|
+
stopVideoStreaming2(obj2);
|
|
1884
|
+
}
|
|
1885
|
+
completeCallback(obj2);
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
function existingVideo() {
|
|
1889
|
+
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1890
|
+
const callback = obj.callback;
|
|
1891
|
+
let existingVideo2 = obj.existingVideo;
|
|
1892
|
+
const options = obj.options;
|
|
1893
|
+
const skipObj = {
|
|
1894
|
+
getUserMedia: true,
|
|
1895
|
+
"globalThis.URL": true
|
|
1896
|
+
};
|
|
1897
|
+
const errorObj = error.validate(skipObj);
|
|
1898
|
+
const loadedImages = 0;
|
|
1899
|
+
let videoType = void 0;
|
|
1900
|
+
let videoSrc = void 0;
|
|
1901
|
+
const tempImage = void 0;
|
|
1902
|
+
const ag = void 0;
|
|
1903
|
+
if (errorObj.error) {
|
|
1904
|
+
return callback(errorObj);
|
|
1905
|
+
}
|
|
1906
|
+
if (utils.isElement(existingVideo2) && existingVideo2.src) {
|
|
1907
|
+
videoSrc = existingVideo2.src;
|
|
1908
|
+
videoType = utils.getExtension(videoSrc);
|
|
1909
|
+
if (!utils.isSupported.videoCodecs[videoType]) {
|
|
1910
|
+
return callback(error.messages.videoCodecs);
|
|
1911
|
+
}
|
|
1912
|
+
} else if (utils.isArray(existingVideo2)) {
|
|
1913
|
+
utils.each(existingVideo2, function(iterator, videoSrc2) {
|
|
1914
|
+
if (videoSrc2 instanceof Blob) {
|
|
1915
|
+
videoType = videoSrc2.type.substr(videoSrc2.type.lastIndexOf("/") + 1, videoSrc2.length);
|
|
1916
|
+
} else {
|
|
1917
|
+
videoType = videoSrc2.substr(videoSrc2.lastIndexOf(".") + 1, videoSrc2.length);
|
|
1918
|
+
}
|
|
1919
|
+
if (utils.isSupported.videoCodecs[videoType]) {
|
|
1920
|
+
existingVideo2 = videoSrc2;
|
|
1921
|
+
return false;
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
videoStream.startStreaming({
|
|
1926
|
+
completed: function completed(obj2) {
|
|
1927
|
+
obj2.options = options || {};
|
|
1928
|
+
createAndGetGIF(obj2, callback);
|
|
1929
|
+
},
|
|
1930
|
+
existingVideo: existingVideo2,
|
|
1931
|
+
crossOrigin: options.crossOrigin,
|
|
1932
|
+
options
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
function existingWebcam() {
|
|
1936
|
+
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1937
|
+
const callback = obj.callback;
|
|
1938
|
+
const lastCameraStream = obj.lastCameraStream;
|
|
1939
|
+
const options = obj.options;
|
|
1940
|
+
const webcamVideoElement = obj.webcamVideoElement;
|
|
1941
|
+
if (!isWebCamGIFSupported()) {
|
|
1942
|
+
return callback(error.validate());
|
|
1943
|
+
}
|
|
1944
|
+
if (options.savedRenderingContexts.length) {
|
|
1945
|
+
screenShot.getGIF(options, function(obj2) {
|
|
1946
|
+
callback(obj2);
|
|
1947
|
+
});
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
videoStream.startVideoStreaming(
|
|
1951
|
+
function() {
|
|
1952
|
+
const obj2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1953
|
+
obj2.options = options || {};
|
|
1954
|
+
createAndGetGIF(obj2, callback);
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
lastCameraStream,
|
|
1958
|
+
callback,
|
|
1959
|
+
webcamVideoElement,
|
|
1960
|
+
crossOrigin: options.crossOrigin
|
|
1961
|
+
}
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
function createGIF(userOptions, callback) {
|
|
1965
|
+
callback = utils.isFunction(userOptions) ? userOptions : callback;
|
|
1966
|
+
userOptions = utils.isObject(userOptions) ? userOptions : {};
|
|
1967
|
+
if (!utils.isFunction(callback)) {
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
let options = utils.normalizeOptions(defaultOptions, userOptions) || {};
|
|
1971
|
+
const lastCameraStream = userOptions.cameraStream;
|
|
1972
|
+
const images = options.images;
|
|
1973
|
+
const imagesLength = images ? images.length : 0;
|
|
1974
|
+
const video = options.video;
|
|
1975
|
+
const webcamVideoElement = options.webcamVideoElement;
|
|
1976
|
+
options = utils.normalizeOptions(options, {
|
|
1977
|
+
gifWidth: Math.floor(options.gifWidth),
|
|
1978
|
+
gifHeight: Math.floor(options.gifHeight)
|
|
1979
|
+
});
|
|
1980
|
+
if (imagesLength) {
|
|
1981
|
+
existingImages({
|
|
1982
|
+
images,
|
|
1983
|
+
imagesLength,
|
|
1984
|
+
callback,
|
|
1985
|
+
options
|
|
1986
|
+
});
|
|
1987
|
+
} else if (video) {
|
|
1988
|
+
existingVideo({
|
|
1989
|
+
existingVideo: video,
|
|
1990
|
+
callback,
|
|
1991
|
+
options
|
|
1992
|
+
});
|
|
1993
|
+
} else {
|
|
1994
|
+
existingWebcam({
|
|
1995
|
+
lastCameraStream,
|
|
1996
|
+
callback,
|
|
1997
|
+
webcamVideoElement,
|
|
1998
|
+
options
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
function takeSnapShot(userOptions, callback) {
|
|
2003
|
+
callback = utils.isFunction(userOptions) ? userOptions : callback;
|
|
2004
|
+
userOptions = utils.isObject(userOptions) ? userOptions : {};
|
|
2005
|
+
if (!utils.isFunction(callback)) {
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
const mergedOptions = utils.normalizeOptions(defaultOptions, userOptions);
|
|
2009
|
+
const options = utils.normalizeOptions(mergedOptions, {
|
|
2010
|
+
interval: 0.1,
|
|
2011
|
+
numFrames: 1,
|
|
2012
|
+
gifWidth: Math.floor(mergedOptions.gifWidth),
|
|
2013
|
+
gifHeight: Math.floor(mergedOptions.gifHeight)
|
|
2014
|
+
});
|
|
2015
|
+
createGIF(options, callback);
|
|
2016
|
+
}
|
|
2017
|
+
var API = {
|
|
2018
|
+
utils: utils$2,
|
|
2019
|
+
error: error$2,
|
|
2020
|
+
defaultOptions: defaultOptions$2,
|
|
2021
|
+
createGIF,
|
|
2022
|
+
takeSnapShot,
|
|
2023
|
+
stopVideoStreaming: stopVideoStreaming2,
|
|
2024
|
+
isSupported,
|
|
2025
|
+
isWebCamGIFSupported,
|
|
2026
|
+
isExistingVideoGIFSupported,
|
|
2027
|
+
isExistingImagesGIFSupported: isSupported$1,
|
|
2028
|
+
VERSION: "0.4.5"
|
|
2029
|
+
};
|
|
2030
|
+
var gifshot_default = API;
|
|
2031
|
+
|
|
2032
|
+
// src/gif-builder.ts
|
|
2033
|
+
var GIF_BUILDER_OPTIONS = {
|
|
2034
|
+
source: "images",
|
|
2035
|
+
width: 200,
|
|
2036
|
+
// Desired width of the image
|
|
2037
|
+
height: 200,
|
|
2038
|
+
// Desired height of the image
|
|
2039
|
+
crossOrigin: "Anonymous",
|
|
2040
|
+
// Options are 'Anonymous', 'use-credentials', or a falsy value to not set a CORS attribute.
|
|
2041
|
+
// CALLBACKS
|
|
2042
|
+
progressCallback: (captureProgress) => {
|
|
2043
|
+
},
|
|
2044
|
+
// Callback that provides the current progress of the current image
|
|
2045
|
+
completeCallback: () => {
|
|
2046
|
+
},
|
|
2047
|
+
// Callback function that is called when the current image is completed
|
|
2048
|
+
// QUALITY SETTINGS
|
|
2049
|
+
numWorkers: 2,
|
|
2050
|
+
// how many web workers to use to process the animated GIF frames. Default is 2.
|
|
2051
|
+
sampleInterval: 10,
|
|
2052
|
+
// pixels to skip when creating the palette. Default is 10. Less is better, but slower.
|
|
2053
|
+
interval: 0.1,
|
|
2054
|
+
// The amount of time (in seconds) to wait between each frame capture
|
|
2055
|
+
offset: null,
|
|
2056
|
+
// The amount of time (in seconds) to start capturing the GIF (only for HTML5 videos)
|
|
2057
|
+
numFrames: 10,
|
|
2058
|
+
// The number of frames to use to create the animated GIF. Note: Each frame is captured every 100 milliseconds of a video and every ms for existing images
|
|
2059
|
+
frameDuration: 1,
|
|
2060
|
+
// The amount of time (10 = 1s) to stay on each frame
|
|
2061
|
+
// CSS FILTER OPTIONS
|
|
2062
|
+
filter: "",
|
|
2063
|
+
// CSS filter that will be applied to the image (eg. blur(5px))
|
|
2064
|
+
// WATERMARK OPTIONS
|
|
2065
|
+
waterMark: null,
|
|
2066
|
+
// If an image is given here, it will be stamped on top of the GIF frames
|
|
2067
|
+
waterMarkHeight: null,
|
|
2068
|
+
// Height of the waterMark
|
|
2069
|
+
waterMarkWidth: null,
|
|
2070
|
+
// Height of the waterMark
|
|
2071
|
+
waterMarkXCoordinate: 1,
|
|
2072
|
+
// The X (horizontal) Coordinate of the watermark image
|
|
2073
|
+
waterMarkYCoordinate: 1,
|
|
2074
|
+
// The Y (vertical) Coordinate of the watermark image
|
|
2075
|
+
// TEXT OPTIONS
|
|
2076
|
+
text: "",
|
|
2077
|
+
// The text that covers the animated GIF
|
|
2078
|
+
showFrameText: true,
|
|
2079
|
+
// If frame-specific text is supplied with the image array, you can force to not be displayed
|
|
2080
|
+
fontWeight: "normal",
|
|
2081
|
+
// The font weight of the text that covers the animated GIF
|
|
2082
|
+
fontSize: "16px",
|
|
2083
|
+
// The font size of the text that covers the animated GIF
|
|
2084
|
+
minFontSize: "10px",
|
|
2085
|
+
// The minimum font size of the text that covers the animated GIF
|
|
2086
|
+
resizeFont: false,
|
|
2087
|
+
// Whether or not the animated GIF text will be resized to fit within the GIF container
|
|
2088
|
+
fontFamily: "sans-serif",
|
|
2089
|
+
// The font family of the text that covers the animated GIF
|
|
2090
|
+
fontColor: "#ffffff",
|
|
2091
|
+
// The font color of the text that covers the animated GIF
|
|
2092
|
+
textAlign: "center",
|
|
2093
|
+
// The horizontal text alignment of the text that covers the animated GIF
|
|
2094
|
+
textBaseline: "bottom",
|
|
2095
|
+
// The vertical text alignment of the text that covers the animated GIF
|
|
2096
|
+
textXCoordinate: null,
|
|
2097
|
+
// The X (horizontal) Coordinate of the text that covers the animated GIF
|
|
2098
|
+
textYCoordinate: null,
|
|
2099
|
+
// The Y (vertical) Coordinate of the text that covers the animated GIF
|
|
2100
|
+
// ADVANCED OPTIONS
|
|
2101
|
+
// WEBCAM CAPTURE OPTIONS
|
|
2102
|
+
webcamVideoElement: null,
|
|
2103
|
+
// You can pass an existing video element to use for the webcam GIF creation process,
|
|
2104
|
+
keepCameraOn: false,
|
|
2105
|
+
// Whether or not you would like the user's camera to stay on after the GIF is created
|
|
2106
|
+
cameraStream: null,
|
|
2107
|
+
// Expects a cameraStream Media object
|
|
2108
|
+
// CANVAS OPTIMIZATION OPTIONS
|
|
2109
|
+
saveRenderingContexts: false,
|
|
2110
|
+
// Whether or not you would like to save all of the canvas image binary data
|
|
2111
|
+
savedRenderingContexts: []
|
|
2112
|
+
// Array of canvas image data
|
|
2113
|
+
};
|
|
2114
|
+
var GIFBuilder = class {
|
|
2115
|
+
static get properties() {
|
|
2116
|
+
return {
|
|
2117
|
+
id: "gif",
|
|
2118
|
+
name: "GIF",
|
|
2119
|
+
extensions: ["gif"],
|
|
2120
|
+
mimeTypes: ["image/gif"],
|
|
2121
|
+
builder: GIFBuilder,
|
|
2122
|
+
options: GIF_BUILDER_OPTIONS
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
constructor(options) {
|
|
2126
|
+
this.options = { ...options };
|
|
2127
|
+
this.source = options.source;
|
|
2128
|
+
delete options.source;
|
|
2129
|
+
this.files = [];
|
|
2130
|
+
this.gifshot = gifshot_default;
|
|
2131
|
+
}
|
|
2132
|
+
async initialize(options) {
|
|
2133
|
+
}
|
|
2134
|
+
async add(file) {
|
|
2135
|
+
await this.initialize();
|
|
2136
|
+
this.files.push(file);
|
|
2137
|
+
}
|
|
2138
|
+
async build() {
|
|
2139
|
+
await this.initialize();
|
|
2140
|
+
this._cleanOptions(this.options);
|
|
2141
|
+
switch (this.source) {
|
|
2142
|
+
case "images":
|
|
2143
|
+
this.options.images = this.files;
|
|
2144
|
+
break;
|
|
2145
|
+
case "video":
|
|
2146
|
+
this.options.video = this.files;
|
|
2147
|
+
break;
|
|
2148
|
+
case "webcam":
|
|
2149
|
+
assert(this.files.length === 0);
|
|
2150
|
+
break;
|
|
2151
|
+
default:
|
|
2152
|
+
throw new Error("GIFBuilder: invalid source");
|
|
2153
|
+
}
|
|
2154
|
+
return await this._createGIF();
|
|
2155
|
+
}
|
|
2156
|
+
// PRIVATE
|
|
2157
|
+
async _createGIF() {
|
|
2158
|
+
return new Promise((resolve, reject) => {
|
|
2159
|
+
this.gifshot.createGIF(this.options, (result) => {
|
|
2160
|
+
if (result.error) {
|
|
2161
|
+
reject(result.errorMsg);
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
resolve(result.image);
|
|
2165
|
+
});
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
// Remove some gifshot options
|
|
2169
|
+
_cleanOptions(options) {
|
|
2170
|
+
if (options.video || options.images || options.gifWidth || options.gifHeight) {
|
|
2171
|
+
console.warn("GIFBuilder: ignoring options");
|
|
2172
|
+
}
|
|
2173
|
+
delete options.video;
|
|
2174
|
+
delete options.images;
|
|
2175
|
+
options.gifWidth = options.width;
|
|
2176
|
+
options.gifHeight = options.height;
|
|
2177
|
+
delete options.width;
|
|
2178
|
+
delete options.height;
|
|
2179
|
+
}
|
|
2180
|
+
};
|