const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
export function detectSupportedImageMimeType(buffer) {
    if (startsWith(buffer, [0xff, 0xd8, 0xff]))
        return buffer[3] === 0xf7 ? undefined : "image/jpeg";
    if (startsWith(buffer, PNG_SIGNATURE))
        return isPng(buffer) && !isAnimatedPng(buffer) ? "image/png" : undefined;
    if (startsWithAscii(buffer, 0, "GIF"))
        return "image/gif";
    if (startsWithAscii(buffer, 0, "RIFF") && startsWithAscii(buffer, 8, "WEBP"))
        return "image/webp";
    if (startsWithAscii(buffer, 0, "BM") && isBmp(buffer))
        return "image/bmp";
    return undefined;
}
export function encodeBase64(bytes) {
    const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    let output = "";
    for (let index = 0; index < bytes.length; index += 3) {
        const first = bytes[index] ?? 0;
        const second = bytes[index + 1];
        const third = bytes[index + 2];
        output += alphabet[first >> 2];
        output += alphabet[((first & 0x03) << 4) | ((second ?? 0) >> 4)];
        output += second === undefined ? "=" : alphabet[((second & 0x0f) << 2) | ((third ?? 0) >> 6)];
        output += third === undefined ? "=" : alphabet[third & 0x3f];
    }
    return output;
}
function isPng(buffer) {
    return (buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, "IHDR"));
}
function isAnimatedPng(buffer) {
    let offset = PNG_SIGNATURE.length;
    while (offset + 8 <= buffer.length) {
        const chunkLength = readUint32BE(buffer, offset);
        const chunkTypeOffset = offset + 4;
        if (startsWithAscii(buffer, chunkTypeOffset, "acTL"))
            return true;
        if (startsWithAscii(buffer, chunkTypeOffset, "IDAT"))
            return false;
        const nextOffset = offset + 8 + chunkLength + 4;
        if (nextOffset <= offset || nextOffset > buffer.length)
            return false;
        offset = nextOffset;
    }
    return false;
}
function isBmp(buffer) {
    if (buffer.length < 26)
        return false;
    const declaredFileSize = readUint32LE(buffer, 2);
    const pixelDataOffset = readUint32LE(buffer, 10);
    const dibHeaderSize = readUint32LE(buffer, 14);
    if (declaredFileSize !== 0 && declaredFileSize < 26)
        return false;
    if (pixelDataOffset < 14 + dibHeaderSize)
        return false;
    if (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize)
        return false;
    let colorPlanes;
    let bitsPerPixel;
    if (dibHeaderSize === 12) {
        colorPlanes = readUint16LE(buffer, 22);
        bitsPerPixel = readUint16LE(buffer, 24);
    }
    else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {
        if (buffer.length < 30)
            return false;
        colorPlanes = readUint16LE(buffer, 26);
        bitsPerPixel = readUint16LE(buffer, 28);
    }
    else {
        return false;
    }
    return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);
}
function readUint16LE(buffer, offset) {
    return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);
}
function readUint32BE(buffer, offset) {
    return ((buffer[offset] ?? 0) * 0x1000000 +
        ((buffer[offset + 1] ?? 0) << 16) +
        ((buffer[offset + 2] ?? 0) << 8) +
        (buffer[offset + 3] ?? 0));
}
function readUint32LE(buffer, offset) {
    return ((buffer[offset] ?? 0) +
        ((buffer[offset + 1] ?? 0) << 8) +
        ((buffer[offset + 2] ?? 0) << 16) +
        (buffer[offset + 3] ?? 0) * 0x1000000);
}
function startsWith(buffer, bytes) {
    if (buffer.length < bytes.length)
        return false;
    return bytes.every((byte, index) => buffer[index] === byte);
}
function startsWithAscii(buffer, offset, text) {
    if (buffer.length < offset + text.length)
        return false;
    for (let index = 0; index < text.length; index++) {
        if (buffer[offset + index] !== text.charCodeAt(index))
            return false;
    }
    return true;
}
//# sourceMappingURL=image.js.map