@opengeni/artifact-tool 0.2.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/LICENSE +190 -0
- package/README.md +104 -0
- package/dist/bounded-zip.d.ts +28 -0
- package/dist/chunk-4BSENMAE.js +39 -0
- package/dist/chunk-4BSENMAE.js.map +1 -0
- package/dist/chunk-4FRFNNBM.js +276 -0
- package/dist/chunk-4FRFNNBM.js.map +1 -0
- package/dist/chunk-5XIA6KHZ.js +49 -0
- package/dist/chunk-5XIA6KHZ.js.map +1 -0
- package/dist/chunk-66CT2ZRP.js +2229 -0
- package/dist/chunk-66CT2ZRP.js.map +1 -0
- package/dist/chunk-72SYDU4O.js +319 -0
- package/dist/chunk-72SYDU4O.js.map +1 -0
- package/dist/chunk-B2ZJRZDA.js +279 -0
- package/dist/chunk-B2ZJRZDA.js.map +1 -0
- package/dist/chunk-DCTLTNPW.js +2458 -0
- package/dist/chunk-DCTLTNPW.js.map +1 -0
- package/dist/chunk-FGZM4FQ6.js +473 -0
- package/dist/chunk-FGZM4FQ6.js.map +1 -0
- package/dist/chunk-HTJBLBDE.js +591 -0
- package/dist/chunk-HTJBLBDE.js.map +1 -0
- package/dist/chunk-IYFXZQ34.js +5306 -0
- package/dist/chunk-IYFXZQ34.js.map +1 -0
- package/dist/chunk-J6N7IR44.js +172 -0
- package/dist/chunk-J6N7IR44.js.map +1 -0
- package/dist/chunk-N2IHNWBS.js +1002 -0
- package/dist/chunk-N2IHNWBS.js.map +1 -0
- package/dist/chunk-NAG44K67.js +549 -0
- package/dist/chunk-NAG44K67.js.map +1 -0
- package/dist/chunk-O24KTEGP.js +33 -0
- package/dist/chunk-O24KTEGP.js.map +1 -0
- package/dist/chunk-PI2AZVGK.js +2074 -0
- package/dist/chunk-PI2AZVGK.js.map +1 -0
- package/dist/chunk-Q2FFHEY7.js +40 -0
- package/dist/chunk-Q2FFHEY7.js.map +1 -0
- package/dist/chunk-RBGQADXA.js +57 -0
- package/dist/chunk-RBGQADXA.js.map +1 -0
- package/dist/chunk-U5G2BKM2.js +613 -0
- package/dist/chunk-U5G2BKM2.js.map +1 -0
- package/dist/chunk-VOJHMSM3.js +39 -0
- package/dist/chunk-VOJHMSM3.js.map +1 -0
- package/dist/chunk-VUNV25KB.js +16 -0
- package/dist/chunk-VUNV25KB.js.map +1 -0
- package/dist/chunk-XIFUNVBO.js +101 -0
- package/dist/chunk-XIFUNVBO.js.map +1 -0
- package/dist/chunk-ZCJYRJGB.js +489 -0
- package/dist/chunk-ZCJYRJGB.js.map +1 -0
- package/dist/chunk-ZZXPEE4S.js +2260 -0
- package/dist/chunk-ZZXPEE4S.js.map +1 -0
- package/dist/document-docx-api.d.ts +49 -0
- package/dist/document-docx-codec.d.ts +9 -0
- package/dist/document-docx-codec.js +4765 -0
- package/dist/document-docx-codec.js.map +1 -0
- package/dist/document-docx-import.d.ts +261 -0
- package/dist/document-docx-packer.d.ts +18 -0
- package/dist/document-docx-state.d.ts +12 -0
- package/dist/document-render.d.ts +3 -0
- package/dist/document-render.js +492 -0
- package/dist/document-render.js.map +1 -0
- package/dist/document.d.ts +432 -0
- package/dist/document.js +37 -0
- package/dist/document.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/file-blob.d.ts +11 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +186 -0
- package/dist/index.js.map +1 -0
- package/dist/inspection.d.ts +12 -0
- package/dist/kernel.d.ts +101 -0
- package/dist/lib-GQLPACFK.js +9746 -0
- package/dist/lib-GQLPACFK.js.map +1 -0
- package/dist/materializer-cli-entry.d.ts +2 -0
- package/dist/materializer-cli-entry.js +29 -0
- package/dist/materializer-cli-entry.js.map +1 -0
- package/dist/materializer-cli.d.ts +24 -0
- package/dist/materializer-cli.js +24 -0
- package/dist/materializer-cli.js.map +1 -0
- package/dist/native-raster.d.ts +10 -0
- package/dist/native.d.ts +129 -0
- package/dist/native.js +31 -0
- package/dist/native.js.map +1 -0
- package/dist/office-import.d.ts +48 -0
- package/dist/office-import.js +154 -0
- package/dist/office-import.js.map +1 -0
- package/dist/presentation-pptx-api.d.ts +60 -0
- package/dist/presentation-pptx-import.d.ts +5 -0
- package/dist/presentation-pptx-state-digest-765CZZED.js +10 -0
- package/dist/presentation-pptx-state-digest-765CZZED.js.map +1 -0
- package/dist/presentation-pptx-state-digest.d.ts +3 -0
- package/dist/presentation-pptx-state.d.ts +4 -0
- package/dist/presentation-pptx-xml.d.ts +29 -0
- package/dist/presentation-pptx.d.ts +5 -0
- package/dist/presentation-pptx.js +2365 -0
- package/dist/presentation-pptx.js.map +1 -0
- package/dist/presentation-render.d.ts +29 -0
- package/dist/presentation-render.js +375 -0
- package/dist/presentation-render.js.map +1 -0
- package/dist/presentation.d.ts +565 -0
- package/dist/presentation.js +71 -0
- package/dist/presentation.js.map +1 -0
- package/dist/production-composite.d.ts +68 -0
- package/dist/production-document.d.ts +2 -0
- package/dist/production-document.js +176 -0
- package/dist/production-document.js.map +1 -0
- package/dist/production-native-codecs.d.ts +94 -0
- package/dist/production-presentation.d.ts +2 -0
- package/dist/production-presentation.js +176 -0
- package/dist/production-presentation.js.map +1 -0
- package/dist/production-sha256.d.ts +2 -0
- package/dist/production-spreadsheet-native.d.ts +12 -0
- package/dist/production-spreadsheet.d.ts +2 -0
- package/dist/production-spreadsheet.js +176 -0
- package/dist/production-spreadsheet.js.map +1 -0
- package/dist/production.d.ts +96 -0
- package/dist/raster-image.d.ts +34 -0
- package/dist/reference.d.ts +17 -0
- package/dist/reference.js +574 -0
- package/dist/reference.js.map +1 -0
- package/dist/runtime-cli-entry.d.ts +2 -0
- package/dist/runtime-cli-entry.js +21 -0
- package/dist/runtime-cli-entry.js.map +1 -0
- package/dist/runtime-cli.d.ts +76 -0
- package/dist/runtime-cli.js +26 -0
- package/dist/runtime-cli.js.map +1 -0
- package/dist/runtime-development.d.ts +73 -0
- package/dist/runtime-development.js +30 -0
- package/dist/runtime-development.js.map +1 -0
- package/dist/runtime-receipt.d.ts +19 -0
- package/dist/runtime.d.ts +355 -0
- package/dist/runtime.js +42 -0
- package/dist/runtime.js.map +1 -0
- package/dist/snapshot.d.ts +26 -0
- package/dist/snapshot.js +61 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/spreadsheet-address.d.ts +18 -0
- package/dist/spreadsheet-file.d.ts +17 -0
- package/dist/spreadsheet-formula.d.ts +67 -0
- package/dist/spreadsheet-image.d.ts +17 -0
- package/dist/spreadsheet-render.d.ts +5 -0
- package/dist/spreadsheet-render.js +752 -0
- package/dist/spreadsheet-render.js.map +1 -0
- package/dist/spreadsheet-types.d.ts +155 -0
- package/dist/spreadsheet-xlsx-api.d.ts +88 -0
- package/dist/spreadsheet-xlsx-codec.d.ts +16 -0
- package/dist/spreadsheet-xlsx-codec.js +16 -0
- package/dist/spreadsheet-xlsx-codec.js.map +1 -0
- package/dist/spreadsheet-xlsx-state.d.ts +16 -0
- package/dist/spreadsheet.d.ts +724 -0
- package/dist/spreadsheet.js +67 -0
- package/dist/spreadsheet.js.map +1 -0
- package/package.json +129 -0
- package/src/bounded-zip.ts +450 -0
- package/src/document-docx-api.ts +64 -0
- package/src/document-docx-codec.ts +2253 -0
- package/src/document-docx-import.ts +3814 -0
- package/src/document-docx-packer.ts +72 -0
- package/src/document-docx-state.ts +59 -0
- package/src/document-render.ts +615 -0
- package/src/document.ts +2800 -0
- package/src/errors.ts +45 -0
- package/src/file-blob.ts +43 -0
- package/src/index.ts +4 -0
- package/src/inspection.ts +50 -0
- package/src/kernel.ts +525 -0
- package/src/materializer-cli-entry.ts +11 -0
- package/src/materializer-cli.ts +743 -0
- package/src/native-raster.ts +141 -0
- package/src/native.ts +390 -0
- package/src/office-import.ts +243 -0
- package/src/presentation-pptx-api.ts +107 -0
- package/src/presentation-pptx-import.ts +2065 -0
- package/src/presentation-pptx-state-digest.ts +46 -0
- package/src/presentation-pptx-state.ts +18 -0
- package/src/presentation-pptx-xml.ts +473 -0
- package/src/presentation-pptx.ts +447 -0
- package/src/presentation-render.ts +532 -0
- package/src/presentation.ts +2599 -0
- package/src/production-composite.ts +805 -0
- package/src/production-document.ts +2 -0
- package/src/production-native-codecs.ts +1141 -0
- package/src/production-presentation.ts +2 -0
- package/src/production-sha256.ts +150 -0
- package/src/production-spreadsheet-native.ts +686 -0
- package/src/production-spreadsheet.ts +2 -0
- package/src/production.ts +1022 -0
- package/src/raster-image.ts +586 -0
- package/src/reference.ts +17 -0
- package/src/runtime-cli-entry.ts +13 -0
- package/src/runtime-cli.ts +670 -0
- package/src/runtime-development.ts +689 -0
- package/src/runtime-receipt.ts +169 -0
- package/src/runtime.ts +1463 -0
- package/src/snapshot.ts +88 -0
- package/src/spreadsheet-address.ts +90 -0
- package/src/spreadsheet-file.ts +71 -0
- package/src/spreadsheet-formula.ts +1212 -0
- package/src/spreadsheet-image.ts +242 -0
- package/src/spreadsheet-render.ts +985 -0
- package/src/spreadsheet-types.ts +171 -0
- package/src/spreadsheet-xlsx-api.ts +123 -0
- package/src/spreadsheet-xlsx-codec.ts +3063 -0
- package/src/spreadsheet-xlsx-state.ts +191 -0
- package/src/spreadsheet.ts +5195 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// src/raster-image.ts
|
|
2
|
+
var RasterImageValidationError = class extends Error {
|
|
3
|
+
name = "RasterImageValidationError";
|
|
4
|
+
get detail() {
|
|
5
|
+
return this.message;
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
function decodeRasterBase64(encoded) {
|
|
9
|
+
const native = Uint8Array.fromBase64;
|
|
10
|
+
if (native) return native(encoded);
|
|
11
|
+
const binary = atob(encoded);
|
|
12
|
+
const bytes = new Uint8Array(binary.length);
|
|
13
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
14
|
+
bytes[index] = binary.charCodeAt(index);
|
|
15
|
+
}
|
|
16
|
+
return bytes;
|
|
17
|
+
}
|
|
18
|
+
function encodeRasterBase64(bytes) {
|
|
19
|
+
const native = bytes.toBase64;
|
|
20
|
+
if (native) return native.call(bytes);
|
|
21
|
+
const chunkSize = 32768;
|
|
22
|
+
let binary = "";
|
|
23
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
24
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
|
|
25
|
+
}
|
|
26
|
+
return btoa(binary);
|
|
27
|
+
}
|
|
28
|
+
var RASTER_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
29
|
+
"image/png",
|
|
30
|
+
"image/jpeg",
|
|
31
|
+
"image/gif",
|
|
32
|
+
"image/webp"
|
|
33
|
+
]);
|
|
34
|
+
function normalizeRasterContentType(value) {
|
|
35
|
+
if (typeof value !== "string") throw invalid("content type must be a string");
|
|
36
|
+
const normalized = value.toLowerCase();
|
|
37
|
+
if (!RASTER_CONTENT_TYPES.has(normalized)) {
|
|
38
|
+
throw invalid("content type must be image/png, image/jpeg, image/gif, or image/webp");
|
|
39
|
+
}
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
function validateRasterImageBytes(bytes, declaredType) {
|
|
43
|
+
const detected = inspectRasterImage(bytes).contentType;
|
|
44
|
+
if (declaredType !== void 0 && normalizeRasterContentType(declaredType) !== detected) {
|
|
45
|
+
throw invalid("content type does not match the image bytes");
|
|
46
|
+
}
|
|
47
|
+
return detected;
|
|
48
|
+
}
|
|
49
|
+
function canonicalizeRasterDataUrl(value, maximumBytes) {
|
|
50
|
+
if (typeof value !== "string" || value.length > Math.ceil(maximumBytes * 4 / 3) + 128) {
|
|
51
|
+
throw invalid("data URL must be a bounded string");
|
|
52
|
+
}
|
|
53
|
+
const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/i.exec(value);
|
|
54
|
+
if (!match) throw invalid("data URL must contain inline base64 raster bytes");
|
|
55
|
+
const declaredType = normalizeRasterContentType(match[1]);
|
|
56
|
+
const encoded = match[2];
|
|
57
|
+
if (encoded.length === 0 || encoded.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded)) {
|
|
58
|
+
throw invalid("data URL contains malformed base64");
|
|
59
|
+
}
|
|
60
|
+
let bytes;
|
|
61
|
+
try {
|
|
62
|
+
bytes = decodeRasterBase64(encoded);
|
|
63
|
+
} catch {
|
|
64
|
+
throw invalid("data URL contains malformed base64");
|
|
65
|
+
}
|
|
66
|
+
if (bytes.byteLength > maximumBytes) {
|
|
67
|
+
throw invalid(`decoded image exceeds ${maximumBytes} bytes`);
|
|
68
|
+
}
|
|
69
|
+
const contentType = validateRasterImageBytes(bytes, declaredType);
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
contentType,
|
|
72
|
+
canonical: `data:${contentType};base64,${encodeRasterBase64(bytes)}`,
|
|
73
|
+
byteLength: bytes.byteLength
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function boundedUtf8ByteLength(value, maximum) {
|
|
77
|
+
let bytes = 0;
|
|
78
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
79
|
+
const codePoint = value.codePointAt(index);
|
|
80
|
+
if (codePoint <= 127) bytes += 1;
|
|
81
|
+
else if (codePoint <= 2047) bytes += 2;
|
|
82
|
+
else if (codePoint <= 65535) bytes += 3;
|
|
83
|
+
else {
|
|
84
|
+
bytes += 4;
|
|
85
|
+
index += 1;
|
|
86
|
+
}
|
|
87
|
+
if (bytes > maximum) return bytes;
|
|
88
|
+
}
|
|
89
|
+
return bytes;
|
|
90
|
+
}
|
|
91
|
+
var MAX_RASTER_DIMENSION = 16384;
|
|
92
|
+
var MAX_RASTER_PIXELS = 16777216;
|
|
93
|
+
var MAX_ANIMATION_FRAMES = 500;
|
|
94
|
+
var MAX_ANIMATION_DECODED_PIXELS = 67108864;
|
|
95
|
+
function inspectRasterImage(bytes) {
|
|
96
|
+
if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) {
|
|
97
|
+
return parsePngHeader(bytes);
|
|
98
|
+
}
|
|
99
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
|
|
100
|
+
return parseJpegHeader(bytes);
|
|
101
|
+
}
|
|
102
|
+
if (bytes.length >= 6) {
|
|
103
|
+
const signature = ascii(bytes, 0, 6);
|
|
104
|
+
if (signature === "GIF87a" || signature === "GIF89a") return parseGifHeader(bytes);
|
|
105
|
+
}
|
|
106
|
+
if (bytes.length >= 12 && ascii(bytes, 0, 4) === "RIFF" && ascii(bytes, 8, 4) === "WEBP") {
|
|
107
|
+
return parseWebpHeader(bytes);
|
|
108
|
+
}
|
|
109
|
+
throw invalid("does not have a supported PNG, JPEG, GIF, or WebP signature");
|
|
110
|
+
}
|
|
111
|
+
function parsePngHeader(bytes) {
|
|
112
|
+
if (bytes.length < 45 || readU32Be(bytes, 8) !== 13 || ascii(bytes, 12, 4) !== "IHDR") {
|
|
113
|
+
throw malformed("PNG has no complete leading IHDR chunk");
|
|
114
|
+
}
|
|
115
|
+
const width = readU32Be(bytes, 16);
|
|
116
|
+
const height = readU32Be(bytes, 20);
|
|
117
|
+
assertRasterDimensions(width, height);
|
|
118
|
+
const bitDepth = bytes[24];
|
|
119
|
+
const colorType = bytes[25];
|
|
120
|
+
const allowedDepths = {
|
|
121
|
+
0: [1, 2, 4, 8, 16],
|
|
122
|
+
2: [8, 16],
|
|
123
|
+
3: [1, 2, 4, 8],
|
|
124
|
+
4: [8, 16],
|
|
125
|
+
6: [8, 16]
|
|
126
|
+
};
|
|
127
|
+
if (!allowedDepths[colorType]?.includes(bitDepth) || bytes[26] !== 0 || bytes[27] !== 0 || bytes[28] !== 0 && bytes[28] !== 1) {
|
|
128
|
+
throw malformed("PNG IHDR fields are invalid");
|
|
129
|
+
}
|
|
130
|
+
if (pngCrc32(bytes, 12, 29) !== readU32Be(bytes, 29)) {
|
|
131
|
+
throw malformed("PNG IHDR checksum is invalid");
|
|
132
|
+
}
|
|
133
|
+
let offset = 33;
|
|
134
|
+
let sawIdat = false;
|
|
135
|
+
let declaredFrames;
|
|
136
|
+
let frameCount = 0;
|
|
137
|
+
let animationPixels = 0;
|
|
138
|
+
while (offset < bytes.length) {
|
|
139
|
+
if (offset + 12 > bytes.length) throw malformed("PNG chunk is truncated");
|
|
140
|
+
const length = readU32Be(bytes, offset);
|
|
141
|
+
if (length > bytes.length - offset - 12) {
|
|
142
|
+
throw malformed("PNG chunk length exceeds the input");
|
|
143
|
+
}
|
|
144
|
+
const chunkType = ascii(bytes, offset + 4, 4);
|
|
145
|
+
if (!/^[A-Za-z]{4}$/.test(chunkType)) {
|
|
146
|
+
throw malformed("PNG chunk type is invalid");
|
|
147
|
+
}
|
|
148
|
+
if (chunkType === "IHDR") throw malformed("PNG contains duplicate IHDR");
|
|
149
|
+
if (chunkType === "IDAT") sawIdat = true;
|
|
150
|
+
if (chunkType === "acTL") {
|
|
151
|
+
if (length !== 8 || declaredFrames !== void 0) {
|
|
152
|
+
throw malformed("APNG animation control is invalid");
|
|
153
|
+
}
|
|
154
|
+
declaredFrames = readU32Be(bytes, offset + 8);
|
|
155
|
+
if (declaredFrames === 0 || declaredFrames > MAX_ANIMATION_FRAMES) {
|
|
156
|
+
throw invalid(`animation frame limit exceeded (maximum ${MAX_ANIMATION_FRAMES})`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (chunkType === "fcTL") {
|
|
160
|
+
if (length !== 26 || declaredFrames === void 0) {
|
|
161
|
+
throw malformed("APNG frame control is invalid");
|
|
162
|
+
}
|
|
163
|
+
const frameWidth = readU32Be(bytes, offset + 12);
|
|
164
|
+
const frameHeight = readU32Be(bytes, offset + 16);
|
|
165
|
+
const frameX = readU32Be(bytes, offset + 20);
|
|
166
|
+
const frameY = readU32Be(bytes, offset + 24);
|
|
167
|
+
assertRasterDimensions(frameWidth, frameHeight);
|
|
168
|
+
if (frameX + frameWidth > width || frameY + frameHeight > height) {
|
|
169
|
+
throw malformed("APNG frame exceeds its canvas dimensions");
|
|
170
|
+
}
|
|
171
|
+
frameCount += 1;
|
|
172
|
+
animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);
|
|
173
|
+
}
|
|
174
|
+
const next = offset + 12 + length;
|
|
175
|
+
if (chunkType === "IEND") {
|
|
176
|
+
if (length !== 0 || !sawIdat || next !== bytes.length || declaredFrames !== void 0 && frameCount !== declaredFrames) {
|
|
177
|
+
throw malformed("PNG terminal chunks are invalid");
|
|
178
|
+
}
|
|
179
|
+
return { contentType: "image/png", width, height };
|
|
180
|
+
}
|
|
181
|
+
offset = next;
|
|
182
|
+
}
|
|
183
|
+
throw malformed("PNG has no terminal IEND chunk");
|
|
184
|
+
}
|
|
185
|
+
function parseJpegHeader(bytes) {
|
|
186
|
+
if (bytes.length < 12 || bytes[0] !== 255 || bytes[1] !== 216 || bytes.at(-2) !== 255 || bytes.at(-1) !== 217) {
|
|
187
|
+
throw malformed("JPEG framing is incomplete");
|
|
188
|
+
}
|
|
189
|
+
let offset = 2;
|
|
190
|
+
let dimensions;
|
|
191
|
+
while (offset < bytes.length - 2) {
|
|
192
|
+
if (bytes[offset] !== 255) throw malformed("JPEG marker prefix is invalid");
|
|
193
|
+
while (offset < bytes.length && bytes[offset] === 255) offset += 1;
|
|
194
|
+
if (offset >= bytes.length) throw malformed("JPEG marker is truncated");
|
|
195
|
+
const marker = bytes[offset++];
|
|
196
|
+
if (marker === 0) throw malformed("JPEG contains an escaped marker in headers");
|
|
197
|
+
if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) continue;
|
|
198
|
+
if (marker === 217) throw malformed("JPEG ended before image data");
|
|
199
|
+
if (offset + 2 > bytes.length) throw malformed("JPEG segment is truncated");
|
|
200
|
+
const length = readU16Be(bytes, offset);
|
|
201
|
+
if (length < 2 || length > bytes.length - offset) {
|
|
202
|
+
throw malformed("JPEG segment length exceeds the input");
|
|
203
|
+
}
|
|
204
|
+
if (marker === 218) {
|
|
205
|
+
if (!dimensions) {
|
|
206
|
+
throw malformed("JPEG has no supported frame header before image data");
|
|
207
|
+
}
|
|
208
|
+
const scanComponents = bytes[offset + 2];
|
|
209
|
+
if (scanComponents === void 0 || scanComponents === 0 || scanComponents > 4 || length !== 6 + 2 * scanComponents) {
|
|
210
|
+
throw malformed("JPEG scan header is invalid");
|
|
211
|
+
}
|
|
212
|
+
return dimensions;
|
|
213
|
+
}
|
|
214
|
+
if (isJpegStartOfFrame(marker)) {
|
|
215
|
+
if (dimensions) throw malformed("JPEG contains duplicate frame headers");
|
|
216
|
+
if (length < 8) throw malformed("JPEG frame header is too short");
|
|
217
|
+
const height = readU16Be(bytes, offset + 3);
|
|
218
|
+
const width = readU16Be(bytes, offset + 5);
|
|
219
|
+
const components = bytes[offset + 7];
|
|
220
|
+
if (components === 0 || components > 4 || length !== 8 + 3 * components) {
|
|
221
|
+
throw malformed("JPEG frame component table is invalid");
|
|
222
|
+
}
|
|
223
|
+
assertRasterDimensions(width, height);
|
|
224
|
+
dimensions = { contentType: "image/jpeg", width, height };
|
|
225
|
+
}
|
|
226
|
+
offset += length;
|
|
227
|
+
}
|
|
228
|
+
throw malformed("JPEG has no complete scan data");
|
|
229
|
+
}
|
|
230
|
+
function isJpegStartOfFrame(marker) {
|
|
231
|
+
return marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207;
|
|
232
|
+
}
|
|
233
|
+
function parseGifHeader(bytes) {
|
|
234
|
+
if (bytes.length < 14) throw malformed("GIF logical screen descriptor is truncated");
|
|
235
|
+
const width = readU16Le(bytes, 6);
|
|
236
|
+
const height = readU16Le(bytes, 8);
|
|
237
|
+
assertRasterDimensions(width, height);
|
|
238
|
+
const packed = bytes[10];
|
|
239
|
+
let offset = 13;
|
|
240
|
+
if ((packed & 128) !== 0) {
|
|
241
|
+
const tableBytes = 3 * 2 ** ((packed & 7) + 1);
|
|
242
|
+
if (tableBytes > bytes.length - offset) {
|
|
243
|
+
throw malformed("GIF global color table is truncated");
|
|
244
|
+
}
|
|
245
|
+
offset += tableBytes;
|
|
246
|
+
}
|
|
247
|
+
let sawImage = false;
|
|
248
|
+
let frameCount = 0;
|
|
249
|
+
let animationPixels = 0;
|
|
250
|
+
while (offset < bytes.length) {
|
|
251
|
+
const marker = bytes[offset++];
|
|
252
|
+
if (marker === 59) {
|
|
253
|
+
if (!sawImage || offset !== bytes.length) {
|
|
254
|
+
throw malformed("GIF trailer or image data is invalid");
|
|
255
|
+
}
|
|
256
|
+
return { contentType: "image/gif", width, height };
|
|
257
|
+
}
|
|
258
|
+
if (marker === 33) {
|
|
259
|
+
if (offset >= bytes.length) throw malformed("GIF extension is truncated");
|
|
260
|
+
offset += 1;
|
|
261
|
+
offset = skipGifSubBlocks(bytes, offset);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (marker !== 44 || offset + 9 > bytes.length) {
|
|
265
|
+
throw malformed("GIF block structure is invalid");
|
|
266
|
+
}
|
|
267
|
+
const frameLeft = readU16Le(bytes, offset);
|
|
268
|
+
const frameTop = readU16Le(bytes, offset + 2);
|
|
269
|
+
const frameWidth = readU16Le(bytes, offset + 4);
|
|
270
|
+
const frameHeight = readU16Le(bytes, offset + 6);
|
|
271
|
+
assertRasterDimensions(frameWidth, frameHeight);
|
|
272
|
+
if (frameLeft + frameWidth > width || frameTop + frameHeight > height) {
|
|
273
|
+
throw malformed("GIF frame exceeds its canvas dimensions");
|
|
274
|
+
}
|
|
275
|
+
const framePacked = bytes[offset + 8];
|
|
276
|
+
offset += 9;
|
|
277
|
+
if ((framePacked & 128) !== 0) {
|
|
278
|
+
const tableBytes = 3 * 2 ** ((framePacked & 7) + 1);
|
|
279
|
+
if (tableBytes > bytes.length - offset) {
|
|
280
|
+
throw malformed("GIF local color table is truncated");
|
|
281
|
+
}
|
|
282
|
+
offset += tableBytes;
|
|
283
|
+
}
|
|
284
|
+
if (offset >= bytes.length) {
|
|
285
|
+
throw malformed("GIF LZW header is missing");
|
|
286
|
+
}
|
|
287
|
+
const minimumCodeSize = bytes[offset++];
|
|
288
|
+
if (minimumCodeSize < 2 || minimumCodeSize > 8) {
|
|
289
|
+
throw malformed("GIF LZW header is invalid");
|
|
290
|
+
}
|
|
291
|
+
offset = skipGifSubBlocks(bytes, offset);
|
|
292
|
+
frameCount += 1;
|
|
293
|
+
animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);
|
|
294
|
+
sawImage = true;
|
|
295
|
+
}
|
|
296
|
+
throw malformed("GIF has no trailer");
|
|
297
|
+
}
|
|
298
|
+
function skipGifSubBlocks(bytes, start) {
|
|
299
|
+
let offset = start;
|
|
300
|
+
while (offset < bytes.length) {
|
|
301
|
+
const length = bytes[offset++];
|
|
302
|
+
if (length === 0) return offset;
|
|
303
|
+
if (length > bytes.length - offset) {
|
|
304
|
+
throw malformed("GIF data sub-block is truncated");
|
|
305
|
+
}
|
|
306
|
+
offset += length;
|
|
307
|
+
}
|
|
308
|
+
throw malformed("GIF data sub-block has no terminator");
|
|
309
|
+
}
|
|
310
|
+
function parseWebpHeader(bytes) {
|
|
311
|
+
if (bytes.length < 30 || readU32Le(bytes, 4) + 8 !== bytes.length) {
|
|
312
|
+
throw malformed("WebP RIFF container length is invalid");
|
|
313
|
+
}
|
|
314
|
+
let offset = 12;
|
|
315
|
+
let dimensions;
|
|
316
|
+
let extended = false;
|
|
317
|
+
let sawImage = false;
|
|
318
|
+
let frameCount = 0;
|
|
319
|
+
let animationPixels = 0;
|
|
320
|
+
while (offset < bytes.length) {
|
|
321
|
+
if (offset + 8 > bytes.length) throw malformed("WebP chunk is truncated");
|
|
322
|
+
const type = ascii(bytes, offset, 4);
|
|
323
|
+
const length = readU32Le(bytes, offset + 4);
|
|
324
|
+
const dataOffset = offset + 8;
|
|
325
|
+
if (length > bytes.length - dataOffset) {
|
|
326
|
+
throw malformed("WebP chunk length exceeds the input");
|
|
327
|
+
}
|
|
328
|
+
if (type === "VP8X") {
|
|
329
|
+
if (offset !== 12 || dimensions || length !== 10) {
|
|
330
|
+
throw malformed("WebP VP8X header placement or length is invalid");
|
|
331
|
+
}
|
|
332
|
+
dimensions = {
|
|
333
|
+
width: readU24Le(bytes, dataOffset + 4) + 1,
|
|
334
|
+
height: readU24Le(bytes, dataOffset + 7) + 1
|
|
335
|
+
};
|
|
336
|
+
assertRasterDimensions(dimensions.width, dimensions.height);
|
|
337
|
+
extended = true;
|
|
338
|
+
} else if (type === "VP8 ") {
|
|
339
|
+
if (length < 10 || bytes[dataOffset + 3] !== 157 || bytes[dataOffset + 4] !== 1 || bytes[dataOffset + 5] !== 42) {
|
|
340
|
+
throw malformed("WebP VP8 frame header is invalid");
|
|
341
|
+
}
|
|
342
|
+
const frame = {
|
|
343
|
+
width: readU16Le(bytes, dataOffset + 6) & 16383,
|
|
344
|
+
height: readU16Le(bytes, dataOffset + 8) & 16383
|
|
345
|
+
};
|
|
346
|
+
assertRasterDimensions(frame.width, frame.height);
|
|
347
|
+
if (dimensions && (frame.width > dimensions.width || frame.height > dimensions.height)) {
|
|
348
|
+
throw malformed("WebP frame exceeds its canvas dimensions");
|
|
349
|
+
}
|
|
350
|
+
dimensions ??= frame;
|
|
351
|
+
frameCount += 1;
|
|
352
|
+
animationPixels = addAnimationPixels(animationPixels, frame.width, frame.height, frameCount);
|
|
353
|
+
sawImage = true;
|
|
354
|
+
} else if (type === "VP8L") {
|
|
355
|
+
if (length < 5 || bytes[dataOffset] !== 47) {
|
|
356
|
+
throw malformed("WebP VP8L frame header is invalid");
|
|
357
|
+
}
|
|
358
|
+
const b1 = bytes[dataOffset + 1];
|
|
359
|
+
const b2 = bytes[dataOffset + 2];
|
|
360
|
+
const b3 = bytes[dataOffset + 3];
|
|
361
|
+
const b4 = bytes[dataOffset + 4];
|
|
362
|
+
const frame = {
|
|
363
|
+
width: 1 + b1 + ((b2 & 63) << 8),
|
|
364
|
+
height: 1 + (b2 >> 6) + (b3 << 2) + ((b4 & 15) << 10)
|
|
365
|
+
};
|
|
366
|
+
assertRasterDimensions(frame.width, frame.height);
|
|
367
|
+
if (dimensions && (frame.width > dimensions.width || frame.height > dimensions.height)) {
|
|
368
|
+
throw malformed("WebP frame exceeds its canvas dimensions");
|
|
369
|
+
}
|
|
370
|
+
dimensions ??= frame;
|
|
371
|
+
frameCount += 1;
|
|
372
|
+
animationPixels = addAnimationPixels(animationPixels, frame.width, frame.height, frameCount);
|
|
373
|
+
sawImage = true;
|
|
374
|
+
} else if (type === "ANMF") {
|
|
375
|
+
if (!extended || !dimensions || length < 24) {
|
|
376
|
+
throw malformed("WebP animation frame header is invalid");
|
|
377
|
+
}
|
|
378
|
+
const frameX = readU24Le(bytes, dataOffset) * 2;
|
|
379
|
+
const frameY = readU24Le(bytes, dataOffset + 3) * 2;
|
|
380
|
+
const frameWidth = readU24Le(bytes, dataOffset + 6) + 1;
|
|
381
|
+
const frameHeight = readU24Le(bytes, dataOffset + 9) + 1;
|
|
382
|
+
assertRasterDimensions(frameWidth, frameHeight);
|
|
383
|
+
if (frameX + frameWidth > dimensions.width || frameY + frameHeight > dimensions.height) {
|
|
384
|
+
throw malformed("WebP animation frame exceeds its canvas dimensions");
|
|
385
|
+
}
|
|
386
|
+
frameCount += 1;
|
|
387
|
+
animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);
|
|
388
|
+
sawImage = true;
|
|
389
|
+
}
|
|
390
|
+
const paddedLength = length + (length & 1);
|
|
391
|
+
if (paddedLength > bytes.length - dataOffset) {
|
|
392
|
+
throw malformed("WebP chunk padding is truncated");
|
|
393
|
+
}
|
|
394
|
+
offset = dataOffset + paddedLength;
|
|
395
|
+
}
|
|
396
|
+
if (offset !== bytes.length || !dimensions || !sawImage) {
|
|
397
|
+
throw malformed("WebP has no complete image payload");
|
|
398
|
+
}
|
|
399
|
+
return { contentType: "image/webp", ...dimensions };
|
|
400
|
+
}
|
|
401
|
+
function assertRasterDimensions(width, height) {
|
|
402
|
+
if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
|
|
403
|
+
throw invalid("image dimensions must be positive integers");
|
|
404
|
+
}
|
|
405
|
+
if (width > MAX_RASTER_DIMENSION || height > MAX_RASTER_DIMENSION) {
|
|
406
|
+
throw invalid(
|
|
407
|
+
`image dimension limit exceeded (${width}x${height}; maximum ${MAX_RASTER_DIMENSION})`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
if (width > Math.floor(MAX_RASTER_PIXELS / height)) {
|
|
411
|
+
throw invalid(
|
|
412
|
+
`decoded pixel limit exceeded (${width}x${height}; maximum ${MAX_RASTER_PIXELS})`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function addAnimationPixels(current, width, height, frames) {
|
|
417
|
+
if (frames > MAX_ANIMATION_FRAMES) {
|
|
418
|
+
throw invalid(`animation frame limit exceeded (maximum ${MAX_ANIMATION_FRAMES})`);
|
|
419
|
+
}
|
|
420
|
+
const framePixels = width * height;
|
|
421
|
+
if (current > MAX_ANIMATION_DECODED_PIXELS - framePixels) {
|
|
422
|
+
throw invalid(
|
|
423
|
+
`animation decoded pixel limit exceeded (maximum ${MAX_ANIMATION_DECODED_PIXELS})`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return current + framePixels;
|
|
427
|
+
}
|
|
428
|
+
function malformed(detail) {
|
|
429
|
+
return invalid(`malformed raster image: ${detail}`);
|
|
430
|
+
}
|
|
431
|
+
function invalid(detail) {
|
|
432
|
+
return new RasterImageValidationError(detail);
|
|
433
|
+
}
|
|
434
|
+
function readU16Be(bytes, offset) {
|
|
435
|
+
return bytes[offset] * 256 + bytes[offset + 1];
|
|
436
|
+
}
|
|
437
|
+
function readU16Le(bytes, offset) {
|
|
438
|
+
return bytes[offset] + bytes[offset + 1] * 256;
|
|
439
|
+
}
|
|
440
|
+
function readU24Le(bytes, offset) {
|
|
441
|
+
return bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536;
|
|
442
|
+
}
|
|
443
|
+
function readU32Be(bytes, offset) {
|
|
444
|
+
return bytes[offset] * 16777216 + bytes[offset + 1] * 65536 + bytes[offset + 2] * 256 + bytes[offset + 3];
|
|
445
|
+
}
|
|
446
|
+
function readU32Le(bytes, offset) {
|
|
447
|
+
return bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536 + bytes[offset + 3] * 16777216;
|
|
448
|
+
}
|
|
449
|
+
function ascii(bytes, offset, length) {
|
|
450
|
+
return String.fromCharCode(...bytes.subarray(offset, offset + length));
|
|
451
|
+
}
|
|
452
|
+
function pngCrc32(bytes, start, end) {
|
|
453
|
+
let crc = 4294967295;
|
|
454
|
+
for (let index = start; index < end; index += 1) {
|
|
455
|
+
crc ^= bytes[index];
|
|
456
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
457
|
+
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return (crc ^ 4294967295) >>> 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export {
|
|
464
|
+
RasterImageValidationError,
|
|
465
|
+
decodeRasterBase64,
|
|
466
|
+
encodeRasterBase64,
|
|
467
|
+
normalizeRasterContentType,
|
|
468
|
+
validateRasterImageBytes,
|
|
469
|
+
canonicalizeRasterDataUrl,
|
|
470
|
+
boundedUtf8ByteLength,
|
|
471
|
+
inspectRasterImage
|
|
472
|
+
};
|
|
473
|
+
//# sourceMappingURL=chunk-FGZM4FQ6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/raster-image.ts"],"sourcesContent":["export type RasterImageContentType = \"image/png\" | \"image/jpeg\" | \"image/gif\" | \"image/webp\";\n\nexport type RasterImageMetadata = {\n contentType: RasterImageContentType;\n width: number;\n height: number;\n};\n\n/** Internal validation failure. Public model boundaries translate this to their typed error. */\nexport class RasterImageValidationError extends Error {\n readonly name = \"RasterImageValidationError\";\n\n get detail(): string {\n return this.message;\n }\n}\n\n/** Decode already-syntax-checked base64 without forcing a large intermediary string when supported. */\nexport function decodeRasterBase64(encoded: string): Uint8Array<ArrayBuffer> {\n const native = (\n Uint8Array as typeof Uint8Array & {\n fromBase64?: (value: string) => Uint8Array<ArrayBuffer>;\n }\n ).fromBase64;\n if (native) return native(encoded);\n\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return bytes;\n}\n\n/** Encode bytes using the zero-copy native primitive where available, with a bounded fallback. */\nexport function encodeRasterBase64(bytes: Uint8Array): string {\n const native = (bytes as Uint8Array & { toBase64?: () => string }).toBase64;\n if (native) return native.call(bytes);\n\n const chunkSize = 0x8000;\n let binary = \"\";\n for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n }\n return btoa(binary);\n}\n\nconst RASTER_CONTENT_TYPES = new Set<RasterImageContentType>([\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n]);\n\n/** Normalize one supported raster MIME without admitting active image formats. */\nexport function normalizeRasterContentType(value: unknown): RasterImageContentType {\n if (typeof value !== \"string\") throw invalid(\"content type must be a string\");\n const normalized = value.toLowerCase();\n if (!RASTER_CONTENT_TYPES.has(normalized as RasterImageContentType)) {\n throw invalid(\"content type must be image/png, image/jpeg, image/gif, or image/webp\");\n }\n return normalized as RasterImageContentType;\n}\n\n/** Validate bytes and, when supplied, bind the declared MIME to their signature. */\nexport function validateRasterImageBytes(\n bytes: Uint8Array,\n declaredType?: unknown,\n): RasterImageContentType {\n const detected = inspectRasterImage(bytes).contentType;\n if (declaredType !== undefined && normalizeRasterContentType(declaredType) !== detected) {\n throw invalid(\"content type does not match the image bytes\");\n }\n return detected;\n}\n\n/** Strictly decode and canonicalize an inline raster source under a byte cap. */\nexport function canonicalizeRasterDataUrl(\n value: unknown,\n maximumBytes: number,\n): Readonly<{\n contentType: RasterImageContentType;\n canonical: string;\n byteLength: number;\n}> {\n if (typeof value !== \"string\" || value.length > Math.ceil((maximumBytes * 4) / 3) + 128) {\n throw invalid(\"data URL must be a bounded string\");\n }\n const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/i.exec(value);\n if (!match) throw invalid(\"data URL must contain inline base64 raster bytes\");\n const declaredType = normalizeRasterContentType(match[1]!);\n const encoded = match[2]!;\n if (\n encoded.length === 0 ||\n encoded.length % 4 !== 0 ||\n !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded)\n ) {\n throw invalid(\"data URL contains malformed base64\");\n }\n let bytes: Uint8Array;\n try {\n bytes = decodeRasterBase64(encoded);\n } catch {\n throw invalid(\"data URL contains malformed base64\");\n }\n if (bytes.byteLength > maximumBytes) {\n throw invalid(`decoded image exceeds ${maximumBytes} bytes`);\n }\n const contentType = validateRasterImageBytes(bytes, declaredType);\n return Object.freeze({\n contentType,\n canonical: `data:${contentType};base64,${encodeRasterBase64(bytes)}`,\n byteLength: bytes.byteLength,\n });\n}\n\n/** Count UTF-8 bytes without allocating an encoded copy; returns as soon as the cap is crossed. */\nexport function boundedUtf8ByteLength(value: string, maximum: number): number {\n let bytes = 0;\n for (let index = 0; index < value.length; index += 1) {\n const codePoint = value.codePointAt(index)!;\n if (codePoint <= 0x7f) bytes += 1;\n else if (codePoint <= 0x7ff) bytes += 2;\n else if (codePoint <= 0xffff) bytes += 3;\n else {\n bytes += 4;\n index += 1;\n }\n if (bytes > maximum) return bytes;\n }\n return bytes;\n}\n\nconst MAX_RASTER_DIMENSION = 16_384;\nconst MAX_RASTER_PIXELS = 16_777_216;\nconst MAX_ANIMATION_FRAMES = 500;\nconst MAX_ANIMATION_DECODED_PIXELS = 67_108_864;\n\n/**\n * Structurally validates supported raster bytes before a native/browser decoder sees them.\n *\n * Callers must separately bound the encoded byte length. This parser bounds decoded canvas,\n * animation frame count, and cumulative animated pixels while walking each container once.\n */\nexport function inspectRasterImage(bytes: Uint8Array): RasterImageMetadata {\n if (\n bytes.length >= 8 &&\n bytes[0] === 0x89 &&\n bytes[1] === 0x50 &&\n bytes[2] === 0x4e &&\n bytes[3] === 0x47 &&\n bytes[4] === 0x0d &&\n bytes[5] === 0x0a &&\n bytes[6] === 0x1a &&\n bytes[7] === 0x0a\n ) {\n return parsePngHeader(bytes);\n }\n if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {\n return parseJpegHeader(bytes);\n }\n if (bytes.length >= 6) {\n const signature = ascii(bytes, 0, 6);\n if (signature === \"GIF87a\" || signature === \"GIF89a\") return parseGifHeader(bytes);\n }\n if (bytes.length >= 12 && ascii(bytes, 0, 4) === \"RIFF\" && ascii(bytes, 8, 4) === \"WEBP\") {\n return parseWebpHeader(bytes);\n }\n throw invalid(\"does not have a supported PNG, JPEG, GIF, or WebP signature\");\n}\n\nfunction parsePngHeader(bytes: Uint8Array): RasterImageMetadata {\n if (bytes.length < 45 || readU32Be(bytes, 8) !== 13 || ascii(bytes, 12, 4) !== \"IHDR\") {\n throw malformed(\"PNG has no complete leading IHDR chunk\");\n }\n const width = readU32Be(bytes, 16);\n const height = readU32Be(bytes, 20);\n assertRasterDimensions(width, height);\n\n const bitDepth = bytes[24]!;\n const colorType = bytes[25]!;\n const allowedDepths: Readonly<Record<number, readonly number[]>> = {\n 0: [1, 2, 4, 8, 16],\n 2: [8, 16],\n 3: [1, 2, 4, 8],\n 4: [8, 16],\n 6: [8, 16],\n };\n if (\n !allowedDepths[colorType]?.includes(bitDepth) ||\n bytes[26] !== 0 ||\n bytes[27] !== 0 ||\n (bytes[28] !== 0 && bytes[28] !== 1)\n ) {\n throw malformed(\"PNG IHDR fields are invalid\");\n }\n if (pngCrc32(bytes, 12, 29) !== readU32Be(bytes, 29)) {\n throw malformed(\"PNG IHDR checksum is invalid\");\n }\n\n let offset = 33;\n let sawIdat = false;\n let declaredFrames: number | undefined;\n let frameCount = 0;\n let animationPixels = 0;\n while (offset < bytes.length) {\n if (offset + 12 > bytes.length) throw malformed(\"PNG chunk is truncated\");\n const length = readU32Be(bytes, offset);\n if (length > bytes.length - offset - 12) {\n throw malformed(\"PNG chunk length exceeds the input\");\n }\n const chunkType = ascii(bytes, offset + 4, 4);\n if (!/^[A-Za-z]{4}$/.test(chunkType)) {\n throw malformed(\"PNG chunk type is invalid\");\n }\n if (chunkType === \"IHDR\") throw malformed(\"PNG contains duplicate IHDR\");\n if (chunkType === \"IDAT\") sawIdat = true;\n if (chunkType === \"acTL\") {\n if (length !== 8 || declaredFrames !== undefined) {\n throw malformed(\"APNG animation control is invalid\");\n }\n declaredFrames = readU32Be(bytes, offset + 8);\n if (declaredFrames === 0 || declaredFrames > MAX_ANIMATION_FRAMES) {\n throw invalid(`animation frame limit exceeded (maximum ${MAX_ANIMATION_FRAMES})`);\n }\n }\n if (chunkType === \"fcTL\") {\n if (length !== 26 || declaredFrames === undefined) {\n throw malformed(\"APNG frame control is invalid\");\n }\n const frameWidth = readU32Be(bytes, offset + 12);\n const frameHeight = readU32Be(bytes, offset + 16);\n const frameX = readU32Be(bytes, offset + 20);\n const frameY = readU32Be(bytes, offset + 24);\n assertRasterDimensions(frameWidth, frameHeight);\n if (frameX + frameWidth > width || frameY + frameHeight > height) {\n throw malformed(\"APNG frame exceeds its canvas dimensions\");\n }\n frameCount += 1;\n animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);\n }\n const next = offset + 12 + length;\n if (chunkType === \"IEND\") {\n if (\n length !== 0 ||\n !sawIdat ||\n next !== bytes.length ||\n (declaredFrames !== undefined && frameCount !== declaredFrames)\n ) {\n throw malformed(\"PNG terminal chunks are invalid\");\n }\n return { contentType: \"image/png\", width, height };\n }\n offset = next;\n }\n throw malformed(\"PNG has no terminal IEND chunk\");\n}\n\nfunction parseJpegHeader(bytes: Uint8Array): RasterImageMetadata {\n if (\n bytes.length < 12 ||\n bytes[0] !== 0xff ||\n bytes[1] !== 0xd8 ||\n bytes.at(-2) !== 0xff ||\n bytes.at(-1) !== 0xd9\n ) {\n throw malformed(\"JPEG framing is incomplete\");\n }\n let offset = 2;\n let dimensions: RasterImageMetadata | undefined;\n while (offset < bytes.length - 2) {\n if (bytes[offset] !== 0xff) throw malformed(\"JPEG marker prefix is invalid\");\n while (offset < bytes.length && bytes[offset] === 0xff) offset += 1;\n if (offset >= bytes.length) throw malformed(\"JPEG marker is truncated\");\n const marker = bytes[offset++]!;\n if (marker === 0x00) throw malformed(\"JPEG contains an escaped marker in headers\");\n if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue;\n if (marker === 0xd9) throw malformed(\"JPEG ended before image data\");\n if (offset + 2 > bytes.length) throw malformed(\"JPEG segment is truncated\");\n const length = readU16Be(bytes, offset);\n if (length < 2 || length > bytes.length - offset) {\n throw malformed(\"JPEG segment length exceeds the input\");\n }\n if (marker === 0xda) {\n if (!dimensions) {\n throw malformed(\"JPEG has no supported frame header before image data\");\n }\n const scanComponents = bytes[offset + 2];\n if (\n scanComponents === undefined ||\n scanComponents === 0 ||\n scanComponents > 4 ||\n length !== 6 + 2 * scanComponents\n ) {\n throw malformed(\"JPEG scan header is invalid\");\n }\n return dimensions;\n }\n if (isJpegStartOfFrame(marker)) {\n if (dimensions) throw malformed(\"JPEG contains duplicate frame headers\");\n if (length < 8) throw malformed(\"JPEG frame header is too short\");\n const height = readU16Be(bytes, offset + 3);\n const width = readU16Be(bytes, offset + 5);\n const components = bytes[offset + 7]!;\n if (components === 0 || components > 4 || length !== 8 + 3 * components) {\n throw malformed(\"JPEG frame component table is invalid\");\n }\n assertRasterDimensions(width, height);\n dimensions = { contentType: \"image/jpeg\", width, height };\n }\n offset += length;\n }\n throw malformed(\"JPEG has no complete scan data\");\n}\n\nfunction isJpegStartOfFrame(marker: number): boolean {\n return (\n (marker >= 0xc0 && marker <= 0xc3) ||\n (marker >= 0xc5 && marker <= 0xc7) ||\n (marker >= 0xc9 && marker <= 0xcb) ||\n (marker >= 0xcd && marker <= 0xcf)\n );\n}\n\nfunction parseGifHeader(bytes: Uint8Array): RasterImageMetadata {\n if (bytes.length < 14) throw malformed(\"GIF logical screen descriptor is truncated\");\n const width = readU16Le(bytes, 6);\n const height = readU16Le(bytes, 8);\n assertRasterDimensions(width, height);\n const packed = bytes[10]!;\n let offset = 13;\n if ((packed & 0x80) !== 0) {\n const tableBytes = 3 * 2 ** ((packed & 0x07) + 1);\n if (tableBytes > bytes.length - offset) {\n throw malformed(\"GIF global color table is truncated\");\n }\n offset += tableBytes;\n }\n let sawImage = false;\n let frameCount = 0;\n let animationPixels = 0;\n while (offset < bytes.length) {\n const marker = bytes[offset++]!;\n if (marker === 0x3b) {\n if (!sawImage || offset !== bytes.length) {\n throw malformed(\"GIF trailer or image data is invalid\");\n }\n return { contentType: \"image/gif\", width, height };\n }\n if (marker === 0x21) {\n if (offset >= bytes.length) throw malformed(\"GIF extension is truncated\");\n offset += 1;\n offset = skipGifSubBlocks(bytes, offset);\n continue;\n }\n if (marker !== 0x2c || offset + 9 > bytes.length) {\n throw malformed(\"GIF block structure is invalid\");\n }\n const frameLeft = readU16Le(bytes, offset);\n const frameTop = readU16Le(bytes, offset + 2);\n const frameWidth = readU16Le(bytes, offset + 4);\n const frameHeight = readU16Le(bytes, offset + 6);\n assertRasterDimensions(frameWidth, frameHeight);\n if (frameLeft + frameWidth > width || frameTop + frameHeight > height) {\n throw malformed(\"GIF frame exceeds its canvas dimensions\");\n }\n const framePacked = bytes[offset + 8]!;\n offset += 9;\n if ((framePacked & 0x80) !== 0) {\n const tableBytes = 3 * 2 ** ((framePacked & 0x07) + 1);\n if (tableBytes > bytes.length - offset) {\n throw malformed(\"GIF local color table is truncated\");\n }\n offset += tableBytes;\n }\n if (offset >= bytes.length) {\n throw malformed(\"GIF LZW header is missing\");\n }\n const minimumCodeSize = bytes[offset++]!;\n if (minimumCodeSize < 2 || minimumCodeSize > 8) {\n throw malformed(\"GIF LZW header is invalid\");\n }\n offset = skipGifSubBlocks(bytes, offset);\n frameCount += 1;\n animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);\n sawImage = true;\n }\n throw malformed(\"GIF has no trailer\");\n}\n\nfunction skipGifSubBlocks(bytes: Uint8Array, start: number): number {\n let offset = start;\n while (offset < bytes.length) {\n const length = bytes[offset++]!;\n if (length === 0) return offset;\n if (length > bytes.length - offset) {\n throw malformed(\"GIF data sub-block is truncated\");\n }\n offset += length;\n }\n throw malformed(\"GIF data sub-block has no terminator\");\n}\n\nfunction parseWebpHeader(bytes: Uint8Array): RasterImageMetadata {\n if (bytes.length < 30 || readU32Le(bytes, 4) + 8 !== bytes.length) {\n throw malformed(\"WebP RIFF container length is invalid\");\n }\n let offset = 12;\n let dimensions: { width: number; height: number } | undefined;\n let extended = false;\n let sawImage = false;\n let frameCount = 0;\n let animationPixels = 0;\n while (offset < bytes.length) {\n if (offset + 8 > bytes.length) throw malformed(\"WebP chunk is truncated\");\n const type = ascii(bytes, offset, 4);\n const length = readU32Le(bytes, offset + 4);\n const dataOffset = offset + 8;\n if (length > bytes.length - dataOffset) {\n throw malformed(\"WebP chunk length exceeds the input\");\n }\n if (type === \"VP8X\") {\n if (offset !== 12 || dimensions || length !== 10) {\n throw malformed(\"WebP VP8X header placement or length is invalid\");\n }\n dimensions = {\n width: readU24Le(bytes, dataOffset + 4) + 1,\n height: readU24Le(bytes, dataOffset + 7) + 1,\n };\n assertRasterDimensions(dimensions.width, dimensions.height);\n extended = true;\n } else if (type === \"VP8 \") {\n if (\n length < 10 ||\n bytes[dataOffset + 3] !== 0x9d ||\n bytes[dataOffset + 4] !== 0x01 ||\n bytes[dataOffset + 5] !== 0x2a\n ) {\n throw malformed(\"WebP VP8 frame header is invalid\");\n }\n const frame = {\n width: readU16Le(bytes, dataOffset + 6) & 0x3fff,\n height: readU16Le(bytes, dataOffset + 8) & 0x3fff,\n };\n assertRasterDimensions(frame.width, frame.height);\n if (dimensions && (frame.width > dimensions.width || frame.height > dimensions.height)) {\n throw malformed(\"WebP frame exceeds its canvas dimensions\");\n }\n dimensions ??= frame;\n frameCount += 1;\n animationPixels = addAnimationPixels(animationPixels, frame.width, frame.height, frameCount);\n sawImage = true;\n } else if (type === \"VP8L\") {\n if (length < 5 || bytes[dataOffset] !== 0x2f) {\n throw malformed(\"WebP VP8L frame header is invalid\");\n }\n const b1 = bytes[dataOffset + 1]!;\n const b2 = bytes[dataOffset + 2]!;\n const b3 = bytes[dataOffset + 3]!;\n const b4 = bytes[dataOffset + 4]!;\n const frame = {\n width: 1 + b1 + ((b2 & 0x3f) << 8),\n height: 1 + (b2 >> 6) + (b3 << 2) + ((b4 & 0x0f) << 10),\n };\n assertRasterDimensions(frame.width, frame.height);\n if (dimensions && (frame.width > dimensions.width || frame.height > dimensions.height)) {\n throw malformed(\"WebP frame exceeds its canvas dimensions\");\n }\n dimensions ??= frame;\n frameCount += 1;\n animationPixels = addAnimationPixels(animationPixels, frame.width, frame.height, frameCount);\n sawImage = true;\n } else if (type === \"ANMF\") {\n if (!extended || !dimensions || length < 24) {\n throw malformed(\"WebP animation frame header is invalid\");\n }\n const frameX = readU24Le(bytes, dataOffset) * 2;\n const frameY = readU24Le(bytes, dataOffset + 3) * 2;\n const frameWidth = readU24Le(bytes, dataOffset + 6) + 1;\n const frameHeight = readU24Le(bytes, dataOffset + 9) + 1;\n assertRasterDimensions(frameWidth, frameHeight);\n if (frameX + frameWidth > dimensions.width || frameY + frameHeight > dimensions.height) {\n throw malformed(\"WebP animation frame exceeds its canvas dimensions\");\n }\n frameCount += 1;\n animationPixels = addAnimationPixels(animationPixels, frameWidth, frameHeight, frameCount);\n sawImage = true;\n }\n const paddedLength = length + (length & 1);\n if (paddedLength > bytes.length - dataOffset) {\n throw malformed(\"WebP chunk padding is truncated\");\n }\n offset = dataOffset + paddedLength;\n }\n if (offset !== bytes.length || !dimensions || !sawImage) {\n throw malformed(\"WebP has no complete image payload\");\n }\n return { contentType: \"image/webp\", ...dimensions };\n}\n\nfunction assertRasterDimensions(width: number, height: number): void {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw invalid(\"image dimensions must be positive integers\");\n }\n if (width > MAX_RASTER_DIMENSION || height > MAX_RASTER_DIMENSION) {\n throw invalid(\n `image dimension limit exceeded (${width}x${height}; maximum ${MAX_RASTER_DIMENSION})`,\n );\n }\n if (width > Math.floor(MAX_RASTER_PIXELS / height)) {\n throw invalid(\n `decoded pixel limit exceeded (${width}x${height}; maximum ${MAX_RASTER_PIXELS})`,\n );\n }\n}\n\nfunction addAnimationPixels(\n current: number,\n width: number,\n height: number,\n frames: number,\n): number {\n if (frames > MAX_ANIMATION_FRAMES) {\n throw invalid(`animation frame limit exceeded (maximum ${MAX_ANIMATION_FRAMES})`);\n }\n const framePixels = width * height;\n if (current > MAX_ANIMATION_DECODED_PIXELS - framePixels) {\n throw invalid(\n `animation decoded pixel limit exceeded (maximum ${MAX_ANIMATION_DECODED_PIXELS})`,\n );\n }\n return current + framePixels;\n}\n\nfunction malformed(detail: string): RasterImageValidationError {\n return invalid(`malformed raster image: ${detail}`);\n}\n\nfunction invalid(detail: string): RasterImageValidationError {\n return new RasterImageValidationError(detail);\n}\n\nfunction readU16Be(bytes: Uint8Array, offset: number): number {\n return bytes[offset]! * 0x100 + bytes[offset + 1]!;\n}\n\nfunction readU16Le(bytes: Uint8Array, offset: number): number {\n return bytes[offset]! + bytes[offset + 1]! * 0x100;\n}\n\nfunction readU24Le(bytes: Uint8Array, offset: number): number {\n return bytes[offset]! + bytes[offset + 1]! * 0x100 + bytes[offset + 2]! * 0x1_0000;\n}\n\nfunction readU32Be(bytes: Uint8Array, offset: number): number {\n return (\n bytes[offset]! * 0x1_000000 +\n bytes[offset + 1]! * 0x1_0000 +\n bytes[offset + 2]! * 0x100 +\n bytes[offset + 3]!\n );\n}\n\nfunction readU32Le(bytes: Uint8Array, offset: number): number {\n return (\n bytes[offset]! +\n bytes[offset + 1]! * 0x100 +\n bytes[offset + 2]! * 0x1_0000 +\n bytes[offset + 3]! * 0x1_000000\n );\n}\n\nfunction ascii(bytes: Uint8Array, offset: number, length: number): string {\n return String.fromCharCode(...bytes.subarray(offset, offset + length));\n}\n\nfunction pngCrc32(bytes: Uint8Array, start: number, end: number): number {\n let crc = 0xffff_ffff;\n for (let index = start; index < end; index += 1) {\n crc ^= bytes[index]!;\n for (let bit = 0; bit < 8; bit += 1) {\n crc = (crc >>> 1) ^ (crc & 1 ? 0xedb8_8320 : 0);\n }\n }\n return (crc ^ 0xffff_ffff) >>> 0;\n}\n"],"mappings":"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","names":[]}
|