1
0
Fork 0
mirror of https://github.com/codedread/bitjs synced 2025-10-05 02:19:24 +02:00

Move EXIF profile extraction from jpeg.js into exif.js

This commit is contained in:
Jeff Schiller 2024-01-18 21:00:11 -08:00
parent 17b3850745
commit 29ca69e874
2 changed files with 75 additions and 66 deletions

View file

@ -223,6 +223,78 @@ export function getExifValue(stream, lookAheadStream, DEBUG = false) {
return exifValue;
}
/**
* Reads an Image File Directory from stream, populating the map.
* @param {ByteStream} stream The stream to extract the Exif value descriptors.
* @param {ByteStream} lookAheadStream The lookahead stream if the offset is used.
* @param {Map<number, ExifValue} exifValueMap This map to add the Exif values.
* @returns {number} The next IFD offset.
*/
function getExifIfd(stream, lookAheadStream, exifValueMap) {
let exifOffsetStream;
const numDirectoryEntries = stream.readNumber(2);
for (let entry = 0; entry < numDirectoryEntries; ++entry) {
const exifValue = getExifValue(stream, lookAheadStream);
const exifTagNumber = exifValue.tagNumber;
exifValueMap.set(exifTagNumber, exifValue);
if (exifValue.tagNumber === ExifTagNumber.EXIF_OFFSET) {
exifOffsetStream = lookAheadStream.tee().skip(exifValue.numericalValue);
}
} // Loop over Directory Entries.
if (exifOffsetStream) {
getExifIfd(exifOffsetStream, lookAheadStream, exifValueMap);
}
const nextIfdOffset = stream.readNumber(4);
return nextIfdOffset;
}
/**
* Reads the entire EXIF profile. The first 2 bytes in the stream must be the TIFF marker (II/MM).
* @param {ByteStream} stream
* @returns {Map<number, ExifValue} A map of all EXIF values found. The key is the EXIF tag number.
*/
export function getExifProfile(stream) {
const lookAheadStream = stream.tee();
const tiffByteAlign = stream.readString(2);
if (tiffByteAlign === 'II') {
stream.setLittleEndian();
lookAheadStream.setLittleEndian();
} else if (tiffByteAlign === 'MM') {
stream.setBigEndian();
lookAheadStream.setBigEndian();
} else {
throw `Invalid TIFF byte align symbol: ${tiffByteAlign}`;
}
const tiffMarker = stream.readNumber(2);
if (tiffMarker !== 0x002A) {
throw `Invalid marker, not 0x002a: 0x${tiffMarker.toString(16)}`;
}
/** @type {Map<number, ExifValue} */
const exifValueMap = new Map();
// The offset includes the tiffByteAlign (2), marker (2), and the offset field itself (4).
// It is usually 0x00000008, which means ifdOffsetSkip will almost always be zero.
const ifdOffsetSkip = stream.readNumber(4) - 8;
let ifdStream = stream.skip(ifdOffsetSkip).tee();
let nextIfdOffset;
while (true) {
nextIfdOffset = getExifIfd(ifdStream, lookAheadStream, exifValueMap);
// No more IFDs, so stop the loop.
if (nextIfdOffset === 0) break;
// Else, we have another IFD to read, point the stream at it.
ifdStream = lookAheadStream.tee().skip(nextIfdOffset);
}
return exifValueMap;
}
/**
* @param {Object} obj A numeric enum.
* @param {number} valToFind The value to find.