|
@@ -2,6 +2,8 @@ import he from 'he';
|
|
|
import sax from '../../../../server/core/BookConverter/sax';
|
|
|
import {sleep} from '../../../share/utils';
|
|
|
|
|
|
+const maxImageLineCount = 100;
|
|
|
+
|
|
|
export default class BookParser {
|
|
|
constructor() {
|
|
|
// defaults
|
|
@@ -37,6 +39,10 @@ export default class BookParser {
|
|
|
let center = false;
|
|
|
let bold = false;
|
|
|
let italic = false;
|
|
|
+ this.binary = {};
|
|
|
+ let binaryId = '';
|
|
|
+ let binaryType = '';
|
|
|
+ let dimPromises = [];
|
|
|
|
|
|
let paraIndex = -1;
|
|
|
let paraOffset = 0;
|
|
@@ -50,6 +56,28 @@ export default class BookParser {
|
|
|
addIndex: Number, //индекс добавляемого пустого параграфа (addEmptyParagraphs)
|
|
|
}
|
|
|
*/
|
|
|
+ const getImageDimensions = (binaryId, binaryType, data) => {
|
|
|
+ return new Promise (async(resolve, reject) => {
|
|
|
+ const i = new Image();
|
|
|
+ let resolved = false;
|
|
|
+ i.onload = () => {
|
|
|
+ resolved = true;
|
|
|
+ this.binary[binaryId] = {
|
|
|
+ w: i.width,
|
|
|
+ h: i.height,
|
|
|
+ type: binaryType,
|
|
|
+ data
|
|
|
+ };
|
|
|
+ resolve();
|
|
|
+ };
|
|
|
+
|
|
|
+ i.src = `data:${binaryType};base64,${data}`;
|
|
|
+ await sleep(30*1000);
|
|
|
+ if (!resolved)
|
|
|
+ reject('Не удалось получить размер изображения');
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
const newParagraph = (text, len, addIndex) => {
|
|
|
paraIndex++;
|
|
|
let p = {
|
|
@@ -103,13 +131,26 @@ export default class BookParser {
|
|
|
paraOffset += p.length;
|
|
|
};
|
|
|
|
|
|
- const onStartNode = (elemName) => {// eslint-disable-line no-unused-vars
|
|
|
+ const onStartNode = (elemName, tail) => {// eslint-disable-line no-unused-vars
|
|
|
if (elemName == '?xml')
|
|
|
return;
|
|
|
|
|
|
tag = elemName;
|
|
|
path += '/' + elemName;
|
|
|
|
|
|
+ if (tag == 'binary') {
|
|
|
+ let attrs = sax.getAttrsSync(tail);
|
|
|
+ binaryType = (attrs['content-type'].value ? attrs['content-type'].value : '');
|
|
|
+ if (binaryType == 'image/jpeg' || binaryType == 'image/png')
|
|
|
+ binaryId = (attrs.id.value ? attrs.id.value : '');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tag == 'image') {
|
|
|
+ let attrs = sax.getAttrsSync(tail);
|
|
|
+ if (attrs.href.value)
|
|
|
+ newParagraph(`<image href="${attrs.href.value}">${' '.repeat(maxImageLineCount)}</image>`, maxImageLineCount);
|
|
|
+ }
|
|
|
+
|
|
|
if (path.indexOf('/fictionbook/body') == 0) {
|
|
|
if (tag == 'title') {
|
|
|
newParagraph(' ', 1);
|
|
@@ -146,6 +187,10 @@ export default class BookParser {
|
|
|
|
|
|
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
|
|
|
if (tag == elemName) {
|
|
|
+ if (tag == 'binary') {
|
|
|
+ binaryId = '';
|
|
|
+ }
|
|
|
+
|
|
|
if (path.indexOf('/fictionbook/body') == 0) {
|
|
|
if (tag == 'title') {
|
|
|
bold = false;
|
|
@@ -245,6 +290,10 @@ export default class BookParser {
|
|
|
growParagraph(`${tOpen}${text}${tClose}`, text.length);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (binaryId) {
|
|
|
+ dimPromises.push(getImageDimensions(binaryId, binaryType, text));
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const onProgress = async(prog) => {
|
|
@@ -256,6 +305,14 @@ export default class BookParser {
|
|
|
onStartNode, onEndNode, onTextNode, onProgress
|
|
|
});
|
|
|
|
|
|
+ if (dimPromises.length) {
|
|
|
+ try {
|
|
|
+ await Promise.all(dimPromises);
|
|
|
+ } catch (e) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
this.fb2 = fb2;
|
|
|
this.para = para;
|
|
|
|
|
@@ -292,18 +349,26 @@ export default class BookParser {
|
|
|
splitToStyle(s) {
|
|
|
let result = [];/*array of {
|
|
|
style: {bold: Boolean, italic: Boolean, center: Boolean},
|
|
|
+ image: Boolean,
|
|
|
+ imageId: String,
|
|
|
text: String,
|
|
|
}*/
|
|
|
let style = {};
|
|
|
+ let image = {};
|
|
|
|
|
|
+ /*let attrs = sax.getAttrsSync(tail);
|
|
|
+ if (attrs.href.value)
|
|
|
+ newParagraph(' '.repeat(maxImageLineCount) + `<image href="${attrs.href.value}" />`, maxImageLineCount);
|
|
|
+*/
|
|
|
const onTextNode = async(text) => {// eslint-disable-line no-unused-vars
|
|
|
result.push({
|
|
|
style: Object.assign({}, style),
|
|
|
- text: text
|
|
|
+ image,
|
|
|
+ text
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- const onStartNode = async(elemName) => {// eslint-disable-line no-unused-vars
|
|
|
+ const onStartNode = async(elemName, tail) => {// eslint-disable-line no-unused-vars
|
|
|
switch (elemName) {
|
|
|
case 'strong':
|
|
|
style.bold = true;
|
|
@@ -314,6 +379,9 @@ export default class BookParser {
|
|
|
case 'center':
|
|
|
style.center = true;
|
|
|
break;
|
|
|
+ case 'image':
|
|
|
+ image = {};
|
|
|
+ break;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -328,6 +396,9 @@ export default class BookParser {
|
|
|
case 'center':
|
|
|
style.center = false;
|
|
|
break;
|
|
|
+ case 'image':
|
|
|
+ image = {};
|
|
|
+ break;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -335,7 +406,6 @@ export default class BookParser {
|
|
|
onStartNode, onEndNode, onTextNode
|
|
|
});
|
|
|
|
|
|
-
|
|
|
//длинные слова (или белиберду без пробелов) тоже разобьем
|
|
|
const maxWordLength = this.maxWordLength;
|
|
|
const parts = result;
|
|
@@ -350,7 +420,7 @@ export default class BookParser {
|
|
|
|
|
|
if (i - spaceIndex >= maxWordLength && i < p.text.length - 1 &&
|
|
|
this.measureText(p.text.substr(spaceIndex + 1, i - spaceIndex), p.style) >= this.w - this.p) {
|
|
|
- result.push({style: p.style, text: p.text.substr(0, i + 1)});
|
|
|
+ result.push({style: p.style, image: p.image, text: p.text.substr(0, i + 1)});
|
|
|
p = {style: p.style, text: p.text.substr(i + 1)};
|
|
|
spaceIndex = -1;
|
|
|
i = -1;
|