@cjser/sindresorhus__gifkit 0.1.0-cjser.2
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-cjser/index.cjs +2168 -0
- package/index.d.ts +838 -0
- package/index.js +118 -0
- package/license +9 -0
- package/package.json +83 -0
- package/readme.md +294 -0
- package/source/byte-stream.js +141 -0
- package/source/constants.js +36 -0
- package/source/decode.js +453 -0
- package/source/encode.js +536 -0
- package/source/loop-count.js +72 -0
- package/source/lzw.js +322 -0
- package/source/quantize.js +185 -0
- package/source/render.js +470 -0
- package/source/validate.js +485 -0
|
@@ -0,0 +1,2168 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/index.js
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
decodeAnimatedGIF: () => decodeAnimatedGIF,
|
|
23
|
+
decodeGIF: () => decodeGIF,
|
|
24
|
+
encodeAnimatedGIF: () => encodeAnimatedGIF,
|
|
25
|
+
encodeGIF: () => encodeGIF,
|
|
26
|
+
indexedImage: () => indexedImage,
|
|
27
|
+
renderGIFFrameSequence: () => renderGIFFrameSequence,
|
|
28
|
+
renderGIFFrames: () => renderGIFFrames
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/constants.js
|
|
33
|
+
var asciiTextEncoder = new TextEncoder();
|
|
34
|
+
var asciiTextDecoder = new TextDecoder("ascii", { fatal: false });
|
|
35
|
+
var uint8ArraySubarray = Uint8Array.prototype.subarray;
|
|
36
|
+
var extensionIntroducer = 33;
|
|
37
|
+
var imageSeparator = 44;
|
|
38
|
+
var trailerByte = 59;
|
|
39
|
+
var graphicControlExtensionLabel = 249;
|
|
40
|
+
var commentExtensionLabel = 254;
|
|
41
|
+
var plainTextExtensionLabel = 1;
|
|
42
|
+
var appExtensionLabel = 255;
|
|
43
|
+
var netscapeLoopingAppIdentifier = "NETSCAPE";
|
|
44
|
+
var netscapeLoopingAppAuthenticationCode = "2.0";
|
|
45
|
+
var netscapeLoopingAppAuthenticationCodeBytes = asciiTextEncoder.encode(netscapeLoopingAppAuthenticationCode);
|
|
46
|
+
var defaultMaximumPixelCount = 1e8;
|
|
47
|
+
var defaultMaximumRenderPixelCount = 16777216;
|
|
48
|
+
var defaultMaximumIndexedImagePixelCount = 16777216;
|
|
49
|
+
var defaultMaximumBlockCount = 1e5;
|
|
50
|
+
var defaultMaximumDataSubBlockCount = 3e5;
|
|
51
|
+
var defaultMaximumDataPayloadByteLength = 64 * 1024 * 1024;
|
|
52
|
+
var defaultMaximumEncodeWorkCost = defaultMaximumPixelCount;
|
|
53
|
+
var defaultMaximumEncodedByteLength = 256 * 1024 * 1024;
|
|
54
|
+
var endiannessProbe = new Uint32Array([168496141]);
|
|
55
|
+
var isLittleEndian = new Uint8Array(endiannessProbe.buffer, endiannessProbe.byteOffset, endiannessProbe.byteLength)[0] === 13;
|
|
56
|
+
var disposalMethodNames = [
|
|
57
|
+
"unspecified",
|
|
58
|
+
"keep",
|
|
59
|
+
"restoreBackground",
|
|
60
|
+
"restorePrevious"
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/validate.js
|
|
64
|
+
var import_node_util = require("node:util");
|
|
65
|
+
var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
66
|
+
var typedArrayBufferGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
|
|
67
|
+
var typedArrayByteOffsetGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset").get;
|
|
68
|
+
var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength").get;
|
|
69
|
+
function isUint8Array(value) {
|
|
70
|
+
return import_node_util.types.isUint8Array(value);
|
|
71
|
+
}
|
|
72
|
+
function isUint8ClampedArray(value) {
|
|
73
|
+
return import_node_util.types.isUint8ClampedArray(value);
|
|
74
|
+
}
|
|
75
|
+
function toUint8ArrayView(value) {
|
|
76
|
+
return new Uint8Array(
|
|
77
|
+
typedArrayBufferGetter.call(value),
|
|
78
|
+
typedArrayByteOffsetGetter.call(value),
|
|
79
|
+
typedArrayByteLengthGetter.call(value)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function normalizeByteArray(value, fieldName) {
|
|
83
|
+
const byteLength = value.length;
|
|
84
|
+
const bytes = new Uint8Array(byteLength);
|
|
85
|
+
let index = 0;
|
|
86
|
+
while (index < byteLength) {
|
|
87
|
+
bytes[index] = requireByte(value[index], `${fieldName}[${index}]`);
|
|
88
|
+
index += 1;
|
|
89
|
+
}
|
|
90
|
+
return bytes;
|
|
91
|
+
}
|
|
92
|
+
function areBytesEqual(leftBytes, rightBytes) {
|
|
93
|
+
if (leftBytes.length !== rightBytes.length) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
let index = 0;
|
|
97
|
+
while (index < leftBytes.length) {
|
|
98
|
+
if (leftBytes[index] !== rightBytes[index]) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
index += 1;
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
function isPowerOfTwo(value) {
|
|
106
|
+
return (value & value - 1) === 0;
|
|
107
|
+
}
|
|
108
|
+
function requireIntegerInRange(value, minimum, maximum, fieldName) {
|
|
109
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
110
|
+
throw new Error(`${fieldName} must be an integer between ${minimum} and ${maximum}, got ${value}`);
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
function requireFiniteNumberInRange(value, minimum, maximum, fieldName) {
|
|
115
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum) {
|
|
116
|
+
throw new Error(`${fieldName} must be a number between ${minimum} and ${maximum}, got ${value}`);
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
function requirePositiveFiniteNumber(value, fieldName) {
|
|
121
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
122
|
+
throw new Error(`${fieldName} must be a number greater than 0, got ${value}`);
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
function requireByte(value, fieldName) {
|
|
127
|
+
return requireIntegerInRange(value, 0, 255, fieldName);
|
|
128
|
+
}
|
|
129
|
+
function requireUnsigned16(value, fieldName) {
|
|
130
|
+
return requireIntegerInRange(value, 0, 65535, fieldName);
|
|
131
|
+
}
|
|
132
|
+
function requireNonZeroUnsigned16(value, fieldName) {
|
|
133
|
+
return requireIntegerInRange(value, 1, 65535, fieldName);
|
|
134
|
+
}
|
|
135
|
+
function requirePixelCountWithinLimit(width, height, maximumPixelCount, description) {
|
|
136
|
+
const pixelCount = width * height;
|
|
137
|
+
requirePixelCountValueWithinLimit(pixelCount, maximumPixelCount, description);
|
|
138
|
+
return pixelCount;
|
|
139
|
+
}
|
|
140
|
+
function requirePixelCountValueWithinLimit(pixelCount, maximumPixelCount, description) {
|
|
141
|
+
if (pixelCount > maximumPixelCount) {
|
|
142
|
+
throw new Error(`${description} has ${pixelCount} pixels, which exceeds the limit of ${maximumPixelCount}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function requireCountWithinLimit(count, maximumCount, description) {
|
|
146
|
+
if (count > maximumCount) {
|
|
147
|
+
throw new Error(`${description} ${count} exceeds the limit of ${maximumCount}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function requireByteLengthWithinLimit(byteLength, maximumByteLength, description) {
|
|
151
|
+
if (byteLength > maximumByteLength) {
|
|
152
|
+
throw new Error(`${description} has ${byteLength} bytes, which exceeds the limit of ${maximumByteLength}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function requireBlockObject(block) {
|
|
156
|
+
if (!block || typeof block !== "object") {
|
|
157
|
+
throw new TypeError("Each block must be an object");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function normalizeColorTable(value, fieldName) {
|
|
161
|
+
if (value === void 0) {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
if (isUint8Array(value)) {
|
|
165
|
+
const bytes = toUint8ArrayView(value);
|
|
166
|
+
validateColorTableBytes(bytes, fieldName);
|
|
167
|
+
return bytes;
|
|
168
|
+
}
|
|
169
|
+
if (Array.isArray(value)) {
|
|
170
|
+
const flatBytes = normalizeColorTableArray(value, fieldName);
|
|
171
|
+
validateColorTableBytes(flatBytes, fieldName);
|
|
172
|
+
return flatBytes;
|
|
173
|
+
}
|
|
174
|
+
throw new TypeError(`${fieldName} must be undefined, a Uint8Array, a flat byte array, or an array of RGB triplets`);
|
|
175
|
+
}
|
|
176
|
+
function normalizeColorTableArray(value, fieldName) {
|
|
177
|
+
const colorTableLength = value.length;
|
|
178
|
+
if (colorTableLength === 0) {
|
|
179
|
+
throw new Error(`${fieldName} cannot be empty`);
|
|
180
|
+
}
|
|
181
|
+
if (colorTableLength > 768) {
|
|
182
|
+
throw new Error(`${fieldName} cannot contain more than 768 flat bytes or 256 RGB triplets`);
|
|
183
|
+
}
|
|
184
|
+
const flatEntryCount = colorTableLength / 3;
|
|
185
|
+
const canBeFlatByteArray = colorTableLength % 3 === 0 && flatEntryCount >= 2 && flatEntryCount <= 256 && isPowerOfTwo(flatEntryCount);
|
|
186
|
+
const canBeTripletArray = colorTableLength >= 2 && colorTableLength <= 256 && isPowerOfTwo(colorTableLength);
|
|
187
|
+
const firstElementDescriptor = canBeTripletArray && !canBeFlatByteArray ? Object.getOwnPropertyDescriptor(value, 0) : void 0;
|
|
188
|
+
const isTripletArray = firstElementDescriptor !== void 0 && "value" in firstElementDescriptor && Array.isArray(firstElementDescriptor.value);
|
|
189
|
+
if (isTripletArray) {
|
|
190
|
+
const flatArray = [];
|
|
191
|
+
let paletteIndex = 0;
|
|
192
|
+
while (paletteIndex < colorTableLength) {
|
|
193
|
+
const element = value[paletteIndex];
|
|
194
|
+
const triplet = normalizeSingleColorTriplet(element, `${fieldName}[${paletteIndex}]`);
|
|
195
|
+
flatArray.push(triplet[0], triplet[1], triplet[2]);
|
|
196
|
+
paletteIndex += 1;
|
|
197
|
+
}
|
|
198
|
+
return Uint8Array.from(flatArray);
|
|
199
|
+
}
|
|
200
|
+
if (!canBeFlatByteArray) {
|
|
201
|
+
validateColorTableEntryCountFromFlatLength(colorTableLength, fieldName);
|
|
202
|
+
}
|
|
203
|
+
return normalizeByteArray(value, fieldName);
|
|
204
|
+
}
|
|
205
|
+
function validateColorTableBytes(flatBytes, fieldName) {
|
|
206
|
+
if (flatBytes.length % 3 !== 0) {
|
|
207
|
+
throw new Error(`${fieldName} length must be divisible by 3`);
|
|
208
|
+
}
|
|
209
|
+
const entryCount = flatBytes.length / 3;
|
|
210
|
+
if (entryCount < 2 || entryCount > 256) {
|
|
211
|
+
throw new Error(`${fieldName} must contain between 2 and 256 entries, got ${entryCount}`);
|
|
212
|
+
}
|
|
213
|
+
if (!isPowerOfTwo(entryCount)) {
|
|
214
|
+
throw new Error(`${fieldName} must contain a power-of-two number of entries, got ${entryCount}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function validateColorTableEntryCountFromFlatLength(byteLength, fieldName) {
|
|
218
|
+
if (byteLength % 3 !== 0) {
|
|
219
|
+
throw new Error(`${fieldName} length must be divisible by 3`);
|
|
220
|
+
}
|
|
221
|
+
const entryCount = byteLength / 3;
|
|
222
|
+
if (entryCount < 2 || entryCount > 256) {
|
|
223
|
+
throw new Error(`${fieldName} must contain between 2 and 256 entries, got ${entryCount}`);
|
|
224
|
+
}
|
|
225
|
+
throw new Error(`${fieldName} must contain a power-of-two number of entries, got ${entryCount}`);
|
|
226
|
+
}
|
|
227
|
+
function normalizeSingleColorTriplet(value, fieldName) {
|
|
228
|
+
if (!Array.isArray(value) || value.length !== 3) {
|
|
229
|
+
throw new TypeError(`${fieldName} must be an array of exactly 3 bytes`);
|
|
230
|
+
}
|
|
231
|
+
return [
|
|
232
|
+
requireByte(value[0], `${fieldName}[0]`),
|
|
233
|
+
requireByte(value[1], `${fieldName}[1]`),
|
|
234
|
+
requireByte(value[2], `${fieldName}[2]`)
|
|
235
|
+
];
|
|
236
|
+
}
|
|
237
|
+
function padColorTableToPowerOfTwo(colorTable) {
|
|
238
|
+
const entryCount = colorTable.length / 3;
|
|
239
|
+
if (entryCount === 0) {
|
|
240
|
+
throw new Error("Color table must contain at least one entry");
|
|
241
|
+
}
|
|
242
|
+
let paddedEntryCount = 2;
|
|
243
|
+
while (paddedEntryCount < entryCount) {
|
|
244
|
+
paddedEntryCount *= 2;
|
|
245
|
+
}
|
|
246
|
+
if (paddedEntryCount > 256) {
|
|
247
|
+
throw new Error("Color table cannot exceed 256 entries");
|
|
248
|
+
}
|
|
249
|
+
if (paddedEntryCount === entryCount) {
|
|
250
|
+
return colorTable;
|
|
251
|
+
}
|
|
252
|
+
const paddedColorTable = new Uint8Array(paddedEntryCount * 3);
|
|
253
|
+
paddedColorTable.set(colorTable);
|
|
254
|
+
const lastTripletOffset = Math.max(0, colorTable.length - 3);
|
|
255
|
+
for (let offset = colorTable.length; offset < paddedColorTable.length; offset += 3) {
|
|
256
|
+
paddedColorTable[offset] = colorTable[lastTripletOffset];
|
|
257
|
+
paddedColorTable[offset + 1] = colorTable[lastTripletOffset + 1];
|
|
258
|
+
paddedColorTable[offset + 2] = colorTable[lastTripletOffset + 2];
|
|
259
|
+
}
|
|
260
|
+
return paddedColorTable;
|
|
261
|
+
}
|
|
262
|
+
function calculateColorTableSizeField(colorTableEntryCount) {
|
|
263
|
+
if (!Number.isSafeInteger(colorTableEntryCount) || colorTableEntryCount < 2 || colorTableEntryCount > 256) {
|
|
264
|
+
throw new Error(`Color table must contain between 2 and 256 entries, got ${colorTableEntryCount}`);
|
|
265
|
+
}
|
|
266
|
+
if ((colorTableEntryCount & colorTableEntryCount - 1) !== 0) {
|
|
267
|
+
throw new Error(`Color table entry count must be a power of two, got ${colorTableEntryCount}`);
|
|
268
|
+
}
|
|
269
|
+
return Math.round(Math.log2(colorTableEntryCount)) - 1;
|
|
270
|
+
}
|
|
271
|
+
function deriveColorResolution(globalColorTable) {
|
|
272
|
+
if (globalColorTable === void 0) {
|
|
273
|
+
return 8;
|
|
274
|
+
}
|
|
275
|
+
const entryCount = globalColorTable.length / 3;
|
|
276
|
+
return Math.max(1, Math.ceil(Math.log2(entryCount)));
|
|
277
|
+
}
|
|
278
|
+
function deriveMinimumCodeSize(colorTableEntryCount) {
|
|
279
|
+
const clampedEntryCount = Math.max(2, colorTableEntryCount);
|
|
280
|
+
return Math.max(2, Math.ceil(Math.log2(clampedEntryCount)));
|
|
281
|
+
}
|
|
282
|
+
function normalizeIndexedPixels(value, expectedLength, fieldName) {
|
|
283
|
+
if (value === void 0) {
|
|
284
|
+
return void 0;
|
|
285
|
+
}
|
|
286
|
+
let indexedPixels;
|
|
287
|
+
if (isUint8Array(value)) {
|
|
288
|
+
indexedPixels = toUint8ArrayView(value);
|
|
289
|
+
} else if (Array.isArray(value)) {
|
|
290
|
+
if (value.length !== expectedLength) {
|
|
291
|
+
throw new Error(`${fieldName} length must be ${expectedLength}, got ${value.length}`);
|
|
292
|
+
}
|
|
293
|
+
indexedPixels = normalizeByteArray(value, fieldName);
|
|
294
|
+
} else {
|
|
295
|
+
throw new TypeError(`${fieldName} must be a Uint8Array or array of bytes`);
|
|
296
|
+
}
|
|
297
|
+
if (indexedPixels.length !== expectedLength) {
|
|
298
|
+
throw new Error(`${fieldName} length must be ${expectedLength}, got ${indexedPixels.length}`);
|
|
299
|
+
}
|
|
300
|
+
return indexedPixels;
|
|
301
|
+
}
|
|
302
|
+
function normalizeRedGreenBlueAlphaPixels(value, expectedLength, fieldName) {
|
|
303
|
+
let pixels;
|
|
304
|
+
if (isUint8Array(value) || isUint8ClampedArray(value)) {
|
|
305
|
+
pixels = toUint8ArrayView(value);
|
|
306
|
+
} else if (Array.isArray(value)) {
|
|
307
|
+
if (value.length !== expectedLength) {
|
|
308
|
+
throw new Error(`${fieldName} length must be ${expectedLength}, got ${value.length}`);
|
|
309
|
+
}
|
|
310
|
+
pixels = Uint8ClampedArray.from(normalizeByteArray(value, fieldName));
|
|
311
|
+
} else {
|
|
312
|
+
throw new TypeError(`${fieldName} must be a Uint8Array, Uint8ClampedArray, or array of bytes`);
|
|
313
|
+
}
|
|
314
|
+
if (pixels.length !== expectedLength) {
|
|
315
|
+
throw new Error(`${fieldName} length must be ${expectedLength}, got ${pixels.length}`);
|
|
316
|
+
}
|
|
317
|
+
return pixels;
|
|
318
|
+
}
|
|
319
|
+
function normalizeExtensionPayload(value, fieldName) {
|
|
320
|
+
if (typeof value === "string") {
|
|
321
|
+
return normalizeAsciiPayloadString(value, fieldName);
|
|
322
|
+
}
|
|
323
|
+
if (isUint8Array(value)) {
|
|
324
|
+
const bytes = toUint8ArrayView(value);
|
|
325
|
+
requireByteLengthWithinLimit(bytes.length, defaultMaximumDataPayloadByteLength, fieldName);
|
|
326
|
+
return bytes;
|
|
327
|
+
}
|
|
328
|
+
if (Array.isArray(value)) {
|
|
329
|
+
requireByteLengthWithinLimit(value.length, defaultMaximumDataPayloadByteLength, fieldName);
|
|
330
|
+
return normalizeByteArray(value, fieldName);
|
|
331
|
+
}
|
|
332
|
+
throw new TypeError(`${fieldName} must be a string, Uint8Array, or array of bytes`);
|
|
333
|
+
}
|
|
334
|
+
function normalizeAsciiPayloadString(value, fieldName) {
|
|
335
|
+
requireByteLengthWithinLimit(value.length, defaultMaximumDataPayloadByteLength, fieldName);
|
|
336
|
+
const bytes = new Uint8Array(value.length);
|
|
337
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
338
|
+
const codeUnit = value.codePointAt(index);
|
|
339
|
+
if (codeUnit > 127) {
|
|
340
|
+
throw new Error(`${fieldName} must contain only ASCII characters`);
|
|
341
|
+
}
|
|
342
|
+
bytes[index] = codeUnit;
|
|
343
|
+
}
|
|
344
|
+
return bytes;
|
|
345
|
+
}
|
|
346
|
+
function normalizeFixedAsciiField(value, expectedLength, fieldName) {
|
|
347
|
+
if (typeof value !== "string") {
|
|
348
|
+
throw new TypeError(`${fieldName} must be a string`);
|
|
349
|
+
}
|
|
350
|
+
if (value.length !== expectedLength) {
|
|
351
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} ASCII bytes long`);
|
|
352
|
+
}
|
|
353
|
+
const encodedValue = asciiTextEncoder.encode(value);
|
|
354
|
+
if (encodedValue.length !== expectedLength) {
|
|
355
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} ASCII bytes long`);
|
|
356
|
+
}
|
|
357
|
+
for (const byte of encodedValue) {
|
|
358
|
+
if (byte < 32 || byte > 126) {
|
|
359
|
+
throw new Error(`${fieldName} must contain only printable ASCII characters`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return value;
|
|
363
|
+
}
|
|
364
|
+
function normalizeFixedByteField(value, expectedLength, fieldName) {
|
|
365
|
+
if (typeof value === "string") {
|
|
366
|
+
if (value.length !== expectedLength) {
|
|
367
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} bytes long`);
|
|
368
|
+
}
|
|
369
|
+
const encodedValue = asciiTextEncoder.encode(value);
|
|
370
|
+
if (encodedValue.length !== expectedLength) {
|
|
371
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} bytes long`);
|
|
372
|
+
}
|
|
373
|
+
return encodedValue;
|
|
374
|
+
}
|
|
375
|
+
if (isUint8Array(value)) {
|
|
376
|
+
const bytes = toUint8ArrayView(value);
|
|
377
|
+
if (bytes.length !== expectedLength) {
|
|
378
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} bytes long`);
|
|
379
|
+
}
|
|
380
|
+
return bytes;
|
|
381
|
+
}
|
|
382
|
+
if (Array.isArray(value)) {
|
|
383
|
+
if (value.length !== expectedLength) {
|
|
384
|
+
throw new Error(`${fieldName} must be exactly ${expectedLength} bytes long`);
|
|
385
|
+
}
|
|
386
|
+
return normalizeByteArray(value, fieldName);
|
|
387
|
+
}
|
|
388
|
+
throw new TypeError(`${fieldName} must be a string, Uint8Array, or array of bytes`);
|
|
389
|
+
}
|
|
390
|
+
function normalizeImageGeometry(block, { logicalScreenWidth, logicalScreenHeight }) {
|
|
391
|
+
const left = requireUnsigned16(block.left ?? 0, "image.left");
|
|
392
|
+
const top = requireUnsigned16(block.top ?? 0, "image.top");
|
|
393
|
+
const width = requireNonZeroUnsigned16(block.width, "image.width");
|
|
394
|
+
const height = requireNonZeroUnsigned16(block.height, "image.height");
|
|
395
|
+
if (left + width > logicalScreenWidth || top + height > logicalScreenHeight) {
|
|
396
|
+
throw new Error("Image block extends beyond the logical screen bounds");
|
|
397
|
+
}
|
|
398
|
+
requirePixelCountWithinLimit(width, height, defaultMaximumPixelCount, "image block");
|
|
399
|
+
return {
|
|
400
|
+
left,
|
|
401
|
+
top,
|
|
402
|
+
width,
|
|
403
|
+
height
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
function secondsToHundredthsOfASecond(seconds, fieldName) {
|
|
407
|
+
const value = requireFiniteNumberInRange(seconds, 0, 655.35, fieldName);
|
|
408
|
+
return requireUnsigned16(Math.round(value * 100), `${fieldName} in hundredths of a second`);
|
|
409
|
+
}
|
|
410
|
+
function normalizeGraphicControlExtension(graphicControlExtension) {
|
|
411
|
+
if (graphicControlExtension === void 0) {
|
|
412
|
+
return void 0;
|
|
413
|
+
}
|
|
414
|
+
if (typeof graphicControlExtension !== "object" || graphicControlExtension === null) {
|
|
415
|
+
throw new TypeError("graphicControlExtension must be an object or undefined");
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
disposalMethod: normalizeDisposalMethod(graphicControlExtension.disposalMethod ?? "unspecified"),
|
|
419
|
+
delayInHundredthsOfASecond: secondsToHundredthsOfASecond(graphicControlExtension.delay ?? 0, "graphicControlExtension.delay"),
|
|
420
|
+
transparentColorIndex: graphicControlExtension.transparentColorIndex === void 0 ? void 0 : requireByte(graphicControlExtension.transparentColorIndex, "graphicControlExtension.transparentColorIndex")
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function normalizeDisposalMethod(disposalMethod) {
|
|
424
|
+
if (!disposalMethodNames.includes(disposalMethod)) {
|
|
425
|
+
throw new Error(`graphicControlExtension.disposalMethod must be one of ${disposalMethodNames.map((value) => JSON.stringify(value)).join(", ")}, got ${JSON.stringify(disposalMethod)}`);
|
|
426
|
+
}
|
|
427
|
+
return disposalMethod;
|
|
428
|
+
}
|
|
429
|
+
function disposalMethodByte(disposalMethod) {
|
|
430
|
+
return disposalMethodNames.indexOf(disposalMethod);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/byte-stream.js
|
|
434
|
+
var GIFByteReader = class {
|
|
435
|
+
#inputBytes;
|
|
436
|
+
#offset = 0;
|
|
437
|
+
#length;
|
|
438
|
+
constructor(inputBytes) {
|
|
439
|
+
if (!isUint8Array(inputBytes)) {
|
|
440
|
+
throw new TypeError("Expected inputBytes to be a Uint8Array");
|
|
441
|
+
}
|
|
442
|
+
this.#inputBytes = toUint8ArrayView(inputBytes);
|
|
443
|
+
this.#length = this.#inputBytes.length;
|
|
444
|
+
}
|
|
445
|
+
get offset() {
|
|
446
|
+
return this.#offset;
|
|
447
|
+
}
|
|
448
|
+
get length() {
|
|
449
|
+
return this.#length;
|
|
450
|
+
}
|
|
451
|
+
readByte() {
|
|
452
|
+
if (this.#offset >= this.#length) {
|
|
453
|
+
throw new Error("Unexpected end of data");
|
|
454
|
+
}
|
|
455
|
+
const value = this.#inputBytes[this.#offset];
|
|
456
|
+
this.#offset += 1;
|
|
457
|
+
return value;
|
|
458
|
+
}
|
|
459
|
+
readBytes(length) {
|
|
460
|
+
if (!Number.isSafeInteger(length) || length < 0) {
|
|
461
|
+
throw new Error(`Invalid byte length ${length}`);
|
|
462
|
+
}
|
|
463
|
+
if (this.#offset + length > this.#length) {
|
|
464
|
+
throw new Error("Unexpected end of data");
|
|
465
|
+
}
|
|
466
|
+
const value = Uint8Array.from(uint8ArraySubarray.call(this.#inputBytes, this.#offset, this.#offset + length));
|
|
467
|
+
this.#offset += length;
|
|
468
|
+
return value;
|
|
469
|
+
}
|
|
470
|
+
readBytesInto(target, targetOffset, length) {
|
|
471
|
+
if (!Number.isSafeInteger(length) || length < 0) {
|
|
472
|
+
throw new Error(`Invalid byte length ${length}`);
|
|
473
|
+
}
|
|
474
|
+
if (this.#offset + length > this.#length) {
|
|
475
|
+
throw new Error("Unexpected end of data");
|
|
476
|
+
}
|
|
477
|
+
target.set(uint8ArraySubarray.call(this.#inputBytes, this.#offset, this.#offset + length), targetOffset);
|
|
478
|
+
this.#offset += length;
|
|
479
|
+
}
|
|
480
|
+
readUnsignedLittleEndian16() {
|
|
481
|
+
const leastSignificantByte = this.readByte();
|
|
482
|
+
const mostSignificantByte = this.readByte();
|
|
483
|
+
return leastSignificantByte | mostSignificantByte << 8;
|
|
484
|
+
}
|
|
485
|
+
readAsciiString(length) {
|
|
486
|
+
return asciiTextDecoder.decode(this.readBytes(length));
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
var GIFByteWriter = class {
|
|
490
|
+
#bytes = new Uint8Array(1024);
|
|
491
|
+
#byteLength = 0;
|
|
492
|
+
#ensureCapacity(requiredCapacity) {
|
|
493
|
+
if (requiredCapacity <= this.#bytes.length) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const nextCapacity = Math.min(defaultMaximumEncodedByteLength, Math.max(requiredCapacity, this.#bytes.length * 2));
|
|
497
|
+
const nextBytes = new Uint8Array(nextCapacity);
|
|
498
|
+
nextBytes.set(uint8ArraySubarray.call(this.#bytes, 0, this.#byteLength));
|
|
499
|
+
this.#bytes = nextBytes;
|
|
500
|
+
}
|
|
501
|
+
writeByte(value) {
|
|
502
|
+
requireByteLengthWithinLimit(this.#byteLength + 1, defaultMaximumEncodedByteLength, "encoded GIF");
|
|
503
|
+
this.#ensureCapacity(this.#byteLength + 1);
|
|
504
|
+
this.#bytes[this.#byteLength] = requireByte(value, "byte");
|
|
505
|
+
this.#byteLength += 1;
|
|
506
|
+
}
|
|
507
|
+
writeBytes(values) {
|
|
508
|
+
if (isUint8Array(values)) {
|
|
509
|
+
const bytes = toUint8ArrayView(values);
|
|
510
|
+
requireByteLengthWithinLimit(this.#byteLength + bytes.length, defaultMaximumEncodedByteLength, "encoded GIF");
|
|
511
|
+
this.#ensureCapacity(this.#byteLength + bytes.length);
|
|
512
|
+
this.#bytes.set(bytes, this.#byteLength);
|
|
513
|
+
this.#byteLength += bytes.length;
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
requireByteLengthWithinLimit(this.#byteLength + values.length, defaultMaximumEncodedByteLength, "encoded GIF");
|
|
517
|
+
this.#ensureCapacity(this.#byteLength + values.length);
|
|
518
|
+
for (const value of values) {
|
|
519
|
+
this.writeByte(value);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
writeUnsignedLittleEndian16(value) {
|
|
523
|
+
const normalizedValue = requireUnsigned16(value, "unsigned16");
|
|
524
|
+
this.writeByte(normalizedValue & 255);
|
|
525
|
+
this.writeByte(normalizedValue >> 8 & 255);
|
|
526
|
+
}
|
|
527
|
+
writeAsciiString(value) {
|
|
528
|
+
const encodedValue = asciiTextEncoder.encode(value);
|
|
529
|
+
for (const byte of encodedValue) {
|
|
530
|
+
this.writeByte(byte);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
toUint8Array() {
|
|
534
|
+
return this.#bytes.slice(0, this.#byteLength);
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/lzw.js
|
|
539
|
+
function decodeCompressedIndexStream(compressedData, minimumCodeSize, expectedPixelCount, { strict, colorTableEntryCount }) {
|
|
540
|
+
const clearCode = 1 << minimumCodeSize;
|
|
541
|
+
const endOfInformationCode = clearCode + 1;
|
|
542
|
+
const context = {
|
|
543
|
+
compressedData,
|
|
544
|
+
clearCode,
|
|
545
|
+
endOfInformationCode,
|
|
546
|
+
minimumCodeSize,
|
|
547
|
+
prefixCodes: new Int16Array(4096),
|
|
548
|
+
suffixBytes: new Uint8Array(4096),
|
|
549
|
+
outputStack: new Uint8Array(4097),
|
|
550
|
+
decodedPixels: new Uint8Array(expectedPixelCount),
|
|
551
|
+
codeSize: minimumCodeSize + 1,
|
|
552
|
+
nextAvailableCode: clearCode + 2,
|
|
553
|
+
bitBuffer: 0,
|
|
554
|
+
bitCount: 0,
|
|
555
|
+
dataOffset: 0,
|
|
556
|
+
previousCode: -1,
|
|
557
|
+
outputOffset: 0,
|
|
558
|
+
firstByteOfCurrentString: 0,
|
|
559
|
+
currentStackLength: 0,
|
|
560
|
+
currentFirstByte: 0,
|
|
561
|
+
colorTableEntryCount,
|
|
562
|
+
hasReadAnyCode: false
|
|
563
|
+
};
|
|
564
|
+
resetLzwDictionary(context);
|
|
565
|
+
while (true) {
|
|
566
|
+
const currentCode = readNextLzwCode(context);
|
|
567
|
+
validateFirstLzwCode(context, currentCode, { strict });
|
|
568
|
+
if (currentCode === context.clearCode) {
|
|
569
|
+
resetLzwDictionary(context);
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (currentCode === context.endOfInformationCode) {
|
|
573
|
+
validateNoUnusedCompressedData(context, { strict });
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
expandLzwCode(context, currentCode);
|
|
577
|
+
copyLzwStackToPixels(context, expectedPixelCount);
|
|
578
|
+
addLzwDictionaryEntry(context);
|
|
579
|
+
context.previousCode = currentCode;
|
|
580
|
+
}
|
|
581
|
+
if (context.outputOffset !== expectedPixelCount) {
|
|
582
|
+
throw new Error(`Expected ${expectedPixelCount} pixel indices, decoded ${context.outputOffset}`);
|
|
583
|
+
}
|
|
584
|
+
return context.decodedPixels;
|
|
585
|
+
}
|
|
586
|
+
function resetLzwDictionary(context) {
|
|
587
|
+
for (let index = 0; index < context.clearCode; index += 1) {
|
|
588
|
+
context.prefixCodes[index] = -1;
|
|
589
|
+
context.suffixBytes[index] = index;
|
|
590
|
+
}
|
|
591
|
+
context.codeSize = context.minimumCodeSize + 1;
|
|
592
|
+
context.nextAvailableCode = context.clearCode + 2;
|
|
593
|
+
context.previousCode = -1;
|
|
594
|
+
}
|
|
595
|
+
function readNextLzwCode(context) {
|
|
596
|
+
while (context.bitCount < context.codeSize) {
|
|
597
|
+
if (context.dataOffset >= context.compressedData.length) {
|
|
598
|
+
throw new Error("Unexpected end of compressed image data before End of Information code");
|
|
599
|
+
}
|
|
600
|
+
context.bitBuffer |= context.compressedData[context.dataOffset] << context.bitCount;
|
|
601
|
+
context.bitCount += 8;
|
|
602
|
+
context.dataOffset += 1;
|
|
603
|
+
}
|
|
604
|
+
const currentCode = context.bitBuffer & (1 << context.codeSize) - 1;
|
|
605
|
+
context.bitBuffer >>= context.codeSize;
|
|
606
|
+
context.bitCount -= context.codeSize;
|
|
607
|
+
return currentCode;
|
|
608
|
+
}
|
|
609
|
+
function validateFirstLzwCode(context, currentCode, { strict }) {
|
|
610
|
+
if (context.hasReadAnyCode) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
context.hasReadAnyCode = true;
|
|
614
|
+
if (strict && currentCode !== context.clearCode) {
|
|
615
|
+
throw new Error("LZW image data must start with a Clear code");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function validateNoUnusedCompressedData(context, { strict }) {
|
|
619
|
+
if (strict && context.dataOffset < context.compressedData.length) {
|
|
620
|
+
throw new Error("Found unused compressed image data after the End of Information code");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function expandLzwCode(context, currentCode) {
|
|
624
|
+
if (currentCode > context.nextAvailableCode) {
|
|
625
|
+
throw new Error(`Encountered invalid compressed code ${currentCode}`);
|
|
626
|
+
}
|
|
627
|
+
let stackLength = 0;
|
|
628
|
+
let codeToExpand = currentCode;
|
|
629
|
+
if (currentCode === context.nextAvailableCode) {
|
|
630
|
+
if (context.previousCode === -1) {
|
|
631
|
+
throw new Error("Encountered a dictionary-reference code before any previous code existed");
|
|
632
|
+
}
|
|
633
|
+
context.outputStack[stackLength] = context.firstByteOfCurrentString;
|
|
634
|
+
stackLength += 1;
|
|
635
|
+
codeToExpand = context.previousCode;
|
|
636
|
+
}
|
|
637
|
+
while (codeToExpand > context.clearCode + 1) {
|
|
638
|
+
context.outputStack[stackLength] = context.suffixBytes[codeToExpand];
|
|
639
|
+
stackLength += 1;
|
|
640
|
+
codeToExpand = context.prefixCodes[codeToExpand];
|
|
641
|
+
if (stackLength >= context.outputStack.length) {
|
|
642
|
+
throw new Error("Compressed code expansion overflowed the output stack");
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const firstByte = context.suffixBytes[codeToExpand];
|
|
646
|
+
context.outputStack[stackLength] = firstByte;
|
|
647
|
+
stackLength += 1;
|
|
648
|
+
context.firstByteOfCurrentString = firstByte;
|
|
649
|
+
context.currentStackLength = stackLength;
|
|
650
|
+
context.currentFirstByte = firstByte;
|
|
651
|
+
}
|
|
652
|
+
function copyLzwStackToPixels(context, expectedPixelCount) {
|
|
653
|
+
for (let stackIndex = context.currentStackLength - 1; stackIndex >= 0; stackIndex -= 1) {
|
|
654
|
+
if (context.outputOffset >= expectedPixelCount) {
|
|
655
|
+
throw new Error("Decompressed more pixels than the image dimensions allow");
|
|
656
|
+
}
|
|
657
|
+
const pixelIndex = context.outputStack[stackIndex];
|
|
658
|
+
if (context.colorTableEntryCount !== void 0 && pixelIndex >= context.colorTableEntryCount) {
|
|
659
|
+
throw new Error(`Pixel ${context.outputOffset} uses palette index ${pixelIndex}, but the active color table only has ${context.colorTableEntryCount} entries`);
|
|
660
|
+
}
|
|
661
|
+
context.decodedPixels[context.outputOffset] = pixelIndex;
|
|
662
|
+
context.outputOffset += 1;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
function addLzwDictionaryEntry(context) {
|
|
666
|
+
if (context.previousCode === -1 || context.nextAvailableCode >= 4096) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
context.prefixCodes[context.nextAvailableCode] = context.previousCode;
|
|
670
|
+
context.suffixBytes[context.nextAvailableCode] = context.currentFirstByte;
|
|
671
|
+
context.nextAvailableCode += 1;
|
|
672
|
+
if (context.nextAvailableCode === 1 << context.codeSize && context.codeSize < 12) {
|
|
673
|
+
context.codeSize += 1;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
function encodeCompressedIndexStream(indexedPixels, minimumCodeSize) {
|
|
677
|
+
const clearCode = 1 << minimumCodeSize;
|
|
678
|
+
const endOfInformationCode = clearCode + 1;
|
|
679
|
+
const codeSequence = [clearCode];
|
|
680
|
+
if (indexedPixels.length === 0) {
|
|
681
|
+
codeSequence.push(endOfInformationCode);
|
|
682
|
+
return packCompressedCodeSequence(codeSequence, minimumCodeSize);
|
|
683
|
+
}
|
|
684
|
+
if (indexedPixels.length < 4096) {
|
|
685
|
+
return encodeCompressedIndexStreamWithMap(indexedPixels, minimumCodeSize);
|
|
686
|
+
}
|
|
687
|
+
return encodeCompressedIndexStreamWithDenseLookup(indexedPixels, minimumCodeSize);
|
|
688
|
+
}
|
|
689
|
+
function encodeCompressedIndexStreamWithMap(indexedPixels, minimumCodeSize) {
|
|
690
|
+
const clearCode = 1 << minimumCodeSize;
|
|
691
|
+
const endOfInformationCode = clearCode + 1;
|
|
692
|
+
let nextAvailableCode = clearCode + 2;
|
|
693
|
+
const codeLookup = /* @__PURE__ */ new Map();
|
|
694
|
+
const codeSequence = [clearCode];
|
|
695
|
+
function resetDictionary() {
|
|
696
|
+
codeLookup.clear();
|
|
697
|
+
nextAvailableCode = clearCode + 2;
|
|
698
|
+
}
|
|
699
|
+
let currentCode = indexedPixels[0];
|
|
700
|
+
for (let index = 1; index < indexedPixels.length; index += 1) {
|
|
701
|
+
const nextPixelIndex = indexedPixels[index];
|
|
702
|
+
const dictionaryKey = currentCode << 8 | nextPixelIndex;
|
|
703
|
+
const combinedCode = codeLookup.get(dictionaryKey);
|
|
704
|
+
if (combinedCode !== void 0) {
|
|
705
|
+
currentCode = combinedCode;
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
codeSequence.push(currentCode);
|
|
709
|
+
if (nextAvailableCode < 4096) {
|
|
710
|
+
codeLookup.set(dictionaryKey, nextAvailableCode);
|
|
711
|
+
nextAvailableCode += 1;
|
|
712
|
+
} else {
|
|
713
|
+
codeSequence.push(clearCode);
|
|
714
|
+
resetDictionary();
|
|
715
|
+
}
|
|
716
|
+
currentCode = nextPixelIndex;
|
|
717
|
+
}
|
|
718
|
+
codeSequence.push(currentCode, endOfInformationCode);
|
|
719
|
+
return packCompressedCodeSequence(codeSequence, minimumCodeSize);
|
|
720
|
+
}
|
|
721
|
+
function encodeCompressedIndexStreamWithDenseLookup(indexedPixels, minimumCodeSize) {
|
|
722
|
+
const clearCode = 1 << minimumCodeSize;
|
|
723
|
+
const endOfInformationCode = clearCode + 1;
|
|
724
|
+
let nextAvailableCode = clearCode + 2;
|
|
725
|
+
const codeLookup = new Uint16Array(4096 * 256);
|
|
726
|
+
const touchedDictionaryKeys = new Uint32Array(4096);
|
|
727
|
+
let touchedDictionaryKeyCount = 0;
|
|
728
|
+
const codeSequence = [clearCode];
|
|
729
|
+
function resetDictionary() {
|
|
730
|
+
for (let index = 0; index < touchedDictionaryKeyCount; index += 1) {
|
|
731
|
+
codeLookup[touchedDictionaryKeys[index]] = 0;
|
|
732
|
+
}
|
|
733
|
+
touchedDictionaryKeyCount = 0;
|
|
734
|
+
nextAvailableCode = clearCode + 2;
|
|
735
|
+
}
|
|
736
|
+
let currentCode = indexedPixels[0];
|
|
737
|
+
for (let index = 1; index < indexedPixels.length; index += 1) {
|
|
738
|
+
const nextPixelIndex = indexedPixels[index];
|
|
739
|
+
const dictionaryKey = currentCode << 8 | nextPixelIndex;
|
|
740
|
+
const combinedCode = codeLookup[dictionaryKey];
|
|
741
|
+
if (combinedCode !== 0) {
|
|
742
|
+
currentCode = combinedCode;
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
codeSequence.push(currentCode);
|
|
746
|
+
if (nextAvailableCode < 4096) {
|
|
747
|
+
codeLookup[dictionaryKey] = nextAvailableCode;
|
|
748
|
+
touchedDictionaryKeys[touchedDictionaryKeyCount] = dictionaryKey;
|
|
749
|
+
touchedDictionaryKeyCount += 1;
|
|
750
|
+
nextAvailableCode += 1;
|
|
751
|
+
} else {
|
|
752
|
+
codeSequence.push(clearCode);
|
|
753
|
+
resetDictionary();
|
|
754
|
+
}
|
|
755
|
+
currentCode = nextPixelIndex;
|
|
756
|
+
}
|
|
757
|
+
codeSequence.push(currentCode, endOfInformationCode);
|
|
758
|
+
return packCompressedCodeSequence(codeSequence, minimumCodeSize);
|
|
759
|
+
}
|
|
760
|
+
function packCompressedCodeSequence(codeSequence, minimumCodeSize) {
|
|
761
|
+
const clearCode = 1 << minimumCodeSize;
|
|
762
|
+
const endOfInformationCode = clearCode + 1;
|
|
763
|
+
let codeSize = minimumCodeSize + 1;
|
|
764
|
+
let nextAvailableCode = clearCode + 2;
|
|
765
|
+
let previousCode;
|
|
766
|
+
let bitBuffer = 0;
|
|
767
|
+
let bitCount = 0;
|
|
768
|
+
const packedBytes = [];
|
|
769
|
+
for (const code of codeSequence) {
|
|
770
|
+
bitBuffer |= code << bitCount;
|
|
771
|
+
bitCount += codeSize;
|
|
772
|
+
while (bitCount >= 8) {
|
|
773
|
+
packedBytes.push(bitBuffer & 255);
|
|
774
|
+
bitBuffer >>= 8;
|
|
775
|
+
bitCount -= 8;
|
|
776
|
+
}
|
|
777
|
+
if (code === clearCode) {
|
|
778
|
+
codeSize = minimumCodeSize + 1;
|
|
779
|
+
nextAvailableCode = clearCode + 2;
|
|
780
|
+
previousCode = void 0;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
if (code === endOfInformationCode) {
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
if (previousCode !== void 0 && nextAvailableCode < 4096) {
|
|
787
|
+
nextAvailableCode += 1;
|
|
788
|
+
if (nextAvailableCode === 1 << codeSize && codeSize < 12) {
|
|
789
|
+
codeSize += 1;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
previousCode = code;
|
|
793
|
+
}
|
|
794
|
+
if (bitCount > 0) {
|
|
795
|
+
packedBytes.push(bitBuffer & 255);
|
|
796
|
+
}
|
|
797
|
+
return Uint8Array.from(packedBytes);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/loop-count.js
|
|
801
|
+
function renderTotalPlayCount(playCount) {
|
|
802
|
+
return playCount === "forever" ? Infinity : playCount ?? 1;
|
|
803
|
+
}
|
|
804
|
+
function normalizePlayCount(value, name) {
|
|
805
|
+
if (value === "forever") {
|
|
806
|
+
return value;
|
|
807
|
+
}
|
|
808
|
+
return requireIntegerInRange(value, 1, 65536, name);
|
|
809
|
+
}
|
|
810
|
+
function encodeNetscapeLoopCount(playCount, name) {
|
|
811
|
+
if (playCount === "forever") {
|
|
812
|
+
return 0;
|
|
813
|
+
}
|
|
814
|
+
return requireIntegerInRange(playCount, 1, 65536, name) - 1;
|
|
815
|
+
}
|
|
816
|
+
function encodeExplicitNetscapeLoopCount(playCount, name) {
|
|
817
|
+
if (playCount === "forever") {
|
|
818
|
+
return 0;
|
|
819
|
+
}
|
|
820
|
+
return requireIntegerInRange(playCount, 2, 65536, name) - 1;
|
|
821
|
+
}
|
|
822
|
+
function decodeNetscapeLoopCount(loopCount) {
|
|
823
|
+
return loopCount === 0 ? "forever" : loopCount + 1;
|
|
824
|
+
}
|
|
825
|
+
function rejectRenamedLoopCount(object) {
|
|
826
|
+
if (object.loopCount !== void 0) {
|
|
827
|
+
throw new TypeError("loopCount has been renamed to playCount");
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function containsNetscapeLoopingAppExtension(blocks) {
|
|
831
|
+
for (const block of blocks) {
|
|
832
|
+
if (isNetscapeLoopingAppExtension(block)) {
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
function createNetscapeLoopingAppExtension(loopCount) {
|
|
839
|
+
return {
|
|
840
|
+
type: "applicationExtension",
|
|
841
|
+
identifier: netscapeLoopingAppIdentifier,
|
|
842
|
+
authenticationCode: netscapeLoopingAppAuthenticationCode,
|
|
843
|
+
data: Uint8Array.of(1, loopCount & 255, loopCount >> 8 & 255)
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function isNetscapeLoopingAppExtension(block) {
|
|
847
|
+
return block.type === "applicationExtension" && block.identifier === netscapeLoopingAppIdentifier && block.data.length >= 3 && block.data[0] === 1 && areBytesEqual(normalizeFixedByteField(block.authenticationCode, 3, "applicationExtension.authenticationCode"), netscapeLoopingAppAuthenticationCodeBytes);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/decode.js
|
|
851
|
+
function decodeGIF(inputBytes, options = {}) {
|
|
852
|
+
const {
|
|
853
|
+
strict = true
|
|
854
|
+
} = options;
|
|
855
|
+
const byteReader = new GIFByteReader(inputBytes);
|
|
856
|
+
const header = readGIFHeader(byteReader, { strict });
|
|
857
|
+
const stream = readGIFBlockStream(byteReader, {
|
|
858
|
+
...header,
|
|
859
|
+
strict
|
|
860
|
+
});
|
|
861
|
+
if (strict && byteReader.offset !== byteReader.length) {
|
|
862
|
+
throw new Error(`Found ${byteReader.length - byteReader.offset} trailing byte(s) after the GIF trailer`);
|
|
863
|
+
}
|
|
864
|
+
return {
|
|
865
|
+
type: "gif",
|
|
866
|
+
version: header.version,
|
|
867
|
+
width: header.logicalScreenWidth,
|
|
868
|
+
height: header.logicalScreenHeight,
|
|
869
|
+
backgroundColorIndex: header.backgroundColorIndex,
|
|
870
|
+
globalColorTable: header.globalColorTable,
|
|
871
|
+
...stream.playCount !== void 0 && { playCount: stream.playCount },
|
|
872
|
+
blocks: stream.blocks,
|
|
873
|
+
imageBlocks: stream.imageBlocks
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
function readGIFHeader(byteReader, { strict }) {
|
|
877
|
+
const signature = byteReader.readAsciiString(3);
|
|
878
|
+
if (signature !== "GIF") {
|
|
879
|
+
throw new Error(`Expected GIF signature, got ${JSON.stringify(signature)}`);
|
|
880
|
+
}
|
|
881
|
+
const version = byteReader.readAsciiString(3);
|
|
882
|
+
if (version !== "87a" && version !== "89a") {
|
|
883
|
+
throw new Error(`Unsupported GIF version ${JSON.stringify(version)}`);
|
|
884
|
+
}
|
|
885
|
+
const logicalScreenWidth = byteReader.readUnsignedLittleEndian16();
|
|
886
|
+
const logicalScreenHeight = byteReader.readUnsignedLittleEndian16();
|
|
887
|
+
if (strict && (logicalScreenWidth === 0 || logicalScreenHeight === 0)) {
|
|
888
|
+
throw new Error("Logical Screen dimensions must be non-zero in strict mode");
|
|
889
|
+
}
|
|
890
|
+
const packedLogicalScreenField = byteReader.readByte();
|
|
891
|
+
const hasGlobalColorTable = (packedLogicalScreenField & 128) !== 0;
|
|
892
|
+
const globalColorTableSizeField = packedLogicalScreenField & 7;
|
|
893
|
+
const backgroundColorIndex = byteReader.readByte();
|
|
894
|
+
byteReader.readByte();
|
|
895
|
+
const globalColorTable = hasGlobalColorTable ? readColorTable(byteReader, globalColorTableSizeField) : void 0;
|
|
896
|
+
if (strict && globalColorTable !== void 0 && backgroundColorIndex >= globalColorTable.length / 3) {
|
|
897
|
+
throw new Error("Background color index must be inside the global color table in strict mode");
|
|
898
|
+
}
|
|
899
|
+
if (strict && globalColorTable === void 0 && backgroundColorIndex !== 0) {
|
|
900
|
+
throw new Error("Background color index must be zero when there is no global color table in strict mode");
|
|
901
|
+
}
|
|
902
|
+
return {
|
|
903
|
+
version,
|
|
904
|
+
logicalScreenWidth,
|
|
905
|
+
logicalScreenHeight,
|
|
906
|
+
backgroundColorIndex,
|
|
907
|
+
globalColorTable
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function readGIFBlockStream(byteReader, { version, logicalScreenWidth, logicalScreenHeight, globalColorTable, strict }) {
|
|
911
|
+
const blocks = [];
|
|
912
|
+
const imageBlocks = [];
|
|
913
|
+
let pendingGraphicControlExtension;
|
|
914
|
+
let playCount;
|
|
915
|
+
let blockCount = 0;
|
|
916
|
+
while (true) {
|
|
917
|
+
const nextByte = byteReader.readByte();
|
|
918
|
+
if (nextByte === trailerByte) {
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
blockCount += 1;
|
|
922
|
+
requireCountWithinLimit(blockCount, defaultMaximumBlockCount, "block count");
|
|
923
|
+
if (nextByte === imageSeparator) {
|
|
924
|
+
const imageBlock = readImageBlock({
|
|
925
|
+
byteReader,
|
|
926
|
+
logicalScreenWidth,
|
|
927
|
+
logicalScreenHeight,
|
|
928
|
+
globalColorTable,
|
|
929
|
+
graphicControlExtension: pendingGraphicControlExtension,
|
|
930
|
+
strict
|
|
931
|
+
});
|
|
932
|
+
blocks.push(imageBlock);
|
|
933
|
+
imageBlocks.push(imageBlock);
|
|
934
|
+
pendingGraphicControlExtension = void 0;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (nextByte !== extensionIntroducer) {
|
|
938
|
+
throw new Error(`Unexpected block introducer 0x${nextByte.toString(16).padStart(2, "0")} at byte offset ${byteReader.offset - 1}`);
|
|
939
|
+
}
|
|
940
|
+
const extensionLabel = byteReader.readByte();
|
|
941
|
+
if (strict && version === "87a" && isGIF89aExtensionLabel(extensionLabel)) {
|
|
942
|
+
throw new Error(`GIF87a streams cannot contain extension label 0x${extensionLabel.toString(16).padStart(2, "0")}`);
|
|
943
|
+
}
|
|
944
|
+
switch (extensionLabel) {
|
|
945
|
+
case graphicControlExtensionLabel: {
|
|
946
|
+
if (pendingGraphicControlExtension !== void 0 && strict) {
|
|
947
|
+
throw new Error("A second Graphic Control Extension appeared before a graphic rendering block");
|
|
948
|
+
}
|
|
949
|
+
pendingGraphicControlExtension = readGraphicControlExtension(byteReader, { strict });
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
case commentExtensionLabel: {
|
|
953
|
+
const commentBlock = {
|
|
954
|
+
type: "commentExtension",
|
|
955
|
+
data: readDataSubBlocks(byteReader)
|
|
956
|
+
};
|
|
957
|
+
blocks.push(commentBlock);
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
case plainTextExtensionLabel: {
|
|
961
|
+
blocks.push(readUnknownExtension(byteReader, plainTextExtensionLabel));
|
|
962
|
+
pendingGraphicControlExtension = void 0;
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
case appExtensionLabel: {
|
|
966
|
+
const appBlock = readAppExtension(byteReader, { strict });
|
|
967
|
+
blocks.push(appBlock);
|
|
968
|
+
if (isNetscapeLoopingAppExtension(appBlock)) {
|
|
969
|
+
playCount = decodeNetscapeLoopCount(appBlock.data[1] | appBlock.data[2] << 8);
|
|
970
|
+
appBlock.isNetscapeLoopingExtension = true;
|
|
971
|
+
appBlock.playCount = playCount;
|
|
972
|
+
}
|
|
973
|
+
break;
|
|
974
|
+
}
|
|
975
|
+
default: {
|
|
976
|
+
const unknownExtensionBlock = version === "87a" ? readGIF87aUnknownExtension(byteReader, extensionLabel) : readUnknownExtension(byteReader, extensionLabel);
|
|
977
|
+
blocks.push(unknownExtensionBlock);
|
|
978
|
+
if (isGraphicRenderingExtensionLabel(extensionLabel)) {
|
|
979
|
+
pendingGraphicControlExtension = void 0;
|
|
980
|
+
}
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (pendingGraphicControlExtension !== void 0 && strict) {
|
|
986
|
+
throw new Error("A Graphic Control Extension was not followed by a graphic rendering block");
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
playCount,
|
|
990
|
+
blocks,
|
|
991
|
+
imageBlocks
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
function readImageBlock({ byteReader, logicalScreenWidth, logicalScreenHeight, globalColorTable, graphicControlExtension, strict }) {
|
|
995
|
+
const descriptor = readImageDescriptor(byteReader, {
|
|
996
|
+
logicalScreenWidth,
|
|
997
|
+
logicalScreenHeight,
|
|
998
|
+
strict
|
|
999
|
+
});
|
|
1000
|
+
const {
|
|
1001
|
+
left,
|
|
1002
|
+
top,
|
|
1003
|
+
width,
|
|
1004
|
+
height,
|
|
1005
|
+
hasLocalColorTable,
|
|
1006
|
+
isInterlaced,
|
|
1007
|
+
colorTableSizeField
|
|
1008
|
+
} = descriptor;
|
|
1009
|
+
const colorTable = hasLocalColorTable ? readColorTable(byteReader, colorTableSizeField) : void 0;
|
|
1010
|
+
const activeColorTable = colorTable ?? globalColorTable;
|
|
1011
|
+
if (strict && activeColorTable === void 0) {
|
|
1012
|
+
throw new Error("Image block requires an active color table in strict mode");
|
|
1013
|
+
}
|
|
1014
|
+
validateTransparentColorIndex(graphicControlExtension, activeColorTable, { strict });
|
|
1015
|
+
const minimumCodeSize = byteReader.readByte();
|
|
1016
|
+
if (minimumCodeSize < 2 || minimumCodeSize > 8) {
|
|
1017
|
+
throw new Error(`Invalid minimum code size ${minimumCodeSize}; GIF requires a value between 2 and 8`);
|
|
1018
|
+
}
|
|
1019
|
+
const compressedData = readDataSubBlocks(byteReader);
|
|
1020
|
+
const expectedPixelCount = width * height;
|
|
1021
|
+
const colorTableEntryCount = strict && activeColorTable !== void 0 ? activeColorTable.length / 3 : void 0;
|
|
1022
|
+
let indexedPixels = decodeCompressedIndexStream(compressedData, minimumCodeSize, expectedPixelCount, {
|
|
1023
|
+
strict,
|
|
1024
|
+
colorTableEntryCount
|
|
1025
|
+
});
|
|
1026
|
+
if (isInterlaced) {
|
|
1027
|
+
indexedPixels = deinterlaceIndexedPixels(indexedPixels, width, height);
|
|
1028
|
+
}
|
|
1029
|
+
return {
|
|
1030
|
+
type: "image",
|
|
1031
|
+
graphicControlExtension: graphicControlExtension === void 0 ? void 0 : { ...graphicControlExtension },
|
|
1032
|
+
left,
|
|
1033
|
+
top,
|
|
1034
|
+
width,
|
|
1035
|
+
height,
|
|
1036
|
+
isInterlaced,
|
|
1037
|
+
colorTable,
|
|
1038
|
+
minimumCodeSize,
|
|
1039
|
+
pixels: indexedPixels
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
function readImageDescriptor(byteReader, { logicalScreenWidth, logicalScreenHeight, strict }) {
|
|
1043
|
+
const left = byteReader.readUnsignedLittleEndian16();
|
|
1044
|
+
const top = byteReader.readUnsignedLittleEndian16();
|
|
1045
|
+
const width = byteReader.readUnsignedLittleEndian16();
|
|
1046
|
+
const height = byteReader.readUnsignedLittleEndian16();
|
|
1047
|
+
if (strict && (width === 0 || height === 0)) {
|
|
1048
|
+
throw new Error("Image block dimensions must be non-zero in strict mode");
|
|
1049
|
+
}
|
|
1050
|
+
const packedImageField = byteReader.readByte();
|
|
1051
|
+
const hasLocalColorTable = (packedImageField & 128) !== 0;
|
|
1052
|
+
const isInterlaced = (packedImageField & 64) !== 0;
|
|
1053
|
+
const reservedBits = packedImageField >> 3 & 3;
|
|
1054
|
+
if (strict && reservedBits !== 0) {
|
|
1055
|
+
throw new Error("Image Descriptor reserved bits must be zero");
|
|
1056
|
+
}
|
|
1057
|
+
if (left + width > logicalScreenWidth || top + height > logicalScreenHeight) {
|
|
1058
|
+
throw new Error("Image block extends beyond the logical screen bounds");
|
|
1059
|
+
}
|
|
1060
|
+
const colorTableSizeField = packedImageField & 7;
|
|
1061
|
+
requirePixelCountWithinLimit(width, height, defaultMaximumPixelCount, "image block");
|
|
1062
|
+
return {
|
|
1063
|
+
left,
|
|
1064
|
+
top,
|
|
1065
|
+
width,
|
|
1066
|
+
height,
|
|
1067
|
+
hasLocalColorTable,
|
|
1068
|
+
isInterlaced,
|
|
1069
|
+
colorTableSizeField
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
function validateTransparentColorIndex(graphicControlExtension, activeColorTable, { strict }) {
|
|
1073
|
+
if (strict && (graphicControlExtension == null ? void 0 : graphicControlExtension.transparentColorIndex) !== void 0 && activeColorTable !== void 0 && graphicControlExtension.transparentColorIndex >= activeColorTable.length / 3) {
|
|
1074
|
+
throw new Error("Transparent color index must be inside the active color table in strict mode");
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
function readGraphicControlExtension(byteReader, { strict }) {
|
|
1078
|
+
const blockSize = byteReader.readByte();
|
|
1079
|
+
if (blockSize !== 4) {
|
|
1080
|
+
throw new Error(`Invalid Graphic Control Extension block size ${blockSize}; expected 4`);
|
|
1081
|
+
}
|
|
1082
|
+
const packedField = byteReader.readByte();
|
|
1083
|
+
const reservedBits = packedField >> 5;
|
|
1084
|
+
if (reservedBits !== 0 && strict) {
|
|
1085
|
+
throw new Error("Graphic Control Extension reserved bits must be zero");
|
|
1086
|
+
}
|
|
1087
|
+
const disposalMethodField = packedField >> 2 & 7;
|
|
1088
|
+
if (strict && disposalMethodField >= disposalMethodNames.length) {
|
|
1089
|
+
throw new Error("Disposal methods 4-7 are reserved in the GIF89a specification");
|
|
1090
|
+
}
|
|
1091
|
+
const isTransparencyFlag = (packedField & 1) !== 0;
|
|
1092
|
+
const delayInHundredthsOfASecond = byteReader.readUnsignedLittleEndian16();
|
|
1093
|
+
const transparentColorIndex = byteReader.readByte();
|
|
1094
|
+
const blockTerminator = byteReader.readByte();
|
|
1095
|
+
if (blockTerminator !== 0) {
|
|
1096
|
+
throw new Error("Graphic Control Extension is missing its block terminator");
|
|
1097
|
+
}
|
|
1098
|
+
return {
|
|
1099
|
+
disposalMethod: disposalMethodNames[disposalMethodField] ?? "unspecified",
|
|
1100
|
+
delay: delayInHundredthsOfASecond / 100,
|
|
1101
|
+
transparentColorIndex: isTransparencyFlag ? transparentColorIndex : void 0
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
function readAppExtension(byteReader, { strict }) {
|
|
1105
|
+
const blockSize = byteReader.readByte();
|
|
1106
|
+
if (blockSize !== 11) {
|
|
1107
|
+
throw new Error(`Invalid Application Extension block size ${blockSize}; expected 11`);
|
|
1108
|
+
}
|
|
1109
|
+
const identifier = byteReader.readAsciiString(8);
|
|
1110
|
+
if (strict && new RegExp("[^\\u{20}-\\u{7E}]", "v").test(identifier)) {
|
|
1111
|
+
throw new Error("Application Identifier must use printable ASCII characters");
|
|
1112
|
+
}
|
|
1113
|
+
const authenticationCode = byteReader.readBytes(3);
|
|
1114
|
+
const data = readDataSubBlocks(byteReader);
|
|
1115
|
+
return {
|
|
1116
|
+
type: "applicationExtension",
|
|
1117
|
+
identifier,
|
|
1118
|
+
authenticationCode,
|
|
1119
|
+
data
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
function isGIF89aExtensionLabel(extensionLabel) {
|
|
1123
|
+
return [
|
|
1124
|
+
graphicControlExtensionLabel,
|
|
1125
|
+
commentExtensionLabel,
|
|
1126
|
+
plainTextExtensionLabel,
|
|
1127
|
+
appExtensionLabel
|
|
1128
|
+
].includes(extensionLabel);
|
|
1129
|
+
}
|
|
1130
|
+
function readUnknownExtension(byteReader, extensionLabel) {
|
|
1131
|
+
const fixedBlockSize = byteReader.readByte();
|
|
1132
|
+
const fixedData = byteReader.readBytes(fixedBlockSize);
|
|
1133
|
+
if (fixedBlockSize === 0) {
|
|
1134
|
+
return {
|
|
1135
|
+
type: "unknownExtension",
|
|
1136
|
+
extensionLabel,
|
|
1137
|
+
fixedData,
|
|
1138
|
+
data: new Uint8Array()
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
const data = readDataSubBlocks(byteReader);
|
|
1142
|
+
return {
|
|
1143
|
+
type: "unknownExtension",
|
|
1144
|
+
extensionLabel,
|
|
1145
|
+
fixedData,
|
|
1146
|
+
data
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function readGIF87aUnknownExtension(byteReader, extensionLabel) {
|
|
1150
|
+
return {
|
|
1151
|
+
type: "unknownExtension",
|
|
1152
|
+
extensionLabel,
|
|
1153
|
+
fixedData: new Uint8Array(),
|
|
1154
|
+
data: readDataSubBlocks(byteReader)
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
function isGraphicRenderingExtensionLabel(extensionLabel) {
|
|
1158
|
+
return extensionLabel <= 127 && extensionLabel !== trailerByte;
|
|
1159
|
+
}
|
|
1160
|
+
function readDataSubBlocks(byteReader) {
|
|
1161
|
+
let concatenatedData = new Uint8Array(1024);
|
|
1162
|
+
let totalLength = 0;
|
|
1163
|
+
let subBlockCount = 0;
|
|
1164
|
+
while (true) {
|
|
1165
|
+
const blockSize = byteReader.readByte();
|
|
1166
|
+
if (blockSize === 0) {
|
|
1167
|
+
break;
|
|
1168
|
+
}
|
|
1169
|
+
subBlockCount += 1;
|
|
1170
|
+
requireCountWithinLimit(subBlockCount, defaultMaximumDataSubBlockCount, "data sub-block count");
|
|
1171
|
+
const nextTotalLength = totalLength + blockSize;
|
|
1172
|
+
requireByteLengthWithinLimit(nextTotalLength, defaultMaximumDataPayloadByteLength, "data payload");
|
|
1173
|
+
if (nextTotalLength > concatenatedData.length) {
|
|
1174
|
+
const nextCapacity = Math.min(defaultMaximumDataPayloadByteLength, Math.max(nextTotalLength, concatenatedData.length * 2));
|
|
1175
|
+
const nextConcatenatedData = new Uint8Array(nextCapacity);
|
|
1176
|
+
nextConcatenatedData.set(uint8ArraySubarray.call(concatenatedData, 0, totalLength));
|
|
1177
|
+
concatenatedData = nextConcatenatedData;
|
|
1178
|
+
}
|
|
1179
|
+
byteReader.readBytesInto(concatenatedData, totalLength, blockSize);
|
|
1180
|
+
totalLength = nextTotalLength;
|
|
1181
|
+
}
|
|
1182
|
+
return concatenatedData.slice(0, totalLength);
|
|
1183
|
+
}
|
|
1184
|
+
function readColorTable(byteReader, sizeField) {
|
|
1185
|
+
const entryCount = 1 << sizeField + 1;
|
|
1186
|
+
const byteLength = entryCount * 3;
|
|
1187
|
+
return byteReader.readBytes(byteLength);
|
|
1188
|
+
}
|
|
1189
|
+
function deinterlaceIndexedPixels(indexedPixels, width, height) {
|
|
1190
|
+
const deinterlacedPixels = new Uint8Array(indexedPixels.length);
|
|
1191
|
+
let sourceOffset = 0;
|
|
1192
|
+
for (const [startRow, rowStep] of [[0, 8], [4, 8], [2, 4], [1, 2]]) {
|
|
1193
|
+
for (let row = startRow; row < height; row += rowStep) {
|
|
1194
|
+
const destinationOffset = row * width;
|
|
1195
|
+
deinterlacedPixels.set(uint8ArraySubarray.call(indexedPixels, sourceOffset, sourceOffset + width), destinationOffset);
|
|
1196
|
+
sourceOffset += width;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return deinterlacedPixels;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/quantize.js
|
|
1203
|
+
function indexedImage(pixels, options = {}) {
|
|
1204
|
+
const {
|
|
1205
|
+
transparentColor = [0, 0, 0]
|
|
1206
|
+
} = options;
|
|
1207
|
+
if (!isUint8Array(pixels) && !isUint8ClampedArray(pixels)) {
|
|
1208
|
+
throw new TypeError("Expected pixels to be a Uint8Array or Uint8ClampedArray");
|
|
1209
|
+
}
|
|
1210
|
+
const redGreenBlueAlphaBytes = toUint8ArrayView(pixels);
|
|
1211
|
+
if (redGreenBlueAlphaBytes.length % 4 !== 0) {
|
|
1212
|
+
throw new Error("pixels length must be divisible by 4");
|
|
1213
|
+
}
|
|
1214
|
+
requirePixelCountValueWithinLimit(redGreenBlueAlphaBytes.length / 4, defaultMaximumIndexedImagePixelCount, "pixels");
|
|
1215
|
+
const [transparentRed, transparentGreen, transparentBlue] = normalizeSingleColorTriplet(transparentColor, "transparentColor");
|
|
1216
|
+
const paletteLookup = /* @__PURE__ */ new Map();
|
|
1217
|
+
const palette = [];
|
|
1218
|
+
const indexedPixels = new Uint8Array(redGreenBlueAlphaBytes.length / 4);
|
|
1219
|
+
let transparentColorIndex;
|
|
1220
|
+
for (let pixelOffset = 0, pixelIndex = 0; pixelOffset < redGreenBlueAlphaBytes.length; pixelOffset += 4, pixelIndex += 1) {
|
|
1221
|
+
const red = redGreenBlueAlphaBytes[pixelOffset];
|
|
1222
|
+
const green = redGreenBlueAlphaBytes[pixelOffset + 1];
|
|
1223
|
+
const blue = redGreenBlueAlphaBytes[pixelOffset + 2];
|
|
1224
|
+
const alpha = redGreenBlueAlphaBytes[pixelOffset + 3];
|
|
1225
|
+
if (alpha !== 0 && alpha !== 255) {
|
|
1226
|
+
throw new Error(`Pixel ${pixelIndex} has alpha ${alpha}; GIF only supports fully transparent or fully opaque pixels`);
|
|
1227
|
+
}
|
|
1228
|
+
if (alpha === 0) {
|
|
1229
|
+
if (transparentColorIndex === void 0) {
|
|
1230
|
+
transparentColorIndex = palette.length / 3;
|
|
1231
|
+
palette.push(transparentRed, transparentGreen, transparentBlue);
|
|
1232
|
+
}
|
|
1233
|
+
indexedPixels[pixelIndex] = transparentColorIndex;
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
const lookupKey = `${red},${green},${blue}`;
|
|
1237
|
+
let paletteIndex = paletteLookup.get(lookupKey);
|
|
1238
|
+
if (paletteIndex === void 0) {
|
|
1239
|
+
paletteIndex = palette.length / 3;
|
|
1240
|
+
if (paletteIndex >= 256) {
|
|
1241
|
+
throw new Error("The image uses more than 256 palette entries");
|
|
1242
|
+
}
|
|
1243
|
+
palette.push(red, green, blue);
|
|
1244
|
+
paletteLookup.set(lookupKey, paletteIndex);
|
|
1245
|
+
}
|
|
1246
|
+
indexedPixels[pixelIndex] = paletteIndex;
|
|
1247
|
+
}
|
|
1248
|
+
const colorTable = padColorTableToPowerOfTwo(Uint8Array.from(palette));
|
|
1249
|
+
return {
|
|
1250
|
+
pixels: indexedPixels,
|
|
1251
|
+
colorTable,
|
|
1252
|
+
transparentColorIndex
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function normalizeRGBAImageData(pixels, block, graphicControlExtension) {
|
|
1256
|
+
const indexedImageData = indexedImage(pixels, {
|
|
1257
|
+
transparentColor: block.transparentColor ?? [0, 0, 0]
|
|
1258
|
+
});
|
|
1259
|
+
const normalizedGraphicControlExtension = indexedImageData.transparentColorIndex !== void 0 || graphicControlExtension !== void 0 ? {
|
|
1260
|
+
disposalMethod: (graphicControlExtension == null ? void 0 : graphicControlExtension.disposalMethod) ?? "unspecified",
|
|
1261
|
+
delayInHundredthsOfASecond: (graphicControlExtension == null ? void 0 : graphicControlExtension.delayInHundredthsOfASecond) ?? 0,
|
|
1262
|
+
transparentColorIndex: indexedImageData.transparentColorIndex
|
|
1263
|
+
} : void 0;
|
|
1264
|
+
return {
|
|
1265
|
+
indexedPixels: indexedImageData.pixels,
|
|
1266
|
+
colorTable: indexedImageData.colorTable,
|
|
1267
|
+
graphicControlExtension: normalizedGraphicControlExtension
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
function buildQuantizedIndexedImage(pixels, { quality }) {
|
|
1271
|
+
const redGreenBlueAlphaBytes = toUint8ArrayView(pixels);
|
|
1272
|
+
requirePixelCountValueWithinLimit(redGreenBlueAlphaBytes.length / 4, defaultMaximumIndexedImagePixelCount, "pixels");
|
|
1273
|
+
const hasTransparency = hasTransparentPixels(redGreenBlueAlphaBytes);
|
|
1274
|
+
const colorBits = quantizationBitsForQuality(quality, hasTransparency ? 255 : 256);
|
|
1275
|
+
const paletteLookup = /* @__PURE__ */ new Map();
|
|
1276
|
+
const palette = [];
|
|
1277
|
+
const indexedPixels = new Uint8Array(redGreenBlueAlphaBytes.length / 4);
|
|
1278
|
+
let transparentColorIndex;
|
|
1279
|
+
for (let pixelOffset = 0, pixelIndex = 0; pixelOffset < redGreenBlueAlphaBytes.length; pixelOffset += 4, pixelIndex += 1) {
|
|
1280
|
+
const red = redGreenBlueAlphaBytes[pixelOffset];
|
|
1281
|
+
const green = redGreenBlueAlphaBytes[pixelOffset + 1];
|
|
1282
|
+
const blue = redGreenBlueAlphaBytes[pixelOffset + 2];
|
|
1283
|
+
const alpha = redGreenBlueAlphaBytes[pixelOffset + 3];
|
|
1284
|
+
if (alpha === 0) {
|
|
1285
|
+
if (transparentColorIndex === void 0) {
|
|
1286
|
+
transparentColorIndex = palette.length / 3;
|
|
1287
|
+
palette.push(0, 0, 0);
|
|
1288
|
+
}
|
|
1289
|
+
indexedPixels[pixelIndex] = transparentColorIndex;
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
const quantizedRed = quantizeColorChannel(red, colorBits.red);
|
|
1293
|
+
const quantizedGreen = quantizeColorChannel(green, colorBits.green);
|
|
1294
|
+
const quantizedBlue = quantizeColorChannel(blue, colorBits.blue);
|
|
1295
|
+
const lookupKey = `${quantizedRed},${quantizedGreen},${quantizedBlue}`;
|
|
1296
|
+
let paletteIndex = paletteLookup.get(lookupKey);
|
|
1297
|
+
if (paletteIndex === void 0) {
|
|
1298
|
+
paletteIndex = palette.length / 3;
|
|
1299
|
+
palette.push(quantizedRed, quantizedGreen, quantizedBlue);
|
|
1300
|
+
paletteLookup.set(lookupKey, paletteIndex);
|
|
1301
|
+
}
|
|
1302
|
+
indexedPixels[pixelIndex] = paletteIndex;
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
pixels: indexedPixels,
|
|
1306
|
+
colorTable: padColorTableToPowerOfTwo(Uint8Array.from(palette)),
|
|
1307
|
+
transparentColorIndex
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
function hasTransparentPixels(redGreenBlueAlphaBytes) {
|
|
1311
|
+
for (let offset = 3; offset < redGreenBlueAlphaBytes.length; offset += 4) {
|
|
1312
|
+
if (redGreenBlueAlphaBytes[offset] === 0) {
|
|
1313
|
+
return true;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return false;
|
|
1317
|
+
}
|
|
1318
|
+
function quantizationBitsForQuality(quality, maximumColorCount) {
|
|
1319
|
+
const targetColorCount = Math.max(2, Math.min(maximumColorCount, Math.round(2 + quality * (maximumColorCount - 2))));
|
|
1320
|
+
let bitCount = Math.floor(Math.log2(targetColorCount));
|
|
1321
|
+
const bits = [0, 0, 0];
|
|
1322
|
+
let channelIndex = 0;
|
|
1323
|
+
while (bitCount > 0) {
|
|
1324
|
+
bits[channelIndex] += 1;
|
|
1325
|
+
channelIndex = (channelIndex + 1) % bits.length;
|
|
1326
|
+
bitCount -= 1;
|
|
1327
|
+
}
|
|
1328
|
+
return {
|
|
1329
|
+
red: bits[0],
|
|
1330
|
+
green: bits[1],
|
|
1331
|
+
blue: bits[2]
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
function quantizeColorChannel(value, bitCount) {
|
|
1335
|
+
if (bitCount >= 8) {
|
|
1336
|
+
return value;
|
|
1337
|
+
}
|
|
1338
|
+
if (bitCount === 0) {
|
|
1339
|
+
return 0;
|
|
1340
|
+
}
|
|
1341
|
+
const maximumValue = (1 << bitCount) - 1;
|
|
1342
|
+
return Math.round(Math.round(value * maximumValue / 255) * 255 / maximumValue);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/encode.js
|
|
1346
|
+
function encodeGIF(gif) {
|
|
1347
|
+
const normalizedGif = normalizeGIFForEncoding(gif);
|
|
1348
|
+
const byteWriter = new GIFByteWriter();
|
|
1349
|
+
byteWriter.writeAsciiString("GIF");
|
|
1350
|
+
byteWriter.writeAsciiString(normalizedGif.version);
|
|
1351
|
+
writeGIFHeader(byteWriter, normalizedGif);
|
|
1352
|
+
writeGIFBlocks(byteWriter, normalizedGif);
|
|
1353
|
+
byteWriter.writeByte(trailerByte);
|
|
1354
|
+
return byteWriter.toUint8Array();
|
|
1355
|
+
}
|
|
1356
|
+
function normalizeGIFForEncoding(gif) {
|
|
1357
|
+
if (!gif || typeof gif !== "object") {
|
|
1358
|
+
throw new TypeError("Expected a GIF description object");
|
|
1359
|
+
}
|
|
1360
|
+
const logicalScreenWidth = requireNonZeroUnsigned16(gif.width, "width");
|
|
1361
|
+
const logicalScreenHeight = requireNonZeroUnsigned16(gif.height, "height");
|
|
1362
|
+
const globalColorTable = normalizeColorTable(gif.globalColorTable, "globalColorTable");
|
|
1363
|
+
const backgroundColorIndex = requireByte(gif.backgroundColorIndex ?? 0, "backgroundColorIndex");
|
|
1364
|
+
rejectRenamedLoopCount(gif);
|
|
1365
|
+
if (globalColorTable === void 0 && backgroundColorIndex !== 0) {
|
|
1366
|
+
throw new Error("Background color index must be zero when there is no global color table");
|
|
1367
|
+
}
|
|
1368
|
+
if (globalColorTable !== void 0 && backgroundColorIndex >= globalColorTable.length / 3) {
|
|
1369
|
+
throw new Error("Background color index must be inside the global color table");
|
|
1370
|
+
}
|
|
1371
|
+
const loopCount = gif.playCount === void 0 || gif.playCount === 1 ? void 0 : encodeNetscapeLoopCount(gif.playCount, "playCount");
|
|
1372
|
+
const blocks = normalizeBlocksForEncoding(gif, globalColorTable, {
|
|
1373
|
+
loopCount
|
|
1374
|
+
});
|
|
1375
|
+
return {
|
|
1376
|
+
version: "89a",
|
|
1377
|
+
logicalScreenWidth,
|
|
1378
|
+
logicalScreenHeight,
|
|
1379
|
+
backgroundColorIndex,
|
|
1380
|
+
globalColorTable,
|
|
1381
|
+
blocks
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
function normalizeBlocksForEncoding(gif, globalColorTable, { loopCount }) {
|
|
1385
|
+
if (gif.imageBlocks !== void 0) {
|
|
1386
|
+
throw new Error("imageBlocks is not supported when encoding; use blocks");
|
|
1387
|
+
}
|
|
1388
|
+
let sourceBlocks;
|
|
1389
|
+
if (gif.blocks === void 0) {
|
|
1390
|
+
sourceBlocks = [];
|
|
1391
|
+
} else if (Array.isArray(gif.blocks)) {
|
|
1392
|
+
sourceBlocks = gif.blocks;
|
|
1393
|
+
} else {
|
|
1394
|
+
throw new TypeError("blocks must be an array");
|
|
1395
|
+
}
|
|
1396
|
+
const sourceBlockCount = sourceBlocks.length;
|
|
1397
|
+
requireCountWithinLimit(sourceBlockCount, defaultMaximumBlockCount, "block count");
|
|
1398
|
+
validateEncodeWorkCost(sourceBlocks, sourceBlockCount);
|
|
1399
|
+
const blocks = [];
|
|
1400
|
+
let index = 0;
|
|
1401
|
+
while (index < sourceBlockCount) {
|
|
1402
|
+
blocks.push(normalizeBlock(sourceBlocks[index], globalColorTable));
|
|
1403
|
+
index += 1;
|
|
1404
|
+
}
|
|
1405
|
+
if (loopCount === void 0 || containsNetscapeLoopingAppExtension(blocks)) {
|
|
1406
|
+
requireCountWithinLimit(countEncodedStreamBlocks(blocks), defaultMaximumBlockCount, "block count");
|
|
1407
|
+
return blocks;
|
|
1408
|
+
}
|
|
1409
|
+
const blocksWithLoopExtension = [
|
|
1410
|
+
createNetscapeLoopingAppExtension(loopCount),
|
|
1411
|
+
...blocks
|
|
1412
|
+
];
|
|
1413
|
+
requireCountWithinLimit(countEncodedStreamBlocks(blocksWithLoopExtension), defaultMaximumBlockCount, "block count");
|
|
1414
|
+
return blocksWithLoopExtension;
|
|
1415
|
+
}
|
|
1416
|
+
function countEncodedStreamBlocks(blocks) {
|
|
1417
|
+
let blockCount = 0;
|
|
1418
|
+
for (const block of blocks) {
|
|
1419
|
+
blockCount += 1;
|
|
1420
|
+
if (block.type === "image" && (block.graphicControlExtension !== void 0 || block.indexedPixels === void 0 && block.pixels !== void 0)) {
|
|
1421
|
+
blockCount += 1;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return blockCount;
|
|
1425
|
+
}
|
|
1426
|
+
function validateEncodeWorkCost(blocks, blockCount = blocks.length) {
|
|
1427
|
+
let workCost = 0;
|
|
1428
|
+
let index = 0;
|
|
1429
|
+
while (index < blockCount) {
|
|
1430
|
+
const block = blocks[index];
|
|
1431
|
+
if (!block || typeof block !== "object") {
|
|
1432
|
+
index += 1;
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
switch (block.type) {
|
|
1436
|
+
case "commentExtension": {
|
|
1437
|
+
workCost += getPayloadInputLength(block.data ?? "");
|
|
1438
|
+
break;
|
|
1439
|
+
}
|
|
1440
|
+
case "applicationExtension": {
|
|
1441
|
+
workCost += getPayloadInputLength(block.data ?? new Uint8Array());
|
|
1442
|
+
break;
|
|
1443
|
+
}
|
|
1444
|
+
case "image":
|
|
1445
|
+
case "rgbaImage": {
|
|
1446
|
+
const { width, height } = block;
|
|
1447
|
+
if (Number.isSafeInteger(width) && Number.isSafeInteger(height) && width > 0 && height > 0) {
|
|
1448
|
+
workCost += width * height;
|
|
1449
|
+
}
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
default: {
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
requireCountWithinLimit(workCost, defaultMaximumEncodeWorkCost, "encode work cost");
|
|
1457
|
+
index += 1;
|
|
1458
|
+
}
|
|
1459
|
+
return workCost;
|
|
1460
|
+
}
|
|
1461
|
+
function getPayloadInputLength(value) {
|
|
1462
|
+
if (isUint8Array(value)) {
|
|
1463
|
+
return toUint8ArrayView(value).length;
|
|
1464
|
+
}
|
|
1465
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
1466
|
+
return value.length;
|
|
1467
|
+
}
|
|
1468
|
+
return 0;
|
|
1469
|
+
}
|
|
1470
|
+
function writeGIFHeader(byteWriter, gif) {
|
|
1471
|
+
const {
|
|
1472
|
+
logicalScreenWidth,
|
|
1473
|
+
logicalScreenHeight,
|
|
1474
|
+
backgroundColorIndex,
|
|
1475
|
+
globalColorTable
|
|
1476
|
+
} = gif;
|
|
1477
|
+
byteWriter.writeUnsignedLittleEndian16(logicalScreenWidth);
|
|
1478
|
+
byteWriter.writeUnsignedLittleEndian16(logicalScreenHeight);
|
|
1479
|
+
const globalColorTableSizeField = globalColorTable === void 0 ? 0 : calculateColorTableSizeField(globalColorTable.length / 3);
|
|
1480
|
+
const packedLogicalScreenField = (globalColorTable === void 0 ? 0 : 128) | deriveColorResolution(globalColorTable) - 1 << 4 | globalColorTableSizeField;
|
|
1481
|
+
byteWriter.writeByte(packedLogicalScreenField);
|
|
1482
|
+
byteWriter.writeByte(backgroundColorIndex);
|
|
1483
|
+
byteWriter.writeByte(0);
|
|
1484
|
+
if (globalColorTable !== void 0) {
|
|
1485
|
+
writeColorTable(byteWriter, globalColorTable);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
function writeGIFBlocks(byteWriter, gif) {
|
|
1489
|
+
const {
|
|
1490
|
+
logicalScreenWidth,
|
|
1491
|
+
logicalScreenHeight,
|
|
1492
|
+
globalColorTable
|
|
1493
|
+
} = gif;
|
|
1494
|
+
for (const block of gif.blocks) {
|
|
1495
|
+
switch (block.type) {
|
|
1496
|
+
case "commentExtension": {
|
|
1497
|
+
writeCommentExtension(byteWriter, block);
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1500
|
+
case "applicationExtension": {
|
|
1501
|
+
writeAppExtension(byteWriter, block);
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1504
|
+
case "image": {
|
|
1505
|
+
writeImageBlock(byteWriter, block, {
|
|
1506
|
+
logicalScreenWidth,
|
|
1507
|
+
logicalScreenHeight,
|
|
1508
|
+
globalColorTable
|
|
1509
|
+
});
|
|
1510
|
+
break;
|
|
1511
|
+
}
|
|
1512
|
+
default: {
|
|
1513
|
+
throw new Error(`Unsupported block type ${JSON.stringify(block.type)}`);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
function writeImageBlock(byteWriter, block, { logicalScreenWidth, logicalScreenHeight, globalColorTable }) {
|
|
1519
|
+
const geometry = normalizeImageGeometry(block, {
|
|
1520
|
+
logicalScreenWidth,
|
|
1521
|
+
logicalScreenHeight
|
|
1522
|
+
});
|
|
1523
|
+
const imageData = normalizeImageDataForEncoding(block, geometry, globalColorTable);
|
|
1524
|
+
if (imageData.graphicControlExtension !== void 0) {
|
|
1525
|
+
writeGraphicControlExtension(byteWriter, imageData.graphicControlExtension);
|
|
1526
|
+
}
|
|
1527
|
+
writeEncodedImageBlock(byteWriter, block, {
|
|
1528
|
+
...geometry,
|
|
1529
|
+
...imageData
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
function normalizeImageDataForEncoding(block, { width, height }, globalColorTable) {
|
|
1533
|
+
let colorTable = normalizeColorTable(block.colorTable, "image.colorTable");
|
|
1534
|
+
let indexedPixels = normalizeIndexedPixels(block.indexedPixels, width * height, "image.pixels");
|
|
1535
|
+
let graphicControlExtension = normalizeGraphicControlExtension(block.graphicControlExtension);
|
|
1536
|
+
if (indexedPixels === void 0 && block.pixels !== void 0) {
|
|
1537
|
+
requirePixelCountValueWithinLimit(width * height, defaultMaximumIndexedImagePixelCount, "RGBA image data");
|
|
1538
|
+
const pixels = normalizeRedGreenBlueAlphaPixels(block.pixels, width * height * 4, "image.pixels");
|
|
1539
|
+
const indexedImageData = normalizeRGBAImageData(pixels, block, graphicControlExtension);
|
|
1540
|
+
indexedPixels = indexedImageData.indexedPixels;
|
|
1541
|
+
colorTable = indexedImageData.colorTable;
|
|
1542
|
+
graphicControlExtension = indexedImageData.graphicControlExtension;
|
|
1543
|
+
}
|
|
1544
|
+
if (indexedPixels === void 0) {
|
|
1545
|
+
throw new Error("An image block requires pixels");
|
|
1546
|
+
}
|
|
1547
|
+
const activeColorTable = colorTable ?? globalColorTable;
|
|
1548
|
+
if (activeColorTable === void 0) {
|
|
1549
|
+
throw new Error("An image block requires a colorTable or a globalColorTable");
|
|
1550
|
+
}
|
|
1551
|
+
validateIndexedPixelsAgainstColorTable(indexedPixels, activeColorTable, graphicControlExtension == null ? void 0 : graphicControlExtension.transparentColorIndex);
|
|
1552
|
+
let minimumCodeSize = deriveMinimumCodeSize(activeColorTable.length / 3);
|
|
1553
|
+
if (minimumCodeSize < 2) {
|
|
1554
|
+
minimumCodeSize = 2;
|
|
1555
|
+
}
|
|
1556
|
+
return {
|
|
1557
|
+
colorTable,
|
|
1558
|
+
indexedPixels,
|
|
1559
|
+
minimumCodeSize,
|
|
1560
|
+
graphicControlExtension
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
function writeEncodedImageBlock(byteWriter, block, { left, top, width, height, colorTable, indexedPixels, minimumCodeSize }) {
|
|
1564
|
+
const pixelsToEncode = block.isInterlaced ? interlaceIndexedPixels(indexedPixels, width, height) : indexedPixels;
|
|
1565
|
+
const compressedData = encodeCompressedIndexStream(pixelsToEncode, minimumCodeSize);
|
|
1566
|
+
byteWriter.writeByte(imageSeparator);
|
|
1567
|
+
byteWriter.writeUnsignedLittleEndian16(left);
|
|
1568
|
+
byteWriter.writeUnsignedLittleEndian16(top);
|
|
1569
|
+
byteWriter.writeUnsignedLittleEndian16(width);
|
|
1570
|
+
byteWriter.writeUnsignedLittleEndian16(height);
|
|
1571
|
+
const packedImageField = (colorTable === void 0 ? 0 : 128) | (block.isInterlaced ? 64 : 0) | (colorTable === void 0 ? 0 : calculateColorTableSizeField(colorTable.length / 3));
|
|
1572
|
+
byteWriter.writeByte(packedImageField);
|
|
1573
|
+
if (colorTable !== void 0) {
|
|
1574
|
+
writeColorTable(byteWriter, colorTable);
|
|
1575
|
+
}
|
|
1576
|
+
byteWriter.writeByte(minimumCodeSize);
|
|
1577
|
+
writeDataSubBlocks(byteWriter, compressedData);
|
|
1578
|
+
}
|
|
1579
|
+
function writeGraphicControlExtension(byteWriter, graphicControlExtension) {
|
|
1580
|
+
if (graphicControlExtension === void 0) {
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
const packedField = disposalMethodByte(graphicControlExtension.disposalMethod) << 2 | (graphicControlExtension.transparentColorIndex === void 0 ? 0 : 1);
|
|
1584
|
+
byteWriter.writeByte(extensionIntroducer);
|
|
1585
|
+
byteWriter.writeByte(graphicControlExtensionLabel);
|
|
1586
|
+
byteWriter.writeByte(4);
|
|
1587
|
+
byteWriter.writeByte(packedField);
|
|
1588
|
+
byteWriter.writeUnsignedLittleEndian16(graphicControlExtension.delayInHundredthsOfASecond);
|
|
1589
|
+
byteWriter.writeByte(graphicControlExtension.transparentColorIndex ?? 0);
|
|
1590
|
+
byteWriter.writeByte(0);
|
|
1591
|
+
}
|
|
1592
|
+
function writeCommentExtension(byteWriter, block) {
|
|
1593
|
+
const data = normalizeExtensionPayload(block.data, "commentExtension.data");
|
|
1594
|
+
byteWriter.writeByte(extensionIntroducer);
|
|
1595
|
+
byteWriter.writeByte(commentExtensionLabel);
|
|
1596
|
+
writeDataSubBlocks(byteWriter, data);
|
|
1597
|
+
}
|
|
1598
|
+
function writeAppExtension(byteWriter, block) {
|
|
1599
|
+
const identifier = normalizeFixedAsciiField(block.identifier, 8, "applicationExtension.identifier");
|
|
1600
|
+
const authenticationCode = normalizeFixedByteField(block.authenticationCode, 3, "applicationExtension.authenticationCode");
|
|
1601
|
+
const data = normalizeExtensionPayload(block.data, "applicationExtension.data");
|
|
1602
|
+
byteWriter.writeByte(extensionIntroducer);
|
|
1603
|
+
byteWriter.writeByte(appExtensionLabel);
|
|
1604
|
+
byteWriter.writeByte(11);
|
|
1605
|
+
byteWriter.writeAsciiString(identifier);
|
|
1606
|
+
byteWriter.writeBytes(authenticationCode);
|
|
1607
|
+
writeDataSubBlocks(byteWriter, data);
|
|
1608
|
+
}
|
|
1609
|
+
function writeDataSubBlocks(byteWriter, data) {
|
|
1610
|
+
requireByteLengthWithinLimit(data.length, defaultMaximumDataPayloadByteLength, "data payload");
|
|
1611
|
+
for (let offset = 0; offset < data.length; offset += 255) {
|
|
1612
|
+
const chunkLength = Math.min(255, data.length - offset);
|
|
1613
|
+
byteWriter.writeByte(chunkLength);
|
|
1614
|
+
byteWriter.writeBytes(uint8ArraySubarray.call(data, offset, offset + chunkLength));
|
|
1615
|
+
}
|
|
1616
|
+
byteWriter.writeByte(0);
|
|
1617
|
+
}
|
|
1618
|
+
function writeColorTable(byteWriter, colorTable) {
|
|
1619
|
+
const normalizedColorTable = normalizeColorTable(colorTable, "colorTable");
|
|
1620
|
+
if (normalizedColorTable === void 0) {
|
|
1621
|
+
throw new Error("Expected a color table");
|
|
1622
|
+
}
|
|
1623
|
+
byteWriter.writeBytes(normalizedColorTable);
|
|
1624
|
+
}
|
|
1625
|
+
function interlaceIndexedPixels(indexedPixels, width, height) {
|
|
1626
|
+
const interlacedPixels = new Uint8Array(indexedPixels.length);
|
|
1627
|
+
let destinationOffset = 0;
|
|
1628
|
+
for (const [startRow, rowStep] of [[0, 8], [4, 8], [2, 4], [1, 2]]) {
|
|
1629
|
+
for (let row = startRow; row < height; row += rowStep) {
|
|
1630
|
+
const sourceOffset = row * width;
|
|
1631
|
+
interlacedPixels.set(uint8ArraySubarray.call(indexedPixels, sourceOffset, sourceOffset + width), destinationOffset);
|
|
1632
|
+
destinationOffset += width;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return interlacedPixels;
|
|
1636
|
+
}
|
|
1637
|
+
function validateIndexedPixelsAgainstColorTable(indexedPixels, colorTable, transparentColorIndex) {
|
|
1638
|
+
const colorTableEntryCount = colorTable.length / 3;
|
|
1639
|
+
let pixelOffset = 0;
|
|
1640
|
+
while (pixelOffset < indexedPixels.length) {
|
|
1641
|
+
const pixelIndex = indexedPixels[pixelOffset];
|
|
1642
|
+
if (pixelIndex >= colorTableEntryCount) {
|
|
1643
|
+
throw new Error(`Pixel ${pixelOffset} uses palette index ${pixelIndex}, but the active color table only has ${colorTableEntryCount} entries`);
|
|
1644
|
+
}
|
|
1645
|
+
pixelOffset += 1;
|
|
1646
|
+
}
|
|
1647
|
+
if (transparentColorIndex !== void 0 && transparentColorIndex >= colorTableEntryCount) {
|
|
1648
|
+
throw new Error(`Transparent color index ${transparentColorIndex} exceeds the active color table`);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
function normalizeBlock(block, globalColorTable) {
|
|
1652
|
+
requireBlockObject(block);
|
|
1653
|
+
switch (block.type) {
|
|
1654
|
+
case "commentExtension": {
|
|
1655
|
+
return normalizeCommentExtensionBlock(block);
|
|
1656
|
+
}
|
|
1657
|
+
case "applicationExtension": {
|
|
1658
|
+
return normalizeAppExtensionBlock(block);
|
|
1659
|
+
}
|
|
1660
|
+
case "image":
|
|
1661
|
+
case "rgbaImage": {
|
|
1662
|
+
return normalizeImageBlock(block, globalColorTable);
|
|
1663
|
+
}
|
|
1664
|
+
default: {
|
|
1665
|
+
throw new Error(`Unsupported block type ${JSON.stringify(block.type)}`);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
function normalizeCommentExtensionBlock(block) {
|
|
1670
|
+
return {
|
|
1671
|
+
type: "commentExtension",
|
|
1672
|
+
data: normalizeExtensionPayload(block.data ?? "", "commentExtension.data")
|
|
1673
|
+
};
|
|
1674
|
+
}
|
|
1675
|
+
function normalizeAppExtensionBlock(block) {
|
|
1676
|
+
const authenticationCode = normalizeFixedByteField(block.authenticationCode, 3, "applicationExtension.authenticationCode");
|
|
1677
|
+
const identifier = normalizeFixedAsciiField(block.identifier, 8, "applicationExtension.identifier");
|
|
1678
|
+
rejectRenamedLoopCount(block);
|
|
1679
|
+
const loopCount = block.playCount === void 0 ? void 0 : encodeExplicitNetscapeLoopCount(block.playCount, "applicationExtension.playCount");
|
|
1680
|
+
const data = block.data ?? (identifier === netscapeLoopingAppIdentifier && areBytesEqual(authenticationCode, netscapeLoopingAppAuthenticationCodeBytes) && loopCount !== void 0 ? Uint8Array.of(1, loopCount & 255, loopCount >> 8) : new Uint8Array());
|
|
1681
|
+
return {
|
|
1682
|
+
type: "applicationExtension",
|
|
1683
|
+
identifier,
|
|
1684
|
+
authenticationCode,
|
|
1685
|
+
data: normalizeExtensionPayload(data, "applicationExtension.data")
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
function normalizeImageBlock(block, globalColorTable) {
|
|
1689
|
+
const isRGBAImage = block.type === "rgbaImage";
|
|
1690
|
+
const width = requireNonZeroUnsigned16(block.width, "image.width");
|
|
1691
|
+
const height = requireNonZeroUnsigned16(block.height, "image.height");
|
|
1692
|
+
requirePixelCountWithinLimit(width, height, defaultMaximumPixelCount, "image block");
|
|
1693
|
+
const colorTable = isRGBAImage ? void 0 : normalizeColorTable(block.colorTable, "image.colorTable");
|
|
1694
|
+
const normalizedImageBlock = {
|
|
1695
|
+
type: "image",
|
|
1696
|
+
graphicControlExtension: block.graphicControlExtension,
|
|
1697
|
+
left: requireUnsigned16(block.left ?? 0, "image.left"),
|
|
1698
|
+
top: requireUnsigned16(block.top ?? 0, "image.top"),
|
|
1699
|
+
width,
|
|
1700
|
+
height,
|
|
1701
|
+
isInterlaced: Boolean(block.isInterlaced),
|
|
1702
|
+
colorTable,
|
|
1703
|
+
indexedPixels: isRGBAImage ? void 0 : block.pixels
|
|
1704
|
+
};
|
|
1705
|
+
if (!isRGBAImage && normalizedImageBlock.colorTable === void 0 && globalColorTable === void 0) {
|
|
1706
|
+
throw new Error("An image block requires a color table or a global color table");
|
|
1707
|
+
}
|
|
1708
|
+
if (isRGBAImage) {
|
|
1709
|
+
normalizedImageBlock.pixels = block.pixels;
|
|
1710
|
+
if (block.transparentColor !== void 0) {
|
|
1711
|
+
normalizedImageBlock.transparentColor = block.transparentColor;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
return normalizedImageBlock;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/source/render.js
|
|
1718
|
+
function renderGIFFrameSequence(gif, options = {}) {
|
|
1719
|
+
const {
|
|
1720
|
+
repeat,
|
|
1721
|
+
signal,
|
|
1722
|
+
...renderOptions
|
|
1723
|
+
} = normalizeFrameSequenceOptions(options);
|
|
1724
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
1725
|
+
return emptyGIFFrameSequence();
|
|
1726
|
+
}
|
|
1727
|
+
const renderState = createGIFRenderState(gif, renderOptions);
|
|
1728
|
+
return renderGIFFrameSequenceFromState(renderState, { repeat, signal });
|
|
1729
|
+
}
|
|
1730
|
+
function renderGIFFrames(gif, options = {}) {
|
|
1731
|
+
const renderState = createGIFRenderState(gif, normalizeRenderOptions(options));
|
|
1732
|
+
const renderedFrames = [];
|
|
1733
|
+
let renderedPixelCount = 0;
|
|
1734
|
+
const beforeRenderFrame = () => {
|
|
1735
|
+
renderedPixelCount += renderState.logicalScreenPixelCount;
|
|
1736
|
+
requirePixelCountValueWithinLimit(renderedPixelCount, defaultMaximumRenderPixelCount, "rendered frame pixels");
|
|
1737
|
+
};
|
|
1738
|
+
for (const frame of renderGIFFrameSequenceFromState(renderState, { beforeRenderFrame })) {
|
|
1739
|
+
renderedFrames.push(toRenderedFrame(frame));
|
|
1740
|
+
}
|
|
1741
|
+
return {
|
|
1742
|
+
width: renderState.logicalScreenWidth,
|
|
1743
|
+
height: renderState.logicalScreenHeight,
|
|
1744
|
+
...renderState.playCount !== void 0 && { playCount: renderState.playCount },
|
|
1745
|
+
frames: renderedFrames
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
function createGIFRenderState(gif, renderOptions) {
|
|
1749
|
+
const { background, strict } = renderOptions;
|
|
1750
|
+
if (!gif || typeof gif !== "object") {
|
|
1751
|
+
throw new TypeError("Expected a decoded GIF object");
|
|
1752
|
+
}
|
|
1753
|
+
const logicalScreenWidth = requireNonZeroUnsigned16(gif.width, "width");
|
|
1754
|
+
const logicalScreenHeight = requireNonZeroUnsigned16(gif.height, "height");
|
|
1755
|
+
const logicalScreenPixelCount = requirePixelCountWithinLimit(logicalScreenWidth, logicalScreenHeight, defaultMaximumRenderPixelCount, "logical screen");
|
|
1756
|
+
const globalColorTable = normalizeColorTable(gif.globalColorTable, "globalColorTable");
|
|
1757
|
+
const backgroundColorIndex = requireByte(gif.backgroundColorIndex ?? 0, "backgroundColorIndex");
|
|
1758
|
+
rejectRenamedLoopCount(gif);
|
|
1759
|
+
const playCount = gif.playCount === void 0 ? void 0 : normalizePlayCount(gif.playCount, "playCount");
|
|
1760
|
+
let blocks;
|
|
1761
|
+
if (gif.blocks === void 0) {
|
|
1762
|
+
blocks = [];
|
|
1763
|
+
} else if (Array.isArray(gif.blocks)) {
|
|
1764
|
+
blocks = gif.blocks;
|
|
1765
|
+
} else {
|
|
1766
|
+
throw new TypeError("blocks must be an array");
|
|
1767
|
+
}
|
|
1768
|
+
requireCountWithinLimit(blocks.length, defaultMaximumBlockCount, "render block count");
|
|
1769
|
+
const canvasPixels = new Uint8ClampedArray(logicalScreenWidth * logicalScreenHeight * 4);
|
|
1770
|
+
const renderContext = {
|
|
1771
|
+
logicalScreenWidth,
|
|
1772
|
+
logicalScreenHeight,
|
|
1773
|
+
globalColorTable,
|
|
1774
|
+
backgroundColorIndex,
|
|
1775
|
+
background,
|
|
1776
|
+
strict
|
|
1777
|
+
};
|
|
1778
|
+
fillCanvasBackground(canvasPixels, renderContext);
|
|
1779
|
+
return {
|
|
1780
|
+
logicalScreenWidth,
|
|
1781
|
+
logicalScreenHeight,
|
|
1782
|
+
logicalScreenPixelCount,
|
|
1783
|
+
playCount,
|
|
1784
|
+
blocks,
|
|
1785
|
+
canvasPixels,
|
|
1786
|
+
renderContext
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
function* renderGIFFrameSequenceFromState(renderState, { repeat = false, signal, beforeRenderFrame } = {}) {
|
|
1790
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
const totalLoops = repeat ? renderTotalPlayCount(renderState.playCount) : 1;
|
|
1794
|
+
const initialCanvasPixels = totalLoops > 1 ? new Uint8ClampedArray(renderState.canvasPixels) : void 0;
|
|
1795
|
+
let loopIndex = 0;
|
|
1796
|
+
while (loopIndex < totalLoops) {
|
|
1797
|
+
if (loopIndex > 0) {
|
|
1798
|
+
renderState.canvasPixels.set(initialCanvasPixels);
|
|
1799
|
+
}
|
|
1800
|
+
let frameIndex = 0;
|
|
1801
|
+
let blockIndex = 0;
|
|
1802
|
+
const blockCount = renderState.blocks.length;
|
|
1803
|
+
let isRenderedFrameInLoop = false;
|
|
1804
|
+
while (blockIndex < blockCount) {
|
|
1805
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
const block = renderState.blocks[blockIndex];
|
|
1809
|
+
blockIndex += 1;
|
|
1810
|
+
requireBlockObject(block);
|
|
1811
|
+
switch (block.type) {
|
|
1812
|
+
case "image": {
|
|
1813
|
+
isRenderedFrameInLoop = true;
|
|
1814
|
+
beforeRenderFrame == null ? void 0 : beforeRenderFrame();
|
|
1815
|
+
yield {
|
|
1816
|
+
...renderImageBlockToFrame(renderState.canvasPixels, block, renderState.renderContext),
|
|
1817
|
+
index: frameIndex,
|
|
1818
|
+
loopIndex
|
|
1819
|
+
};
|
|
1820
|
+
frameIndex += 1;
|
|
1821
|
+
break;
|
|
1822
|
+
}
|
|
1823
|
+
case "commentExtension":
|
|
1824
|
+
case "applicationExtension":
|
|
1825
|
+
case "unknownExtension": {
|
|
1826
|
+
break;
|
|
1827
|
+
}
|
|
1828
|
+
default: {
|
|
1829
|
+
throw new Error(`Unsupported block type ${JSON.stringify(block.type)}`);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
if (!isRenderedFrameInLoop) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
loopIndex += 1;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
function* emptyGIFFrameSequence() {
|
|
1840
|
+
}
|
|
1841
|
+
function toRenderedFrame(frame) {
|
|
1842
|
+
return {
|
|
1843
|
+
left: frame.left,
|
|
1844
|
+
top: frame.top,
|
|
1845
|
+
width: frame.width,
|
|
1846
|
+
height: frame.height,
|
|
1847
|
+
delay: frame.delay,
|
|
1848
|
+
disposalMethod: frame.disposalMethod,
|
|
1849
|
+
pixels: frame.pixels
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
function normalizeRenderOptions(options) {
|
|
1853
|
+
const {
|
|
1854
|
+
background = "gif",
|
|
1855
|
+
strict = true
|
|
1856
|
+
} = options;
|
|
1857
|
+
if (background !== "transparent" && background !== "gif") {
|
|
1858
|
+
throw new TypeError(`background must be 'transparent' or 'gif', got ${JSON.stringify(background)}`);
|
|
1859
|
+
}
|
|
1860
|
+
if (typeof strict !== "boolean") {
|
|
1861
|
+
throw new TypeError(`strict must be a boolean, got ${JSON.stringify(strict)}`);
|
|
1862
|
+
}
|
|
1863
|
+
return {
|
|
1864
|
+
background,
|
|
1865
|
+
strict
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
function normalizeFrameSequenceOptions(options) {
|
|
1869
|
+
const renderOptions = normalizeRenderOptions(options);
|
|
1870
|
+
const {
|
|
1871
|
+
repeat = true,
|
|
1872
|
+
signal
|
|
1873
|
+
} = options;
|
|
1874
|
+
if (typeof repeat !== "boolean") {
|
|
1875
|
+
throw new TypeError(`repeat must be a boolean, got ${JSON.stringify(repeat)}`);
|
|
1876
|
+
}
|
|
1877
|
+
if (signal !== void 0 && typeof (signal == null ? void 0 : signal.aborted) !== "boolean") {
|
|
1878
|
+
throw new TypeError("signal must be an AbortSignal");
|
|
1879
|
+
}
|
|
1880
|
+
return {
|
|
1881
|
+
...renderOptions,
|
|
1882
|
+
repeat,
|
|
1883
|
+
signal
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
function fillCanvasBackground(canvasPixels, { globalColorTable, backgroundColorIndex, background }) {
|
|
1887
|
+
const backgroundTriplet = getColorTriplet(globalColorTable, backgroundColorIndex);
|
|
1888
|
+
const isUseTransparentBackground = background === "transparent" || backgroundTriplet === void 0;
|
|
1889
|
+
const red = isUseTransparentBackground ? 0 : backgroundTriplet[0];
|
|
1890
|
+
const green = isUseTransparentBackground ? 0 : backgroundTriplet[1];
|
|
1891
|
+
const blue = isUseTransparentBackground ? 0 : backgroundTriplet[2];
|
|
1892
|
+
const alpha = isUseTransparentBackground ? 0 : 255;
|
|
1893
|
+
for (let offset = 0; offset < canvasPixels.length; offset += 4) {
|
|
1894
|
+
canvasPixels[offset] = red;
|
|
1895
|
+
canvasPixels[offset + 1] = green;
|
|
1896
|
+
canvasPixels[offset + 2] = blue;
|
|
1897
|
+
canvasPixels[offset + 3] = alpha;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
function renderImageBlockToFrame(canvasPixels, imageBlock, renderContext) {
|
|
1901
|
+
const geometry = normalizeImageGeometry(imageBlock, {
|
|
1902
|
+
logicalScreenWidth: renderContext.logicalScreenWidth,
|
|
1903
|
+
logicalScreenHeight: renderContext.logicalScreenHeight
|
|
1904
|
+
});
|
|
1905
|
+
const indexedPixels = normalizeIndexedPixels(imageBlock.pixels, geometry.width * geometry.height, "image.pixels");
|
|
1906
|
+
if (indexedPixels === void 0) {
|
|
1907
|
+
throw new Error("An image block requires pixels to render");
|
|
1908
|
+
}
|
|
1909
|
+
const colorTable = normalizeColorTable(imageBlock.colorTable, "colorTable");
|
|
1910
|
+
const activeColorTable = colorTable ?? renderContext.globalColorTable;
|
|
1911
|
+
if (activeColorTable === void 0) {
|
|
1912
|
+
throw new Error("Cannot render an image block without an active color table");
|
|
1913
|
+
}
|
|
1914
|
+
const graphicControlExtension = normalizeGraphicControlExtension(imageBlock.graphicControlExtension);
|
|
1915
|
+
requirePixelCountWithinLimit(geometry.width, geometry.height, defaultMaximumPixelCount, "image block");
|
|
1916
|
+
const transparentColorIndex = graphicControlExtension == null ? void 0 : graphicControlExtension.transparentColorIndex;
|
|
1917
|
+
const disposalMethod = (graphicControlExtension == null ? void 0 : graphicControlExtension.disposalMethod) ?? "unspecified";
|
|
1918
|
+
const normalizedImageBlock = {
|
|
1919
|
+
...imageBlock,
|
|
1920
|
+
...geometry,
|
|
1921
|
+
indexedPixels
|
|
1922
|
+
};
|
|
1923
|
+
const activeColorTableUint32 = isLittleEndian ? createColorTableUint32(activeColorTable) : void 0;
|
|
1924
|
+
if (renderContext.strict && transparentColorIndex !== void 0 && transparentColorIndex >= activeColorTable.length / 3) {
|
|
1925
|
+
throw new Error(`Transparent color index ${transparentColorIndex} exceeds the active color table`);
|
|
1926
|
+
}
|
|
1927
|
+
const snapshotBeforeRendering = disposalMethod === "restorePrevious" ? new Uint8ClampedArray(canvasPixels) : void 0;
|
|
1928
|
+
drawIndexedImageOntoCanvas(canvasPixels, normalizedImageBlock, {
|
|
1929
|
+
...renderContext,
|
|
1930
|
+
activeColorTable,
|
|
1931
|
+
activeColorTableUint32,
|
|
1932
|
+
transparentColorIndex
|
|
1933
|
+
});
|
|
1934
|
+
const renderedFrame = {
|
|
1935
|
+
left: geometry.left,
|
|
1936
|
+
top: geometry.top,
|
|
1937
|
+
width: geometry.width,
|
|
1938
|
+
height: geometry.height,
|
|
1939
|
+
delay: ((graphicControlExtension == null ? void 0 : graphicControlExtension.delayInHundredthsOfASecond) ?? 0) / 100,
|
|
1940
|
+
disposalMethod,
|
|
1941
|
+
pixels: new Uint8ClampedArray(canvasPixels)
|
|
1942
|
+
};
|
|
1943
|
+
if (disposalMethod === "restoreBackground") {
|
|
1944
|
+
restoreAreaToBackground(canvasPixels, normalizedImageBlock, renderContext);
|
|
1945
|
+
} else if (snapshotBeforeRendering !== void 0) {
|
|
1946
|
+
canvasPixels.set(snapshotBeforeRendering);
|
|
1947
|
+
}
|
|
1948
|
+
return renderedFrame;
|
|
1949
|
+
}
|
|
1950
|
+
function drawIndexedImageOntoCanvas(canvasPixels, imageBlock, { activeColorTable, activeColorTableUint32, transparentColorIndex, logicalScreenWidth, strict }) {
|
|
1951
|
+
if (activeColorTableUint32 !== void 0) {
|
|
1952
|
+
drawIndexedImageOntoCanvasUint32(canvasPixels, imageBlock, {
|
|
1953
|
+
activeColorTableUint32,
|
|
1954
|
+
transparentColorIndex,
|
|
1955
|
+
logicalScreenWidth,
|
|
1956
|
+
strict
|
|
1957
|
+
});
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
const {
|
|
1961
|
+
left = 0,
|
|
1962
|
+
top = 0,
|
|
1963
|
+
width,
|
|
1964
|
+
height,
|
|
1965
|
+
indexedPixels
|
|
1966
|
+
} = imageBlock;
|
|
1967
|
+
for (let row = 0; row < height; row += 1) {
|
|
1968
|
+
let sourceOffset = row * width;
|
|
1969
|
+
let destinationOffset = ((top + row) * logicalScreenWidth + left) * 4;
|
|
1970
|
+
for (let column = 0; column < width; column += 1) {
|
|
1971
|
+
const pixelIndex = indexedPixels[sourceOffset];
|
|
1972
|
+
sourceOffset += 1;
|
|
1973
|
+
if (transparentColorIndex !== void 0 && pixelIndex === transparentColorIndex) {
|
|
1974
|
+
destinationOffset += 4;
|
|
1975
|
+
continue;
|
|
1976
|
+
}
|
|
1977
|
+
const colorOffset = pixelIndex * 3;
|
|
1978
|
+
if (colorOffset + 2 >= activeColorTable.length) {
|
|
1979
|
+
if (strict) {
|
|
1980
|
+
throw new Error(`Pixel index ${pixelIndex} is outside the active color table`);
|
|
1981
|
+
}
|
|
1982
|
+
destinationOffset += 4;
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
canvasPixels[destinationOffset] = activeColorTable[colorOffset];
|
|
1986
|
+
canvasPixels[destinationOffset + 1] = activeColorTable[colorOffset + 1];
|
|
1987
|
+
canvasPixels[destinationOffset + 2] = activeColorTable[colorOffset + 2];
|
|
1988
|
+
canvasPixels[destinationOffset + 3] = 255;
|
|
1989
|
+
destinationOffset += 4;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
function drawIndexedImageOntoCanvasUint32(canvasPixels, imageBlock, { activeColorTableUint32, transparentColorIndex, logicalScreenWidth, strict }) {
|
|
1994
|
+
const {
|
|
1995
|
+
left = 0,
|
|
1996
|
+
top = 0,
|
|
1997
|
+
width,
|
|
1998
|
+
height,
|
|
1999
|
+
indexedPixels
|
|
2000
|
+
} = imageBlock;
|
|
2001
|
+
const canvasPixelsUint32 = new Uint32Array(canvasPixels.buffer, canvasPixels.byteOffset, canvasPixels.byteLength / Uint32Array.BYTES_PER_ELEMENT);
|
|
2002
|
+
for (let row = 0; row < height; row += 1) {
|
|
2003
|
+
let sourceOffset = row * width;
|
|
2004
|
+
let destinationOffset = (top + row) * logicalScreenWidth + left;
|
|
2005
|
+
for (let column = 0; column < width; column += 1) {
|
|
2006
|
+
const pixelIndex = indexedPixels[sourceOffset];
|
|
2007
|
+
sourceOffset += 1;
|
|
2008
|
+
if (transparentColorIndex !== void 0 && pixelIndex === transparentColorIndex) {
|
|
2009
|
+
destinationOffset += 1;
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const color = activeColorTableUint32[pixelIndex];
|
|
2013
|
+
if (color === void 0) {
|
|
2014
|
+
if (strict) {
|
|
2015
|
+
throw new Error(`Pixel index ${pixelIndex} is outside the active color table`);
|
|
2016
|
+
}
|
|
2017
|
+
destinationOffset += 1;
|
|
2018
|
+
continue;
|
|
2019
|
+
}
|
|
2020
|
+
canvasPixelsUint32[destinationOffset] = color;
|
|
2021
|
+
destinationOffset += 1;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
function createColorTableUint32(colorTable) {
|
|
2026
|
+
const colorTableUint32 = new Uint32Array(colorTable.length / 3);
|
|
2027
|
+
for (let colorIndex = 0; colorIndex < colorTableUint32.length; colorIndex += 1) {
|
|
2028
|
+
const colorOffset = colorIndex * 3;
|
|
2029
|
+
colorTableUint32[colorIndex] = 4278190080 | colorTable[colorOffset + 2] << 16 | colorTable[colorOffset + 1] << 8 | colorTable[colorOffset];
|
|
2030
|
+
}
|
|
2031
|
+
return colorTableUint32;
|
|
2032
|
+
}
|
|
2033
|
+
function restoreAreaToBackground(canvasPixels, imageBlock, { logicalScreenWidth, logicalScreenHeight, globalColorTable, backgroundColorIndex, background }) {
|
|
2034
|
+
const {
|
|
2035
|
+
left = 0,
|
|
2036
|
+
top = 0,
|
|
2037
|
+
width,
|
|
2038
|
+
height
|
|
2039
|
+
} = imageBlock;
|
|
2040
|
+
const backgroundTriplet = getColorTriplet(globalColorTable, backgroundColorIndex);
|
|
2041
|
+
const isUseTransparentBackground = background === "transparent" || backgroundTriplet === void 0;
|
|
2042
|
+
const red = isUseTransparentBackground ? 0 : backgroundTriplet[0];
|
|
2043
|
+
const green = isUseTransparentBackground ? 0 : backgroundTriplet[1];
|
|
2044
|
+
const blue = isUseTransparentBackground ? 0 : backgroundTriplet[2];
|
|
2045
|
+
const alpha = isUseTransparentBackground ? 0 : 255;
|
|
2046
|
+
for (let row = 0; row < height; row += 1) {
|
|
2047
|
+
const destinationRow = top + row;
|
|
2048
|
+
if (destinationRow < 0 || destinationRow >= logicalScreenHeight) {
|
|
2049
|
+
continue;
|
|
2050
|
+
}
|
|
2051
|
+
for (let column = 0; column < width; column += 1) {
|
|
2052
|
+
const destinationColumn = left + column;
|
|
2053
|
+
if (destinationColumn < 0 || destinationColumn >= logicalScreenWidth) {
|
|
2054
|
+
continue;
|
|
2055
|
+
}
|
|
2056
|
+
const destinationOffset = (destinationRow * logicalScreenWidth + destinationColumn) * 4;
|
|
2057
|
+
canvasPixels[destinationOffset] = red;
|
|
2058
|
+
canvasPixels[destinationOffset + 1] = green;
|
|
2059
|
+
canvasPixels[destinationOffset + 2] = blue;
|
|
2060
|
+
canvasPixels[destinationOffset + 3] = alpha;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
function getColorTriplet(colorTable, paletteIndex) {
|
|
2065
|
+
if (colorTable === void 0) {
|
|
2066
|
+
return void 0;
|
|
2067
|
+
}
|
|
2068
|
+
const colorOffset = paletteIndex * 3;
|
|
2069
|
+
if (colorOffset + 2 >= colorTable.length) {
|
|
2070
|
+
return void 0;
|
|
2071
|
+
}
|
|
2072
|
+
return [
|
|
2073
|
+
colorTable[colorOffset],
|
|
2074
|
+
colorTable[colorOffset + 1],
|
|
2075
|
+
colorTable[colorOffset + 2]
|
|
2076
|
+
];
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// packages/@cjser/sindresorhus__gifkit.tmp-26-1783615518957/index.js
|
|
2080
|
+
function decodeAnimatedGIF(inputBytes, options = {}) {
|
|
2081
|
+
const gif = decodeGIF(inputBytes, options);
|
|
2082
|
+
const rendered = renderGIFFrames(gif, {
|
|
2083
|
+
background: options.background ?? "transparent",
|
|
2084
|
+
strict: options.strict
|
|
2085
|
+
});
|
|
2086
|
+
return {
|
|
2087
|
+
width: rendered.width,
|
|
2088
|
+
height: rendered.height,
|
|
2089
|
+
...rendered.playCount !== void 0 && { playCount: rendered.playCount },
|
|
2090
|
+
frames: rendered.frames.map((frame) => ({
|
|
2091
|
+
pixels: frame.pixels,
|
|
2092
|
+
delay: frame.delay
|
|
2093
|
+
}))
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
function encodeAnimatedGIF(frames, options = {}) {
|
|
2097
|
+
if (!Array.isArray(frames) || frames.length === 0) {
|
|
2098
|
+
throw new TypeError("frames must be a non-empty array");
|
|
2099
|
+
}
|
|
2100
|
+
const width = requireNonZeroUnsigned16(options.width, "width");
|
|
2101
|
+
const height = requireNonZeroUnsigned16(options.height, "height");
|
|
2102
|
+
const quality = requireFiniteNumberInRange(options.quality ?? 0.8, 0, 1, "quality");
|
|
2103
|
+
rejectRenamedLoopCount(options);
|
|
2104
|
+
const hasFrameDelays = frames.some((frame) => isAnimationFrameObject(frame) && frame.delay !== void 0);
|
|
2105
|
+
if (options.fps !== void 0 && hasFrameDelays) {
|
|
2106
|
+
throw new Error("fps cannot be combined with per-frame delay");
|
|
2107
|
+
}
|
|
2108
|
+
if (options.fps === void 0 && frames.some((frame) => !isAnimationFrameObject(frame) || frame.delay === void 0)) {
|
|
2109
|
+
throw new Error("fps is required unless every frame has a delay");
|
|
2110
|
+
}
|
|
2111
|
+
const frameDelay = options.fps === void 0 ? void 0 : 1 / requirePositiveFiniteNumber(options.fps, "fps");
|
|
2112
|
+
const blocks = frames.map((frame, index) => {
|
|
2113
|
+
const pixels = normalizeAnimationFramePixels(frame, width * height * 4, `frames[${index}]`);
|
|
2114
|
+
const delay = frameDelay ?? requireFiniteNumberInRange(frame.delay, 0, 655.35, `frames[${index}].delay`);
|
|
2115
|
+
const imageBlock = {
|
|
2116
|
+
type: "rgbaImage",
|
|
2117
|
+
width,
|
|
2118
|
+
height,
|
|
2119
|
+
graphicControlExtension: {
|
|
2120
|
+
delay
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
if (quality === 1) {
|
|
2124
|
+
return {
|
|
2125
|
+
...imageBlock,
|
|
2126
|
+
pixels
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
const quantizedImage = buildQuantizedIndexedImage(pixels, { quality });
|
|
2130
|
+
return {
|
|
2131
|
+
type: "image",
|
|
2132
|
+
width,
|
|
2133
|
+
height,
|
|
2134
|
+
pixels: quantizedImage.pixels,
|
|
2135
|
+
colorTable: quantizedImage.colorTable,
|
|
2136
|
+
graphicControlExtension: {
|
|
2137
|
+
delay,
|
|
2138
|
+
transparentColorIndex: quantizedImage.transparentColorIndex
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
});
|
|
2142
|
+
const gif = {
|
|
2143
|
+
width,
|
|
2144
|
+
height,
|
|
2145
|
+
blocks
|
|
2146
|
+
};
|
|
2147
|
+
if (options.playCount !== void 0) {
|
|
2148
|
+
gif.playCount = options.playCount;
|
|
2149
|
+
}
|
|
2150
|
+
return encodeGIF(gif);
|
|
2151
|
+
}
|
|
2152
|
+
function normalizeAnimationFramePixels(frame, expectedLength, fieldName) {
|
|
2153
|
+
const pixels = isAnimationFrameObject(frame) ? frame.pixels : frame;
|
|
2154
|
+
return normalizeRedGreenBlueAlphaPixels(pixels, expectedLength, fieldName);
|
|
2155
|
+
}
|
|
2156
|
+
function isAnimationFrameObject(frame) {
|
|
2157
|
+
return frame !== null && typeof frame === "object" && !isUint8Array(frame) && !isUint8ClampedArray(frame) && !Array.isArray(frame);
|
|
2158
|
+
}
|
|
2159
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2160
|
+
0 && (module.exports = {
|
|
2161
|
+
decodeAnimatedGIF,
|
|
2162
|
+
decodeGIF,
|
|
2163
|
+
encodeAnimatedGIF,
|
|
2164
|
+
encodeGIF,
|
|
2165
|
+
indexedImage,
|
|
2166
|
+
renderGIFFrameSequence,
|
|
2167
|
+
renderGIFFrames
|
|
2168
|
+
});
|