FileConverter.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. const metrics = require('metrics-sharelatex')
  2. const logger = require('logger-sharelatex')
  3. const Settings = require('settings-sharelatex')
  4. const { callbackify } = require('util')
  5. const safeExec = require('./SafeExec').promises
  6. const { ConversionError } = require('./Errors')
  7. const APPROVED_FORMATS = ['png']
  8. const FOURTY_SECONDS = 40 * 1000
  9. const KILL_SIGNAL = 'SIGTERM'
  10. module.exports = {
  11. convert: callbackify(convert),
  12. thumbnail: callbackify(thumbnail),
  13. preview: callbackify(preview),
  14. promises: {
  15. convert,
  16. thumbnail,
  17. preview
  18. }
  19. }
  20. async function convert(sourcePath, requestedFormat) {
  21. const width = '600x'
  22. return _convert(sourcePath, requestedFormat, [
  23. 'convert',
  24. '-define',
  25. `pdf:fit-page=${width}`,
  26. '-flatten',
  27. '-density',
  28. '300',
  29. `${sourcePath}[0]`
  30. ])
  31. }
  32. async function thumbnail(sourcePath) {
  33. const width = '260x'
  34. return convert(sourcePath, 'png', [
  35. 'convert',
  36. '-flatten',
  37. '-background',
  38. 'white',
  39. '-density',
  40. '300',
  41. '-define',
  42. `pdf:fit-page=${width}`,
  43. `${sourcePath}[0]`,
  44. '-resize',
  45. width
  46. ])
  47. }
  48. async function preview(sourcePath) {
  49. const width = '548x'
  50. return convert(sourcePath, 'png', [
  51. 'convert',
  52. '-flatten',
  53. '-background',
  54. 'white',
  55. '-density',
  56. '300',
  57. '-define',
  58. `pdf:fit-page=${width}`,
  59. `${sourcePath}[0]`,
  60. '-resize',
  61. width
  62. ])
  63. }
  64. async function _convert(sourcePath, requestedFormat, command) {
  65. logger.log({ sourcePath, requestedFormat }, 'converting file format')
  66. if (!APPROVED_FORMATS.includes(requestedFormat)) {
  67. throw new ConversionError({
  68. message: 'invalid format requested',
  69. info: { format: requestedFormat }
  70. })
  71. }
  72. const timer = new metrics.Timer('imageConvert')
  73. const destPath = `${sourcePath}.${requestedFormat}`
  74. command.push(destPath)
  75. command = Settings.commands.convertCommandPrefix.concat(command)
  76. try {
  77. await safeExec(command, {
  78. killSignal: KILL_SIGNAL,
  79. timeout: FOURTY_SECONDS
  80. })
  81. } catch (err) {
  82. throw new ConversionError({
  83. message: 'something went wrong converting file',
  84. info: { stderr: err.stderr, sourcePath, requestedFormat, destPath }
  85. }).withCause(err)
  86. }
  87. timer.done()
  88. logger.log(
  89. { sourcePath, requestedFormat, destPath },
  90. 'finished converting file'
  91. )
  92. return destPath
  93. }