server.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. const fs = require('fs')
  2. const asfs = require('asfs')
  3. const express = require('express')
  4. const multer = require('multer')
  5. const childProcess = require('child_process')
  6. const bodyParser = require('body-parser')
  7. const pdf2htmlexPath = `${__dirname}/node_modules/@alancnet/pdf2htmlex/bin-win/pdf2htmlEX.exe`
  8. const puppeteer = require('puppeteer')
  9. const uuid = require('uuid')
  10. const parseDataUrl = require('data-urls')
  11. const cors = require('cors')
  12. const path = require('path')
  13. const chromePromise = puppeteer.launch()
  14. const upload = multer({
  15. dest: 'temp/'
  16. })
  17. const app = express()
  18. app.use(cors({
  19. origin: '*'
  20. }))
  21. app.use(bodyParser.urlencoded({extended: false, limit: '100mb'}))
  22. app.use(express.static('./public'))
  23. app.post('/edit', upload.single('document'), async (req, res) => {
  24. let pdfFile, htmlFile
  25. if (req.file) {
  26. pdfFile = req.file.path
  27. htmlFile = `${req.file.path}.html`
  28. } else if (req.body.url) {
  29. pdfFile = `temp/${uuid()}.pdf`
  30. htmlFile = `${pdfFile}.html`
  31. const pdf = parseDataUrl(req.body.url)
  32. await asfs.writeFileAsync(pdfFile, pdf.body)
  33. }
  34. /*
  35. Executes pdf2htmlex[.exe] with:
  36. - 200 horizontal and vertical DPI
  37. - TrueType Font format (because woff does not render in PhantomJS)
  38. - No DRM, overriding any PDF settings forbidding copying or modifying
  39. - The path to the source PDF file
  40. - The path to the output HTML file
  41. */
  42. childProcess.exec(`"${pdf2htmlexPath}" --hdpi 200 --vdpi 200 --font-format ttf --no-drm 1 "${pdfFile}" "${htmlFile}"`, (err, stdout, stderr) => {
  43. if (err) {
  44. res.status(500).send(`<pre>${stderr}</pre>`)
  45. } else {
  46. fs.readFile('public/edit.html', (err, editHtml) => {
  47. fs.readFile(htmlFile, 'utf8', async (err, data) => {
  48. if (err) {
  49. res.status(500).send(`<pre>${err}</pre>`)
  50. } else {
  51. res.status(200).send(data.replace('</body>', `${editHtml}</body>`))
  52. }
  53. await asfs.unlinkAsync(htmlFile)
  54. await asfs.unlinkAsync(pdfFile)
  55. })
  56. })
  57. }
  58. })
  59. })
  60. app.post('/save', (req, res) => {
  61. const tmpUuid = uuid()
  62. const htmlFile = `temp/${tmpUuid}.html`
  63. const htmlUrl = `file://${path.join(process.cwd(), htmlFile)}`
  64. const pdfFile = `temp/${tmpUuid}.pdf`
  65. const pageWidth = /\.w0{width:([\d\.]*)pt/.exec(req.body.html)[1]
  66. const pageHeight = /\.h0{height:([\d\.]*)pt/.exec(req.body.html)[1]
  67. fs.writeFile(htmlFile, req.body.html, 'utf8', async (err) => {
  68. const chrome = await chromePromise
  69. const page = await chrome.newPage()
  70. await page.goto(htmlUrl)
  71. await page.pdf({
  72. path: pdfFile,
  73. preferCSSPageSize: true
  74. })
  75. await page.close()
  76. res.download(pdfFile, 'todo-preserve-filename.pdf', async (err) => {
  77. if (err) {
  78. console.error(err)
  79. res.status(500).send(err)
  80. }
  81. await asfs.unlinkAsync(htmlFile)
  82. await asfs.unlinkAsync(pdfFile)
  83. })
  84. })
  85. })
  86. app.listen(process.env.PORT || 3000)