Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

24
Frontend-Learner/node_modules/image-meta/LICENSE generated vendored Normal file
View file

@ -0,0 +1,24 @@
The MIT License (MIT)
Copyright (c) Pooya Parsa <pooya@pi0.io>
Based on https://github.com/image-size/image-size
Copyright © Aditya Yadav, http://netroy.in
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

64
Frontend-Learner/node_modules/image-meta/README.md generated vendored Normal file
View file

@ -0,0 +1,64 @@
# image-meta
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![bundle][bundle-src]][bundle-href]
[![Codecov][codecov-src]][codecov-href]
Detect image type and size using pure javascript.
## Usage
Install package:
```sh
# npm
npm install image-meta
# yarn
yarn add image-meta
# pnpm
pnpm install image-meta
# bun
bun install image-meta
```
```ts
import { imageMeta } from "image-meta";
const data = await fetch(url).then((res) => res.buffer());
// Meta contains { type, width?, height?, orientation? }
const meta = imageMeta(data);
```
**Note:** `imageMeta` throws an error if either data is not a `Buffer`/`Uint8Array`, or data is invalid or type cannot be determined. You should wrap it into a `try/catch` statement to handle errors.
## Development
- Clone this repository
- Install the latest LTS version of [Node.js](https://nodejs.org/en/)
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`
## License
Made with 💛
🔀 Based on [image-size](https://github.com/image-size/image-size) by [Aditya Yadav](https://github.com/netroy) and [contributors](https://github.com/image-size/image-size/graphs/contributors).
Published under [MIT License](./LICENSE).
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/image-meta?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/image-meta
[npm-downloads-src]: https://img.shields.io/npm/dm/image-meta?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/image-meta
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/image-meta/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/image-meta
[bundle-src]: https://img.shields.io/bundlephobia/minzip/image-meta?style=flat&colorA=18181B&colorB=F0DB4F
[bundle-href]: https://bundlephobia.com/result?p=image-meta

868
Frontend-Learner/node_modules/image-meta/dist/index.cjs generated vendored Normal file
View file

@ -0,0 +1,868 @@
'use strict';
const decoder = new TextDecoder();
const toUTF8String = (input, start = 0, end = input.length) => decoder.decode(input.slice(start, end));
const toHexString = (input, start = 0, end = input.length) => input.slice(start, end).reduce((memo, i) => memo + ("0" + i.toString(16)).slice(-2), "");
const readInt16LE = (input, offset = 0) => {
const val = input[offset] + input[offset + 1] * 2 ** 8;
return val | (val & 2 ** 15) * 131070;
};
const readUInt16BE = (input, offset = 0) => input[offset] * 2 ** 8 + input[offset + 1];
const readUInt16LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8;
const readUInt24LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16;
const readInt32LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16 + (input[offset + 3] << 24);
const readUInt32BE = (input, offset = 0) => input[offset] * 2 ** 24 + input[offset + 1] * 2 ** 16 + input[offset + 2] * 2 ** 8 + input[offset + 3];
const readUInt32LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16 + input[offset + 3] * 2 ** 24;
const methods = {
readUInt16BE,
readUInt16LE,
readUInt32BE,
readUInt32LE
};
function readUInt(input, bits, offset, isBigEndian) {
offset = offset || 0;
const endian = isBigEndian ? "BE" : "LE";
const methodName = "readUInt" + bits + endian;
return methods[methodName](input, offset);
}
const BMP = {
validate: (input) => toUTF8String(input, 0, 2) === "BM",
calculate: (input) => ({
height: Math.abs(readInt32LE(input, 22)),
width: readUInt32LE(input, 18)
})
};
const TYPE_ICON = 1;
const SIZE_HEADER$1 = 2 + 2 + 2;
const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4;
function getSizeFromOffset(input, offset) {
const value = input[offset];
return value === 0 ? 256 : value;
}
function getImageSize$1(input, imageIndex) {
const offset = SIZE_HEADER$1 + imageIndex * SIZE_IMAGE_ENTRY;
return {
height: getSizeFromOffset(input, offset + 1),
width: getSizeFromOffset(input, offset)
};
}
const ICO = {
validate(input) {
const reserved = readUInt16LE(input, 0);
const imageCount = readUInt16LE(input, 4);
if (reserved !== 0 || imageCount === 0) {
return false;
}
const imageType = readUInt16LE(input, 2);
return imageType === TYPE_ICON;
},
calculate(input) {
const nbImages = readUInt16LE(input, 4);
const imageSize = getImageSize$1(input, 0);
if (nbImages === 1) {
return imageSize;
}
const imgs = [imageSize];
for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) {
imgs.push(getImageSize$1(input, imageIndex));
}
return {
height: imageSize.height,
images: imgs,
width: imageSize.width
};
}
};
const TYPE_CURSOR = 2;
const CUR = {
validate(input) {
const reserved = readUInt16LE(input, 0);
const imageCount = readUInt16LE(input, 4);
if (reserved !== 0 || imageCount === 0) {
return false;
}
const imageType = readUInt16LE(input, 2);
return imageType === TYPE_CURSOR;
},
calculate: (input) => ICO.calculate(input)
};
const DDS = {
validate: (input) => readUInt32LE(input, 0) === 542327876,
calculate: (input) => ({
height: readUInt32LE(input, 12),
width: readUInt32LE(input, 16)
})
};
const gifRegexp = /^GIF8[79]a/;
const GIF = {
validate: (input) => gifRegexp.test(toUTF8String(input, 0, 6)),
calculate: (input) => ({
height: readUInt16LE(input, 8),
width: readUInt16LE(input, 6)
})
};
const HEIC = {
validate: (input) => {
const ftypBox = findBox$1(input, "ftyp");
if (!ftypBox) return false;
const majorBrand = toUTF8String(
input,
ftypBox.offset + 8,
ftypBox.offset + 12
);
return ["heic", "heix", "hevc", "hevx", "mif1", "msf1"].includes(
majorBrand
);
},
calculate: (input) => {
const metaBox = findBox$1(input, "meta");
if (!metaBox) throw new TypeError("heic: meta box not found");
const iprpBox = findBox$1(
input,
"iprp",
metaBox.offset + 12,
metaBox.offset + metaBox.size
);
if (!iprpBox) throw new TypeError("heic: iprp box not found");
const ipcoBox = findBox$1(
input,
"ipco",
iprpBox.offset + 8,
iprpBox.offset + iprpBox.size
);
if (!ipcoBox) throw new TypeError("heic: ipco box not found");
const dimensions = findAllBoxes(
input,
"ispe",
ipcoBox.offset + 8,
ipcoBox.offset + ipcoBox.size
).map((box) => ({
width: readUInt32BE(input, box.offset + 12),
height: readUInt32BE(input, box.offset + 16)
}));
if (dimensions.length === 0)
throw new TypeError("heic: ispe box not found");
let largestDimension = dimensions[0];
for (let i = 1; i < dimensions.length; i++) {
const curr = dimensions[i];
if (curr.width * curr.height > largestDimension.width * largestDimension.height) {
largestDimension = curr;
}
}
return largestDimension;
}
};
function findBox$1(input, type, startOffset = 0, endOffset = input.length) {
let offset = startOffset;
while (offset < endOffset) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
return { offset, size };
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
return void 0;
}
function findAllBoxes(input, type, startOffset = 0, endOffset = input.length) {
let offset = startOffset;
const boxes = [];
while (offset < endOffset) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
boxes.push({ offset, size });
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
return boxes;
}
const SIZE_HEADER = 4 + 4;
const FILE_LENGTH_OFFSET = 4;
const ENTRY_LENGTH_OFFSET = 4;
const ICON_TYPE_SIZE = {
ICON: 32,
"ICN#": 32,
// m => 16 x 16
"icm#": 16,
icm4: 16,
icm8: 16,
// s => 16 x 16
"ics#": 16,
ics4: 16,
ics8: 16,
is32: 16,
s8mk: 16,
icp4: 16,
// l => 32 x 32
icl4: 32,
icl8: 32,
il32: 32,
l8mk: 32,
icp5: 32,
ic11: 32,
// h => 48 x 48
ich4: 48,
ich8: 48,
ih32: 48,
h8mk: 48,
// . => 64 x 64
icp6: 64,
ic12: 32,
// t => 128 x 128
it32: 128,
t8mk: 128,
ic07: 128,
// . => 256 x 256
ic08: 256,
ic13: 256,
// . => 512 x 512
ic09: 512,
ic14: 512,
// . => 1024 x 1024
ic10: 1024
};
function readImageHeader(input, imageOffset) {
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET;
return [
toUTF8String(input, imageOffset, imageLengthOffset),
readUInt32BE(input, imageLengthOffset)
];
}
function getImageSize(type) {
const size = ICON_TYPE_SIZE[type];
return { width: size, height: size, type };
}
const ICNS = {
validate: (input) => toUTF8String(input, 0, 4) === "icns",
calculate(input) {
const inputLength = input.length;
const fileLength = readUInt32BE(input, FILE_LENGTH_OFFSET);
let imageOffset = SIZE_HEADER;
let imageHeader = readImageHeader(input, imageOffset);
let imageSize = getImageSize(imageHeader[0]);
imageOffset += imageHeader[1];
if (imageOffset === fileLength) {
return imageSize;
}
const result = {
height: imageSize.height,
images: [imageSize],
width: imageSize.width
};
while (imageOffset < fileLength && imageOffset < inputLength) {
imageHeader = readImageHeader(input, imageOffset);
imageSize = getImageSize(imageHeader[0]);
imageOffset += imageHeader[1];
result.images.push(imageSize);
}
return result;
}
};
const J2C = {
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
validate: (input) => toHexString(input, 0, 4) === "ff4fff51",
calculate: (input) => ({
height: readUInt32BE(input, 12),
width: readUInt32BE(input, 8)
})
};
const BoxTypes = {
ftyp: "66747970",
jp2h: "6a703268",
jp__: "6a502020",
rreq: "72726571"};
const calculateRREQLength = (box) => {
const unit = box[0];
let offset = 1 + 2 * unit;
const numStdFlags = readUInt16BE(box, offset);
const flagsLength = numStdFlags * (2 + unit);
offset = offset + 2 + flagsLength;
const numVendorFeatures = readUInt16BE(box, offset);
const featuresLength = numVendorFeatures * (16 + unit);
return offset + 2 + featuresLength;
};
const parseIHDR = (box) => {
return {
height: readUInt32BE(box, 4),
width: readUInt32BE(box, 8)
};
};
const JP2 = {
validate(input) {
const signature = toHexString(input, 4, 8);
const signatureLength = readUInt32BE(input, 0);
if (signature !== BoxTypes.jp__ || signatureLength < 1) {
return false;
}
const ftypeBoxStart = signatureLength + 4;
const ftypBoxLength = readUInt32BE(input, signatureLength);
const ftypBox = input.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength);
return toHexString(ftypBox, 0, 4) === BoxTypes.ftyp;
},
calculate(input) {
const signatureLength = readUInt32BE(input, 0);
const ftypBoxLength = readUInt16BE(input, signatureLength + 2);
let offset = signatureLength + 4 + ftypBoxLength;
const nextBoxType = toHexString(input, offset, offset + 4);
switch (nextBoxType) {
case BoxTypes.rreq: {
const MAGIC = 4;
offset = offset + 4 + MAGIC + calculateRREQLength(input.slice(offset + 4));
return parseIHDR(input.slice(offset + 8, offset + 24));
}
case BoxTypes.jp2h: {
return parseIHDR(input.slice(offset + 8, offset + 24));
}
default: {
throw new TypeError(
"Unsupported header found: " + toUTF8String(input, offset, offset + 4)
);
}
}
}
};
const EXIF_MARKER = "45786966";
const APP1_DATA_SIZE_BYTES = 2;
const EXIF_HEADER_BYTES = 6;
const TIFF_BYTE_ALIGN_BYTES = 2;
const BIG_ENDIAN_BYTE_ALIGN = "4d4d";
const LITTLE_ENDIAN_BYTE_ALIGN = "4949";
const IDF_ENTRY_BYTES = 12;
const NUM_DIRECTORY_ENTRIES_BYTES = 2;
function isEXIF(input) {
return toHexString(input, 2, 6) === EXIF_MARKER;
}
function extractSize(input, index) {
return {
height: readUInt16BE(input, index),
width: readUInt16BE(input, index + 2)
};
}
function extractOrientation(exifBlock, isBigEndian) {
const idfOffset = 8;
const offset = EXIF_HEADER_BYTES + idfOffset;
const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian);
for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) {
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + directoryEntryNumber * IDF_ENTRY_BYTES;
const end = start + IDF_ENTRY_BYTES;
if (start > exifBlock.length) {
return;
}
const block = exifBlock.slice(start, end);
const tagNumber = readUInt(block, 16, 0, isBigEndian);
if (tagNumber === 274) {
const dataFormat = readUInt(block, 16, 2, isBigEndian);
if (dataFormat !== 3) {
return;
}
const numberOfComponents = readUInt(block, 32, 4, isBigEndian);
if (numberOfComponents !== 1) {
return;
}
return readUInt(block, 16, 8, isBigEndian);
}
}
}
function validateExifBlock(input, index) {
const exifBlock = input.slice(APP1_DATA_SIZE_BYTES, index);
const byteAlign = toHexString(
exifBlock,
EXIF_HEADER_BYTES,
EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES
);
const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN;
const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN;
if (isBigEndian || isLittleEndian) {
return extractOrientation(exifBlock, isBigEndian);
}
}
function validateInput(input, index) {
if (index > input.length) {
throw new TypeError("Corrupt JPG, exceeded buffer limits");
}
if (input[index] !== 255) {
throw new TypeError("Invalid JPG, marker table corrupted");
}
}
const JPG = {
validate: (input) => toHexString(input, 0, 2) === "ffd8",
calculate(input) {
input = input.slice(4);
let orientation;
let next;
while (input.length > 0) {
const i = readUInt16BE(input, 0);
if (isEXIF(input)) {
orientation = validateExifBlock(input, i);
}
validateInput(input, i);
next = input[i + 1];
if (next === 192 || next === 193 || next === 194) {
const size = extractSize(input, i + 5);
if (!orientation) {
return size;
}
return {
height: size.height,
orientation,
width: size.width
};
}
input = input.slice(i + 2);
}
throw new TypeError("Invalid JPG, no size found");
}
};
const KTX = {
validate: (input) => toUTF8String(input, 1, 7) === "KTX 11",
calculate: (input) => ({
height: readUInt32LE(input, 40),
width: readUInt32LE(input, 36)
})
};
const pngSignature = "PNG\r\n\n";
const pngImageHeaderChunkName = "IHDR";
const pngFriedChunkName = "CgBI";
const PNG = {
validate(input) {
if (pngSignature === toUTF8String(input, 1, 8)) {
let chunkName = toUTF8String(input, 12, 16);
if (chunkName === pngFriedChunkName) {
chunkName = toUTF8String(input, 28, 32);
}
if (chunkName !== pngImageHeaderChunkName) {
throw new TypeError("Invalid PNG");
}
return true;
}
return false;
},
calculate(input) {
if (toUTF8String(input, 12, 16) === pngFriedChunkName) {
return {
height: readUInt32BE(input, 36),
width: readUInt32BE(input, 32)
};
}
return {
height: readUInt32BE(input, 20),
width: readUInt32BE(input, 16)
};
}
};
const PNMTypes = {
P1: "pbm/ascii",
P2: "pgm/ascii",
P3: "ppm/ascii",
P4: "pbm",
P5: "pgm",
P6: "ppm",
P7: "pam",
PF: "pfm"
};
const handlers = {
default: (lines) => {
let dimensions = [];
while (lines.length > 0) {
const line = lines.shift();
if (line[0] === "#") {
continue;
}
dimensions = line.split(" ");
break;
}
if (dimensions.length === 2) {
return {
height: Number.parseInt(dimensions[1], 10),
width: Number.parseInt(dimensions[0], 10)
};
} else {
throw new TypeError("Invalid PNM");
}
},
pam: (lines) => {
const size = {};
while (lines.length > 0) {
const line = lines.shift();
if (line.length > 16 || (line.codePointAt(0) || 0) > 128) {
continue;
}
const [key, value] = line.split(" ");
if (key && value) {
size[key.toLowerCase()] = Number.parseInt(value, 10);
}
if (size.height && size.width) {
break;
}
}
if (size.height && size.width) {
return {
height: size.height,
width: size.width
};
} else {
throw new TypeError("Invalid PAM");
}
}
};
const PNM = {
validate: (input) => toUTF8String(input, 0, 2) in PNMTypes,
calculate(input) {
const signature = toUTF8String(input, 0, 2);
const type = PNMTypes[signature];
const lines = toUTF8String(input, 3).split(/[\n\r]+/);
const handler = handlers[type] || handlers.default;
return handler(lines);
}
};
const PSD = {
validate: (input) => toUTF8String(input, 0, 4) === "8BPS",
calculate: (input) => ({
height: readUInt32BE(input, 14),
width: readUInt32BE(input, 18)
})
};
const svgReg = /<svg\s([^"'>]|"[^"]*"|'[^']*')*>/;
const extractorRegExps = {
height: /\sheight=(["'])([^%]+?)\1/,
root: svgReg,
viewbox: /\sviewbox=(["'])(.+?)\1/i,
width: /\swidth=(["'])([^%]+?)\1/
};
const INCH_CM = 2.54;
const units = {
in: 96,
cm: 96 / INCH_CM,
em: 16,
ex: 8,
m: 96 / INCH_CM * 100,
mm: 96 / INCH_CM / 10,
pc: 96 / 72 / 12,
pt: 96 / 72,
px: 1
};
const unitsReg = new RegExp(
`^([0-9.]+(?:e\\d+)?)(${Object.keys(units).join("|")})?$`
);
function parseLength(len) {
const m = unitsReg.exec(len);
if (!m) {
return void 0;
}
return Math.round(Number(m[1]) * (units[m[2]] || 1));
}
function parseViewbox(viewbox) {
const bounds = viewbox.split(" ");
return {
height: parseLength(bounds[3]),
width: parseLength(bounds[2])
};
}
function parseAttributes(root) {
const width = root.match(extractorRegExps.width);
const height = root.match(extractorRegExps.height);
const viewbox = root.match(extractorRegExps.viewbox);
return {
height: height && parseLength(height[2]),
viewbox: viewbox && parseViewbox(viewbox[2]),
width: width && parseLength(width[2])
};
}
function calculateByDimensions(attrs) {
return {
height: attrs.height,
width: attrs.width
};
}
function calculateByViewbox(attrs, viewbox) {
const ratio = viewbox.width / viewbox.height;
if (attrs.width) {
return {
height: Math.floor(attrs.width / ratio),
width: attrs.width
};
}
if (attrs.height) {
return {
height: attrs.height,
width: Math.floor(attrs.height * ratio)
};
}
return {
height: viewbox.height,
width: viewbox.width
};
}
const SVG = {
// Scan only the first kilo-byte to speed up the check on larger files
validate: (input) => svgReg.test(toUTF8String(input, 0, 1e3)),
calculate(input) {
const root = toUTF8String(input).match(extractorRegExps.root);
if (root) {
const attrs = parseAttributes(root[0]);
if (attrs.width && attrs.height) {
return calculateByDimensions(attrs);
}
if (attrs.viewbox) {
return calculateByViewbox(attrs, attrs.viewbox);
}
}
throw new TypeError("Invalid SVG");
}
};
const TGA = {
validate(input) {
return readUInt16LE(input, 0) === 0 && readUInt16LE(input, 4) === 0;
},
calculate(input) {
return {
height: readUInt16LE(input, 14),
width: readUInt16LE(input, 12)
};
}
};
function readIFD(buffer, isBigEndian) {
const ifdOffset = readUInt(buffer, 32, 4, isBigEndian);
let bufferSize = 1024;
const fileSize = buffer.length;
if (ifdOffset + bufferSize > fileSize) {
bufferSize = fileSize - ifdOffset - 10;
}
return buffer.slice(ifdOffset + 2, ifdOffset + 2 + bufferSize);
}
function readValue(buffer, isBigEndian) {
const low = readUInt(buffer, 16, 8, isBigEndian);
const high = readUInt(buffer, 16, 10, isBigEndian);
return (high << 16) + low;
}
function nextTag(buffer) {
if (buffer.length > 24) {
return buffer.slice(12);
}
}
function extractTags(buffer, isBigEndian) {
const tags = {};
let temp = buffer;
while (temp && temp.length > 0) {
const code = readUInt(temp, 16, 0, isBigEndian);
const type = readUInt(temp, 16, 2, isBigEndian);
const length = readUInt(temp, 32, 4, isBigEndian);
if (code === 0) {
break;
} else {
if (length === 1 && (type === 3 || type === 4)) {
tags[code] = readValue(temp, isBigEndian);
}
temp = nextTag(temp);
}
}
return tags;
}
function determineEndianness(input) {
const signature = toUTF8String(input, 0, 2);
if (signature === "II") {
return "LE";
} else if (signature === "MM") {
return "BE";
}
}
const signatures = /* @__PURE__ */ new Set([
// '492049', // currently not supported
"49492a00",
// Little endian
"4d4d002a"
// Big Endian
// '4d4d002a', // BigTIFF > 4GB. currently not supported
]);
const TIFF = {
validate: (input) => signatures.has(toHexString(input, 0, 4)),
calculate(input) {
const isBigEndian = determineEndianness(input) === "BE";
const ifdBuffer = readIFD(input, isBigEndian);
const tags = extractTags(ifdBuffer, isBigEndian);
const width = tags[256];
const height = tags[257];
if (!width || !height) {
throw new TypeError("Invalid Tiff. Missing tags");
}
return { height, width };
}
};
function calculateExtended(input) {
return {
height: 1 + readUInt24LE(input, 7),
width: 1 + readUInt24LE(input, 4)
};
}
function calculateLossless(input) {
return {
height: 1 + ((input[4] & 15) << 10 | input[3] << 2 | (input[2] & 192) >> 6),
width: 1 + ((input[2] & 63) << 8 | input[1])
};
}
function calculateLossy(input) {
return {
height: readInt16LE(input, 8) & 16383,
width: readInt16LE(input, 6) & 16383
};
}
const WEBP = {
validate(input) {
const riffHeader = toUTF8String(input, 0, 4) === "RIFF";
const webpHeader = toUTF8String(input, 8, 12) === "WEBP";
const vp8Header = toUTF8String(input, 12, 15) === "VP8";
return riffHeader && webpHeader && vp8Header;
},
calculate(input) {
const chunkHeader = toUTF8String(input, 12, 16);
input = input.slice(20, 30);
if (chunkHeader === "VP8X") {
const extendedHeader = input[0];
const validStart = (extendedHeader & 192) === 0;
const validEnd = (extendedHeader & 1) === 0;
if (validStart && validEnd) {
return calculateExtended(input);
} else {
throw new TypeError("Invalid WebP");
}
}
if (chunkHeader === "VP8 " && input[0] !== 47) {
return calculateLossy(input);
}
const signature = toHexString(input, 3, 6);
if (chunkHeader === "VP8L" && signature !== "9d012a") {
return calculateLossless(input);
}
throw new TypeError("Invalid WebP");
}
};
const AVIF = {
validate: (input) => toUTF8String(input, 8, 12) === "avif",
calculate: (input) => {
const metaBox = findBox(input, "meta");
const iprpBox = findBox(
input,
"iprp",
metaBox.offset + 12,
metaBox.offset + metaBox.size
);
const ipcoBox = findBox(
input,
"ipco",
iprpBox.offset + 8,
iprpBox.offset + iprpBox.size
);
const ispeBox = findBox(
input,
"ispe",
ipcoBox.offset + 8,
ipcoBox.offset + ipcoBox.size
);
const width = readUInt32BE(input, ispeBox.offset + 12);
const height = readUInt32BE(input, ispeBox.offset + 16);
return { width, height };
}
};
function findBox(input, type, startOffset = 0, endOffset = input.length) {
for (let offset = startOffset; offset < endOffset; ) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
return { offset, size };
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
throw new Error(`${type} box not found`);
}
const typeHandlers = {
bmp: BMP,
cur: CUR,
dds: DDS,
gif: GIF,
heic: HEIC,
icns: ICNS,
ico: ICO,
j2c: J2C,
jp2: JP2,
jpg: JPG,
ktx: KTX,
png: PNG,
pnm: PNM,
psd: PSD,
svg: SVG,
tga: TGA,
tiff: TIFF,
webp: WEBP,
avif: AVIF
};
const keys = Object.keys(typeHandlers);
const firstBytes = {
56: "psd",
66: "bmp",
68: "dds",
71: "gif",
73: "tiff",
77: "tiff",
82: "webp",
105: "icns",
137: "png",
255: "jpg"
};
function detector(input) {
const byte = input[0];
if (byte in firstBytes) {
const type = firstBytes[byte];
if (type && typeHandlers[type].validate(input)) {
return type;
}
}
return keys.find((key) => typeHandlers[key].validate(input));
}
function imageMeta(input) {
if (!(input instanceof Uint8Array)) {
throw new TypeError("Input should be a Uint8Array");
}
const type = detector(input);
if (type !== void 0 && type in typeHandlers) {
const size = typeHandlers[type].calculate(input);
if (size !== void 0) {
size.type = type;
return size;
}
}
throw new TypeError(`Unsupported file type: ${type}`);
}
exports.imageMeta = imageMeta;

View file

@ -0,0 +1,16 @@
type ImageMeta = {
images?: Omit<ImageMeta, "images">[];
width: number | undefined;
height: number | undefined;
orientation?: number;
type?: string;
};
/**
* @param {Uint8Array|string} input - Uint8Array or relative/absolute path of the image file
* @param {Function=} [callback] - optional function for async detection
*/
declare function imageMeta(input: Uint8Array): ImageMeta;
export { imageMeta };
export type { ImageMeta };

View file

@ -0,0 +1,16 @@
type ImageMeta = {
images?: Omit<ImageMeta, "images">[];
width: number | undefined;
height: number | undefined;
orientation?: number;
type?: string;
};
/**
* @param {Uint8Array|string} input - Uint8Array or relative/absolute path of the image file
* @param {Function=} [callback] - optional function for async detection
*/
declare function imageMeta(input: Uint8Array): ImageMeta;
export { imageMeta };
export type { ImageMeta };

View file

@ -0,0 +1,16 @@
type ImageMeta = {
images?: Omit<ImageMeta, "images">[];
width: number | undefined;
height: number | undefined;
orientation?: number;
type?: string;
};
/**
* @param {Uint8Array|string} input - Uint8Array or relative/absolute path of the image file
* @param {Function=} [callback] - optional function for async detection
*/
declare function imageMeta(input: Uint8Array): ImageMeta;
export { imageMeta };
export type { ImageMeta };

866
Frontend-Learner/node_modules/image-meta/dist/index.mjs generated vendored Normal file
View file

@ -0,0 +1,866 @@
const decoder = new TextDecoder();
const toUTF8String = (input, start = 0, end = input.length) => decoder.decode(input.slice(start, end));
const toHexString = (input, start = 0, end = input.length) => input.slice(start, end).reduce((memo, i) => memo + ("0" + i.toString(16)).slice(-2), "");
const readInt16LE = (input, offset = 0) => {
const val = input[offset] + input[offset + 1] * 2 ** 8;
return val | (val & 2 ** 15) * 131070;
};
const readUInt16BE = (input, offset = 0) => input[offset] * 2 ** 8 + input[offset + 1];
const readUInt16LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8;
const readUInt24LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16;
const readInt32LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16 + (input[offset + 3] << 24);
const readUInt32BE = (input, offset = 0) => input[offset] * 2 ** 24 + input[offset + 1] * 2 ** 16 + input[offset + 2] * 2 ** 8 + input[offset + 3];
const readUInt32LE = (input, offset = 0) => input[offset] + input[offset + 1] * 2 ** 8 + input[offset + 2] * 2 ** 16 + input[offset + 3] * 2 ** 24;
const methods = {
readUInt16BE,
readUInt16LE,
readUInt32BE,
readUInt32LE
};
function readUInt(input, bits, offset, isBigEndian) {
offset = offset || 0;
const endian = isBigEndian ? "BE" : "LE";
const methodName = "readUInt" + bits + endian;
return methods[methodName](input, offset);
}
const BMP = {
validate: (input) => toUTF8String(input, 0, 2) === "BM",
calculate: (input) => ({
height: Math.abs(readInt32LE(input, 22)),
width: readUInt32LE(input, 18)
})
};
const TYPE_ICON = 1;
const SIZE_HEADER$1 = 2 + 2 + 2;
const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4;
function getSizeFromOffset(input, offset) {
const value = input[offset];
return value === 0 ? 256 : value;
}
function getImageSize$1(input, imageIndex) {
const offset = SIZE_HEADER$1 + imageIndex * SIZE_IMAGE_ENTRY;
return {
height: getSizeFromOffset(input, offset + 1),
width: getSizeFromOffset(input, offset)
};
}
const ICO = {
validate(input) {
const reserved = readUInt16LE(input, 0);
const imageCount = readUInt16LE(input, 4);
if (reserved !== 0 || imageCount === 0) {
return false;
}
const imageType = readUInt16LE(input, 2);
return imageType === TYPE_ICON;
},
calculate(input) {
const nbImages = readUInt16LE(input, 4);
const imageSize = getImageSize$1(input, 0);
if (nbImages === 1) {
return imageSize;
}
const imgs = [imageSize];
for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) {
imgs.push(getImageSize$1(input, imageIndex));
}
return {
height: imageSize.height,
images: imgs,
width: imageSize.width
};
}
};
const TYPE_CURSOR = 2;
const CUR = {
validate(input) {
const reserved = readUInt16LE(input, 0);
const imageCount = readUInt16LE(input, 4);
if (reserved !== 0 || imageCount === 0) {
return false;
}
const imageType = readUInt16LE(input, 2);
return imageType === TYPE_CURSOR;
},
calculate: (input) => ICO.calculate(input)
};
const DDS = {
validate: (input) => readUInt32LE(input, 0) === 542327876,
calculate: (input) => ({
height: readUInt32LE(input, 12),
width: readUInt32LE(input, 16)
})
};
const gifRegexp = /^GIF8[79]a/;
const GIF = {
validate: (input) => gifRegexp.test(toUTF8String(input, 0, 6)),
calculate: (input) => ({
height: readUInt16LE(input, 8),
width: readUInt16LE(input, 6)
})
};
const HEIC = {
validate: (input) => {
const ftypBox = findBox$1(input, "ftyp");
if (!ftypBox) return false;
const majorBrand = toUTF8String(
input,
ftypBox.offset + 8,
ftypBox.offset + 12
);
return ["heic", "heix", "hevc", "hevx", "mif1", "msf1"].includes(
majorBrand
);
},
calculate: (input) => {
const metaBox = findBox$1(input, "meta");
if (!metaBox) throw new TypeError("heic: meta box not found");
const iprpBox = findBox$1(
input,
"iprp",
metaBox.offset + 12,
metaBox.offset + metaBox.size
);
if (!iprpBox) throw new TypeError("heic: iprp box not found");
const ipcoBox = findBox$1(
input,
"ipco",
iprpBox.offset + 8,
iprpBox.offset + iprpBox.size
);
if (!ipcoBox) throw new TypeError("heic: ipco box not found");
const dimensions = findAllBoxes(
input,
"ispe",
ipcoBox.offset + 8,
ipcoBox.offset + ipcoBox.size
).map((box) => ({
width: readUInt32BE(input, box.offset + 12),
height: readUInt32BE(input, box.offset + 16)
}));
if (dimensions.length === 0)
throw new TypeError("heic: ispe box not found");
let largestDimension = dimensions[0];
for (let i = 1; i < dimensions.length; i++) {
const curr = dimensions[i];
if (curr.width * curr.height > largestDimension.width * largestDimension.height) {
largestDimension = curr;
}
}
return largestDimension;
}
};
function findBox$1(input, type, startOffset = 0, endOffset = input.length) {
let offset = startOffset;
while (offset < endOffset) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
return { offset, size };
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
return void 0;
}
function findAllBoxes(input, type, startOffset = 0, endOffset = input.length) {
let offset = startOffset;
const boxes = [];
while (offset < endOffset) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
boxes.push({ offset, size });
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
return boxes;
}
const SIZE_HEADER = 4 + 4;
const FILE_LENGTH_OFFSET = 4;
const ENTRY_LENGTH_OFFSET = 4;
const ICON_TYPE_SIZE = {
ICON: 32,
"ICN#": 32,
// m => 16 x 16
"icm#": 16,
icm4: 16,
icm8: 16,
// s => 16 x 16
"ics#": 16,
ics4: 16,
ics8: 16,
is32: 16,
s8mk: 16,
icp4: 16,
// l => 32 x 32
icl4: 32,
icl8: 32,
il32: 32,
l8mk: 32,
icp5: 32,
ic11: 32,
// h => 48 x 48
ich4: 48,
ich8: 48,
ih32: 48,
h8mk: 48,
// . => 64 x 64
icp6: 64,
ic12: 32,
// t => 128 x 128
it32: 128,
t8mk: 128,
ic07: 128,
// . => 256 x 256
ic08: 256,
ic13: 256,
// . => 512 x 512
ic09: 512,
ic14: 512,
// . => 1024 x 1024
ic10: 1024
};
function readImageHeader(input, imageOffset) {
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET;
return [
toUTF8String(input, imageOffset, imageLengthOffset),
readUInt32BE(input, imageLengthOffset)
];
}
function getImageSize(type) {
const size = ICON_TYPE_SIZE[type];
return { width: size, height: size, type };
}
const ICNS = {
validate: (input) => toUTF8String(input, 0, 4) === "icns",
calculate(input) {
const inputLength = input.length;
const fileLength = readUInt32BE(input, FILE_LENGTH_OFFSET);
let imageOffset = SIZE_HEADER;
let imageHeader = readImageHeader(input, imageOffset);
let imageSize = getImageSize(imageHeader[0]);
imageOffset += imageHeader[1];
if (imageOffset === fileLength) {
return imageSize;
}
const result = {
height: imageSize.height,
images: [imageSize],
width: imageSize.width
};
while (imageOffset < fileLength && imageOffset < inputLength) {
imageHeader = readImageHeader(input, imageOffset);
imageSize = getImageSize(imageHeader[0]);
imageOffset += imageHeader[1];
result.images.push(imageSize);
}
return result;
}
};
const J2C = {
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
validate: (input) => toHexString(input, 0, 4) === "ff4fff51",
calculate: (input) => ({
height: readUInt32BE(input, 12),
width: readUInt32BE(input, 8)
})
};
const BoxTypes = {
ftyp: "66747970",
jp2h: "6a703268",
jp__: "6a502020",
rreq: "72726571"};
const calculateRREQLength = (box) => {
const unit = box[0];
let offset = 1 + 2 * unit;
const numStdFlags = readUInt16BE(box, offset);
const flagsLength = numStdFlags * (2 + unit);
offset = offset + 2 + flagsLength;
const numVendorFeatures = readUInt16BE(box, offset);
const featuresLength = numVendorFeatures * (16 + unit);
return offset + 2 + featuresLength;
};
const parseIHDR = (box) => {
return {
height: readUInt32BE(box, 4),
width: readUInt32BE(box, 8)
};
};
const JP2 = {
validate(input) {
const signature = toHexString(input, 4, 8);
const signatureLength = readUInt32BE(input, 0);
if (signature !== BoxTypes.jp__ || signatureLength < 1) {
return false;
}
const ftypeBoxStart = signatureLength + 4;
const ftypBoxLength = readUInt32BE(input, signatureLength);
const ftypBox = input.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength);
return toHexString(ftypBox, 0, 4) === BoxTypes.ftyp;
},
calculate(input) {
const signatureLength = readUInt32BE(input, 0);
const ftypBoxLength = readUInt16BE(input, signatureLength + 2);
let offset = signatureLength + 4 + ftypBoxLength;
const nextBoxType = toHexString(input, offset, offset + 4);
switch (nextBoxType) {
case BoxTypes.rreq: {
const MAGIC = 4;
offset = offset + 4 + MAGIC + calculateRREQLength(input.slice(offset + 4));
return parseIHDR(input.slice(offset + 8, offset + 24));
}
case BoxTypes.jp2h: {
return parseIHDR(input.slice(offset + 8, offset + 24));
}
default: {
throw new TypeError(
"Unsupported header found: " + toUTF8String(input, offset, offset + 4)
);
}
}
}
};
const EXIF_MARKER = "45786966";
const APP1_DATA_SIZE_BYTES = 2;
const EXIF_HEADER_BYTES = 6;
const TIFF_BYTE_ALIGN_BYTES = 2;
const BIG_ENDIAN_BYTE_ALIGN = "4d4d";
const LITTLE_ENDIAN_BYTE_ALIGN = "4949";
const IDF_ENTRY_BYTES = 12;
const NUM_DIRECTORY_ENTRIES_BYTES = 2;
function isEXIF(input) {
return toHexString(input, 2, 6) === EXIF_MARKER;
}
function extractSize(input, index) {
return {
height: readUInt16BE(input, index),
width: readUInt16BE(input, index + 2)
};
}
function extractOrientation(exifBlock, isBigEndian) {
const idfOffset = 8;
const offset = EXIF_HEADER_BYTES + idfOffset;
const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian);
for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) {
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + directoryEntryNumber * IDF_ENTRY_BYTES;
const end = start + IDF_ENTRY_BYTES;
if (start > exifBlock.length) {
return;
}
const block = exifBlock.slice(start, end);
const tagNumber = readUInt(block, 16, 0, isBigEndian);
if (tagNumber === 274) {
const dataFormat = readUInt(block, 16, 2, isBigEndian);
if (dataFormat !== 3) {
return;
}
const numberOfComponents = readUInt(block, 32, 4, isBigEndian);
if (numberOfComponents !== 1) {
return;
}
return readUInt(block, 16, 8, isBigEndian);
}
}
}
function validateExifBlock(input, index) {
const exifBlock = input.slice(APP1_DATA_SIZE_BYTES, index);
const byteAlign = toHexString(
exifBlock,
EXIF_HEADER_BYTES,
EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES
);
const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN;
const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN;
if (isBigEndian || isLittleEndian) {
return extractOrientation(exifBlock, isBigEndian);
}
}
function validateInput(input, index) {
if (index > input.length) {
throw new TypeError("Corrupt JPG, exceeded buffer limits");
}
if (input[index] !== 255) {
throw new TypeError("Invalid JPG, marker table corrupted");
}
}
const JPG = {
validate: (input) => toHexString(input, 0, 2) === "ffd8",
calculate(input) {
input = input.slice(4);
let orientation;
let next;
while (input.length > 0) {
const i = readUInt16BE(input, 0);
if (isEXIF(input)) {
orientation = validateExifBlock(input, i);
}
validateInput(input, i);
next = input[i + 1];
if (next === 192 || next === 193 || next === 194) {
const size = extractSize(input, i + 5);
if (!orientation) {
return size;
}
return {
height: size.height,
orientation,
width: size.width
};
}
input = input.slice(i + 2);
}
throw new TypeError("Invalid JPG, no size found");
}
};
const KTX = {
validate: (input) => toUTF8String(input, 1, 7) === "KTX 11",
calculate: (input) => ({
height: readUInt32LE(input, 40),
width: readUInt32LE(input, 36)
})
};
const pngSignature = "PNG\r\n\n";
const pngImageHeaderChunkName = "IHDR";
const pngFriedChunkName = "CgBI";
const PNG = {
validate(input) {
if (pngSignature === toUTF8String(input, 1, 8)) {
let chunkName = toUTF8String(input, 12, 16);
if (chunkName === pngFriedChunkName) {
chunkName = toUTF8String(input, 28, 32);
}
if (chunkName !== pngImageHeaderChunkName) {
throw new TypeError("Invalid PNG");
}
return true;
}
return false;
},
calculate(input) {
if (toUTF8String(input, 12, 16) === pngFriedChunkName) {
return {
height: readUInt32BE(input, 36),
width: readUInt32BE(input, 32)
};
}
return {
height: readUInt32BE(input, 20),
width: readUInt32BE(input, 16)
};
}
};
const PNMTypes = {
P1: "pbm/ascii",
P2: "pgm/ascii",
P3: "ppm/ascii",
P4: "pbm",
P5: "pgm",
P6: "ppm",
P7: "pam",
PF: "pfm"
};
const handlers = {
default: (lines) => {
let dimensions = [];
while (lines.length > 0) {
const line = lines.shift();
if (line[0] === "#") {
continue;
}
dimensions = line.split(" ");
break;
}
if (dimensions.length === 2) {
return {
height: Number.parseInt(dimensions[1], 10),
width: Number.parseInt(dimensions[0], 10)
};
} else {
throw new TypeError("Invalid PNM");
}
},
pam: (lines) => {
const size = {};
while (lines.length > 0) {
const line = lines.shift();
if (line.length > 16 || (line.codePointAt(0) || 0) > 128) {
continue;
}
const [key, value] = line.split(" ");
if (key && value) {
size[key.toLowerCase()] = Number.parseInt(value, 10);
}
if (size.height && size.width) {
break;
}
}
if (size.height && size.width) {
return {
height: size.height,
width: size.width
};
} else {
throw new TypeError("Invalid PAM");
}
}
};
const PNM = {
validate: (input) => toUTF8String(input, 0, 2) in PNMTypes,
calculate(input) {
const signature = toUTF8String(input, 0, 2);
const type = PNMTypes[signature];
const lines = toUTF8String(input, 3).split(/[\n\r]+/);
const handler = handlers[type] || handlers.default;
return handler(lines);
}
};
const PSD = {
validate: (input) => toUTF8String(input, 0, 4) === "8BPS",
calculate: (input) => ({
height: readUInt32BE(input, 14),
width: readUInt32BE(input, 18)
})
};
const svgReg = /<svg\s([^"'>]|"[^"]*"|'[^']*')*>/;
const extractorRegExps = {
height: /\sheight=(["'])([^%]+?)\1/,
root: svgReg,
viewbox: /\sviewbox=(["'])(.+?)\1/i,
width: /\swidth=(["'])([^%]+?)\1/
};
const INCH_CM = 2.54;
const units = {
in: 96,
cm: 96 / INCH_CM,
em: 16,
ex: 8,
m: 96 / INCH_CM * 100,
mm: 96 / INCH_CM / 10,
pc: 96 / 72 / 12,
pt: 96 / 72,
px: 1
};
const unitsReg = new RegExp(
`^([0-9.]+(?:e\\d+)?)(${Object.keys(units).join("|")})?$`
);
function parseLength(len) {
const m = unitsReg.exec(len);
if (!m) {
return void 0;
}
return Math.round(Number(m[1]) * (units[m[2]] || 1));
}
function parseViewbox(viewbox) {
const bounds = viewbox.split(" ");
return {
height: parseLength(bounds[3]),
width: parseLength(bounds[2])
};
}
function parseAttributes(root) {
const width = root.match(extractorRegExps.width);
const height = root.match(extractorRegExps.height);
const viewbox = root.match(extractorRegExps.viewbox);
return {
height: height && parseLength(height[2]),
viewbox: viewbox && parseViewbox(viewbox[2]),
width: width && parseLength(width[2])
};
}
function calculateByDimensions(attrs) {
return {
height: attrs.height,
width: attrs.width
};
}
function calculateByViewbox(attrs, viewbox) {
const ratio = viewbox.width / viewbox.height;
if (attrs.width) {
return {
height: Math.floor(attrs.width / ratio),
width: attrs.width
};
}
if (attrs.height) {
return {
height: attrs.height,
width: Math.floor(attrs.height * ratio)
};
}
return {
height: viewbox.height,
width: viewbox.width
};
}
const SVG = {
// Scan only the first kilo-byte to speed up the check on larger files
validate: (input) => svgReg.test(toUTF8String(input, 0, 1e3)),
calculate(input) {
const root = toUTF8String(input).match(extractorRegExps.root);
if (root) {
const attrs = parseAttributes(root[0]);
if (attrs.width && attrs.height) {
return calculateByDimensions(attrs);
}
if (attrs.viewbox) {
return calculateByViewbox(attrs, attrs.viewbox);
}
}
throw new TypeError("Invalid SVG");
}
};
const TGA = {
validate(input) {
return readUInt16LE(input, 0) === 0 && readUInt16LE(input, 4) === 0;
},
calculate(input) {
return {
height: readUInt16LE(input, 14),
width: readUInt16LE(input, 12)
};
}
};
function readIFD(buffer, isBigEndian) {
const ifdOffset = readUInt(buffer, 32, 4, isBigEndian);
let bufferSize = 1024;
const fileSize = buffer.length;
if (ifdOffset + bufferSize > fileSize) {
bufferSize = fileSize - ifdOffset - 10;
}
return buffer.slice(ifdOffset + 2, ifdOffset + 2 + bufferSize);
}
function readValue(buffer, isBigEndian) {
const low = readUInt(buffer, 16, 8, isBigEndian);
const high = readUInt(buffer, 16, 10, isBigEndian);
return (high << 16) + low;
}
function nextTag(buffer) {
if (buffer.length > 24) {
return buffer.slice(12);
}
}
function extractTags(buffer, isBigEndian) {
const tags = {};
let temp = buffer;
while (temp && temp.length > 0) {
const code = readUInt(temp, 16, 0, isBigEndian);
const type = readUInt(temp, 16, 2, isBigEndian);
const length = readUInt(temp, 32, 4, isBigEndian);
if (code === 0) {
break;
} else {
if (length === 1 && (type === 3 || type === 4)) {
tags[code] = readValue(temp, isBigEndian);
}
temp = nextTag(temp);
}
}
return tags;
}
function determineEndianness(input) {
const signature = toUTF8String(input, 0, 2);
if (signature === "II") {
return "LE";
} else if (signature === "MM") {
return "BE";
}
}
const signatures = /* @__PURE__ */ new Set([
// '492049', // currently not supported
"49492a00",
// Little endian
"4d4d002a"
// Big Endian
// '4d4d002a', // BigTIFF > 4GB. currently not supported
]);
const TIFF = {
validate: (input) => signatures.has(toHexString(input, 0, 4)),
calculate(input) {
const isBigEndian = determineEndianness(input) === "BE";
const ifdBuffer = readIFD(input, isBigEndian);
const tags = extractTags(ifdBuffer, isBigEndian);
const width = tags[256];
const height = tags[257];
if (!width || !height) {
throw new TypeError("Invalid Tiff. Missing tags");
}
return { height, width };
}
};
function calculateExtended(input) {
return {
height: 1 + readUInt24LE(input, 7),
width: 1 + readUInt24LE(input, 4)
};
}
function calculateLossless(input) {
return {
height: 1 + ((input[4] & 15) << 10 | input[3] << 2 | (input[2] & 192) >> 6),
width: 1 + ((input[2] & 63) << 8 | input[1])
};
}
function calculateLossy(input) {
return {
height: readInt16LE(input, 8) & 16383,
width: readInt16LE(input, 6) & 16383
};
}
const WEBP = {
validate(input) {
const riffHeader = toUTF8String(input, 0, 4) === "RIFF";
const webpHeader = toUTF8String(input, 8, 12) === "WEBP";
const vp8Header = toUTF8String(input, 12, 15) === "VP8";
return riffHeader && webpHeader && vp8Header;
},
calculate(input) {
const chunkHeader = toUTF8String(input, 12, 16);
input = input.slice(20, 30);
if (chunkHeader === "VP8X") {
const extendedHeader = input[0];
const validStart = (extendedHeader & 192) === 0;
const validEnd = (extendedHeader & 1) === 0;
if (validStart && validEnd) {
return calculateExtended(input);
} else {
throw new TypeError("Invalid WebP");
}
}
if (chunkHeader === "VP8 " && input[0] !== 47) {
return calculateLossy(input);
}
const signature = toHexString(input, 3, 6);
if (chunkHeader === "VP8L" && signature !== "9d012a") {
return calculateLossless(input);
}
throw new TypeError("Invalid WebP");
}
};
const AVIF = {
validate: (input) => toUTF8String(input, 8, 12) === "avif",
calculate: (input) => {
const metaBox = findBox(input, "meta");
const iprpBox = findBox(
input,
"iprp",
metaBox.offset + 12,
metaBox.offset + metaBox.size
);
const ipcoBox = findBox(
input,
"ipco",
iprpBox.offset + 8,
iprpBox.offset + iprpBox.size
);
const ispeBox = findBox(
input,
"ispe",
ipcoBox.offset + 8,
ipcoBox.offset + ipcoBox.size
);
const width = readUInt32BE(input, ispeBox.offset + 12);
const height = readUInt32BE(input, ispeBox.offset + 16);
return { width, height };
}
};
function findBox(input, type, startOffset = 0, endOffset = input.length) {
for (let offset = startOffset; offset < endOffset; ) {
const size = readUInt32BE(input, offset);
const boxType = toUTF8String(input, offset + 4, offset + 8);
if (boxType === type) {
return { offset, size };
}
if (size <= 0 || offset + size > endOffset) {
break;
}
offset += size;
}
throw new Error(`${type} box not found`);
}
const typeHandlers = {
bmp: BMP,
cur: CUR,
dds: DDS,
gif: GIF,
heic: HEIC,
icns: ICNS,
ico: ICO,
j2c: J2C,
jp2: JP2,
jpg: JPG,
ktx: KTX,
png: PNG,
pnm: PNM,
psd: PSD,
svg: SVG,
tga: TGA,
tiff: TIFF,
webp: WEBP,
avif: AVIF
};
const keys = Object.keys(typeHandlers);
const firstBytes = {
56: "psd",
66: "bmp",
68: "dds",
71: "gif",
73: "tiff",
77: "tiff",
82: "webp",
105: "icns",
137: "png",
255: "jpg"
};
function detector(input) {
const byte = input[0];
if (byte in firstBytes) {
const type = firstBytes[byte];
if (type && typeHandlers[type].validate(input)) {
return type;
}
}
return keys.find((key) => typeHandlers[key].validate(input));
}
function imageMeta(input) {
if (!(input instanceof Uint8Array)) {
throw new TypeError("Input should be a Uint8Array");
}
const type = detector(input);
if (type !== void 0 && type in typeHandlers) {
const size = typeHandlers[type].calculate(input);
if (size !== void 0) {
size.type = type;
return size;
}
}
throw new TypeError(`Unsupported file type: ${type}`);
}
export { imageMeta };

46
Frontend-Learner/node_modules/image-meta/package.json generated vendored Normal file
View file

@ -0,0 +1,46 @@
{
"name": "image-meta",
"version": "0.2.2",
"description": "Detect image type and size using pure javascript",
"repository": "unjs/image-meta",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "vitest dev",
"play": "jiti playground",
"lint": "eslint --cache . && prettier -c src test",
"lint:fix": "eslint --cache . --fix && prettier -c src test -w",
"prepack": "pnpm run build",
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
"test:types": "tsc --noEmit --skipLibCheck"
},
"devDependencies": {
"@types/node": "^24.7.0",
"@vitest/coverage-v8": "^3.2.4",
"changelogen": "^0.6.2",
"eslint": "^9.37.0",
"eslint-config-unjs": "^0.5.0",
"jiti": "^2.6.1",
"prettier": "^3.6.2",
"typescript": "^5.9.3",
"unbuild": "^3.6.1",
"vitest": "^3.2.4"
},
"packageManager": "pnpm@10.18.1"
}