FileConverter.js 2.1 KB

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