index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. 'use strict';
  2. var fs = require('fs');
  3. var path = require('path');
  4. var typeHandlers = require('./types');
  5. var detector = require('./detector');
  6. // Maximum buffer size, with a default of 512 kilobytes.
  7. // TO-DO: make this adaptive based on the initial signature of the image
  8. var MaxBufferSize = 512*1024;
  9. /**
  10. * Return size information based on a buffer
  11. *
  12. * @param {Buffer} buffer
  13. * @param {String} filepath
  14. * @returns {Object}
  15. */
  16. function lookup (buffer, filepath) {
  17. // detect the file type.. don't rely on the extension
  18. var type = detector(buffer, filepath);
  19. // find an appropriate handler for this file type
  20. if (type in typeHandlers) {
  21. var size = typeHandlers[type].calculate(buffer, filepath);
  22. if (size !== false) {
  23. size.type = type;
  24. return size;
  25. }
  26. }
  27. // throw up, if we don't understand the file
  28. throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')');
  29. }
  30. /**
  31. * Reads a file into a buffer.
  32. *
  33. * The callback will be called after the process has completed. The
  34. * callback's first argument will be an error (or null). The second argument
  35. * will be the Buffer, if the operation was successful.
  36. *
  37. * @param {String} filepath
  38. * @param {Function} callback
  39. */
  40. function asyncFileToBuffer (filepath, callback) {
  41. // open the file in read only mode
  42. fs.open(filepath, 'r', function (err, descriptor) {
  43. if (err) { return callback(err); }
  44. fs.fstat(descriptor, function (err, stats) {
  45. if (err) { return callback(err); }
  46. var size = stats.size;
  47. if (size <= 0) {
  48. return callback(new Error('File size is not greater than 0 —— ' + filepath));
  49. }
  50. var bufferSize = Math.min(size, MaxBufferSize);
  51. var buffer = new Buffer(bufferSize);
  52. // read first buffer block from the file, asynchronously
  53. fs.read(descriptor, buffer, 0, bufferSize, 0, function (err) {
  54. if (err) { return callback(err); }
  55. // close the file, we are done
  56. fs.close(descriptor, function (err) {
  57. callback(err, buffer);
  58. });
  59. });
  60. });
  61. });
  62. }
  63. /**
  64. * Synchronously reads a file into a buffer, blocking the nodejs process.
  65. *
  66. * @param {String} filepath
  67. * @returns {Buffer}
  68. */
  69. function syncFileToBuffer (filepath) {
  70. // read from the file, synchronously
  71. var descriptor = fs.openSync(filepath, 'r');
  72. var size = fs.fstatSync(descriptor).size;
  73. var bufferSize = Math.min(size, MaxBufferSize);
  74. var buffer = new Buffer(bufferSize);
  75. fs.readSync(descriptor, buffer, 0, bufferSize, 0);
  76. fs.closeSync(descriptor);
  77. return buffer;
  78. }
  79. /**
  80. * @param {Buffer|string} input - buffer or relative/absolute path of the image file
  81. * @param {Function} callback - optional function for async detection
  82. */
  83. module.exports = function (input, callback) {
  84. // Handle buffer input
  85. if (Buffer.isBuffer(input)) {
  86. return lookup(input);
  87. }
  88. // input should be a string at this point
  89. if (typeof input !== 'string') {
  90. throw new TypeError('invalid invocation');
  91. }
  92. // resolve the file path
  93. var filepath = path.resolve(input);
  94. if (typeof callback === 'function') {
  95. asyncFileToBuffer(filepath, function (err, buffer) {
  96. if (err) { return callback(err); }
  97. // return the dimensions
  98. var dimensions;
  99. try {
  100. dimensions = lookup(buffer, filepath);
  101. } catch (e) {
  102. err = e;
  103. }
  104. callback(err, dimensions);
  105. });
  106. } else {
  107. var buffer = syncFileToBuffer(filepath);
  108. return lookup(buffer, filepath);
  109. }
  110. };
  111. module.exports.types = Object.keys(typeHandlers);