diff --git a/core.js b/core.js index 8a4ae73b..e060be2e 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,94 @@ async function _fromTokenizer(tokenizer) { }; } + async function readTiffTag(bigEndian) { + const tagId = await tokenizer.readToken(bigEndian ? Token.UINT16_BE : Token.UINT16_LE); + tokenizer.ignore(10); + switch (tagId) { + case 50_341: + return { + ext: 'arw', + mime: 'image/x-sony-arw', + }; + case 50_706: + return { + ext: 'dng', + mime: 'image/x-adobe-dng', + }; + default: + } + } + + async function readTiffIFD(bigEndian) { + const numberOfTags = await tokenizer.readToken(bigEndian ? Token.UINT16_BE : Token.UINT16_LE); + for (let n = 0; n < numberOfTags; ++n) { + const fileType = await readTiffTag(bigEndian); + if (fileType) { + return fileType; + } + } + } + // TIFF, little-endian type - if (check([0x49, 0x49, 0x2A, 0x0])) { - if (checkString('CR', {offset: 8})) { - return { - ext: 'cr2', - mime: 'image/x-canon-cr2', + 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.UINT32_LE.get(buffer, 4); + await tokenizer.ignore(ifdOffset); + const fileType = await readTiffIFD(false); + return fileType ? fileType : { + ext: 'tif', + mime: 'image/tiff', }; } - if (check([0x1C, 0x00, 0xFE, 0x00], {offset: 8}) || check([0x1F, 0x00, 0x0B, 0x00], {offset: 8})) { + if (version === 43) { + // Big TIFF file header return { - ext: 'nef', - mime: 'image/x-nikon-nef', + ext: 'tif', + mime: 'image/tiff', }; } + } - 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, big-endian type + if (check([0x4D, 0x4D])) { + const version = Token.UINT16_BE.get(buffer, 2); + + if (version === 42) { + const ifdOffset = Token.UINT32_BE.get(buffer, 4); + await tokenizer.ignore(ifdOffset); + const fileType = await readTiffIFD(true); + 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 ')) { diff --git a/fixture/fixture-Leica-M10.dng b/fixture/fixture-Leica-M10.dng new file mode 100644 index 00000000..b2d13c79 Binary files /dev/null and b/fixture/fixture-Leica-M10.dng differ diff --git a/fixture/fixture-sony-zv-e10.arw b/fixture/fixture-sony-zv-e10.arw new file mode 100644 index 00000000..fab4fafd Binary files /dev/null and b/fixture/fixture-sony-zv-e10.arw differ diff --git a/fixture/fixture.arw b/fixture/fixture.arw deleted file mode 100644 index d4a4fb75..00000000 Binary files a/fixture/fixture.arw and /dev/null differ diff --git a/fixture/fixture.dng b/fixture/fixture.dng deleted file mode 100755 index 4c1d2115..00000000 Binary files a/fixture/fixture.dng and /dev/null differ diff --git a/fixture/fixture2.arw b/fixture/fixture2.arw deleted file mode 100644 index dce68885..00000000 Binary files a/fixture/fixture2.arw and /dev/null differ diff --git a/fixture/fixture2.dng b/fixture/fixture2.dng deleted file mode 100644 index 36f4d4bd..00000000 Binary files a/fixture/fixture2.dng and /dev/null differ diff --git a/fixture/fixture3.arw b/fixture/fixture3.arw deleted file mode 100644 index b408d4eb..00000000 Binary files a/fixture/fixture3.arw and /dev/null differ diff --git a/fixture/fixture4.arw b/fixture/fixture4.arw deleted file mode 100644 index b5ed4981..00000000 Binary files a/fixture/fixture4.arw and /dev/null differ diff --git a/fixture/fixture5.arw b/fixture/fixture5.arw deleted file mode 100644 index 095a142c..00000000 Binary files a/fixture/fixture5.arw and /dev/null differ diff --git a/test.js b/test.js index be7d95de..2cddb270 100644 --- a/test.js +++ b/test.js @@ -35,18 +35,13 @@ const names = { 'fixture2', ], arw: [ - 'fixture', - 'fixture2', - 'fixture3', - 'fixture4', - 'fixture5', + 'fixture-sony-zv-e10', ], cr3: [ 'fixture', ], dng: [ - 'fixture', - 'fixture2', + 'fixture-Leica-M10', ], nef: [ 'fixture',