tiff.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use strict';
  2. // based on http://www.compix.com/fileformattif.htm
  3. // TO-DO: support big-endian as well
  4. var fs = require('fs');
  5. var readUInt = require('../readUInt');
  6. function isTIFF (buffer) {
  7. var hex4 = buffer.toString('hex', 0, 4);
  8. return ('49492a00' === hex4 || '4d4d002a' === hex4);
  9. }
  10. // Read IFD (image-file-directory) into a buffer
  11. function readIFD (buffer, filepath, isBigEndian) {
  12. var ifdOffset = readUInt(buffer, 32, 4, isBigEndian);
  13. // read only till the end of the file
  14. var bufferSize = 1024;
  15. var fileSize = fs.statSync(filepath).size;
  16. if (ifdOffset + bufferSize > fileSize) {
  17. bufferSize = fileSize - ifdOffset - 10;
  18. }
  19. // populate the buffer
  20. var endBuffer = new Buffer(bufferSize);
  21. var descriptor = fs.openSync(filepath, 'r');
  22. fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset);
  23. // var ifdLength = readUInt(endBuffer, 16, 0, isBigEndian);
  24. var ifdBuffer = endBuffer.slice(2); //, 2 + 12 * ifdLength);
  25. return ifdBuffer;
  26. }
  27. // TIFF values seem to be messed up on Big-Endian, this helps
  28. function readValue (buffer, isBigEndian) {
  29. var low = readUInt(buffer, 16, 8, isBigEndian);
  30. var high = readUInt(buffer, 16, 10, isBigEndian);
  31. return (high << 16) + low;
  32. }
  33. // move to the next tag
  34. function nextTag (buffer) {
  35. if (buffer.length > 24) {
  36. return buffer.slice(12);
  37. }
  38. }
  39. // Extract IFD tags from TIFF metadata
  40. function extractTags (buffer, isBigEndian) {
  41. var tags = {};
  42. var code, type, length;
  43. while (buffer && buffer.length) {
  44. code = readUInt(buffer, 16, 0, isBigEndian);
  45. type = readUInt(buffer, 16, 2, isBigEndian);
  46. length = readUInt(buffer, 32, 4, isBigEndian);
  47. // 0 means end of IFD
  48. if (code === 0) {
  49. break;
  50. } else {
  51. // 256 is width, 257 is height
  52. // if (code === 256 || code === 257) {
  53. if (length === 1 && (type === 3 || type === 4)) {
  54. tags[code] = readValue(buffer, isBigEndian);
  55. }
  56. // move to the next tag
  57. buffer = nextTag(buffer);
  58. }
  59. }
  60. return tags;
  61. }
  62. // Test if the TIFF is Big Endian or Little Endian
  63. function determineEndianness (buffer) {
  64. var signature = buffer.toString('ascii', 0, 2);
  65. if ('II' === signature) {
  66. return 'LE';
  67. } else if ('MM' === signature) {
  68. return 'BE';
  69. }
  70. }
  71. function calculate (buffer, filepath) {
  72. if (!filepath) {
  73. throw new TypeError('Tiff doesn\'t support buffer');
  74. }
  75. // Determine BE/LE
  76. var isBigEndian = determineEndianness(buffer) === 'BE';
  77. // read the IFD
  78. var ifdBuffer = readIFD(buffer, filepath, isBigEndian);
  79. // extract the tags from the IFD
  80. var tags = extractTags(ifdBuffer, isBigEndian);
  81. var width = tags[256];
  82. var height = tags[257];
  83. if (!width || !height) {
  84. throw new TypeError('Invalid Tiff, missing tags');
  85. }
  86. return {
  87. 'width': width,
  88. 'height': height
  89. };
  90. }
  91. module.exports = {
  92. 'detect': isTIFF,
  93. 'calculate': calculate
  94. };