Initial commit: New MoreminiMore website with fresh design

This commit is contained in:
MoreminiMore
2026-04-22 01:59:05 +07:00
commit 76409638cc
14010 changed files with 2052041 additions and 0 deletions

23
node_modules/astro/dist/assets/utils/assets.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import type { Environment, Rollup } from 'vite';
type PluginContext = Rollup.PluginContext;
type EmitFileOptions = Parameters<Rollup.PluginContext['emitFile']>[0];
/**
* Gets or creates the handle set for an environment
*/
export declare function getHandles(env: Environment): Set<string>;
/**
* Resets the handle tracking for an environment.
* Called at the start of each build.
*/
export declare function resetHandles(env: Environment): void;
/**
* Emit a client asset and track it for later movement to the client directory.
* Use this instead of pluginContext.emitFile for assets that should
* be moved from the server/prerender directory to the client directory.
*
* Note: The pluginContext is typed as Rollup.PluginContext for compatibility
* with content entry types, but in practice it will always have the `environment`
* property when running in Vite.
*/
export declare function emitClientAsset(pluginContext: PluginContext, options: EmitFileOptions): string;
export {};

24
node_modules/astro/dist/assets/utils/assets.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
const assetHandlesByEnvironment = /* @__PURE__ */ new WeakMap();
function getHandles(env) {
let handles = assetHandlesByEnvironment.get(env);
if (!handles) {
handles = /* @__PURE__ */ new Set();
assetHandlesByEnvironment.set(env, handles);
}
return handles;
}
function resetHandles(env) {
assetHandlesByEnvironment.set(env, /* @__PURE__ */ new Set());
}
function emitClientAsset(pluginContext, options) {
const env = pluginContext.environment;
const handle = pluginContext.emitFile(options);
const handles = getHandles(env);
handles.add(handle);
return handle;
}
export {
emitClientAsset,
getHandles,
resetHandles
};

View File

@@ -0,0 +1,10 @@
/**
* Vendored from deterministic-object-hash@2.0.2 (MIT)
* https://github.com/nicholasgasior/deterministic-object-hash
*
* Only `deterministicString` is needed - the async `deterministicHash` (which
* pulls in `node:crypto`) is intentionally excluded so this module stays
* runtime-agnostic (works in Node, workerd, browsers, etc.).
*/
/** Recursively serializes any JS value into a deterministic string. */
export declare function deterministicString(input: unknown): string;

View File

@@ -0,0 +1,104 @@
const objConstructorString = Function.prototype.toString.call(Object);
function isPlainObject(value) {
if (typeof value !== "object" || value === null || Object.prototype.toString.call(value) !== "[object Object]") {
return false;
}
const proto = Object.getPrototypeOf(value);
if (proto === null) {
return true;
}
if (!Object.prototype.hasOwnProperty.call(proto, "constructor")) {
return false;
}
return typeof proto.constructor === "function" && proto.constructor instanceof proto.constructor && Function.prototype.toString.call(proto.constructor) === objConstructorString;
}
function deterministicString(input) {
if (typeof input === "string") {
return JSON.stringify(input);
} else if (typeof input === "symbol" || typeof input === "function") {
return input.toString();
} else if (typeof input === "bigint") {
return `${input}n`;
} else if (input === globalThis || input === void 0 || input === null || typeof input === "boolean" || typeof input === "number" || typeof input !== "object") {
return `${input}`;
} else if (input instanceof Date) {
return `(${input.constructor.name}:${input.getTime()})`;
} else if (input instanceof RegExp || input instanceof Error || input instanceof WeakMap || input instanceof WeakSet) {
return `(${input.constructor.name}:${input.toString()})`;
} else if (input instanceof Set) {
let ret2 = `(${input.constructor.name}:[`;
for (const val of input.values()) {
ret2 += `${deterministicString(val)},`;
}
ret2 += "])";
return ret2;
} else if (Array.isArray(input) || input instanceof Int8Array || input instanceof Uint8Array || input instanceof Uint8ClampedArray || input instanceof Int16Array || input instanceof Uint16Array || input instanceof Int32Array || input instanceof Uint32Array || input instanceof Float32Array || input instanceof Float64Array || input instanceof BigInt64Array || input instanceof BigUint64Array) {
let ret2 = `(${input.constructor.name}:[`;
for (const [k, v] of input.entries()) {
ret2 += `(${k}:${deterministicString(v)}),`;
}
ret2 += "])";
return ret2;
} else if (input instanceof ArrayBuffer || input instanceof SharedArrayBuffer) {
if (input.byteLength % 8 === 0) {
return deterministicString(new BigUint64Array(input));
} else if (input.byteLength % 4 === 0) {
return deterministicString(new Uint32Array(input));
} else if (input.byteLength % 2 === 0) {
return deterministicString(new Uint16Array(input));
} else {
let ret2 = "(";
for (let i = 0; i < input.byteLength; i++) {
ret2 += `${deterministicString(new Uint8Array(input.slice(i, i + 1)))},`;
}
ret2 += ")";
return ret2;
}
} else if (input instanceof Map || isPlainObject(input)) {
const sortable = [];
const entries = input instanceof Map ? input.entries() : Object.entries(input);
for (const [k, v] of entries) {
sortable.push([deterministicString(k), deterministicString(v)]);
}
if (!(input instanceof Map)) {
const symbolKeys2 = Object.getOwnPropertySymbols(input);
for (let i = 0; i < symbolKeys2.length; i++) {
sortable.push([
deterministicString(symbolKeys2[i]),
deterministicString(input[symbolKeys2[i]])
]);
}
}
sortable.sort(([a], [b]) => a.localeCompare(b));
let ret2 = `(${input.constructor.name}:[`;
for (const [k, v] of sortable) {
ret2 += `(${k}:${v}),`;
}
ret2 += "])";
return ret2;
}
const allEntries = [];
for (const k in input) {
allEntries.push([
deterministicString(k),
deterministicString(input[k])
]);
}
const symbolKeys = Object.getOwnPropertySymbols(input);
for (let i = 0; i < symbolKeys.length; i++) {
allEntries.push([
deterministicString(symbolKeys[i]),
deterministicString(input[symbolKeys[i]])
]);
}
allEntries.sort(([a], [b]) => a.localeCompare(b));
let ret = `(${input.constructor.name}:[`;
for (const [k, v] of allEntries) {
ret += `(${k}:${v}),`;
}
ret += "])";
return ret;
}
export {
deterministicString
};

1
node_modules/astro/dist/assets/utils/etag.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare const etag: (payload: string, weak?: boolean) => string;

27
node_modules/astro/dist/assets/utils/etag.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
const fnv1a52 = (str) => {
const len = str.length;
let i = 0, t0 = 0, v0 = 8997, t1 = 0, v1 = 33826, t2 = 0, v2 = 40164, t3 = 0, v3 = 52210;
while (i < len) {
v0 ^= str.charCodeAt(i++);
t0 = v0 * 435;
t1 = v1 * 435;
t2 = v2 * 435;
t3 = v3 * 435;
t2 += v0 << 8;
t3 += v1 << 8;
t1 += t0 >>> 16;
v0 = t0 & 65535;
t2 += t1 >>> 16;
v1 = t1 & 65535;
v3 = t3 + (t2 >>> 16) & 65535;
v2 = t2 & 65535;
}
return (v3 & 15) * 281474976710656 + v2 * 4294967296 + v1 * 65536 + (v0 ^ v3 >> 4);
};
const etag = (payload, weak = false) => {
const prefix = weak ? 'W/"' : '"';
return prefix + fnv1a52(payload).toString(36) + payload.length.toString(36) + '"';
};
export {
etag
};

View File

@@ -0,0 +1 @@
export declare function generateImageStylesCSS(defaultObjectFit?: string, defaultObjectPosition?: string): string;

View File

@@ -0,0 +1,38 @@
import { cssFitValues } from "../internal.js";
function generateImageStylesCSS(defaultObjectFit, defaultObjectPosition) {
const fitStyles = cssFitValues.map(
(fit) => `
[data-astro-image-fit="${fit}"] {
object-fit: ${fit};
}`
).join("\n");
const defaultFitStyle = defaultObjectFit && cssFitValues.includes(defaultObjectFit) ? `
:where([data-astro-image]:not([data-astro-image-fit])) {
object-fit: ${defaultObjectFit};
}` : "";
const positionStyle = defaultObjectPosition ? `
[data-astro-image-pos="${defaultObjectPosition.replace(/\s+/g, "-")}"] {
object-position: ${defaultObjectPosition};
}
:where([data-astro-image]:not([data-astro-image-pos])) {
object-position: ${defaultObjectPosition};
}` : "";
return `
:where([data-astro-image]) {
height: auto;
}
:where([data-astro-image="full-width"]) {
width: 100%;
}
:where([data-astro-image="constrained"]) {
max-width: 100%;
}
${fitStyles}
${defaultFitStyle}
${positionStyle}
`.trim();
}
export {
generateImageStylesCSS
};

View File

@@ -0,0 +1,2 @@
import type { AssetsPrefix } from '../../core/app/types.js';
export declare function getAssetsPrefix(fileExtension: string, assetsPrefix?: AssetsPrefix): string;

View File

@@ -0,0 +1,15 @@
function getAssetsPrefix(fileExtension, assetsPrefix) {
let prefix = "";
if (!assetsPrefix) {
prefix = "";
} else if (typeof assetsPrefix === "string") {
prefix = assetsPrefix;
} else {
const dotLessFileExtension = fileExtension.slice(1);
prefix = assetsPrefix[dotLessFileExtension] || assetsPrefix.fallback;
}
return prefix;
}
export {
getAssetsPrefix
};

9
node_modules/astro/dist/assets/utils/hash.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import type { ImageTransform } from '../types.js';
/**
* Converts a file path and transformation properties into a formatted filename.
*
* `<prefixDirname>/<baseFilename>_<hash><outputExtension>`
*/
export declare function propsToFilename(filePath: string, transform: ImageTransform, hash: string): string;
/** Hashes the subset of transform properties that affect the output image. */
export declare function hashTransform(transform: ImageTransform, imageService: string, propertiesToHash: string[]): string;

54
node_modules/astro/dist/assets/utils/hash.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
import { deterministicString } from "./deterministic-string.js";
import { removeQueryString } from "@astrojs/internal-helpers/path";
import { shorthash } from "../../runtime/server/shorthash.js";
import { isESMImportedImage } from "./imageKind.js";
const INVALID_CHAR_REGEX = /[\u0000-\u001F"#$%&*+,:;<=>?[\]^`{|}\u007F]/g;
function basename(filePath, ext) {
let end = filePath.length;
while (end > 0 && filePath[end - 1] === "/") end--;
const stripped = filePath.slice(0, end);
const lastSlash = stripped.lastIndexOf("/");
const base = lastSlash === -1 ? stripped : stripped.slice(lastSlash + 1);
if (ext && base.endsWith(ext)) {
return base.slice(0, base.length - ext.length);
}
return base;
}
function dirname(filePath) {
const lastSlash = filePath.lastIndexOf("/");
if (lastSlash === -1) return ".";
if (lastSlash === 0) return "/";
return filePath.slice(0, lastSlash);
}
function extname(filePath) {
const base = basename(filePath);
const dotIndex = base.lastIndexOf(".");
if (dotIndex <= 0) return "";
return base.slice(dotIndex);
}
function propsToFilename(filePath, transform, hash) {
let filename = decodeURIComponent(removeQueryString(filePath));
const ext = extname(filename);
if (filePath.startsWith("data:")) {
filename = shorthash(filePath);
} else {
filename = basename(filename, ext).replace(INVALID_CHAR_REGEX, "_");
}
const prefixDirname = isESMImportedImage(transform.src) ? dirname(filePath) : "";
let outputExt = transform.format ? `.${transform.format}` : ext;
return `${prefixDirname}/${filename}_${hash}${outputExt}`;
}
function hashTransform(transform, imageService, propertiesToHash) {
const hashFields = propertiesToHash.reduce(
(acc, prop) => {
acc[prop] = transform[prop];
return acc;
},
{ imageService }
);
return shorthash(deterministicString(hashFields));
}
export {
hashTransform,
propsToFilename
};

22
node_modules/astro/dist/assets/utils/imageKind.d.ts generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import type { ImageMetadata, UnresolvedImageTransform } from '../types.js';
/**
* Determines if the given source is an ECMAScript Module (ESM) imported image.
*
* @param {ImageMetadata | string} src - The source to check. It can be an `ImageMetadata` object or a string.
* @return {boolean} Returns `true` if the source is an `ImageMetadata` object; otherwise, `false`.
*/
export declare function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata;
/**
* Determines if the provided source is a remote image URL in the form of a string.
*
* @param {ImageMetadata | string} src - The source to check, which can either be an `ImageMetadata` object or a string.
* @return {boolean} Returns `true` if the source is a string; otherwise, `false`.
*/
export declare function isRemoteImage(src: ImageMetadata | string): src is string;
/**
* Resolves the source of an image transformation by handling asynchronous or synchronous inputs.
*
* @param {UnresolvedImageTransform['src']} src - The source of the image transformation.
* @return {Promise<string | ImageMetadata>} A promise that resolves to the image source. It returns either the default export of the resolved source or the resolved source itself if the default export doesn't exist.
*/
export declare function resolveSrc(src: UnresolvedImageTransform['src']): Promise<string | ImageMetadata>;

18
node_modules/astro/dist/assets/utils/imageKind.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
function isESMImportedImage(src) {
return typeof src === "object" || typeof src === "function" && "src" in src;
}
function isRemoteImage(src) {
return typeof src === "string";
}
async function resolveSrc(src) {
if (typeof src === "object" && "then" in src) {
const resource = await src;
return resource.default ?? resource;
}
return src;
}
export {
isESMImportedImage,
isRemoteImage,
resolveSrc
};

12
node_modules/astro/dist/assets/utils/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,12 @@
/**
* NOTE: this is a public module exposed to the user, so all functions exposed
* here must be documented via JsDoc and in the docs website.
*
* If some functions don't need to be exposed, just import the file that contains the functions.
*/
export { isRemoteAllowed, matchPattern, type RemotePattern, } from '@astrojs/internal-helpers/remote';
export { emitClientAsset } from './assets.js';
export { isESMImportedImage, isRemoteImage, resolveSrc } from './imageKind.js';
export { imageMetadata } from './metadata.js';
export { getOrigQueryParams } from './queryParams.js';
export { inferRemoteSize } from './remoteProbe.js';

20
node_modules/astro/dist/assets/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import {
isRemoteAllowed,
matchPattern
} from "@astrojs/internal-helpers/remote";
import { emitClientAsset } from "./assets.js";
import { isESMImportedImage, isRemoteImage, resolveSrc } from "./imageKind.js";
import { imageMetadata } from "./metadata.js";
import { getOrigQueryParams } from "./queryParams.js";
import { inferRemoteSize } from "./remoteProbe.js";
export {
emitClientAsset,
getOrigQueryParams,
imageMetadata,
inferRemoteSize,
isESMImportedImage,
isRemoteAllowed,
isRemoteImage,
matchPattern,
resolveSrc
};

View File

@@ -0,0 +1,6 @@
/**
* Infer the image format from a source path or URL by examining
* the file extension. For data: URIs, the MIME type is extracted.
* Returns undefined if the format cannot be determined.
*/
export declare function inferSourceFormat(src: string): string | undefined;

View File

@@ -0,0 +1,21 @@
import { removeQueryString } from "@astrojs/internal-helpers/path";
const DATA_PREFIX = "data:";
function inferSourceFormat(src) {
if (src.startsWith(DATA_PREFIX)) {
const mime = src.slice(DATA_PREFIX.length, src.indexOf(";"));
if (mime === "image/svg+xml") return "svg";
const sub = mime.split("/")[1];
return sub || void 0;
}
try {
const cleanSrc = removeQueryString(src).split("#")[0];
const lastDot = cleanSrc.lastIndexOf(".");
if (lastDot === -1) return void 0;
return cleanSrc.slice(lastDot + 1).toLowerCase();
} catch {
return void 0;
}
}
export {
inferSourceFormat
};

10
node_modules/astro/dist/assets/utils/metadata.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import type { ImageMetadata } from '../types.js';
/**
* Extracts image metadata such as dimensions, format, and orientation from the provided image data.
*
* @param {Uint8Array} data - The binary data of the image.
* @param {string} [src] - The source path or URL of the image, used for error messages. Optional.
* @return {Promise<Omit<ImageMetadata, 'src' | 'fsPath'>>} A promise that resolves with the extracted metadata, excluding `src` and `fsPath`.
* @throws {AstroError} Throws an error if the image metadata cannot be extracted.
*/
export declare function imageMetadata(data: Uint8Array, src?: string): Promise<Omit<ImageMetadata, 'src' | 'fsPath'>>;

30
node_modules/astro/dist/assets/utils/metadata.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { lookup as probe } from "../utils/vendor/image-size/lookup.js";
async function imageMetadata(data, src) {
let result;
try {
result = probe(data);
} catch {
throw new AstroError({
...AstroErrorData.NoImageMetadata,
message: AstroErrorData.NoImageMetadata.message(src)
});
}
if (!result.height || !result.width || !result.type) {
throw new AstroError({
...AstroErrorData.NoImageMetadata,
message: AstroErrorData.NoImageMetadata.message(src)
});
}
const { width, height, type, orientation } = result;
const isPortrait = (orientation || 0) >= 5;
return {
width: isPortrait ? height : width,
height: isPortrait ? width : height,
format: type,
orientation
};
}
export {
imageMetadata
};

15
node_modules/astro/dist/assets/utils/node.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import type * as vite from 'vite';
import type { ImageMetadata } from '../types.js';
export { hashTransform, propsToFilename } from './hash.js';
type FileEmitter = vite.Rollup.EmitFile;
type ImageMetadataWithContents = ImageMetadata & {
contents?: Buffer;
};
/**
* Processes an image file and emits its metadata and optionally its contents. This function supports both build and development modes.
*
* @param {string | undefined} id - The identifier or path of the image file to process. If undefined, the function returns immediately.
* @param {FileEmitter | undefined} [fileEmitter] - Function for emitting files during the build process. May throw in certain scenarios.
* @return {Promise<ImageMetadataWithContents | undefined>} Resolves to metadata with optional image contents or `undefined` if processing fails.
*/
export declare function emitImageMetadata(id: string | undefined, fileEmitter?: FileEmitter): Promise<ImageMetadataWithContents | undefined>;

95
node_modules/astro/dist/assets/utils/node.js generated vendored Normal file
View File

@@ -0,0 +1,95 @@
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { generateContentHash } from "../../core/encryption.js";
import { prependForwardSlash, slash } from "../../core/path.js";
import { imageMetadata } from "./metadata.js";
import { hashTransform, propsToFilename } from "./hash.js";
const svgContentCache = /* @__PURE__ */ new WeakMap();
const keyRegistry = /* @__PURE__ */ new Map();
function keyFor(hash) {
let key = keyRegistry.get(hash);
if (!key) {
key = { hash };
keyRegistry.set(hash, key);
}
return key;
}
async function handleSvgDeduplication(fileData, filename, fileEmitter) {
const contentHash = await generateContentHash(fileData.buffer);
const key = keyFor(contentHash);
const existing = svgContentCache.get(key);
if (existing) {
const handle = fileEmitter({
name: existing.filename,
source: fileData,
type: "asset"
});
return handle;
} else {
const handle = fileEmitter({
name: filename,
source: fileData,
type: "asset"
});
svgContentCache.set(key, { handle, filename });
return handle;
}
}
async function emitImageMetadata(id, fileEmitter) {
if (!id) {
return void 0;
}
const url = pathToFileURL(id);
let fileData;
try {
fileData = await fs.readFile(url);
} catch {
return void 0;
}
const fileMetadata = await imageMetadata(fileData, id);
const emittedImage = {
src: "",
...fileMetadata
};
Object.defineProperty(emittedImage, "fsPath", {
enumerable: false,
writable: false,
value: fileURLToNormalizedPath(url)
});
let isBuild = typeof fileEmitter === "function";
if (isBuild) {
const pathname = decodeURI(url.pathname);
const filename = path.basename(pathname, path.extname(pathname) + `.${fileMetadata.format}`);
try {
let handle;
if (fileMetadata.format === "svg") {
handle = await handleSvgDeduplication(fileData, filename, fileEmitter);
} else {
handle = fileEmitter({
name: filename,
source: fileData,
type: "asset"
});
}
emittedImage.src = `__ASTRO_ASSET_IMAGE__${handle}__`;
} catch {
isBuild = false;
}
}
if (!isBuild) {
url.searchParams.append("origWidth", fileMetadata.width.toString());
url.searchParams.append("origHeight", fileMetadata.height.toString());
url.searchParams.append("origFormat", fileMetadata.format);
emittedImage.src = `/@fs` + prependForwardSlash(fileURLToNormalizedPath(url));
}
return emittedImage;
}
function fileURLToNormalizedPath(filePath) {
return slash(fileURLToPath(filePath) + filePath.search).replace(/\\/g, "/");
}
export {
emitImageMetadata,
hashTransform,
propsToFilename
};

2
node_modules/astro/dist/assets/utils/proxy.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { ImageMetadata } from '../types.js';
export declare function getProxyCode(options: ImageMetadata, isSSR: boolean): string;

20
node_modules/astro/dist/assets/utils/proxy.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
function getProxyCode(options, isSSR) {
const stringifiedFSPath = JSON.stringify(options.fsPath);
return `
new Proxy(${JSON.stringify(options)}, {
get(target, name, receiver) {
if (name === 'clone') {
return structuredClone(target);
}
if (name === 'fsPath') {
return ${stringifiedFSPath};
}
${!isSSR ? `if (target[name] !== undefined && globalThis.astroAsset) globalThis.astroAsset?.referencedImages?.add(${stringifiedFSPath});` : ""}
return target[name];
}
})
`;
}
export {
getProxyCode
};

11
node_modules/astro/dist/assets/utils/queryParams.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import type { ImageMetadata } from '../types.js';
/**
* Extracts the original image query parameters (width, height, format) from the given `URLSearchParams` object
* and returns them as an object. If any of the required parameters are missing or invalid, the function returns undefined.
*
* The `width` and `height` are parsed to integer values.
*
* @param {URLSearchParams} params - The `URLSearchParams` object containing the query parameters.
* @return {Pick<ImageMetadata, 'width' | 'height' | 'format'> | undefined} An object with the original image parameters (width, height, format) or undefined if any parameter is missing.
*/
export declare function getOrigQueryParams(params: URLSearchParams): Pick<ImageMetadata, 'width' | 'height' | 'format'> | undefined;

16
node_modules/astro/dist/assets/utils/queryParams.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
function getOrigQueryParams(params) {
const width = params.get("origWidth");
const height = params.get("origHeight");
const format = params.get("origFormat");
if (!width || !height || !format) {
return void 0;
}
return {
width: Number.parseInt(width),
height: Number.parseInt(height),
format
};
}
export {
getOrigQueryParams
};

13
node_modules/astro/dist/assets/utils/remoteProbe.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import type { AstroConfig } from '../../types/public/config.js';
import type { ImageMetadata } from '../types.js';
type RemoteImageConfig = Pick<AstroConfig['image'], 'domains' | 'remotePatterns'>;
/**
* Infers the dimensions of a remote image by streaming its data and analyzing it progressively until sufficient metadata is available.
*
* @param {string} url - The URL of the remote image from which to infer size metadata.
* @param {RemoteImageConfig} [imageConfig] - Optional image config used to validate remote allowlists.
* @return {Promise<Omit<ImageMetadata, 'src' | 'fsPath'>>} Returns a promise that resolves to an object containing the image dimensions metadata excluding `src` and `fsPath`.
* @throws {AstroError} Thrown when the fetching fails or metadata cannot be extracted.
*/
export declare function inferRemoteSize(url: string, imageConfig?: RemoteImageConfig): Promise<Omit<ImageMetadata, 'src' | 'fsPath'>>;
export {};

73
node_modules/astro/dist/assets/utils/remoteProbe.js generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { imageMetadata } from "./metadata.js";
async function inferRemoteSize(url, imageConfig) {
if (!URL.canParse(url)) {
throw new AstroError({
...AstroErrorData.FailedToFetchRemoteImageDimensions,
message: AstroErrorData.FailedToFetchRemoteImageDimensions.message(url)
});
}
const allowlistConfig = imageConfig ? {
domains: imageConfig.domains ?? [],
remotePatterns: imageConfig.remotePatterns ?? []
} : void 0;
if (!allowlistConfig) {
const parsedUrl = new URL(url);
if (!["http:", "https:"].includes(parsedUrl.protocol)) {
throw new AstroError({
...AstroErrorData.FailedToFetchRemoteImageDimensions,
message: AstroErrorData.FailedToFetchRemoteImageDimensions.message(url)
});
}
}
if (allowlistConfig && !isRemoteAllowed(url, allowlistConfig)) {
throw new AstroError({
...AstroErrorData.RemoteImageNotAllowed,
message: AstroErrorData.RemoteImageNotAllowed.message(url)
});
}
const response = await fetch(url, { redirect: "manual" });
if (response.status >= 300 && response.status < 400) {
throw new AstroError({
...AstroErrorData.FailedToFetchRemoteImageDimensions,
message: AstroErrorData.FailedToFetchRemoteImageDimensions.message(url)
});
}
if (!response.body || !response.ok) {
throw new AstroError({
...AstroErrorData.FailedToFetchRemoteImageDimensions,
message: AstroErrorData.FailedToFetchRemoteImageDimensions.message(url)
});
}
const reader = response.body.getReader();
let done, value;
let accumulatedChunks = new Uint8Array();
while (!done) {
const readResult = await reader.read();
done = readResult.done;
if (done) break;
if (readResult.value) {
value = readResult.value;
let tmp = new Uint8Array(accumulatedChunks.length + value.length);
tmp.set(accumulatedChunks, 0);
tmp.set(value, accumulatedChunks.length);
accumulatedChunks = tmp;
try {
const dimensions = await imageMetadata(accumulatedChunks, url);
if (dimensions) {
await reader.cancel();
return dimensions;
}
} catch {
}
}
}
throw new AstroError({
...AstroErrorData.NoImageMetadata,
message: AstroErrorData.NoImageMetadata.message(url)
});
}
export {
inferRemoteSize
};

View File

@@ -0,0 +1,9 @@
/**
* Resolves an image src from a content file (such as markdown) to a module ID or import that can be resolved by Vite.
*
* @param imageSrc The src attribute of an image tag
* @param filePath The path to the file that contains the image relative to the site root
* @returns A module id of the image that can be resolved by Vite, or undefined if it is not a local image
*/
export declare function imageSrcToImportId(imageSrc: string, filePath?: string): string | undefined;
export declare const importIdToSymbolName: (importId: string) => string;

24
node_modules/astro/dist/assets/utils/resolveImports.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { isRemotePath, removeBase } from "@astrojs/internal-helpers/path";
import { CONTENT_IMAGE_FLAG, IMAGE_IMPORT_PREFIX } from "../../content/consts.js";
import { shorthash } from "../../runtime/server/shorthash.js";
import { VALID_INPUT_FORMATS } from "../consts.js";
function imageSrcToImportId(imageSrc, filePath) {
imageSrc = removeBase(imageSrc, IMAGE_IMPORT_PREFIX);
if (isRemotePath(imageSrc)) {
return;
}
const ext = imageSrc.split(".").at(-1)?.toLowerCase();
if (!ext || !VALID_INPUT_FORMATS.includes(ext)) {
return;
}
const params = new URLSearchParams(CONTENT_IMAGE_FLAG);
if (filePath) {
params.set("importer", filePath);
}
return `${imageSrc}?${params.toString()}`;
}
const importIdToSymbolName = (importId) => `__ASTRO_IMAGE_IMPORT_${shorthash(importId)}`;
export {
imageSrcToImportId,
importIdToSymbolName
};

3
node_modules/astro/dist/assets/utils/svg.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import type { AstroConfig } from '../../types/public/config.js';
import type { ImageMetadata } from '../types.js';
export declare function makeSvgComponent(meta: ImageMetadata, contents: Buffer | string, svgoConfig: AstroConfig['experimental']['svgo']): string;

82
node_modules/astro/dist/assets/utils/svg.js generated vendored Normal file
View File

@@ -0,0 +1,82 @@
import { optimize } from "svgo";
import { ELEMENT_NODE, TEXT_NODE, parse, renderSync } from "ultrahtml";
import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { dropAttributes } from "../runtime.js";
function parseSvg({
path,
contents,
svgoConfig
}) {
let processedContents = contents;
if (svgoConfig) {
try {
const config = typeof svgoConfig === "boolean" ? void 0 : svgoConfig;
const result = optimize(contents, config);
processedContents = result.data;
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotOptimizeSvg,
message: AstroErrorData.CannotOptimizeSvg.message(path)
},
{ cause }
);
}
}
const root = parse(processedContents);
const svgNode = root.children.find(
({ name, type }) => type === ELEMENT_NODE && name === "svg"
);
if (!svgNode) {
throw new Error("SVG file does not contain an <svg> element");
}
const { attributes, children } = svgNode;
const body = renderSync({ ...root, children });
const styles = [];
for (const child of children) {
if (child.type === ELEMENT_NODE && child.name === "style") {
const textContent = child.children?.filter((c) => c.type === TEXT_NODE).map((c) => c.value).join("");
if (textContent) {
styles.push(textContent);
}
}
}
return { attributes, body, styles };
}
function makeSvgComponent(meta, contents, svgoConfig) {
const file = typeof contents === "string" ? contents : contents.toString("utf-8");
const {
attributes,
body: children,
styles
} = parseSvg({
path: meta.fsPath,
contents: file,
svgoConfig
});
const props = {
meta,
attributes: dropAttributes(attributes),
children,
styles
};
return `import { createSvgComponent } from 'astro/assets/runtime';
export default createSvgComponent(${JSON.stringify(props)})`;
}
function parseSvgComponentData(meta, contents, svgoConfig) {
const file = typeof contents === "string" ? contents : contents.toString("utf-8");
const {
attributes,
body: children,
styles
} = parseSvg({
path: meta.fsPath,
contents: file,
svgoConfig
});
return { attributes: dropAttributes(attributes), children, styles };
}
export {
makeSvgComponent,
parseSvgComponentData
};

16
node_modules/astro/dist/assets/utils/url.d.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/**
* Creates a URL object from a path or URL string, using a placeholder base for relative paths.
* This allows safe manipulation of URLs using the native URL API.
*
* @param pathOrUrl - A relative path (e.g., '/_astro/image.png') or absolute URL (e.g., 'https://cdn.example.com/...')
* @returns A URL object that can be safely manipulated
*/
export declare function createPlaceholderURL(pathOrUrl: string): URL;
/**
* Extracts the pathname and search parameters from a URL created with `createPlaceholderURL`.
* Removes the placeholder base, returning just the path and query string.
*
* @param url - A URL object created with `createPlaceholderURL`
* @returns The URL string without the placeholder base
*/
export declare function stringifyPlaceholderURL(url: URL): string;

11
node_modules/astro/dist/assets/utils/url.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
const PLACEHOLDER_BASE = "astro://placeholder";
function createPlaceholderURL(pathOrUrl) {
return new URL(pathOrUrl, PLACEHOLDER_BASE);
}
function stringifyPlaceholderURL(url) {
return url.href.replace(PLACEHOLDER_BASE, "");
}
export {
createPlaceholderURL,
stringifyPlaceholderURL
};

View File

@@ -0,0 +1,2 @@
import type { imageType } from './types/index.ts';
export declare function detector(input: Uint8Array): imageType | undefined;

View File

@@ -0,0 +1,25 @@
import { typeHandlers, types } from "./types/index.js";
const firstBytes = /* @__PURE__ */ new Map([
[0, "heif"],
[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];
const type = firstBytes.get(byte);
if (type && typeHandlers.get(type).validate(input)) {
return type;
}
return types.find((imageType) => typeHandlers.get(imageType).validate(input));
}
export {
detector
};

View File

@@ -0,0 +1,8 @@
import type { ISizeCalculationResult } from './types/interface.ts';
/**
* Return size information based on an Uint8Array
*
* @param {Uint8Array} input
* @returns {ISizeCalculationResult}
*/
export declare function lookup(input: Uint8Array): ISizeCalculationResult;

View File

@@ -0,0 +1,16 @@
import { typeHandlers } from "./types/index.js";
import { detector } from "./detector.js";
function lookup(input) {
const type = detector(input);
if (typeof type !== "undefined") {
const size = typeHandlers.get(type).calculate(input);
if (size !== void 0) {
size.type = size.type ?? type;
return size;
}
}
throw new TypeError("unsupported file type: " + type);
}
export {
lookup
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const BMP: IImage;

View File

@@ -0,0 +1,11 @@
import { readInt32LE, readUInt32LE, toUTF8String } from "./utils.js";
const BMP = {
validate: (input) => toUTF8String(input, 0, 2) === "BM",
calculate: (input) => ({
height: Math.abs(readInt32LE(input, 22)),
width: readUInt32LE(input, 18)
})
};
export {
BMP
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const CUR: IImage;

View File

@@ -0,0 +1,16 @@
import { ICO } from "./ico.js";
import { readUInt16LE } from "./utils.js";
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)
};
export {
CUR
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const DDS: IImage;

View File

@@ -0,0 +1,11 @@
import { readUInt32LE } from "./utils.js";
const DDS = {
validate: (input) => readUInt32LE(input, 0) === 542327876,
calculate: (input) => ({
height: readUInt32LE(input, 12),
width: readUInt32LE(input, 16)
})
};
export {
DDS
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const GIF: IImage;

View File

@@ -0,0 +1,12 @@
import { readUInt16LE, toUTF8String } from "./utils.js";
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)
})
};
export {
GIF
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const HEIF: IImage;

View File

@@ -0,0 +1,77 @@
import { findBox, readUInt32BE, toUTF8String } from "./utils.js";
const brandMap = {
avif: "avif",
avis: "avif",
// avif-sequence
mif1: "heif",
msf1: "heif",
// heif-sequence
heic: "heic",
heix: "heic",
hevc: "heic",
// heic-sequence
hevx: "heic"
// heic-sequence
};
function detectType(input, start, end) {
let hasAvif = false;
let hasHeic = false;
let hasHeif = false;
for (let i = start; i <= end; i += 4) {
const brand = toUTF8String(input, i, i + 4);
if (brand === "avif" || brand === "avis") hasAvif = true;
else if (brand === "heic" || brand === "heix" || brand === "hevc" || brand === "hevx") hasHeic = true;
else if (brand === "mif1" || brand === "msf1") hasHeif = true;
}
if (hasAvif) return "avif";
if (hasHeic) return "heic";
if (hasHeif) return "heif";
}
const HEIF = {
validate(input) {
const boxType = toUTF8String(input, 4, 8);
if (boxType !== "ftyp") return false;
const ftypBox = findBox(input, "ftyp", 0);
if (!ftypBox) return false;
const brand = toUTF8String(input, ftypBox.offset + 8, ftypBox.offset + 12);
return brand in brandMap;
},
calculate(input) {
const metaBox = findBox(input, "meta", 0);
const iprpBox = metaBox && findBox(input, "iprp", metaBox.offset + 12);
const ipcoBox = iprpBox && findBox(input, "ipco", iprpBox.offset + 8);
if (!ipcoBox) {
throw new TypeError("Invalid HEIF, no ipco box found");
}
const type = detectType(input, 8, metaBox.offset);
const images = [];
let currentOffset = ipcoBox.offset + 8;
while (currentOffset < ipcoBox.offset + ipcoBox.size) {
const ispeBox = findBox(input, "ispe", currentOffset);
if (!ispeBox) break;
const rawWidth = readUInt32BE(input, ispeBox.offset + 12);
const rawHeight = readUInt32BE(input, ispeBox.offset + 16);
const clapBox = findBox(input, "clap", currentOffset);
let width = rawWidth;
let height = rawHeight;
if (clapBox && clapBox.offset < ipcoBox.offset + ipcoBox.size) {
const cropRight = readUInt32BE(input, clapBox.offset + 12);
width = rawWidth - cropRight;
}
images.push({ height, width });
currentOffset = ispeBox.offset + ispeBox.size;
}
if (images.length === 0) {
throw new TypeError("Invalid HEIF, no sizes found");
}
return {
width: images[0].width,
height: images[0].height,
type,
...images.length > 1 ? { images } : {}
};
}
};
export {
HEIF
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const ICNS: IImage;

View File

@@ -0,0 +1,83 @@
import { readUInt32BE, toUTF8String } from "./utils.js";
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;
const images = [];
while (imageOffset < fileLength && imageOffset < inputLength) {
const imageHeader = readImageHeader(input, imageOffset);
const imageSize = getImageSize(imageHeader[0]);
images.push(imageSize);
imageOffset += imageHeader[1];
}
if (images.length === 0) {
throw new TypeError("Invalid ICNS, no sizes found");
}
return {
width: images[0].width,
height: images[0].height,
...images.length > 1 ? { images } : {}
};
}
};
export {
ICNS
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const ICO: IImage;

View File

@@ -0,0 +1,41 @@
import { readUInt16LE } from "./utils.js";
const TYPE_ICON = 1;
const SIZE_HEADER = 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(input, imageIndex) {
const offset = SIZE_HEADER + 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(input, 0);
if (nbImages === 1) return imageSize;
const images = [];
for (let imageIndex = 0; imageIndex < nbImages; imageIndex += 1) {
images.push(getImageSize(input, imageIndex));
}
return {
width: imageSize.width,
height: imageSize.height,
images
};
}
};
export {
ICO
};

View File

@@ -0,0 +1,3 @@
export declare const typeHandlers: Map<"jpg" | "png" | "tiff" | "webp" | "gif" | "svg" | "heif" | "icns" | "ktx" | "bmp" | "cur" | "dds" | "ico" | "j2c" | "jp2" | "jxl" | "jxl-stream" | "pnm" | "psd" | "tga", import("./interface.js").IImage>;
export declare const types: ("jpg" | "png" | "tiff" | "webp" | "gif" | "svg" | "heif" | "icns" | "ktx" | "bmp" | "cur" | "dds" | "ico" | "j2c" | "jp2" | "jxl" | "jxl-stream" | "pnm" | "psd" | "tga")[];
export type imageType = (typeof types)[number];

View File

@@ -0,0 +1,47 @@
import { BMP } from "./bmp.js";
import { CUR } from "./cur.js";
import { DDS } from "./dds.js";
import { GIF } from "./gif.js";
import { HEIF } from "./heif.js";
import { ICNS } from "./icns.js";
import { ICO } from "./ico.js";
import { J2C } from "./j2c.js";
import { JP2 } from "./jp2.js";
import { JPG } from "./jpg.js";
import { JXL } from "./jxl.js";
import { JXLStream } from "./jxl-stream.js";
import { KTX } from "./ktx.js";
import { PNG } from "./png.js";
import { PNM } from "./pnm.js";
import { PSD } from "./psd.js";
import { SVG } from "./svg.js";
import { TGA } from "./tga.js";
import { TIFF } from "./tiff.js";
import { WEBP } from "./webp.js";
const typeHandlers = /* @__PURE__ */ new Map([
["bmp", BMP],
["cur", CUR],
["dds", DDS],
["gif", GIF],
["heif", HEIF],
["icns", ICNS],
["ico", ICO],
["j2c", J2C],
["jp2", JP2],
["jpg", JPG],
["jxl", JXL],
["jxl-stream", JXLStream],
["ktx", KTX],
["png", PNG],
["pnm", PNM],
["psd", PSD],
["svg", SVG],
["tga", TGA],
["tiff", TIFF],
["webp", WEBP]
]);
const types = Array.from(typeHandlers.keys());
export {
typeHandlers,
types
};

View File

@@ -0,0 +1,13 @@
export interface ISize {
width: number;
height: number;
orientation?: number;
type?: string;
}
export type ISizeCalculationResult = {
images?: ISize[];
} & ISize;
export interface IImage {
validate: (input: Uint8Array) => boolean;
calculate: (input: Uint8Array) => ISizeCalculationResult;
}

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const J2C: IImage;

View File

@@ -0,0 +1,12 @@
import { readUInt32BE } from "./utils.js";
const J2C = {
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
validate: (input) => readUInt32BE(input, 0) === 4283432785,
calculate: (input) => ({
height: readUInt32BE(input, 12),
width: readUInt32BE(input, 8)
})
};
export {
J2C
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const JP2: IImage;

View File

@@ -0,0 +1,25 @@
import { findBox, readUInt32BE, toUTF8String } from "./utils.js";
const JP2 = {
validate(input) {
const boxType = toUTF8String(input, 4, 8);
if (boxType !== "jP ") return false;
const ftypBox = findBox(input, "ftyp", 0);
if (!ftypBox) return false;
const brand = toUTF8String(input, ftypBox.offset + 8, ftypBox.offset + 12);
return brand === "jp2 ";
},
calculate(input) {
const jp2hBox = findBox(input, "jp2h", 0);
const ihdrBox = jp2hBox && findBox(input, "ihdr", jp2hBox.offset + 8);
if (ihdrBox) {
return {
height: readUInt32BE(input, ihdrBox.offset + 8),
width: readUInt32BE(input, ihdrBox.offset + 12)
};
}
throw new TypeError("Unsupported JPEG 2000 format");
}
};
export {
JP2
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const JPG: IImage;

View File

@@ -0,0 +1,97 @@
import { readUInt, readUInt16BE, toHexString } from "./utils.js";
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");
}
}
const JPG = {
validate: (input) => toHexString(input, 0, 2) === "ffd8",
calculate(_input) {
let input = _input.slice(4);
let orientation;
let next;
while (input.length) {
const i = readUInt16BE(input, 0);
validateInput(input, i);
if (input[i] !== 255) {
input = input.slice(1);
continue;
}
if (isEXIF(input)) {
orientation = validateExifBlock(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");
}
};
export {
JPG
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const JXLStream: IImage;

View File

@@ -0,0 +1,36 @@
import { BitReader } from "../utils/bit-reader.js";
import { toHexString } from "./utils.js";
function calculateImageDimension(reader, isSmallImage) {
if (isSmallImage) {
return 8 * (1 + reader.getBits(5));
}
const sizeClass = reader.getBits(2);
const extraBits = [9, 13, 18, 30][sizeClass];
return 1 + reader.getBits(extraBits);
}
function calculateImageWidth(reader, isSmallImage, widthMode, height) {
if (isSmallImage && widthMode === 0) {
return 8 * (1 + reader.getBits(5));
}
if (widthMode === 0) {
return calculateImageDimension(reader, false);
}
const aspectRatios = [1, 1.2, 4 / 3, 1.5, 16 / 9, 5 / 4, 2];
return Math.floor(height * aspectRatios[widthMode - 1]);
}
const JXLStream = {
validate: (input) => {
return toHexString(input, 0, 2) === "ff0a";
},
calculate(input) {
const reader = new BitReader(input, "little-endian");
const isSmallImage = reader.getBits(1) === 1;
const height = calculateImageDimension(reader, isSmallImage);
const widthMode = reader.getBits(3);
const width = calculateImageWidth(reader, isSmallImage, widthMode, height);
return { width, height };
}
};
export {
JXLStream
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const JXL: IImage;

View File

@@ -0,0 +1,57 @@
import { JXLStream } from "./jxl-stream.js";
import { findBox, toUTF8String } from "./utils.js";
function extractCodestream(input) {
const jxlcBox = findBox(input, "jxlc", 0);
if (jxlcBox) {
return input.slice(jxlcBox.offset + 8, jxlcBox.offset + jxlcBox.size);
}
const partialStreams = extractPartialStreams(input);
if (partialStreams.length > 0) {
return concatenateCodestreams(partialStreams);
}
return void 0;
}
function extractPartialStreams(input) {
const partialStreams = [];
let offset = 0;
while (offset < input.length) {
const jxlpBox = findBox(input, "jxlp", offset);
if (!jxlpBox) break;
partialStreams.push(
input.slice(jxlpBox.offset + 12, jxlpBox.offset + jxlpBox.size)
);
offset = jxlpBox.offset + jxlpBox.size;
}
return partialStreams;
}
function concatenateCodestreams(partialCodestreams) {
const totalLength = partialCodestreams.reduce(
(acc, curr) => acc + curr.length,
0
);
const codestream = new Uint8Array(totalLength);
let position = 0;
for (const partial of partialCodestreams) {
codestream.set(partial, position);
position += partial.length;
}
return codestream;
}
const JXL = {
validate: (input) => {
const boxType = toUTF8String(input, 4, 8);
if (boxType !== "JXL ") return false;
const ftypBox = findBox(input, "ftyp", 0);
if (!ftypBox) return false;
const brand = toUTF8String(input, ftypBox.offset + 8, ftypBox.offset + 12);
return brand === "jxl ";
},
calculate(input) {
const codestream = extractCodestream(input);
if (codestream) return JXLStream.calculate(codestream);
throw new Error("No codestream found in JXL container");
}
};
export {
JXL
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const KTX: IImage;

View File

@@ -0,0 +1,19 @@
import { readUInt32LE, toUTF8String } from "./utils.js";
const KTX = {
validate: (input) => {
const signature = toUTF8String(input, 1, 7);
return ["KTX 11", "KTX 20"].includes(signature);
},
calculate: (input) => {
const type = input[5] === 49 ? "ktx" : "ktx2";
const offset = type === "ktx" ? 36 : 20;
return {
height: readUInt32LE(input, offset + 4),
width: readUInt32LE(input, offset),
type
};
}
};
export {
KTX
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const PNG: IImage;

View File

@@ -0,0 +1,34 @@
import { readUInt32BE, toUTF8String } from "./utils.js";
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)
};
}
};
export {
PNG
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const PNM: IImage;

View File

@@ -0,0 +1,67 @@
import { toUTF8String } from "./utils.js";
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)
};
}
throw new TypeError("Invalid PNM");
},
pam: (lines) => {
const size = {};
while (lines.length > 0) {
const line = lines.shift();
if (line.length > 16 || line.charCodeAt(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
};
}
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(/[\r\n]+/);
const handler = handlers[type] || handlers.default;
return handler(lines);
}
};
export {
PNM
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const PSD: IImage;

View File

@@ -0,0 +1,11 @@
import { readUInt32BE, toUTF8String } from "./utils.js";
const PSD = {
validate: (input) => toUTF8String(input, 0, 4) === "8BPS",
calculate: (input) => ({
height: readUInt32BE(input, 14),
width: readUInt32BE(input, 18)
})
};
export {
PSD
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const SVG: IImage;

View File

@@ -0,0 +1,92 @@
import { toUTF8String } from "./utils.js";
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 = extractorRegExps.width.exec(root);
const height = extractorRegExps.height.exec(root);
const viewbox = extractorRegExps.viewbox.exec(root);
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 = extractorRegExps.root.exec(toUTF8String(input));
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");
}
};
export {
SVG
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const TGA: IImage;

View File

@@ -0,0 +1,15 @@
import { readUInt16LE } from "./utils.js";
const TGA = {
validate(input) {
return readUInt16LE(input, 0) === 0 && readUInt16LE(input, 4) === 0;
},
calculate(input) {
return {
height: readUInt16LE(input, 14),
width: readUInt16LE(input, 12)
};
}
};
export {
TGA
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const TIFF: IImage;

View File

@@ -0,0 +1,119 @@
import { readUInt, readUInt64, toHexString, toUTF8String } from "./utils.js";
const CONSTANTS = {
TAG: {
WIDTH: 256,
HEIGHT: 257,
COMPRESSION: 259
},
TYPE: {
SHORT: 3,
LONG: 4,
LONG8: 16
},
ENTRY_SIZE: {
STANDARD: 12,
BIG: 20
},
COUNT_SIZE: {
STANDARD: 2,
BIG: 8
}
};
function readIFD(input, { isBigEndian, isBigTiff }) {
const ifdOffset = isBigTiff ? Number(readUInt64(input, 8, isBigEndian)) : readUInt(input, 32, 4, isBigEndian);
const entryCountSize = isBigTiff ? CONSTANTS.COUNT_SIZE.BIG : CONSTANTS.COUNT_SIZE.STANDARD;
return input.slice(ifdOffset + entryCountSize);
}
function readTagValue(input, type, offset, isBigEndian) {
switch (type) {
case CONSTANTS.TYPE.SHORT:
return readUInt(input, 16, offset, isBigEndian);
case CONSTANTS.TYPE.LONG:
return readUInt(input, 32, offset, isBigEndian);
case CONSTANTS.TYPE.LONG8: {
const value = Number(readUInt64(input, offset, isBigEndian));
if (value > Number.MAX_SAFE_INTEGER) {
throw new TypeError("Value too large");
}
return value;
}
default:
return 0;
}
}
function nextTag(input, isBigTiff) {
const entrySize = isBigTiff ? CONSTANTS.ENTRY_SIZE.BIG : CONSTANTS.ENTRY_SIZE.STANDARD;
if (input.length > entrySize) {
return input.slice(entrySize);
}
}
function extractTags(input, { isBigEndian, isBigTiff }) {
const tags = {};
let temp = input;
while (temp?.length) {
const code = readUInt(temp, 16, 0, isBigEndian);
const type = readUInt(temp, 16, 2, isBigEndian);
const length = isBigTiff ? Number(readUInt64(temp, 4, isBigEndian)) : readUInt(temp, 32, 4, isBigEndian);
if (code === 0) break;
if (length === 1 && (type === CONSTANTS.TYPE.SHORT || type === CONSTANTS.TYPE.LONG || isBigTiff && type === CONSTANTS.TYPE.LONG8)) {
const valueOffset = isBigTiff ? 12 : 8;
tags[code] = readTagValue(temp, type, valueOffset, isBigEndian);
}
temp = nextTag(temp, isBigTiff);
}
return tags;
}
function determineFormat(input) {
const signature = toUTF8String(input, 0, 2);
const version = readUInt(input, 16, 2, signature === "MM");
return {
isBigEndian: signature === "MM",
isBigTiff: version === 43
};
}
function validateBigTIFFHeader(input, isBigEndian) {
const byteSize = readUInt(input, 16, 4, isBigEndian);
const reserved = readUInt(input, 16, 6, isBigEndian);
if (byteSize !== 8 || reserved !== 0) {
throw new TypeError("Invalid BigTIFF header");
}
}
const signatures = /* @__PURE__ */ new Set([
"49492a00",
// Little Endian
"4d4d002a",
// Big Endian
"49492b00",
// BigTIFF Little Endian
"4d4d002b"
// BigTIFF Big Endian
]);
const TIFF = {
validate: (input) => {
const signature = toHexString(input, 0, 4);
return signatures.has(signature);
},
calculate(input) {
const format = determineFormat(input);
if (format.isBigTiff) {
validateBigTIFFHeader(input, format.isBigEndian);
}
const ifdBuffer = readIFD(input, format);
const tags = extractTags(ifdBuffer, format);
const info = {
height: tags[CONSTANTS.TAG.HEIGHT],
width: tags[CONSTANTS.TAG.WIDTH],
type: format.isBigTiff ? "bigtiff" : "tiff"
};
if (tags[CONSTANTS.TAG.COMPRESSION]) {
info.compression = tags[CONSTANTS.TAG.COMPRESSION];
}
if (!info.width || !info.height) {
throw new TypeError("Invalid Tiff. Missing tags");
}
return info;
}
};
export {
TIFF
};

View File

@@ -0,0 +1,16 @@
export declare const toUTF8String: (input: Uint8Array, start?: number, end?: number) => string;
export declare const toHexString: (input: Uint8Array, start?: number, end?: number) => string;
export declare const readInt16LE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt16BE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt16LE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt24LE: (input: Uint8Array, offset?: number) => number;
export declare const readInt32LE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt32BE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt32LE: (input: Uint8Array, offset?: number) => number;
export declare const readUInt64: (input: Uint8Array, offset: number, isBigEndian: boolean) => bigint;
export declare function readUInt(input: Uint8Array, bits: 16 | 32, offset?: number, isBigEndian?: boolean): number;
export declare function findBox(input: Uint8Array, boxName: string, currentOffset: number): {
name: string;
offset: number;
size: number;
} | undefined;

View File

@@ -0,0 +1,58 @@
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 getView = (input, offset) => new DataView(input.buffer, input.byteOffset + offset);
const readInt16LE = (input, offset = 0) => getView(input, offset).getInt16(0, true);
const readUInt16BE = (input, offset = 0) => getView(input, offset).getUint16(0, false);
const readUInt16LE = (input, offset = 0) => getView(input, offset).getUint16(0, true);
const readUInt24LE = (input, offset = 0) => {
const view = getView(input, offset);
return view.getUint16(0, true) + (view.getUint8(2) << 16);
};
const readInt32LE = (input, offset = 0) => getView(input, offset).getInt32(0, true);
const readUInt32BE = (input, offset = 0) => getView(input, offset).getUint32(0, false);
const readUInt32LE = (input, offset = 0) => getView(input, offset).getUint32(0, true);
const readUInt64 = (input, offset, isBigEndian) => getView(input, offset).getBigUint64(0, !isBigEndian);
const methods = {
readUInt16BE,
readUInt16LE,
readUInt32BE,
readUInt32LE
};
function readUInt(input, bits, offset = 0, isBigEndian = false) {
const endian = isBigEndian ? "BE" : "LE";
const methodName = `readUInt${bits}${endian}`;
return methods[methodName](input, offset);
}
function readBox(input, offset) {
if (input.length - offset < 4) return;
const boxSize = readUInt32BE(input, offset);
if (input.length - offset < boxSize) return;
return {
name: toUTF8String(input, 4 + offset, 8 + offset),
offset,
size: boxSize
};
}
function findBox(input, boxName, currentOffset) {
while (currentOffset < input.length) {
const box = readBox(input, currentOffset);
if (!box) break;
if (box.name === boxName) return box;
currentOffset += box.size > 0 ? box.size : 8;
}
}
export {
findBox,
readInt16LE,
readInt32LE,
readUInt,
readUInt16BE,
readUInt16LE,
readUInt24LE,
readUInt32BE,
readUInt32LE,
readUInt64,
toHexString,
toUTF8String
};

View File

@@ -0,0 +1,2 @@
import type { IImage } from './interface.ts';
export declare const WEBP: IImage;

View File

@@ -0,0 +1,51 @@
import { readInt16LE, readUInt24LE, toHexString, toUTF8String } from "./utils.js";
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 = "RIFF" === toUTF8String(input, 0, 4);
const webpHeader = "WEBP" === toUTF8String(input, 8, 12);
const vp8Header = "VP8" === toUTF8String(input, 12, 15);
return riffHeader && webpHeader && vp8Header;
},
calculate(_input) {
const chunkHeader = toUTF8String(_input, 12, 16);
const 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);
}
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");
}
};
export {
WEBP
};

View File

@@ -0,0 +1,10 @@
/** This class helps read Uint8Array bit-by-bit */
export declare class BitReader {
private byteOffset;
private bitOffset;
private readonly input;
private readonly endianness;
constructor(input: Uint8Array, endianness: 'big-endian' | 'little-endian');
/** Reads a specified number of bits, and move the offset */
getBits(length?: number): number;
}

View File

@@ -0,0 +1,43 @@
class BitReader {
// Skip the first 16 bits (2 bytes) of signature
byteOffset = 2;
bitOffset = 0;
input;
endianness;
constructor(input, endianness) {
this.input = input;
this.endianness = endianness;
}
/** Reads a specified number of bits, and move the offset */
getBits(length = 1) {
let result = 0;
let bitsRead = 0;
while (bitsRead < length) {
if (this.byteOffset >= this.input.length) {
throw new Error("Reached end of input");
}
const currentByte = this.input[this.byteOffset];
const bitsLeft = 8 - this.bitOffset;
const bitsToRead = Math.min(length - bitsRead, bitsLeft);
if (this.endianness === "little-endian") {
const mask = (1 << bitsToRead) - 1;
const bits = currentByte >> this.bitOffset & mask;
result |= bits << bitsRead;
} else {
const mask = (1 << bitsToRead) - 1 << 8 - this.bitOffset - bitsToRead;
const bits = (currentByte & mask) >> 8 - this.bitOffset - bitsToRead;
result = result << bitsToRead | bits;
}
bitsRead += bitsToRead;
this.bitOffset += bitsToRead;
if (this.bitOffset === 8) {
this.byteOffset++;
this.bitOffset = 0;
}
}
return result;
}
}
export {
BitReader
};