67 lines
1.8 KiB
Plaintext
67 lines
1.8 KiB
Plaintext
import { readUInt, toHexString, toUTF8String } from "./utils.js";
|
|
function readIFD(input, isBigEndian) {
|
|
const ifdOffset = readUInt(input, 32, 4, isBigEndian);
|
|
return input.slice(ifdOffset + 2);
|
|
}
|
|
function readValue(input, isBigEndian) {
|
|
const low = readUInt(input, 16, 8, isBigEndian);
|
|
const high = readUInt(input, 16, 10, isBigEndian);
|
|
return (high << 16) + low;
|
|
}
|
|
function nextTag(input) {
|
|
if (input.length > 24) {
|
|
return input.slice(12);
|
|
}
|
|
}
|
|
function extractTags(input, isBigEndian) {
|
|
const tags = {};
|
|
let temp = input;
|
|
while (temp && temp.length) {
|
|
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 ("II" === signature) {
|
|
return "LE";
|
|
} else if ("MM" === signature) {
|
|
return "BE";
|
|
}
|
|
}
|
|
const signatures = [
|
|
// '492049', // currently not supported
|
|
"49492a00",
|
|
// Little endian
|
|
"4d4d002a"
|
|
// Big Endian
|
|
// '4d4d002a', // BigTIFF > 4GB. currently not supported
|
|
];
|
|
const TIFF = {
|
|
validate: (input) => signatures.includes(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 };
|
|
}
|
|
};
|
|
export {
|
|
TIFF
|
|
};
|