@remotion/gif 3.3.61 → 3.3.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Gif.d.ts +7 -0
- package/dist/cjs/Gif.js +19 -0
- package/dist/cjs/GifForDevelopment.d.ts +3 -0
- package/dist/cjs/GifForDevelopment.js +81 -0
- package/dist/cjs/GifForRendering.d.ts +3 -0
- package/dist/cjs/GifForRendering.js +80 -0
- package/dist/cjs/canvas.d.ts +13 -0
- package/dist/cjs/canvas.js +96 -0
- package/dist/cjs/get-gif-duration-in-seconds.d.ts +5 -0
- package/dist/cjs/get-gif-duration-in-seconds.js +34 -0
- package/dist/cjs/gif-cache.d.ts +4 -0
- package/dist/cjs/gif-cache.js +6 -0
- package/dist/cjs/gifuct/deinterlace.d.ts +4 -0
- package/dist/cjs/gifuct/deinterlace.js +26 -0
- package/dist/cjs/gifuct/index.d.ts +4 -0
- package/dist/cjs/gifuct/index.js +54 -0
- package/dist/cjs/gifuct/lzw.d.ts +5 -0
- package/dist/cjs/gifuct/lzw.js +119 -0
- package/dist/cjs/gifuct/types.d.ts +96 -0
- package/dist/cjs/gifuct/types.js +2 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +9 -0
- package/dist/cjs/is-cors-error.d.ts +1 -0
- package/dist/cjs/is-cors-error.js +13 -0
- package/dist/cjs/js-binary-schema-parser/gif.d.ts +51 -0
- package/dist/cjs/js-binary-schema-parser/gif.js +158 -0
- package/dist/cjs/js-binary-schema-parser/parser.d.ts +9 -0
- package/dist/cjs/js-binary-schema-parser/parser.js +54 -0
- package/dist/cjs/js-binary-schema-parser/uint8-parser.d.ts +17 -0
- package/dist/cjs/js-binary-schema-parser/uint8-parser.js +79 -0
- package/dist/cjs/lru/index.d.ts +101 -0
- package/dist/cjs/lru/index.js +258 -0
- package/dist/cjs/parse-generate.d.ts +18 -0
- package/dist/cjs/parse-generate.js +96 -0
- package/dist/cjs/parser/decompress-frames.d.ts +2 -0
- package/dist/cjs/parser/decompress-frames.js +19 -0
- package/dist/cjs/preload-gif.d.ts +8 -0
- package/dist/cjs/preload-gif.js +41 -0
- package/dist/cjs/props.d.ts +24 -0
- package/dist/cjs/props.js +2 -0
- package/dist/cjs/react-tools.d.ts +9 -0
- package/dist/cjs/react-tools.js +40 -0
- package/dist/cjs/resolve-gif-source.d.ts +1 -0
- package/dist/cjs/resolve-gif-source.js +7 -0
- package/dist/cjs/use-element-size.d.ts +6 -0
- package/dist/cjs/use-element-size.js +73 -0
- package/dist/cjs/useCurrentGifIndex.d.ts +2 -0
- package/dist/cjs/useCurrentGifIndex.js +35 -0
- package/dist/cjs/worker/index.d.ts +1 -0
- package/dist/cjs/worker/index.js +12 -0
- package/dist/cjs/worker/source.d.ts +1 -0
- package/dist/cjs/worker/source.js +7 -0
- package/dist/cjs/worker/worker.d.ts +1 -0
- package/dist/cjs/worker/worker.js +39 -0
- package/dist/esm/Gif.d.ts +7 -0
- package/dist/esm/GifForDevelopment.d.ts +3 -0
- package/dist/esm/GifForRendering.d.ts +3 -0
- package/dist/esm/canvas.d.ts +13 -0
- package/dist/esm/get-gif-duration-in-seconds.d.ts +5 -0
- package/dist/esm/gif-cache.d.ts +4 -0
- package/dist/esm/gifuct/deinterlace.d.ts +4 -0
- package/dist/esm/gifuct/index.d.ts +4 -0
- package/dist/esm/gifuct/lzw.d.ts +5 -0
- package/dist/esm/gifuct/types.d.ts +96 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.mjs +1276 -0
- package/dist/esm/is-cors-error.d.ts +1 -0
- package/dist/esm/js-binary-schema-parser/gif.d.ts +51 -0
- package/dist/esm/js-binary-schema-parser/parser.d.ts +9 -0
- package/dist/esm/js-binary-schema-parser/uint8-parser.d.ts +17 -0
- package/dist/esm/lru/index.d.ts +101 -0
- package/dist/esm/parse-generate.d.ts +18 -0
- package/dist/esm/parser/decompress-frames.d.ts +2 -0
- package/dist/esm/preload-gif.d.ts +8 -0
- package/dist/esm/props.d.ts +24 -0
- package/dist/esm/react-tools.d.ts +9 -0
- package/dist/esm/resolve-gif-source.d.ts +1 -0
- package/dist/esm/use-element-size.d.ts +6 -0
- package/dist/esm/useCurrentGifIndex.d.ts +2 -0
- package/dist/esm/worker/index.d.ts +1 -0
- package/dist/esm/worker/source.d.ts +1 -0
- package/dist/esm/worker/worker.d.ts +1 -0
- package/dist/react-tools.js +0 -1
- package/dist/tsconfig-esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +19 -8
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuickLRU = void 0;
|
|
4
|
+
class QuickLRU {
|
|
5
|
+
/**
|
|
6
|
+
Simple ["Least Recently Used" (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29).
|
|
7
|
+
|
|
8
|
+
The instance is an [`Iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) of `[key, value]` pairs so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
|
|
9
|
+
|
|
10
|
+
@example
|
|
11
|
+
```
|
|
12
|
+
import { QuickLRU } from 'quick-lru-ts';
|
|
13
|
+
|
|
14
|
+
const lru = new QuickLRU({maxSize: 1000});
|
|
15
|
+
|
|
16
|
+
lru.set('🦄', '🌈');
|
|
17
|
+
|
|
18
|
+
lru.has('🦄');
|
|
19
|
+
//=> true
|
|
20
|
+
|
|
21
|
+
lru.get('🦄');
|
|
22
|
+
//=> '🌈'
|
|
23
|
+
```
|
|
24
|
+
*/
|
|
25
|
+
constructor(options) {
|
|
26
|
+
if (!(options.maxSize && options.maxSize > 0)) {
|
|
27
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
28
|
+
}
|
|
29
|
+
if (typeof options.maxAge === 'number' && options.maxAge === 0) {
|
|
30
|
+
throw new TypeError('`maxAge` must be a number greater than 0');
|
|
31
|
+
}
|
|
32
|
+
this.maxSize = options.maxSize;
|
|
33
|
+
this.maxAge = options.maxAge || Number.POSITIVE_INFINITY;
|
|
34
|
+
this.onEviction = options.onEviction;
|
|
35
|
+
this.cache = new Map();
|
|
36
|
+
this.oldCache = new Map();
|
|
37
|
+
this._size = 0;
|
|
38
|
+
}
|
|
39
|
+
_emitEvictions(cache) {
|
|
40
|
+
if (typeof this.onEviction !== 'function') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const [key, item] of cache) {
|
|
44
|
+
this.onEviction(key, item.value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
_deleteIfExpired(key, item) {
|
|
48
|
+
if (item === undefined)
|
|
49
|
+
return true;
|
|
50
|
+
if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {
|
|
51
|
+
if (typeof this.onEviction === 'function') {
|
|
52
|
+
this.onEviction(key, item.value);
|
|
53
|
+
}
|
|
54
|
+
return this.delete(key);
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
_getOrDeleteIfExpired(key, item) {
|
|
59
|
+
const deleted = this._deleteIfExpired(key, item);
|
|
60
|
+
if (deleted === false) {
|
|
61
|
+
return item.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
_getItemValue(key, item) {
|
|
65
|
+
if (item === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;
|
|
68
|
+
}
|
|
69
|
+
_peek(key, cache) {
|
|
70
|
+
const item = cache.get(key);
|
|
71
|
+
return this._getItemValue(key, item);
|
|
72
|
+
}
|
|
73
|
+
_set(key, value) {
|
|
74
|
+
this.cache.set(key, value);
|
|
75
|
+
this._size++;
|
|
76
|
+
if (this._size >= this.maxSize) {
|
|
77
|
+
this._size = 0;
|
|
78
|
+
this._emitEvictions(this.oldCache);
|
|
79
|
+
this.oldCache = this.cache;
|
|
80
|
+
this.cache = new Map();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
_moveToRecent(key, item) {
|
|
84
|
+
this.oldCache.delete(key);
|
|
85
|
+
this._set(key, item);
|
|
86
|
+
}
|
|
87
|
+
*_entriesAscending() {
|
|
88
|
+
for (const item of this.oldCache) {
|
|
89
|
+
const [key, value] = item;
|
|
90
|
+
if (!this.cache.has(key)) {
|
|
91
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
92
|
+
if (deleted === false) {
|
|
93
|
+
yield item;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const item of this.cache) {
|
|
98
|
+
const [key, value] = item;
|
|
99
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
100
|
+
if (deleted === false) {
|
|
101
|
+
yield item;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
Get an item.
|
|
107
|
+
|
|
108
|
+
@returns The stored item or `undefined`.
|
|
109
|
+
*/
|
|
110
|
+
get(key) {
|
|
111
|
+
if (this.cache.has(key)) {
|
|
112
|
+
const item = this.cache.get(key);
|
|
113
|
+
return this._getItemValue(key, item);
|
|
114
|
+
}
|
|
115
|
+
if (this.oldCache.has(key)) {
|
|
116
|
+
const item = this.oldCache.get(key);
|
|
117
|
+
if (this._deleteIfExpired(key, item) === false) {
|
|
118
|
+
this._moveToRecent(key, item);
|
|
119
|
+
return item.value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
set(key, value, { maxAge = this.maxAge } = {}) {
|
|
124
|
+
const expiry = typeof maxAge === 'number' && maxAge !== Number.POSITIVE_INFINITY
|
|
125
|
+
? Date.now() + maxAge
|
|
126
|
+
: undefined;
|
|
127
|
+
if (this.cache.has(key)) {
|
|
128
|
+
this.cache.set(key, {
|
|
129
|
+
value,
|
|
130
|
+
expiry,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this._set(key, { value, expiry });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
has(key) {
|
|
138
|
+
if (this.cache.has(key)) {
|
|
139
|
+
return !this._deleteIfExpired(key, this.cache.get(key));
|
|
140
|
+
}
|
|
141
|
+
if (this.oldCache.has(key)) {
|
|
142
|
+
return !this._deleteIfExpired(key, this.oldCache.get(key));
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
peek(key) {
|
|
147
|
+
if (this.cache.has(key)) {
|
|
148
|
+
return this._peek(key, this.cache);
|
|
149
|
+
}
|
|
150
|
+
if (this.oldCache.has(key)) {
|
|
151
|
+
return this._peek(key, this.oldCache);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
delete(key) {
|
|
155
|
+
const deleted = this.cache.delete(key);
|
|
156
|
+
if (deleted) {
|
|
157
|
+
this._size--;
|
|
158
|
+
}
|
|
159
|
+
return this.oldCache.delete(key) || deleted;
|
|
160
|
+
}
|
|
161
|
+
clear() {
|
|
162
|
+
this.cache.clear();
|
|
163
|
+
this.oldCache.clear();
|
|
164
|
+
this._size = 0;
|
|
165
|
+
}
|
|
166
|
+
resize(maxSize) {
|
|
167
|
+
if (!(maxSize && maxSize > 0)) {
|
|
168
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
169
|
+
}
|
|
170
|
+
const items = [...this._entriesAscending()];
|
|
171
|
+
const removeCount = items.length - maxSize;
|
|
172
|
+
if (removeCount < 0) {
|
|
173
|
+
this.cache = new Map(items);
|
|
174
|
+
this.oldCache = new Map();
|
|
175
|
+
this._size = items.length;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
if (removeCount > 0) {
|
|
179
|
+
this._emitEvictions(items.slice(0, removeCount));
|
|
180
|
+
}
|
|
181
|
+
this.oldCache = new Map(items.slice(removeCount));
|
|
182
|
+
this.cache = new Map();
|
|
183
|
+
this._size = 0;
|
|
184
|
+
}
|
|
185
|
+
this.maxSize = maxSize;
|
|
186
|
+
}
|
|
187
|
+
*keys() {
|
|
188
|
+
for (const [key] of this) {
|
|
189
|
+
yield key;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
*values() {
|
|
193
|
+
for (const [, value] of this) {
|
|
194
|
+
yield value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
*[Symbol.iterator]() {
|
|
198
|
+
for (const item of this.cache) {
|
|
199
|
+
const [key, value] = item;
|
|
200
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
201
|
+
if (deleted === false) {
|
|
202
|
+
yield [key, value.value];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const item of this.oldCache) {
|
|
206
|
+
const [key, value] = item;
|
|
207
|
+
if (!this.cache.has(key)) {
|
|
208
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
209
|
+
if (deleted === false) {
|
|
210
|
+
yield [key, value.value];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
Iterable for all entries, starting with the newest (descending in recency).
|
|
217
|
+
*/
|
|
218
|
+
*entriesDescending() {
|
|
219
|
+
let items = [...this.cache];
|
|
220
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
221
|
+
const item = items[i];
|
|
222
|
+
const [key, value] = item;
|
|
223
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
224
|
+
if (deleted === false) {
|
|
225
|
+
yield [key, value.value];
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
items = [...this.oldCache];
|
|
229
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
230
|
+
const item = items[i];
|
|
231
|
+
const [key, value] = item;
|
|
232
|
+
if (!this.cache.has(key)) {
|
|
233
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
234
|
+
if (deleted === false) {
|
|
235
|
+
yield [key, value.value];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
*entriesAscending() {
|
|
241
|
+
for (const [key, value] of this._entriesAscending()) {
|
|
242
|
+
yield [key, value.value];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
get size() {
|
|
246
|
+
if (!this._size) {
|
|
247
|
+
return this.oldCache.size;
|
|
248
|
+
}
|
|
249
|
+
let oldCacheSize = 0;
|
|
250
|
+
for (const key of this.oldCache.keys()) {
|
|
251
|
+
if (!this.cache.has(key)) {
|
|
252
|
+
oldCacheSize++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return Math.min(this._size + oldCacheSize, this.maxSize);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
exports.QuickLRU = QuickLRU;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GifState } from './props';
|
|
2
|
+
export declare const parse: (src: string, { signal, }: {
|
|
3
|
+
signal: AbortController['signal'];
|
|
4
|
+
}) => Promise<{
|
|
5
|
+
loaded: boolean;
|
|
6
|
+
delays: number[];
|
|
7
|
+
frames: Uint8ClampedArray[];
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}>;
|
|
11
|
+
declare type ParserCallbackArgs = {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
delays: number[];
|
|
15
|
+
frames: Uint8ClampedArray[];
|
|
16
|
+
};
|
|
17
|
+
export declare const generate: (info: ParserCallbackArgs) => GifState;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generate = exports.parse = void 0;
|
|
4
|
+
const gifuct_1 = require("./gifuct");
|
|
5
|
+
const decompress_frames_1 = require("./parser/decompress-frames");
|
|
6
|
+
const validateAndFix = (gif) => {
|
|
7
|
+
let currentGce = null;
|
|
8
|
+
for (const frame of gif.frames) {
|
|
9
|
+
currentGce = frame.gce ? frame.gce : currentGce;
|
|
10
|
+
// fix loosing graphic control extension for same frames
|
|
11
|
+
if ('image' in frame && !('gce' in frame) && currentGce !== null) {
|
|
12
|
+
frame.gce = currentGce;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const parse = (src, { signal, }) => fetch(src, { signal })
|
|
17
|
+
.then((resp) => {
|
|
18
|
+
var _a;
|
|
19
|
+
if (!((_a = resp.headers.get('Content-Type')) === null || _a === void 0 ? void 0 : _a.includes('image/gif')))
|
|
20
|
+
throw Error(`Wrong content type: "${resp.headers.get('Content-Type')}"`);
|
|
21
|
+
return resp.arrayBuffer();
|
|
22
|
+
})
|
|
23
|
+
.then((buffer) => (0, gifuct_1.parseGIF)(buffer))
|
|
24
|
+
.then((gif) => {
|
|
25
|
+
validateAndFix(gif);
|
|
26
|
+
return gif;
|
|
27
|
+
})
|
|
28
|
+
.then((gif) => Promise.all([
|
|
29
|
+
(0, decompress_frames_1.decompressFrames)(gif),
|
|
30
|
+
{ width: gif.lsd.width, height: gif.lsd.height },
|
|
31
|
+
]))
|
|
32
|
+
.then(([frames, options]) => {
|
|
33
|
+
const readyFrames = [];
|
|
34
|
+
const size = options.width * options.height * 4;
|
|
35
|
+
let canvas = new Uint8ClampedArray(size);
|
|
36
|
+
for (let i = 0; i < frames.length; ++i) {
|
|
37
|
+
const frame = frames[i];
|
|
38
|
+
// Read about different disposal types
|
|
39
|
+
// https://giflib.sourceforge.net/whatsinagif/animation_and_transparency.html
|
|
40
|
+
const prevCanvas = frames[i].disposalType === 3 ? canvas.slice() : null;
|
|
41
|
+
readyFrames.push(putPixels(canvas, frame, options));
|
|
42
|
+
// Disposal type 2: The canvas should be restored to the background color
|
|
43
|
+
if (frames[i].disposalType === 2) {
|
|
44
|
+
canvas = new Uint8ClampedArray(size);
|
|
45
|
+
}
|
|
46
|
+
// Disposal type 3: The decoder should restore the canvas to its previous state before the current image was drawn
|
|
47
|
+
else if (frames[i].disposalType === 3) {
|
|
48
|
+
if (!prevCanvas) {
|
|
49
|
+
throw Error('Disposal type 3 without previous frame');
|
|
50
|
+
}
|
|
51
|
+
canvas = prevCanvas;
|
|
52
|
+
}
|
|
53
|
+
// Disposal type 1: Draw the next image on top of it
|
|
54
|
+
else {
|
|
55
|
+
canvas = readyFrames[i].slice();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...options,
|
|
60
|
+
loaded: true,
|
|
61
|
+
delays: frames.map((frame) => frame.delay),
|
|
62
|
+
frames: readyFrames,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
exports.parse = parse;
|
|
66
|
+
const putPixels = (typedArray, frame, gifSize) => {
|
|
67
|
+
const { width, height, top: dy, left: dx } = frame.dims;
|
|
68
|
+
const offset = dy * gifSize.width + dx;
|
|
69
|
+
for (let y = 0; y < height; y++) {
|
|
70
|
+
for (let x = 0; x < width; x++) {
|
|
71
|
+
const pPos = y * width + x;
|
|
72
|
+
const colorIndex = frame.pixels[pPos];
|
|
73
|
+
if (colorIndex !== frame.transparentIndex) {
|
|
74
|
+
const taPos = offset + y * gifSize.width + x;
|
|
75
|
+
const color = frame.colorTable[colorIndex];
|
|
76
|
+
typedArray[taPos * 4] = color[0];
|
|
77
|
+
typedArray[taPos * 4 + 1] = color[1];
|
|
78
|
+
typedArray[taPos * 4 + 2] = color[2];
|
|
79
|
+
typedArray[taPos * 4 + 3] =
|
|
80
|
+
colorIndex === frame.transparentIndex ? 0 : 255;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return typedArray;
|
|
85
|
+
};
|
|
86
|
+
const generate = (info) => {
|
|
87
|
+
return {
|
|
88
|
+
...info,
|
|
89
|
+
frames: info.frames.map((buffer) => {
|
|
90
|
+
const image = new ImageData(info.width, info.height);
|
|
91
|
+
image.data.set(new Uint8ClampedArray(buffer));
|
|
92
|
+
return image;
|
|
93
|
+
}),
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
exports.generate = generate;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decompressFrames = void 0;
|
|
4
|
+
const gifuct_1 = require("../gifuct");
|
|
5
|
+
const decompressFrames = (parsedGif) => {
|
|
6
|
+
return parsedGif.frames
|
|
7
|
+
.filter((f) => {
|
|
8
|
+
return !('application' in f);
|
|
9
|
+
})
|
|
10
|
+
.map((f) => {
|
|
11
|
+
const fr = f.image
|
|
12
|
+
? (0, gifuct_1.decompressFrame)(f, parsedGif.gct)
|
|
13
|
+
: null;
|
|
14
|
+
return fr;
|
|
15
|
+
})
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.map((f) => f);
|
|
18
|
+
};
|
|
19
|
+
exports.decompressFrames = decompressFrames;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Returns an object with two entries: waitUntilDone() that returns a Promise which can be awaited and free() which will cancel preloading or free up the memory if the GIF is not being used anymore.
|
|
3
|
+
* @see [Documentation](https://www.remotion.dev/docs/gif/preload-gif)
|
|
4
|
+
*/
|
|
5
|
+
export declare const preloadGif: (src: string) => {
|
|
6
|
+
waitUntilDone: () => Promise<void>;
|
|
7
|
+
free: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preloadGif = void 0;
|
|
4
|
+
const gif_cache_1 = require("./gif-cache");
|
|
5
|
+
const react_tools_1 = require("./react-tools");
|
|
6
|
+
const resolve_gif_source_1 = require("./resolve-gif-source");
|
|
7
|
+
/**
|
|
8
|
+
* @description Returns an object with two entries: waitUntilDone() that returns a Promise which can be awaited and free() which will cancel preloading or free up the memory if the GIF is not being used anymore.
|
|
9
|
+
* @see [Documentation](https://www.remotion.dev/docs/gif/preload-gif)
|
|
10
|
+
*/
|
|
11
|
+
const preloadGif = (src) => {
|
|
12
|
+
const resolvedSrc = (0, resolve_gif_source_1.resolveGifSource)(src);
|
|
13
|
+
if (gif_cache_1.volatileGifCache.has(resolvedSrc)) {
|
|
14
|
+
return {
|
|
15
|
+
waitUntilDone: () => Promise.resolve(),
|
|
16
|
+
free: () => gif_cache_1.volatileGifCache.delete(resolvedSrc),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (gif_cache_1.manuallyManagedGifCache.has(resolvedSrc)) {
|
|
20
|
+
return {
|
|
21
|
+
waitUntilDone: () => Promise.resolve(),
|
|
22
|
+
free: () => gif_cache_1.manuallyManagedGifCache.delete(resolvedSrc),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const { prom, cancel } = (0, react_tools_1.parseWithWorker)(resolvedSrc);
|
|
26
|
+
let deleted = false;
|
|
27
|
+
prom.then((p) => {
|
|
28
|
+
if (!deleted) {
|
|
29
|
+
gif_cache_1.manuallyManagedGifCache.set(resolvedSrc, p);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
waitUntilDone: () => prom.then(() => undefined),
|
|
34
|
+
free: () => {
|
|
35
|
+
cancel();
|
|
36
|
+
deleted = true;
|
|
37
|
+
gif_cache_1.manuallyManagedGifCache.delete(resolvedSrc);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
exports.preloadGif = preloadGif;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare type GifLoopBehavior = 'loop' | 'pause-after-finish' | 'unmount-after-finish';
|
|
3
|
+
export declare type RemotionGifProps = {
|
|
4
|
+
src: string;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
onLoad?: (info: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
delays: number[];
|
|
11
|
+
frames: ImageData[];
|
|
12
|
+
}) => void;
|
|
13
|
+
onError?: (error: Error) => void;
|
|
14
|
+
fit?: GifFillMode;
|
|
15
|
+
style?: React.CSSProperties;
|
|
16
|
+
loopBehavior?: GifLoopBehavior;
|
|
17
|
+
};
|
|
18
|
+
export declare type GifState = {
|
|
19
|
+
delays: number[];
|
|
20
|
+
frames: ImageData[];
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
export declare type GifFillMode = 'contain' | 'cover' | 'fill';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GifState } from './props';
|
|
2
|
+
export declare const parseGif: ({ src, controller, }: {
|
|
3
|
+
src: string;
|
|
4
|
+
controller: AbortController;
|
|
5
|
+
}) => Promise<GifState>;
|
|
6
|
+
export declare const parseWithWorker: (src: string) => {
|
|
7
|
+
prom: Promise<GifState>;
|
|
8
|
+
cancel: () => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseWithWorker = exports.parseGif = void 0;
|
|
4
|
+
const parse_generate_1 = require("./parse-generate");
|
|
5
|
+
const worker_1 = require("./worker");
|
|
6
|
+
const parseGif = async ({ src, controller, }) => {
|
|
7
|
+
const raw = await (0, parse_generate_1.parse)(src, { signal: controller.signal });
|
|
8
|
+
return (0, parse_generate_1.generate)(raw);
|
|
9
|
+
};
|
|
10
|
+
exports.parseGif = parseGif;
|
|
11
|
+
const parseWithWorker = (src) => {
|
|
12
|
+
const worker = (0, worker_1.makeWorker)();
|
|
13
|
+
let handler = null;
|
|
14
|
+
const prom = new Promise((resolve, reject) => {
|
|
15
|
+
handler = (e) => {
|
|
16
|
+
const message = e.data || e;
|
|
17
|
+
if (message.src === src) {
|
|
18
|
+
if (message.error) {
|
|
19
|
+
reject(new Error(message.error));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const data = message.error ? message : (0, parse_generate_1.generate)(message);
|
|
23
|
+
resolve(data);
|
|
24
|
+
worker.terminate();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
worker.addEventListener('message', handler);
|
|
29
|
+
worker.postMessage({ src, type: 'parse' });
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
prom,
|
|
33
|
+
cancel: () => {
|
|
34
|
+
worker.postMessage({ src, type: 'cancel' });
|
|
35
|
+
worker.removeEventListener('message', handler);
|
|
36
|
+
worker.terminate();
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
exports.parseWithWorker = parseWithWorker;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolveGifSource: (src: string) => string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveGifSource = void 0;
|
|
4
|
+
const resolveGifSource = (src) => {
|
|
5
|
+
return new URL(src, typeof window === 'undefined' ? undefined : window.location.origin).href;
|
|
6
|
+
};
|
|
7
|
+
exports.resolveGifSource = resolveGifSource;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useElementSize = exports.updateAllElementsSizes = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
let elementSizeHooks = [];
|
|
6
|
+
const updateAllElementsSizes = () => {
|
|
7
|
+
for (const listener of elementSizeHooks) {
|
|
8
|
+
listener();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
exports.updateAllElementsSizes = updateAllElementsSizes;
|
|
12
|
+
const useElementSize = (ref) => {
|
|
13
|
+
const [size, setSize] = (0, react_1.useState)(null);
|
|
14
|
+
const observer = (0, react_1.useMemo)(() => {
|
|
15
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return new ResizeObserver((entries) => {
|
|
19
|
+
// The contentRect returns the width without any `scale()`'s being applied. The height is wrong
|
|
20
|
+
const { contentRect } = entries[0];
|
|
21
|
+
// The clientRect returns the size with `scale()` being applied.
|
|
22
|
+
const newSize = entries[0].target.getClientRects();
|
|
23
|
+
if (!newSize || !newSize[0]) {
|
|
24
|
+
setSize(null);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const probableCssParentScale = newSize[0].width / contentRect.width;
|
|
28
|
+
const width = newSize[0].width * (1 / probableCssParentScale);
|
|
29
|
+
const height = newSize[0].height * (1 / probableCssParentScale);
|
|
30
|
+
setSize({
|
|
31
|
+
width,
|
|
32
|
+
height,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}, []);
|
|
36
|
+
const updateSize = (0, react_1.useCallback)(() => {
|
|
37
|
+
if (!ref.current) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const rect = ref.current.getClientRects();
|
|
41
|
+
if (!rect[0]) {
|
|
42
|
+
setSize(null);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setSize({
|
|
46
|
+
width: rect[0].width,
|
|
47
|
+
height: rect[0].height,
|
|
48
|
+
});
|
|
49
|
+
}, [ref]);
|
|
50
|
+
(0, react_1.useEffect)(() => {
|
|
51
|
+
if (!observer) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
updateSize();
|
|
55
|
+
const { current } = ref;
|
|
56
|
+
if (ref.current) {
|
|
57
|
+
observer.observe(ref.current);
|
|
58
|
+
}
|
|
59
|
+
return () => {
|
|
60
|
+
if (current) {
|
|
61
|
+
observer.unobserve(current);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}, [observer, ref, updateSize]);
|
|
65
|
+
(0, react_1.useEffect)(() => {
|
|
66
|
+
elementSizeHooks.push(updateSize);
|
|
67
|
+
return () => {
|
|
68
|
+
elementSizeHooks = elementSizeHooks.filter((e) => e !== updateSize);
|
|
69
|
+
};
|
|
70
|
+
}, [updateSize]);
|
|
71
|
+
return size;
|
|
72
|
+
};
|
|
73
|
+
exports.useElementSize = useElementSize;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useCurrentGifIndex = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const remotion_1 = require("remotion");
|
|
6
|
+
function useCurrentGifIndex(delays, loopBehavior) {
|
|
7
|
+
const currentFrame = (0, remotion_1.useCurrentFrame)();
|
|
8
|
+
const videoConfig = (0, remotion_1.useVideoConfig)();
|
|
9
|
+
const duration = (0, react_1.useMemo)(() => {
|
|
10
|
+
if (delays.length !== 0) {
|
|
11
|
+
return delays.reduce((sum, delay) => sum + (delay !== null && delay !== void 0 ? delay : 0), 0);
|
|
12
|
+
}
|
|
13
|
+
return 1;
|
|
14
|
+
}, [delays]);
|
|
15
|
+
if (delays.length === 0) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
const time = (currentFrame / videoConfig.fps) * 1000;
|
|
19
|
+
if (loopBehavior === 'pause-after-finish' && time >= duration) {
|
|
20
|
+
return delays.length - 1;
|
|
21
|
+
}
|
|
22
|
+
if (loopBehavior === 'unmount-after-finish' && time >= duration) {
|
|
23
|
+
return -1;
|
|
24
|
+
}
|
|
25
|
+
let currentTime = time % duration;
|
|
26
|
+
for (let i = 0; i < delays.length; i++) {
|
|
27
|
+
const delay = delays[i];
|
|
28
|
+
if (currentTime < delay) {
|
|
29
|
+
return i;
|
|
30
|
+
}
|
|
31
|
+
currentTime -= delay;
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
exports.useCurrentGifIndex = useCurrentGifIndex;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const makeWorker: () => Worker;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeWorker = void 0;
|
|
4
|
+
const source_1 = require("./source");
|
|
5
|
+
const makeWorker = () => {
|
|
6
|
+
const blob = new Blob([source_1.src], { type: 'application/javascript' });
|
|
7
|
+
const url = URL.createObjectURL(blob);
|
|
8
|
+
const worker = new Worker(url);
|
|
9
|
+
URL.revokeObjectURL(url);
|
|
10
|
+
return worker;
|
|
11
|
+
};
|
|
12
|
+
exports.makeWorker = makeWorker;
|