epubDocument.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. const Handler = require("./documentHandler.js").DocumentHandler,
  2. assert = require("assert"),
  3. AdmZip = require("adm-zip"),
  4. Xml2js = require("xml2js"),
  5. Canvas = require("canvas"),
  6. fs = require("fs");
  7. function EpubHandler(doc) {
  8. Handler.call(this, doc);
  9. this.data = null;
  10. this.loading = null;
  11. }
  12. EpubHandler.prototype = Object.create(Handler.prototype);
  13. EpubHandler.prototype.parseFile = function() {
  14. return new Promise(async (res, rej) => {
  15. const zip = new AdmZip(this.doc.path),
  16. entries = zip.getEntries(),
  17. entriesByPath = {};
  18. entries.forEach(i => {
  19. entriesByPath[i.entryName] = i;
  20. });
  21. if (!entriesByPath["content.opf"])
  22. rej();
  23. Xml2js.parseString(entriesByPath["content.opf"].getData().toString("utf8"), ((err, result) => {
  24. if (err) {
  25. console.error("Malformed XML data in epub file", err);
  26. rej();
  27. }
  28. if (!result ||
  29. !result.package ||
  30. !result.package.manifest ||
  31. !result.package.manifest[0] ||
  32. !result.package.manifest[0].item ||
  33. !Array.isArray(result.package.manifest[0].item)) {
  34. console.error("Cannot read metadata epub file");
  35. rej();
  36. }
  37. this.data = {};
  38. for (var i =0, len = result.package.manifest[0].item.length;
  39. i < len;
  40. ++i) {
  41. var item = result.package.manifest[0].item[i]["$"];
  42. if (item && item.id === "cover") {
  43. if (!entriesByPath[item.href]) {
  44. console.error("Referenced file " +item.href +" not found");
  45. continue;
  46. }
  47. this.data.cover = entriesByPath[item.href].getData();
  48. break;
  49. }
  50. }
  51. if (!this.data.cover) {
  52. console.error("Cannot find cover");
  53. this.data = null;
  54. rej();
  55. }
  56. res(this.data);
  57. }).bind(this));
  58. });
  59. }
  60. EpubHandler.prototype.loadDocument = function() {
  61. return new Promise(((res, rej) => {
  62. if (this.data) {
  63. res(this.data);
  64. } else {
  65. if (this.loading)
  66. this.loading = this.loading.then((() => res(this.data)).bind(this));
  67. else
  68. this.loading = this.parseFile().then(doc => res(this.data));
  69. }
  70. }).bind(this));
  71. }
  72. EpubHandler.prototype.getPageCount = function() {
  73. return new Promise((res, rej) => res(null));
  74. };
  75. EpubHandler.prototype.getThumbmailViewport = function(fullWidth, fullHeight) {
  76. const maxSize = require("../config").thumbmailMaxSize;
  77. var ratio = Math.min(maxSize /fullHeight, maxSize /fullWidth);
  78. return {
  79. height: ratio *fullHeight,
  80. width: ratio *fullWidth
  81. };
  82. };
  83. EpubHandler.prototype.getCover = function() {
  84. return new Promise(async (res, rej) => {
  85. const data = await this.loadDocument(),
  86. image = new Canvas.Image();
  87. image.src = data.cover;
  88. const size = this.getThumbmailViewport(image.width, image.height),
  89. canvas = Canvas.createCanvas(size.width, size.height),
  90. ctx = canvas.getContext('2d');
  91. ctx.drawImage(image, 0, 0, size.width, size.height);
  92. canvas.toBuffer((err, buf) => res(buf), "image/png");
  93. });
  94. };
  95. EpubHandler.prototype.getPngPage = function(page, isThumbmail) {
  96. return new Promise((res, rej) => res(null));
  97. };
  98. module.exports.EpubHandler = EpubHandler;