diff --git a/core.js b/core.js index 8a4ae73b..07674880 100644 --- a/core.js +++ b/core.js @@ -68,7 +68,7 @@ export async function fileTypeFromTokenizer(tokenizer) { } async function _fromTokenizer(tokenizer) { - let buffer = Buffer.alloc(minimumBytes); + const buffer = Buffer.alloc(minimumBytes); const bytesRead = 12; const check = (header, options) => _check(buffer, header, options); const checkString = (header, options) => check(stringToBytes(header), options); @@ -617,58 +617,65 @@ async function _fromTokenizer(tokenizer) { }; } - // TIFF, little-endian type - if (check([0x49, 0x49, 0x2A, 0x0])) { - if (checkString('CR', {offset: 8})) { + async function readTiffTag() { + const tagId = await tokenizer.readToken(Token.UINT16_LE); + await tokenizer.readToken(Token.UINT16_LE); // Tag data + await tokenizer.readToken(Token.UINT32_LE); // Nr of values + if (tagId === 50_706) { // Tag = DNGVersion return { - ext: 'cr2', - mime: 'image/x-canon-cr2', + ext: 'dng', + mime: 'image/x-adobe-dng', }; } + } - if (check([0x1C, 0x00, 0xFE, 0x00], {offset: 8}) || check([0x1F, 0x00, 0x0B, 0x00], {offset: 8})) { - return { - ext: 'nef', - mime: 'image/x-nikon-nef', - }; + async function readTiffIFD() { + const numberOfTags = await tokenizer.readToken(Token.UINT16_LE); + for (let n = 0; n < numberOfTags; ++n) { + const fileType = await readTiffTag(); + if (fileType) { + return fileType; + } } + } - if ( - check([0x08, 0x00, 0x00, 0x00], {offset: 4}) - && (check([0x2D, 0x00, 0xFE, 0x00], {offset: 8}) - || check([0x27, 0x00, 0xFE, 0x00], {offset: 8})) - ) { - return { - ext: 'dng', - mime: 'image/x-adobe-dng', + // TIFF, little-endian type + if (check([0x49, 0x49])) { + const version = Token.UINT16_LE.get(buffer, 2); + + if (version === 42) { + // TIFF file header + + if (checkString('CR', {offset: 8})) { + return { + ext: 'cr2', + mime: 'image/x-canon-cr2', + }; + } + + if (check([0x1C, 0x00, 0xFE, 0x00], {offset: 8}) || check([0x1F, 0x00, 0x0B, 0x00], {offset: 8})) { + return { + ext: 'nef', + mime: 'image/x-nikon-nef', + }; + } + + const ifdOffset = Token.UINT16_LE.get(buffer, 4); + await tokenizer.ignore(ifdOffset); + const fileType = await readTiffIFD(); + return fileType ? fileType : { + ext: 'tif', + mime: 'image/tiff', }; } - buffer = Buffer.alloc(24); - await tokenizer.peekBuffer(buffer); - if ( - (check([0x10, 0xFB, 0x86, 0x01], {offset: 4}) || check([0x08, 0x00, 0x00, 0x00], {offset: 4})) - // This pattern differentiates ARW from other TIFF-ish file types: - && check([0x00, 0xFE, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01], {offset: 9}) - ) { + if (version === 43) { + // Big TIFF file header return { - ext: 'arw', - mime: 'image/x-sony-arw', + ext: 'tif', + mime: 'image/tiff', }; } - - return { - ext: 'tif', - mime: 'image/tiff', - }; - } - - // TIFF, big-endian type - if (check([0x4D, 0x4D, 0x0, 0x2A])) { - return { - ext: 'tif', - mime: 'image/tiff', - }; } if (checkString('MAC ')) {