| 'use strict'; | 
|   | 
| // based on http://www.compix.com/fileformattif.htm | 
| // TO-DO: support big-endian as well | 
|   | 
| var fs = require('fs'); | 
| var readUInt = require('../readUInt'); | 
|   | 
| function isTIFF (buffer) { | 
|   var hex4 = buffer.toString('hex', 0, 4); | 
|   return ('49492a00' === hex4 || '4d4d002a' === hex4); | 
| } | 
|   | 
| // Read IFD (image-file-directory) into a buffer | 
| function readIFD (buffer, filepath, isBigEndian) { | 
|   | 
|   var ifdOffset = readUInt(buffer, 32, 4, isBigEndian); | 
|   | 
|   // read only till the end of the file | 
|   var bufferSize = 1024; | 
|   var fileSize = fs.statSync(filepath).size; | 
|   if (ifdOffset + bufferSize > fileSize) { | 
|     bufferSize = fileSize - ifdOffset - 10; | 
|   } | 
|   | 
|   // populate the buffer | 
|   var endBuffer = new Buffer(bufferSize); | 
|   var descriptor = fs.openSync(filepath, 'r'); | 
|   fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset); | 
|   | 
|   // var ifdLength = readUInt(endBuffer, 16, 0, isBigEndian); | 
|   var ifdBuffer = endBuffer.slice(2); //, 2 + 12 * ifdLength); | 
|   return ifdBuffer; | 
| } | 
|   | 
| // TIFF values seem to be messed up on Big-Endian, this helps | 
| function readValue (buffer, isBigEndian) { | 
|   var low = readUInt(buffer, 16, 8, isBigEndian); | 
|   var high = readUInt(buffer, 16, 10, isBigEndian); | 
|   return (high << 16) + low; | 
| } | 
|   | 
| // move to the next tag | 
| function nextTag (buffer) { | 
|   if (buffer.length > 24) { | 
|     return buffer.slice(12); | 
|   } | 
| } | 
|   | 
| // Extract IFD tags from TIFF metadata | 
| function extractTags (buffer, isBigEndian) { | 
|   var tags = {}; | 
|   var code, type, length; | 
|   | 
|   while (buffer && buffer.length) { | 
|     code = readUInt(buffer, 16, 0, isBigEndian); | 
|     type = readUInt(buffer, 16, 2, isBigEndian); | 
|     length = readUInt(buffer, 32, 4, isBigEndian); | 
|   | 
|     // 0 means end of IFD | 
|     if (code === 0) { | 
|       break; | 
|     } else { | 
|       // 256 is width, 257 is height | 
|       // if (code === 256 || code === 257) { | 
|       if (length === 1 && (type === 3 || type === 4)) { | 
|         tags[code] = readValue(buffer, isBigEndian); | 
|       } | 
|   | 
|       // move to the next tag | 
|       buffer = nextTag(buffer); | 
|     } | 
|   } | 
|   return tags; | 
| } | 
|   | 
| // Test if the TIFF is Big Endian or Little Endian | 
| function determineEndianness (buffer) { | 
|   var signature = buffer.toString('ascii', 0, 2); | 
|   if ('II' === signature) { | 
|     return 'LE'; | 
|   } else if ('MM' === signature) { | 
|     return 'BE'; | 
|   } | 
| } | 
|   | 
| function calculate (buffer, filepath) { | 
|   | 
|   if (!filepath) { | 
|     throw new TypeError('Tiff doesn\'t support buffer'); | 
|   } | 
|   | 
|   // Determine BE/LE | 
|   var isBigEndian = determineEndianness(buffer) === 'BE'; | 
|   | 
|   // read the IFD | 
|   var ifdBuffer = readIFD(buffer, filepath, isBigEndian); | 
|   | 
|   // extract the tags from the IFD | 
|   var tags = extractTags(ifdBuffer, isBigEndian); | 
|   | 
|   var width = tags[256]; | 
|   var height = tags[257]; | 
|   | 
|   if (!width || !height) { | 
|     throw new TypeError('Invalid Tiff, missing tags'); | 
|   } | 
|   | 
|   return { | 
|     'width': width, | 
|     'height': height | 
|   }; | 
| } | 
|   | 
| module.exports = { | 
|   'detect': isTIFF, | 
|   'calculate': calculate | 
| }; |