@utilix-tech/sdk 0.4.0 → 0.6.0
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/README.md +23 -7
- package/dist/{api-8aZtWhSj.d.cts → api-Xl7OzIgq.d.cts} +35 -2
- package/dist/{api-8aZtWhSj.d.ts → api-Xl7OzIgq.d.ts} +35 -2
- package/dist/chunk-FXBB7O5A.js +467 -0
- package/dist/{chunk-FL53T24A.js → chunk-GEFVMGZR.js} +2 -8
- package/dist/{chunk-HFRTZE7T.js → chunk-Q3B3YWOA.js} +51 -1
- package/dist/index.cjs +386 -9
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/media-CHaBS1dI.d.cts +82 -0
- package/dist/media-CHaBS1dI.d.ts +82 -0
- package/dist/tools/api.cjs +50 -0
- package/dist/tools/api.d.cts +1 -1
- package/dist/tools/api.d.ts +1 -1
- package/dist/tools/api.js +1 -1
- package/dist/tools/hashing.cjs +2 -8
- package/dist/tools/hashing.js +1 -1
- package/dist/tools/media.cjs +333 -0
- package/dist/tools/media.d.cts +1 -1
- package/dist/tools/media.d.ts +1 -1
- package/dist/tools/media.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-N7C52YGL.js +0 -134
- package/dist/media-DF2cx3pK.d.cts +0 -28
- package/dist/media-DF2cx3pK.d.ts +0 -28
package/dist/tools/api.cjs
CHANGED
|
@@ -444,6 +444,55 @@ function decodeJwt(token) {
|
|
|
444
444
|
function formatJwtJson(obj) {
|
|
445
445
|
return JSON.stringify(obj, null, 2);
|
|
446
446
|
}
|
|
447
|
+
function base64urlByteLength(s) {
|
|
448
|
+
const clean = s.replace(/=+$/, "");
|
|
449
|
+
return Math.floor(clean.length * 6 / 8);
|
|
450
|
+
}
|
|
451
|
+
function parseJwks(input) {
|
|
452
|
+
const trimmed = input.trim();
|
|
453
|
+
if (!trimmed) return { ok: false, error: "No input provided" };
|
|
454
|
+
let data;
|
|
455
|
+
try {
|
|
456
|
+
data = JSON.parse(trimmed);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
return { ok: false, error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` };
|
|
459
|
+
}
|
|
460
|
+
let rawKeys;
|
|
461
|
+
if (data && typeof data === "object" && Array.isArray(data.keys)) {
|
|
462
|
+
rawKeys = data.keys;
|
|
463
|
+
} else if (data && typeof data === "object" && typeof data.kty === "string") {
|
|
464
|
+
rawKeys = [data];
|
|
465
|
+
} else {
|
|
466
|
+
return { ok: false, error: 'Input must be a JWKS object with a "keys" array, or a single JWK object with a "kty" field' };
|
|
467
|
+
}
|
|
468
|
+
const keys = rawKeys.map((k) => {
|
|
469
|
+
const key = k ?? {};
|
|
470
|
+
const kty = typeof key.kty === "string" ? key.kty : "unknown";
|
|
471
|
+
let keySize = null;
|
|
472
|
+
let curve;
|
|
473
|
+
if (kty === "RSA" && typeof key.n === "string") {
|
|
474
|
+
keySize = base64urlByteLength(key.n) * 8;
|
|
475
|
+
} else if ((kty === "EC" || kty === "OKP") && typeof key.crv === "string") {
|
|
476
|
+
curve = key.crv;
|
|
477
|
+
} else if (kty === "oct" && typeof key.k === "string") {
|
|
478
|
+
keySize = base64urlByteLength(key.k) * 8;
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
kty,
|
|
482
|
+
use: typeof key.use === "string" ? key.use : void 0,
|
|
483
|
+
keyOps: Array.isArray(key.key_ops) ? key.key_ops.filter((x) => typeof x === "string") : void 0,
|
|
484
|
+
alg: typeof key.alg === "string" ? key.alg : void 0,
|
|
485
|
+
kid: typeof key.kid === "string" ? key.kid : void 0,
|
|
486
|
+
keySize,
|
|
487
|
+
curve,
|
|
488
|
+
raw: key
|
|
489
|
+
};
|
|
490
|
+
});
|
|
491
|
+
const kidCounts = /* @__PURE__ */ new Map();
|
|
492
|
+
for (const k of keys) if (k.kid) kidCounts.set(k.kid, (kidCounts.get(k.kid) ?? 0) + 1);
|
|
493
|
+
const duplicateKids = [...kidCounts.entries()].filter(([, c]) => c > 1).map(([kid]) => kid);
|
|
494
|
+
return { ok: true, keys, count: keys.length, duplicateKids };
|
|
495
|
+
}
|
|
447
496
|
var ALG_TO_NODE_HASH = {
|
|
448
497
|
HS256: "sha256",
|
|
449
498
|
HS384: "sha384",
|
|
@@ -1207,6 +1256,7 @@ exports.normalizeUrl = normalizeUrl;
|
|
|
1207
1256
|
exports.parseCspHeader = parseCspHeader;
|
|
1208
1257
|
exports.parseCurl = parseCurl;
|
|
1209
1258
|
exports.parseCurlCommand = parseCurlCommand;
|
|
1259
|
+
exports.parseJwks = parseJwks;
|
|
1210
1260
|
exports.parseMetaTags = parseMetaTags;
|
|
1211
1261
|
exports.parseUrl = parseUrl;
|
|
1212
1262
|
exports.removeParam = removeParam;
|
package/dist/tools/api.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as
|
|
1
|
+
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as JwksError, p as JwksParseResult, q as JwksResult, r as JwtAlgorithm, s as JwtDecodeError, t as JwtDecodeResult, u as JwtExpiry, v as JwtPart, w as JwtResult, x as JwtSignOptions, M as MetaTags, O as OgTags, P as ParsedUrl, R as ResponseFormat, S as SUPPORTED_LANGUAGES, T as TargetLanguage, y as TwitterTags, z as addParam, A as base64urlDecode, B as base64urlEncode, E as buildCurl, G as buildCurlMultiline, I as buildUrl, K as convertToCode, L as decodeJwt, N as decodeUrlComponent, Q as detectFormat, U as encodeUrlComponent, V as extractJsonPaths, W as formatJwtJson, X as formatResponse, Y as generateCors, Z as generateCspHeader, _ as generateFullHeader, $ as generateMetaHtml, a0 as getParam, a1 as getStats, a2 as isValidUrl, a3 as normalizeUrl, a4 as parseCspHeader, a5 as parseCurl, a6 as parseCurlCommand, a7 as parseJwks, a8 as parseMetaTags, a9 as parseUrl, aa as removeParam, ab as signJwt, ac as validateCorsConfig, ad as validateCspConfig, ae as validateOgTags } from '../api-Xl7OzIgq.cjs';
|
package/dist/tools/api.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as
|
|
1
|
+
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as JwksError, p as JwksParseResult, q as JwksResult, r as JwtAlgorithm, s as JwtDecodeError, t as JwtDecodeResult, u as JwtExpiry, v as JwtPart, w as JwtResult, x as JwtSignOptions, M as MetaTags, O as OgTags, P as ParsedUrl, R as ResponseFormat, S as SUPPORTED_LANGUAGES, T as TargetLanguage, y as TwitterTags, z as addParam, A as base64urlDecode, B as base64urlEncode, E as buildCurl, G as buildCurlMultiline, I as buildUrl, K as convertToCode, L as decodeJwt, N as decodeUrlComponent, Q as detectFormat, U as encodeUrlComponent, V as extractJsonPaths, W as formatJwtJson, X as formatResponse, Y as generateCors, Z as generateCspHeader, _ as generateFullHeader, $ as generateMetaHtml, a0 as getParam, a1 as getStats, a2 as isValidUrl, a3 as normalizeUrl, a4 as parseCspHeader, a5 as parseCurl, a6 as parseCurlCommand, a7 as parseJwks, a8 as parseMetaTags, a9 as parseUrl, aa as removeParam, ab as signJwt, ac as validateCorsConfig, ad as validateCspConfig, ae as validateOgTags } from '../api-Xl7OzIgq.js';
|
package/dist/tools/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags } from '../chunk-
|
|
1
|
+
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags } from '../chunk-Q3B3YWOA.js';
|
|
2
2
|
import '../chunk-MLKGABMK.js';
|
package/dist/tools/hashing.cjs
CHANGED
|
@@ -175,13 +175,7 @@ function generateMd5Hash(password) {
|
|
|
175
175
|
return "$apr1$" + md5__default.default(password);
|
|
176
176
|
}
|
|
177
177
|
function generateBcryptHash(password, rounds = 10) {
|
|
178
|
-
|
|
179
|
-
let salt = "";
|
|
180
|
-
for (let i = 0; i < 22; i++) salt += chars[Math.floor(Math.random() * chars.length)];
|
|
181
|
-
const roundStr = rounds.toString().padStart(2, "0");
|
|
182
|
-
let hash = "";
|
|
183
|
-
for (let i = 0; i < 31; i++) hash += chars[Math.floor(Math.random() * chars.length)];
|
|
184
|
-
return `$2b$${roundStr}$${salt}${hash}`;
|
|
178
|
+
return bcrypt__default.default.hashSync(password, rounds);
|
|
185
179
|
}
|
|
186
180
|
function generatePlain(password) {
|
|
187
181
|
return password;
|
|
@@ -190,7 +184,7 @@ function createEntry(username, password, algorithm = "bcrypt") {
|
|
|
190
184
|
let hashedPassword;
|
|
191
185
|
switch (algorithm) {
|
|
192
186
|
case "bcrypt":
|
|
193
|
-
hashedPassword = generateBcryptHash();
|
|
187
|
+
hashedPassword = generateBcryptHash(password);
|
|
194
188
|
break;
|
|
195
189
|
case "sha1":
|
|
196
190
|
hashedPassword = generateSha1Hash(password);
|
package/dist/tools/hashing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { HASH_ALGORITHMS, HASH_BITS, ROUND_OPTIONS, createEntry, generateBcryptHash, generateHtpasswdFile, generateMd5Hash, generatePlain, generateSha1Hash, hashAll, hashOne, hashPassword, hashWithTiming, parseHtpasswdFile, validateRounds, validateUsername, verifyPassword } from '../chunk-
|
|
1
|
+
export { HASH_ALGORITHMS, HASH_BITS, ROUND_OPTIONS, createEntry, generateBcryptHash, generateHtpasswdFile, generateMd5Hash, generatePlain, generateSha1Hash, hashAll, hashOne, hashPassword, hashWithTiming, parseHtpasswdFile, validateRounds, validateUsername, verifyPassword } from '../chunk-GEFVMGZR.js';
|
|
2
2
|
import '../chunk-MLKGABMK.js';
|
package/dist/tools/media.cjs
CHANGED
|
@@ -126,5 +126,338 @@ function readImageInfo(bytes) {
|
|
|
126
126
|
}
|
|
127
127
|
return { error: "Unrecognized image format. Supported formats: PNG, JPEG, GIF, WebP, BMP" };
|
|
128
128
|
}
|
|
129
|
+
var ORIENTATION_LABELS = {
|
|
130
|
+
1: "Normal",
|
|
131
|
+
2: "Mirrored horizontal",
|
|
132
|
+
3: "Rotated 180\xB0",
|
|
133
|
+
4: "Mirrored vertical",
|
|
134
|
+
5: "Mirrored horizontal, rotated 90\xB0 CCW",
|
|
135
|
+
6: "Rotated 90\xB0 CW",
|
|
136
|
+
7: "Mirrored horizontal, rotated 90\xB0 CW",
|
|
137
|
+
8: "Rotated 90\xB0 CCW"
|
|
138
|
+
};
|
|
139
|
+
function tu16(r, o) {
|
|
140
|
+
return r.view.getUint16(o, r.little);
|
|
141
|
+
}
|
|
142
|
+
function tu32(r, o) {
|
|
143
|
+
return r.view.getUint32(o, r.little);
|
|
144
|
+
}
|
|
145
|
+
function readIfdEntries(r, ifdOffset) {
|
|
146
|
+
if (ifdOffset < 0 || ifdOffset + 2 > r.bytes.length) return null;
|
|
147
|
+
const numEntries = tu16(r, ifdOffset);
|
|
148
|
+
const entries = [];
|
|
149
|
+
for (let i = 0; i < numEntries; i++) {
|
|
150
|
+
const entryOffset = ifdOffset + 2 + i * 12;
|
|
151
|
+
if (entryOffset + 12 > r.bytes.length) break;
|
|
152
|
+
entries.push({
|
|
153
|
+
tag: tu16(r, entryOffset),
|
|
154
|
+
type: tu16(r, entryOffset + 2),
|
|
155
|
+
count: tu32(r, entryOffset + 4),
|
|
156
|
+
valueOffsetField: entryOffset + 8
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return { entries };
|
|
160
|
+
}
|
|
161
|
+
function findEntry(entries, tag) {
|
|
162
|
+
return entries.find((e) => e.tag === tag);
|
|
163
|
+
}
|
|
164
|
+
function readAscii(r, entry) {
|
|
165
|
+
const size = entry.count;
|
|
166
|
+
const inline = size <= 4;
|
|
167
|
+
const dataOffset = inline ? entry.valueOffsetField : r.tiffStart + tu32(r, entry.valueOffsetField);
|
|
168
|
+
if (dataOffset < 0 || dataOffset + size > r.bytes.length) return null;
|
|
169
|
+
let out = "";
|
|
170
|
+
for (let i = 0; i < size; i++) {
|
|
171
|
+
const c = r.bytes[dataOffset + i];
|
|
172
|
+
if (c === 0) break;
|
|
173
|
+
out += String.fromCharCode(c);
|
|
174
|
+
}
|
|
175
|
+
const trimmed = out.trim();
|
|
176
|
+
return trimmed || null;
|
|
177
|
+
}
|
|
178
|
+
function readRational(r, entry) {
|
|
179
|
+
const dataOffset = r.tiffStart + tu32(r, entry.valueOffsetField);
|
|
180
|
+
if (dataOffset < 0 || dataOffset + 8 > r.bytes.length) return null;
|
|
181
|
+
return { num: tu32(r, dataOffset), den: tu32(r, dataOffset + 4) };
|
|
182
|
+
}
|
|
183
|
+
function readGpsCoordinate(r, entries, valueTag, refTag) {
|
|
184
|
+
const valueEntry = findEntry(entries, valueTag);
|
|
185
|
+
if (!valueEntry) return null;
|
|
186
|
+
const dataOffset = r.tiffStart + tu32(r, valueEntry.valueOffsetField);
|
|
187
|
+
if (dataOffset < 0 || dataOffset + 24 > r.bytes.length) return null;
|
|
188
|
+
const deg = tu32(r, dataOffset) / (tu32(r, dataOffset + 4) || 1);
|
|
189
|
+
const min = tu32(r, dataOffset + 8) / (tu32(r, dataOffset + 12) || 1);
|
|
190
|
+
const sec = tu32(r, dataOffset + 16) / (tu32(r, dataOffset + 20) || 1);
|
|
191
|
+
let decimal = deg + min / 60 + sec / 3600;
|
|
192
|
+
const refEntry = findEntry(entries, refTag);
|
|
193
|
+
const ref = refEntry ? readAscii(r, refEntry) : null;
|
|
194
|
+
if (ref === "S" || ref === "W") decimal = -decimal;
|
|
195
|
+
return Math.round(decimal * 1e6) / 1e6;
|
|
196
|
+
}
|
|
197
|
+
function gcd(a, b) {
|
|
198
|
+
return b === 0 ? a : gcd(b, a % b);
|
|
199
|
+
}
|
|
200
|
+
function round2(n) {
|
|
201
|
+
return Math.round(n * 100) / 100;
|
|
202
|
+
}
|
|
203
|
+
function formatExposureTime(num, den) {
|
|
204
|
+
if (num === 0) return "0s";
|
|
205
|
+
if (num >= den) return `${round2(num / den)}s`;
|
|
206
|
+
const divisor = gcd(num, den) || 1;
|
|
207
|
+
const n = num / divisor;
|
|
208
|
+
const d = den / divisor;
|
|
209
|
+
return `1/${Math.round(d / n)}`;
|
|
210
|
+
}
|
|
211
|
+
function readExifData(bytes) {
|
|
212
|
+
if (bytes.length < 4 || bytes[0] !== 255 || bytes[1] !== 216) {
|
|
213
|
+
return { error: "Not a JPEG file (EXIF is only read from JPEG files)" };
|
|
214
|
+
}
|
|
215
|
+
let offset = 2;
|
|
216
|
+
let exifStart = -1;
|
|
217
|
+
while (offset + 4 <= bytes.length) {
|
|
218
|
+
if (bytes[offset] !== 255) {
|
|
219
|
+
offset++;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const marker = bytes[offset + 1];
|
|
223
|
+
if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
|
|
224
|
+
offset += 2;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (marker === 217 || marker === 218) break;
|
|
228
|
+
const segmentLength = bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
229
|
+
if (marker === 225) {
|
|
230
|
+
const idOffset = offset + 4;
|
|
231
|
+
if (idOffset + 6 <= bytes.length && bytes[idOffset] === 69 && bytes[idOffset + 1] === 120 && bytes[idOffset + 2] === 105 && bytes[idOffset + 3] === 102 && bytes[idOffset + 4] === 0 && bytes[idOffset + 5] === 0) {
|
|
232
|
+
exifStart = idOffset + 6;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
offset += 2 + segmentLength;
|
|
237
|
+
}
|
|
238
|
+
if (exifStart === -1) return { error: "No EXIF segment found in this JPEG" };
|
|
239
|
+
if (exifStart + 8 > bytes.length) return { error: "Truncated EXIF segment" };
|
|
240
|
+
const byteOrder = String.fromCharCode(bytes[exifStart], bytes[exifStart + 1]);
|
|
241
|
+
if (byteOrder !== "II" && byteOrder !== "MM") return { error: "Invalid TIFF byte order marker in EXIF data" };
|
|
242
|
+
const little = byteOrder === "II";
|
|
243
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
244
|
+
const r = { bytes, view, little, tiffStart: exifStart };
|
|
245
|
+
if (tu16(r, exifStart + 2) !== 42) return { error: "Invalid TIFF magic number in EXIF data" };
|
|
246
|
+
const ifd0Offset = exifStart + tu32(r, exifStart + 4);
|
|
247
|
+
const ifd0 = readIfdEntries(r, ifd0Offset);
|
|
248
|
+
if (!ifd0) return { error: "Could not read IFD0 from EXIF data" };
|
|
249
|
+
const result = { tagCount: ifd0.entries.length };
|
|
250
|
+
const makeEntry = findEntry(ifd0.entries, 271);
|
|
251
|
+
if (makeEntry) {
|
|
252
|
+
const v = readAscii(r, makeEntry);
|
|
253
|
+
if (v) result.make = v;
|
|
254
|
+
}
|
|
255
|
+
const modelEntry = findEntry(ifd0.entries, 272);
|
|
256
|
+
if (modelEntry) {
|
|
257
|
+
const v = readAscii(r, modelEntry);
|
|
258
|
+
if (v) result.model = v;
|
|
259
|
+
}
|
|
260
|
+
const softwareEntry = findEntry(ifd0.entries, 305);
|
|
261
|
+
if (softwareEntry) {
|
|
262
|
+
const v = readAscii(r, softwareEntry);
|
|
263
|
+
if (v) result.software = v;
|
|
264
|
+
}
|
|
265
|
+
const dateTimeEntry = findEntry(ifd0.entries, 306);
|
|
266
|
+
if (dateTimeEntry) {
|
|
267
|
+
const v = readAscii(r, dateTimeEntry);
|
|
268
|
+
if (v) result.dateTime = v;
|
|
269
|
+
}
|
|
270
|
+
const orientEntry = findEntry(ifd0.entries, 274);
|
|
271
|
+
if (orientEntry) {
|
|
272
|
+
const v = tu16(r, orientEntry.valueOffsetField);
|
|
273
|
+
result.orientation = v;
|
|
274
|
+
result.orientationLabel = ORIENTATION_LABELS[v] ?? "Unknown";
|
|
275
|
+
}
|
|
276
|
+
const exifIfdPtr = findEntry(ifd0.entries, 34665);
|
|
277
|
+
if (exifIfdPtr) {
|
|
278
|
+
const subOffset = exifStart + tu32(r, exifIfdPtr.valueOffsetField);
|
|
279
|
+
const sub = readIfdEntries(r, subOffset);
|
|
280
|
+
if (sub) {
|
|
281
|
+
const dtoEntry = findEntry(sub.entries, 36867);
|
|
282
|
+
if (dtoEntry) {
|
|
283
|
+
const v = readAscii(r, dtoEntry);
|
|
284
|
+
if (v) result.dateTimeOriginal = v;
|
|
285
|
+
}
|
|
286
|
+
const expEntry = findEntry(sub.entries, 33434);
|
|
287
|
+
if (expEntry) {
|
|
288
|
+
const rat = readRational(r, expEntry);
|
|
289
|
+
if (rat && rat.den !== 0) result.exposureTime = formatExposureTime(rat.num, rat.den);
|
|
290
|
+
}
|
|
291
|
+
const fEntry = findEntry(sub.entries, 33437);
|
|
292
|
+
if (fEntry) {
|
|
293
|
+
const rat = readRational(r, fEntry);
|
|
294
|
+
if (rat && rat.den !== 0) result.fNumber = round2(rat.num / rat.den);
|
|
295
|
+
}
|
|
296
|
+
const isoEntry = findEntry(sub.entries, 34855);
|
|
297
|
+
if (isoEntry) result.isoSpeed = tu16(r, isoEntry.valueOffsetField);
|
|
298
|
+
const focalEntry = findEntry(sub.entries, 37386);
|
|
299
|
+
if (focalEntry) {
|
|
300
|
+
const rat = readRational(r, focalEntry);
|
|
301
|
+
if (rat && rat.den !== 0) result.focalLength = round2(rat.num / rat.den);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const gpsIfdPtr = findEntry(ifd0.entries, 34853);
|
|
306
|
+
if (gpsIfdPtr) {
|
|
307
|
+
const gpsOffset = exifStart + tu32(r, gpsIfdPtr.valueOffsetField);
|
|
308
|
+
const gps = readIfdEntries(r, gpsOffset);
|
|
309
|
+
if (gps) {
|
|
310
|
+
const lat = readGpsCoordinate(r, gps.entries, 2, 1);
|
|
311
|
+
const lon = readGpsCoordinate(r, gps.entries, 4, 3);
|
|
312
|
+
if (lat !== null) result.gpsLatitude = lat;
|
|
313
|
+
if (lon !== null) result.gpsLongitude = lon;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
function bytesToLatin1(bytes) {
|
|
319
|
+
let out = "";
|
|
320
|
+
const CHUNK = 32768;
|
|
321
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
322
|
+
out += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
323
|
+
}
|
|
324
|
+
return out;
|
|
325
|
+
}
|
|
326
|
+
function decodePdfString(raw, isHex) {
|
|
327
|
+
const bytes = [];
|
|
328
|
+
if (isHex) {
|
|
329
|
+
const hex = raw.replace(/\s+/g, "");
|
|
330
|
+
const padded = hex.length % 2 === 0 ? hex : hex + "0";
|
|
331
|
+
for (let i = 0; i < padded.length; i += 2) bytes.push(parseInt(padded.slice(i, i + 2), 16));
|
|
332
|
+
} else {
|
|
333
|
+
const s = raw.replace(/\\\r\n|\\\r|\\\n/g, "");
|
|
334
|
+
for (let i = 0; i < s.length; i++) {
|
|
335
|
+
const ch = s[i];
|
|
336
|
+
if (ch === "\\" && i + 1 < s.length) {
|
|
337
|
+
const next = s[i + 1];
|
|
338
|
+
if (next === "n") {
|
|
339
|
+
bytes.push(10);
|
|
340
|
+
i++;
|
|
341
|
+
} else if (next === "r") {
|
|
342
|
+
bytes.push(13);
|
|
343
|
+
i++;
|
|
344
|
+
} else if (next === "t") {
|
|
345
|
+
bytes.push(9);
|
|
346
|
+
i++;
|
|
347
|
+
} else if (next === "b") {
|
|
348
|
+
bytes.push(8);
|
|
349
|
+
i++;
|
|
350
|
+
} else if (next === "f") {
|
|
351
|
+
bytes.push(12);
|
|
352
|
+
i++;
|
|
353
|
+
} else if (next === "(" || next === ")" || next === "\\") {
|
|
354
|
+
bytes.push(next.charCodeAt(0));
|
|
355
|
+
i++;
|
|
356
|
+
} else if (/[0-7]/.test(next)) {
|
|
357
|
+
let oct = next;
|
|
358
|
+
i++;
|
|
359
|
+
for (let k = 0; k < 2 && i + 1 < s.length && /[0-7]/.test(s[i + 1]); k++) {
|
|
360
|
+
i++;
|
|
361
|
+
oct += s[i];
|
|
362
|
+
}
|
|
363
|
+
bytes.push(parseInt(oct, 8) & 255);
|
|
364
|
+
} else {
|
|
365
|
+
bytes.push(next.charCodeAt(0));
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
bytes.push(ch.charCodeAt(0) & 255);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (bytes.length >= 2 && bytes[0] === 254 && bytes[1] === 255) {
|
|
374
|
+
let out = "";
|
|
375
|
+
for (let i = 2; i + 1 < bytes.length; i += 2) out += String.fromCharCode(bytes[i] << 8 | bytes[i + 1]);
|
|
376
|
+
return out;
|
|
377
|
+
}
|
|
378
|
+
return bytes.map((b) => String.fromCharCode(b)).join("");
|
|
379
|
+
}
|
|
380
|
+
function extractDictField(dict, key) {
|
|
381
|
+
const litMatch = dict.match(new RegExp(`/${key}\\s*\\(((?:\\\\.|[^\\\\()])*)\\)`));
|
|
382
|
+
if (litMatch) return decodePdfString(litMatch[1], false);
|
|
383
|
+
const hexMatch = dict.match(new RegExp(`/${key}\\s*<([0-9A-Fa-f\\s]*)>`));
|
|
384
|
+
if (hexMatch) return decodePdfString(hexMatch[1], true);
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
function findObject(text, objNum, gen) {
|
|
388
|
+
const m = text.match(new RegExp(`(?:^|[^0-9])${objNum}\\s+${gen}\\s+obj([\\s\\S]*?)endobj`));
|
|
389
|
+
return m ? m[1] : null;
|
|
390
|
+
}
|
|
391
|
+
function parsePdfDate(raw) {
|
|
392
|
+
const m = raw.match(/^D:(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([Z+-])?(\d{2})?'?(\d{2})?'?/);
|
|
393
|
+
if (!m) return null;
|
|
394
|
+
const [, y, mo = "01", d = "01", h = "00", mi = "00", s = "00", tz, tzh, tzm] = m;
|
|
395
|
+
let iso = `${y}-${mo}-${d}T${h}:${mi}:${s}`;
|
|
396
|
+
if (tz === "Z") iso += "Z";
|
|
397
|
+
else if (tz === "+" || tz === "-") iso += `${tz}${tzh ?? "00"}:${tzm ?? "00"}`;
|
|
398
|
+
return iso;
|
|
399
|
+
}
|
|
400
|
+
function readPdfMetadata(bytes) {
|
|
401
|
+
if (bytes.length < 8) return { error: "File too small to be a PDF" };
|
|
402
|
+
const header = bytesToLatin1(bytes.subarray(0, 16));
|
|
403
|
+
const versionMatch = header.match(/%PDF-(\d\.\d)/);
|
|
404
|
+
if (!versionMatch) return { error: "Not a valid PDF file (missing %PDF header)" };
|
|
405
|
+
const version = versionMatch[1];
|
|
406
|
+
const text = bytesToLatin1(bytes);
|
|
407
|
+
const trailerMatches = [...text.matchAll(/trailer\s*<<([\s\S]*?)>>/g)];
|
|
408
|
+
let infoDict = null;
|
|
409
|
+
let encrypted = false;
|
|
410
|
+
if (trailerMatches.length > 0) {
|
|
411
|
+
const trailer = trailerMatches[trailerMatches.length - 1][1];
|
|
412
|
+
encrypted = /\/Encrypt\s+\d+\s+\d+\s+R/.test(trailer);
|
|
413
|
+
const infoRef = trailer.match(/\/Info\s+(\d+)\s+(\d+)\s+R/);
|
|
414
|
+
if (infoRef) infoDict = findObject(text, Number(infoRef[1]), Number(infoRef[2]));
|
|
415
|
+
}
|
|
416
|
+
const objBlocks = [...text.matchAll(/(\d+)\s+(\d+)\s+obj([\s\S]*?)endobj/g)];
|
|
417
|
+
if (!infoDict) {
|
|
418
|
+
for (const b of objBlocks) {
|
|
419
|
+
if (/\/(Title|Author|Producer|Creator|CreationDate)\b/.test(b[3]) && !/\/Type\s*\/(Page|Pages|Catalog|Font)\b/.test(b[3])) {
|
|
420
|
+
infoDict = b[3];
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const title = infoDict ? extractDictField(infoDict, "Title") : null;
|
|
426
|
+
const author = infoDict ? extractDictField(infoDict, "Author") : null;
|
|
427
|
+
const subject = infoDict ? extractDictField(infoDict, "Subject") : null;
|
|
428
|
+
const keywords = infoDict ? extractDictField(infoDict, "Keywords") : null;
|
|
429
|
+
const creator = infoDict ? extractDictField(infoDict, "Creator") : null;
|
|
430
|
+
const producer = infoDict ? extractDictField(infoDict, "Producer") : null;
|
|
431
|
+
const creationDateRaw = infoDict ? extractDictField(infoDict, "CreationDate") : null;
|
|
432
|
+
const modDateRaw = infoDict ? extractDictField(infoDict, "ModDate") : null;
|
|
433
|
+
let pageCount = null;
|
|
434
|
+
for (const b of objBlocks) {
|
|
435
|
+
if (!/\/Type\s*\/Pages\b/.test(b[3])) continue;
|
|
436
|
+
const countMatch = b[3].match(/\/Count\s+(\d+)/);
|
|
437
|
+
if (countMatch) {
|
|
438
|
+
const c = Number(countMatch[1]);
|
|
439
|
+
if (pageCount === null || c > pageCount) pageCount = c;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (pageCount === null) {
|
|
443
|
+
const pageMatches = text.match(/\/Type\s*\/Page(?!s)\b/g);
|
|
444
|
+
if (pageMatches) pageCount = pageMatches.length;
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
version,
|
|
448
|
+
pageCount,
|
|
449
|
+
title,
|
|
450
|
+
author,
|
|
451
|
+
subject,
|
|
452
|
+
keywords,
|
|
453
|
+
creator,
|
|
454
|
+
producer,
|
|
455
|
+
creationDate: creationDateRaw ? parsePdfDate(creationDateRaw) ?? creationDateRaw : null,
|
|
456
|
+
modDate: modDateRaw ? parsePdfDate(modDateRaw) ?? modDateRaw : null,
|
|
457
|
+
encrypted
|
|
458
|
+
};
|
|
459
|
+
}
|
|
129
460
|
|
|
461
|
+
exports.readExifData = readExifData;
|
|
130
462
|
exports.readImageInfo = readImageInfo;
|
|
463
|
+
exports.readPdfMetadata = readPdfMetadata;
|
package/dist/tools/media.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { I as ImageFormat,
|
|
1
|
+
export { E as ExifData, a as ExifError, I as ImageFormat, b as ImageInfo, c as ImageInfoError, P as PdfMetadata, d as PdfMetadataError, r as readExifData, e as readImageInfo, f as readPdfMetadata } from '../media-CHaBS1dI.cjs';
|
package/dist/tools/media.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { I as ImageFormat,
|
|
1
|
+
export { E as ExifData, a as ExifError, I as ImageFormat, b as ImageInfo, c as ImageInfoError, P as PdfMetadata, d as PdfMetadataError, r as readExifData, e as readImageInfo, f as readPdfMetadata } from '../media-CHaBS1dI.js';
|
package/dist/tools/media.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { readImageInfo } from '../chunk-
|
|
1
|
+
export { readExifData, readImageInfo, readPdfMetadata } from '../chunk-FXBB7O5A.js';
|
|
2
2
|
import '../chunk-MLKGABMK.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilix-tech/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "140+ developer utility tools for Node.js: JSON, encoding, hashing, color, CSS, network and more. Runs locally, no API key required.",
|
|
5
5
|
"author": "Utilix <hello@utilix.tech>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"prepublishOnly": "npm run build && npm test"
|
|
139
139
|
},
|
|
140
140
|
"devDependencies": {
|
|
141
|
-
"@types/bcryptjs": "^
|
|
141
|
+
"@types/bcryptjs": "^3.0.0",
|
|
142
142
|
"@types/blueimp-md5": "^2.18.2",
|
|
143
143
|
"@types/js-yaml": "^4.0.9",
|
|
144
144
|
"@types/node": "^20.0.0",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
"vitest": "^2.0.0"
|
|
149
149
|
},
|
|
150
150
|
"dependencies": {
|
|
151
|
-
"bcryptjs": "^
|
|
151
|
+
"bcryptjs": "^3.0.3",
|
|
152
152
|
"blueimp-md5": "^2.19.0",
|
|
153
153
|
"cron-parser": "^4.9.0",
|
|
154
154
|
"date-fns": "^3.6.0",
|
package/dist/chunk-N7C52YGL.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { __export } from './chunk-MLKGABMK.js';
|
|
2
|
-
|
|
3
|
-
// src/tools/media.ts
|
|
4
|
-
var media_exports = {};
|
|
5
|
-
__export(media_exports, {
|
|
6
|
-
readImageInfo: () => readImageInfo
|
|
7
|
-
});
|
|
8
|
-
function readU32BE(bytes, offset) {
|
|
9
|
-
return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
10
|
-
}
|
|
11
|
-
function readI32LE(bytes, offset) {
|
|
12
|
-
return bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24;
|
|
13
|
-
}
|
|
14
|
-
var PNG_COLOR_TYPES = {
|
|
15
|
-
0: "grayscale",
|
|
16
|
-
2: "rgb",
|
|
17
|
-
3: "palette",
|
|
18
|
-
4: "grayscale+alpha",
|
|
19
|
-
6: "rgba"
|
|
20
|
-
};
|
|
21
|
-
function readPng(bytes) {
|
|
22
|
-
if (bytes.length < 33) return { error: "Truncated PNG file" };
|
|
23
|
-
const width = readU32BE(bytes, 16);
|
|
24
|
-
const height = readU32BE(bytes, 20);
|
|
25
|
-
const bitDepth = bytes[24];
|
|
26
|
-
const colorTypeNum = bytes[25];
|
|
27
|
-
const colorType = PNG_COLOR_TYPES[colorTypeNum] ?? "unknown";
|
|
28
|
-
const hasAlpha = colorTypeNum === 4 || colorTypeNum === 6;
|
|
29
|
-
return { format: "png", width, height, bitDepth, colorType, hasAlpha };
|
|
30
|
-
}
|
|
31
|
-
function readGif(bytes) {
|
|
32
|
-
if (bytes.length < 10) return { error: "Truncated GIF file" };
|
|
33
|
-
const width = bytes[6] | bytes[7] << 8;
|
|
34
|
-
const height = bytes[8] | bytes[9] << 8;
|
|
35
|
-
return { format: "gif", width, height };
|
|
36
|
-
}
|
|
37
|
-
function readBmp(bytes) {
|
|
38
|
-
if (bytes.length < 30) return { error: "Truncated BMP file" };
|
|
39
|
-
const width = readI32LE(bytes, 18);
|
|
40
|
-
const heightRaw = readI32LE(bytes, 22);
|
|
41
|
-
const bitDepth = bytes[28] | bytes[29] << 8;
|
|
42
|
-
return { format: "bmp", width: Math.abs(width), height: Math.abs(heightRaw), bitDepth };
|
|
43
|
-
}
|
|
44
|
-
function readWebp(bytes) {
|
|
45
|
-
if (bytes.length < 16) return { error: "Truncated WebP file" };
|
|
46
|
-
const fourCC = String.fromCharCode(bytes[12], bytes[13], bytes[14], bytes[15]);
|
|
47
|
-
if (fourCC === "VP8 ") {
|
|
48
|
-
if (bytes.length < 30) return { error: "Truncated WebP file" };
|
|
49
|
-
const width = (bytes[26] | bytes[27] << 8) & 16383;
|
|
50
|
-
const height = (bytes[28] | bytes[29] << 8) & 16383;
|
|
51
|
-
return { format: "webp", width, height };
|
|
52
|
-
}
|
|
53
|
-
if (fourCC === "VP8L") {
|
|
54
|
-
if (bytes.length < 25) return { error: "Truncated WebP file" };
|
|
55
|
-
const bits = bytes[21] | bytes[22] << 8 | bytes[23] << 16 | bytes[24] << 24;
|
|
56
|
-
const width = (bits & 16383) + 1;
|
|
57
|
-
const height = (bits >>> 14 & 16383) + 1;
|
|
58
|
-
const hasAlpha = !!(bits >>> 28 & 1);
|
|
59
|
-
return { format: "webp", width, height, hasAlpha };
|
|
60
|
-
}
|
|
61
|
-
if (fourCC === "VP8X") {
|
|
62
|
-
if (bytes.length < 30) return { error: "Truncated WebP file" };
|
|
63
|
-
const flags = bytes[20];
|
|
64
|
-
const hasAlpha = !!(flags & 16);
|
|
65
|
-
const width = (bytes[24] | bytes[25] << 8 | bytes[26] << 16) + 1;
|
|
66
|
-
const height = (bytes[27] | bytes[28] << 8 | bytes[29] << 16) + 1;
|
|
67
|
-
return { format: "webp", width, height, hasAlpha };
|
|
68
|
-
}
|
|
69
|
-
return { error: "Unrecognized WebP chunk format" };
|
|
70
|
-
}
|
|
71
|
-
var JPEG_SOF_MARKERS = /* @__PURE__ */ new Set([
|
|
72
|
-
192,
|
|
73
|
-
193,
|
|
74
|
-
194,
|
|
75
|
-
195,
|
|
76
|
-
197,
|
|
77
|
-
198,
|
|
78
|
-
199,
|
|
79
|
-
201,
|
|
80
|
-
202,
|
|
81
|
-
203,
|
|
82
|
-
205,
|
|
83
|
-
206,
|
|
84
|
-
207
|
|
85
|
-
]);
|
|
86
|
-
function readJpeg(bytes) {
|
|
87
|
-
let offset = 2;
|
|
88
|
-
while (offset < bytes.length - 1) {
|
|
89
|
-
if (bytes[offset] !== 255) {
|
|
90
|
-
offset++;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
const marker = bytes[offset + 1];
|
|
94
|
-
if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
|
|
95
|
-
offset += 2;
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
if (marker === 217) break;
|
|
99
|
-
if (offset + 3 >= bytes.length) break;
|
|
100
|
-
const segmentLength = bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
101
|
-
if (JPEG_SOF_MARKERS.has(marker)) {
|
|
102
|
-
if (offset + 9 >= bytes.length) return { error: "Truncated JPEG SOF segment" };
|
|
103
|
-
const bitDepth = bytes[offset + 4];
|
|
104
|
-
const height = bytes[offset + 5] << 8 | bytes[offset + 6];
|
|
105
|
-
const width = bytes[offset + 7] << 8 | bytes[offset + 8];
|
|
106
|
-
const components = bytes[offset + 9];
|
|
107
|
-
const colorType = components === 1 ? "grayscale" : components === 3 ? "rgb" : components === 4 ? "cmyk" : "unknown";
|
|
108
|
-
return { format: "jpeg", width, height, bitDepth, colorType };
|
|
109
|
-
}
|
|
110
|
-
offset += 2 + segmentLength;
|
|
111
|
-
}
|
|
112
|
-
return { error: "No SOF marker found in JPEG (file may be corrupt)" };
|
|
113
|
-
}
|
|
114
|
-
function readImageInfo(bytes) {
|
|
115
|
-
if (bytes.length < 10) return { error: "File too small to determine format" };
|
|
116
|
-
if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) {
|
|
117
|
-
return readPng(bytes);
|
|
118
|
-
}
|
|
119
|
-
if (bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) {
|
|
120
|
-
return readGif(bytes);
|
|
121
|
-
}
|
|
122
|
-
if (bytes[0] === 66 && bytes[1] === 77) {
|
|
123
|
-
return readBmp(bytes);
|
|
124
|
-
}
|
|
125
|
-
if (bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
|
|
126
|
-
return readWebp(bytes);
|
|
127
|
-
}
|
|
128
|
-
if (bytes[0] === 255 && bytes[1] === 216) {
|
|
129
|
-
return readJpeg(bytes);
|
|
130
|
-
}
|
|
131
|
-
return { error: "Unrecognized image format. Supported formats: PNG, JPEG, GIF, WebP, BMP" };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export { media_exports, readImageInfo };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
type ImageFormat = 'png' | 'jpeg' | 'gif' | 'webp' | 'bmp';
|
|
2
|
-
interface ImageInfo {
|
|
3
|
-
format: ImageFormat;
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
bitDepth?: number;
|
|
7
|
-
colorType?: string;
|
|
8
|
-
hasAlpha?: boolean;
|
|
9
|
-
}
|
|
10
|
-
interface ImageInfoError {
|
|
11
|
-
error: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Read image format, dimensions, and basic color info straight from file
|
|
15
|
-
* bytes — no decoding, no image library, no canvas. Supports PNG, JPEG,
|
|
16
|
-
* GIF, WebP, and BMP.
|
|
17
|
-
*/
|
|
18
|
-
declare function readImageInfo(bytes: Uint8Array): ImageInfo | ImageInfoError;
|
|
19
|
-
|
|
20
|
-
type media_ImageFormat = ImageFormat;
|
|
21
|
-
type media_ImageInfo = ImageInfo;
|
|
22
|
-
type media_ImageInfoError = ImageInfoError;
|
|
23
|
-
declare const media_readImageInfo: typeof readImageInfo;
|
|
24
|
-
declare namespace media {
|
|
25
|
-
export { type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, media_readImageInfo as readImageInfo };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { type ImageFormat as I, type ImageInfo as a, type ImageInfoError as b, media as m, readImageInfo as r };
|