screenshotHandler.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. var debug = require('debug')('ylt:screenshotHandler');
  2. var Jimp = require('jimp');
  3. var Q = require('q');
  4. var fs = require('fs');
  5. var path = require('path');
  6. var screenshotHandler = function() {
  7. var tmpFolderPath = 'tmp';
  8. var tmpFolderFullPath = path.join(__dirname, '..', tmpFolderPath);
  9. var tmpFileName = 'temp-screenshot.png';
  10. var tmpFileFullPath = path.join(tmpFolderFullPath, tmpFileName);
  11. this.findAndOptimizeScreenshot = function(width) {
  12. var that = this;
  13. debug('Starting screenshot transformation');
  14. return this.openImage(tmpFileFullPath)
  15. .then(function(image) {
  16. that.deleteTmpFile(tmpFileFullPath);
  17. return that.resizeImage(image, width);
  18. })
  19. .then(this.addWhiteBackground)
  20. .then(this.toBuffer);
  21. };
  22. this.openImage = function(imagePath) {
  23. var deferred = Q.defer();
  24. Jimp.read(imagePath, function(err, image){
  25. if (err) {
  26. debug('Could not open imagePath %s', imagePath);
  27. debug(err);
  28. deferred.reject(err);
  29. } else {
  30. debug('Image correctly open');
  31. deferred.resolve(image);
  32. }
  33. });
  34. return deferred.promise;
  35. };
  36. this.resizeImage = function(image, newWidth) {
  37. var deferred = Q.defer();
  38. var currentWidth = image.bitmap.width;
  39. if (currentWidth > 0) {
  40. var ratio = newWidth / currentWidth;
  41. image.scale(ratio, function(err, image){
  42. if (err) {
  43. debug('Could not resize image');
  44. debug(err);
  45. deferred.reject(err);
  46. } else {
  47. debug('Image correctly resized');
  48. deferred.resolve(image);
  49. }
  50. });
  51. } else {
  52. deferred.reject('Could not resize an empty image');
  53. }
  54. return deferred.promise;
  55. };
  56. // If the page doesn't set a bg color, the default PhantomJS one is transparent
  57. // When transforming PNG to JPG, transparent pixels become black.
  58. // This is why we need to add a transparent background.
  59. this.addWhiteBackground = function(image) {
  60. var deferred = Q.defer();
  61. // Create a canvas with the same dimensions as your image:
  62. new Jimp(image.bitmap.width, image.bitmap.height, 0xFFFFFF, function(err, canvas){
  63. if (err) {
  64. debug('Could not create a white canvas');
  65. debug(err);
  66. deferred.reject(err);
  67. } else {
  68. // Paste original image on top of the canvas
  69. canvas.composite(image, 0, 0, function(err, image){
  70. if (err) {
  71. debug('Could not paste image on the white canvas');
  72. debug(err);
  73. deferred.reject(err);
  74. } else {
  75. // Now image has a white background...
  76. debug('White background correctly added');
  77. deferred.resolve(image);
  78. }
  79. });
  80. }
  81. });
  82. return deferred.promise;
  83. };
  84. this.toBuffer = function(image) {
  85. var deferred = Q.defer();
  86. image.quality(90).getBuffer(Jimp.MIME_JPEG, function(err, buffer){
  87. if (err) {
  88. debug('Could not save image to buffer');
  89. debug(err);
  90. deferred.reject(err);
  91. } else {
  92. debug('Image correctly transformed to buffer');
  93. deferred.resolve(buffer);
  94. }
  95. });
  96. return deferred.promise;
  97. };
  98. this.deleteTmpFile = function(tmpFilePath) {
  99. var deferred = Q.defer();
  100. fs.unlink(tmpFilePath, function (err) {
  101. if (err) {
  102. debug('Screenshot temporary file not found, could not be deleted. But it is not a problem.');
  103. } else {
  104. debug('Screenshot temporary file deleted.');
  105. }
  106. deferred.resolve();
  107. });
  108. return deferred.promise;
  109. };
  110. // Create a /tmp folder on the project's root directory
  111. this.createTmpScreenshotFolder = function() {
  112. var deferred = Q.defer();
  113. // Create the folder if it doesn't exist
  114. fs.exists(tmpFolderFullPath, function(exists) {
  115. if (exists) {
  116. deferred.resolve();
  117. } else {
  118. debug('Creating the tmp image folder', tmpFolderFullPath);
  119. fs.mkdir(tmpFolderFullPath, function(err) {
  120. if (err) {
  121. deferred.reject(err);
  122. } else {
  123. deferred.resolve();
  124. }
  125. });
  126. }
  127. });
  128. return deferred.promise;
  129. };
  130. this.getTmpFileRelativePath = function() {
  131. return tmpFolderPath + '/' + tmpFileName;
  132. };
  133. };
  134. module.exports = new screenshotHandler();