diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue index 07c93487..ea0f12e1 100644 --- a/client/components/Reader/Reader.vue +++ b/client/components/Reader/Reader.vue @@ -319,6 +319,8 @@ class Reader extends Vue { this.showNeedUpdateNotify = settings.showNeedUpdateNotify; this.splitToPara = settings.splitToPara; this.djvuQuality = settings.djvuQuality; + this.pdfAsText = settings.pdfAsText; + this.pdfQuality = settings.pdfQuality; this.readerActionByKeyCode = utils.userHotKeysObjectSwap(settings.userHotKeys); this.$root.readerActionByKeyEvent = (event) => { @@ -979,6 +981,8 @@ class Reader extends Vue { skipHtmlCheck: (this.splitToPara ? true : false), isText: (this.splitToPara ? true : false), djvuQuality: this.djvuQuality, + pdfAsText: this.pdfAsText, + pdfQuality: this.pdfQuality, }, (state) => { progress.setState(state); diff --git a/client/components/Reader/SettingsPage/SettingsPage.vue b/client/components/Reader/SettingsPage/SettingsPage.vue index 2f08064a..ab9bf85c 100644 --- a/client/components/Reader/SettingsPage/SettingsPage.vue +++ b/client/components/Reader/SettingsPage/SettingsPage.vue @@ -223,6 +223,10 @@ class SettingsPage extends Vue { return this.$store.state.config.mode; } + get isExternalConverter() { + return this.$store.state.config.useExternalBookConverter; + } + get settings() { return this.$store.state.reader.settings; } diff --git a/client/components/Reader/SettingsPage/include/ConvertTab.inc b/client/components/Reader/SettingsPage/include/ConvertTab.inc index 2441be44..dd891ac4 100644 --- a/client/components/Reader/SettingsPage/include/ConvertTab.inc +++ b/client/components/Reader/SettingsPage/include/ConvertTab.inc @@ -10,7 +10,7 @@
Текст
- + Опция принудительно включает эвристику разбиения текста на
параграфы в случае, если формат файла определен как html,
@@ -23,7 +23,7 @@
Сайты
- + Html-фильтр вырезает лишние элементы со
страницы для определенных сайтов, таких как:
@@ -37,20 +37,51 @@
-
PDF
+
+
PDF
- -
DJVU
-
-
Качество
-
- - - Качество конвертирования Djvu в Fb2. Чем значение выше, тем больше
- размер итогового файла. Если сервер отказывается конвертировать
- слишком большой файл, то попробуйте понизить качество. -
-
+
+
Формат
+
+ + + Пытается извлечь текст из pdf-файла и переразбить на параграфы.
+ Размер получаемого fb2-файла при этом относительно небольшой.
+ При отключении этой опции, pdf будет представлен как набор
+ изображений (аналогично ковертированию djvu). +
+
+
+
+ +
+
Качество
+
+ + + Качество конвертирования Pdf в Fb2. Чем значение выше, тем больше
+ размер итогового файла. Если сервер отказывается конвертировать
+ слишком большой файл, то попробуйте понизить качество. +
+
+
+ +
+
DJVU
+ +
+
Качество
+
+ + + Качество конвертирования Djvu в Fb2. Чем значение выше, тем больше
+ размер итогового файла. Если сервер отказывается конвертировать
+ слишком большой файл, то попробуйте понизить качество. +
+
+
+
+
diff --git a/client/store/modules/reader.js b/client/store/modules/reader.js index a776633d..484969bb 100644 --- a/client/store/modules/reader.js +++ b/client/store/modules/reader.js @@ -254,6 +254,8 @@ const settingDefaults = { enableSitesFilter: true, splitToPara: false, djvuQuality: 20, + pdfAsText: true, + pdfQuality: 20, showServerStorageMessages: true, showWhatsNewDialog: true, diff --git a/server/controllers/ReaderController.js b/server/controllers/ReaderController.js index 6f521a60..87f69464 100644 --- a/server/controllers/ReaderController.js +++ b/server/controllers/ReaderController.js @@ -24,6 +24,8 @@ class ReaderController extends BaseController { isText: (request.hasOwnProperty('isText') ? request.isText : false), uploadFileName: (request.hasOwnProperty('uploadFileName') ? request.uploadFileName : false), djvuQuality: (request.hasOwnProperty('djvuQuality') ? request.djvuQuality : false), + pdfAsText: (request.hasOwnProperty('pdfAsText') ? request.pdfAsText : false), + pdfQuality: (request.hasOwnProperty('pdfQuality') ? request.pdfQuality : false), }); const state = this.workerState.getState(workerId); return (state ? state : {}); diff --git a/server/core/Reader/BookConverter/ConvertPdf.js b/server/core/Reader/BookConverter/ConvertPdf.js index 1e302740..bec96b22 100644 --- a/server/core/Reader/BookConverter/ConvertPdf.js +++ b/server/core/Reader/BookConverter/ConvertPdf.js @@ -15,7 +15,7 @@ class ConvertPdf extends ConvertHtml { } async run(notUsed, opts) { - if (!this.check(notUsed, opts)) + if (!opts.pdfAsText || !this.check(notUsed, opts)) return false; await this.checkExternalConverterPresent(); diff --git a/server/core/Reader/BookConverter/ConvertPdfImages.js b/server/core/Reader/BookConverter/ConvertPdfImages.js new file mode 100644 index 00000000..c174747c --- /dev/null +++ b/server/core/Reader/BookConverter/ConvertPdfImages.js @@ -0,0 +1,79 @@ +const fs = require('fs-extra'); +const path = require('path'); +const utils = require('../../utils'); + +const ConvertJpegPng = require('./ConvertJpegPng'); + +class ConvertPdfImages extends ConvertJpegPng { + check(data, opts) { + const {inputFiles} = opts; + + return this.config.useExternalBookConverter && + inputFiles.sourceFileType && inputFiles.sourceFileType.ext == 'pdf'; + } + + async run(data, opts) { + if (!this.check(data, opts)) + return false; + + let {inputFiles, callback, abort, pdfQuality} = opts; + + pdfQuality = (pdfQuality && pdfQuality <= 100 && pdfQuality >= 10 ? pdfQuality : 20); + + const pdftoppmPath = '/usr/bin/pdftoppm'; + if (!await fs.pathExists(pdftoppmPath)) + throw new Error('Внешний конвертер pdftoppm не найден'); + + const dir = `${inputFiles.filesDir}/`; + const baseFile = `${dir}${path.basename(inputFiles.sourceFile)}`; + const jpgFiles = `${baseFile}.tmp`; + + //конвертируем в jpeg + let perc = 0; + await this.execConverter(pdftoppmPath, ['-jpeg', '-jpegopt', `quality=${pdfQuality},progressive=y`, inputFiles.sourceFile, jpgFiles], () => { + perc = (perc < 100 ? perc + 1 : 40); + callback(perc); + }, abort); + + const limitSize = 2*this.config.maxUploadFileSize; + let jpgFilesSize = 0; + //ищем изображения + let files = []; + await utils.findFiles(async(file) => { + if (path.extname(file) == '.jpg') { + jpgFilesSize += (await fs.stat(file)).size; + if (jpgFilesSize > limitSize) { + throw new Error(`Файл для конвертирования слишком большой|FORLOG| jpgFilesSize: ${jpgFilesSize} > ${limitSize}`); + } + + files.push({name: file, base: path.basename(file)}); + } + }, dir); + + files.sort((a, b) => a.base.localeCompare(b.base)); + + //схема документа (outline) + //const djvusedResult = await this.execConverter(djvusedPath, ['-u', '-e', 'print-outline', inputFiles.sourceFile]); + const outline = []; + /*const lines = djvusedResult.stdout.match(/\(".*"\s*?"#\d+".*?\)/g); + if (lines) { + lines.forEach(l => { + const m = l.match(/"(.*)"\s*?"#(\d+)"/); + if (m) { + outline[m[2]] = m[1]; + } + }); + }*/ + + await utils.sleep(100); + let i = 0; + const imageFiles = files.map(f => { + i++; + let alt = (outline[i] ? outline[i] : ''); + return {src: f.name, alt}; + }); + return await super.run(data, Object.assign({}, opts, {imageFiles})); + } +} + +module.exports = ConvertPdfImages; diff --git a/server/core/Reader/BookConverter/index.js b/server/core/Reader/BookConverter/index.js index 2f9e9abb..d0d5ec7f 100644 --- a/server/core/Reader/BookConverter/index.js +++ b/server/core/Reader/BookConverter/index.js @@ -7,6 +7,7 @@ const convertClassFactory = [ require('./ConvertEpub'), require('./ConvertDjvu'), require('./ConvertPdf'), + require('./ConvertPdfImages'), require('./ConvertRtf'), require('./ConvertDocX'), require('./ConvertFb3'),