X-Git-Url: https://git.kianting.info/?a=blobdiff_plain;f=src%2Flibclo%2Findex.js;h=fe92ce14683dae9d90116a36ae12de9cf70648ff;hb=714bbb4a64531268d17ca8f7ae60800ec2046a27;hp=665b35971f7fb38105559cef12b02bb105034973;hpb=e9819c8bc28d209d79461117d5b70f7b6b94abb6;p=clo diff --git a/src/libclo/index.js b/src/libclo/index.js index 665b359..fe92ce1 100644 --- a/src/libclo/index.js +++ b/src/libclo/index.js @@ -32,12 +32,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.Clo = exports.calculateTextWidthHeightAux = exports.calculateTextWidthHeight = exports.hyphenTkTree = exports.filterEmptyString = exports.spacesToBreakpoint = exports.hyphenForClo = exports.splitCJKV = exports.twoReturnsToNewline = exports.ptToPx = exports.cjkvRegexPattern = exports.cjkvBlocksInRegex = exports.defaultFrameStyle = exports.defaultTextStyle = exports.A4_IN_PX = exports.Direction = void 0; +exports.Clo = exports.applyVOffset = exports.putInVBox = exports.calculateTextWidthHeightAux = exports.calculateTextWidthHeight = exports.hyphenTkTree = exports.filterEmptyString = exports.spacesToBreakpoint = exports.hyphenForClo = exports.splitCJKV = exports.twoReturnsToNewline = exports.ptToPx = exports.cjkvRegexPattern = exports.cjkvBlocksInRegex = exports.defaultFrameStyle = exports.defaultTextStyle = exports.A4_IN_PX = exports.Direction = void 0; const canva_1 = require("../canva"); const fontkit = __importStar(require("fontkit")); const breakLines = __importStar(require("./breakLines")); const PDFDocument = require('pdfkit'); -const fs = __importStar(require("fs")); +const memfs_1 = require("memfs"); /** * TYPES */ @@ -60,7 +60,7 @@ var Direction; exports.A4_IN_PX = { "width": 793.7, "height": 1122.5 }; exports.defaultTextStyle = { - family: "FreeSerif", + family: "Noto Sans CJK TC", size: ptToPx(12), textWeight: canva_1.TextWeight.REGULAR, fontStyle: canva_1.FontStyle.ITALIC, @@ -70,8 +70,8 @@ exports.defaultFrameStyle = { direction: Direction.TTB, baseLineskip: ptToPx(15), textStyle: exports.defaultTextStyle, - x: exports.A4_IN_PX.width * 0.10 * 0.75, - y: exports.A4_IN_PX.height * 0.10 * 0.75, + x: exports.A4_IN_PX.width * 0.10, + y: exports.A4_IN_PX.height * 0.10, width: exports.A4_IN_PX.width * 0.80, height: exports.A4_IN_PX.height * 0.80, content: null, @@ -103,7 +103,7 @@ exports.ptToPx = ptToPx; * REGISTER PART */ /** - * convert '\n\n' to newline command ["nl"] + * convert '\n\n' to new paragraph command ["br"] * @param arr the input `tkTree` * @param clo the `Clo` object * @returns the input tktree @@ -123,7 +123,7 @@ function twoReturnsToNewline(arr, clo) { for (let j = 0; j < middle.length; j++) { var item = middle[j]; if (!Array.isArray(item) && item == "\n\n") { - result.push(["nl"]); // push a newline command to the result `tkTree` + result.push(["br"]); // push a newline command to the result `tkTree` } else { result.push(middle[j]); @@ -245,8 +245,13 @@ exports.hyphenTkTree = hyphenTkTree; function calculateTextWidthHeight(element, style) { return __awaiter(this, void 0, void 0, function* () { var res = []; + var styleCache = {}; + var fontCache = {}; for (var i = 0; i < element.length; i++) { - res.push(yield calculateTextWidthHeightAux(element[i], style)); + let item = yield calculateTextWidthHeightAux(element[i], style, styleCache, fontCache); + styleCache = item[1]; + fontCache = item[2]; + res.push(item[0]); } res = res.flat(); return res; @@ -258,15 +263,25 @@ exports.calculateTextWidthHeight = calculateTextWidthHeight; * @param preprocessed * @param defaultFontStyle */ -function calculateTextWidthHeightAux(element, style) { +function calculateTextWidthHeightAux(element, style, styleCache, fontCache) { return __awaiter(this, void 0, void 0, function* () { var result = []; - let fontPair = (0, canva_1.fontStyleTofont)(style); - if (fontPair.path.match(/\.ttc$/)) { - var font = yield fontkit.openSync(fontPair.path, fontPair.psName); + var font; + if (style === styleCache) { + font = fontCache; } else { - var font = yield fontkit.openSync(fontPair.path); + let fontPair = (0, canva_1.fontStyleTofont)(style); + if (fontPair.path.match(/\.ttc$/)) { + font = yield fontkit.openSync(fontPair.path, fontPair.psName); + styleCache = style; + fontCache = font; + } + else { + font = yield fontkit.openSync(fontPair.path); + styleCache = style; + fontCache = font; + } } if (!Array.isArray(element)) { var run = font.layout(element, undefined, undefined, undefined, "ltr"); @@ -277,8 +292,8 @@ function calculateTextWidthHeightAux(element, style) { y: null, textStyle: style, direction: Direction.LTR, - width: (runGlyphsItem.advanceWidth) * (style.size) * 0.75 / 1000, - height: (runGlyphsItem.bbox.maxY - runGlyphsItem.bbox.minY) * (style.size) * 0.75 / 1000, + width: (runGlyphsItem.advanceWidth) * (style.size) / 1000 * 0.75, + height: (runGlyphsItem.bbox.maxY - runGlyphsItem.bbox.minY) * (style.size) / 1000 * 0.75, content: element[j], minX: runGlyphsItem.bbox.minX, maxX: runGlyphsItem.bbox.maxX, @@ -287,14 +302,15 @@ function calculateTextWidthHeightAux(element, style) { }; result.push(item); } - return result; + return [result, styleCache, fontCache]; + // break point of a line } else if (element[0] == "bp") { - var beforeNewLine = yield calculateTextWidthHeightAux(element[1], style); + var beforeNewLine = (yield calculateTextWidthHeightAux(element[1], style, styleCache, fontCache))[0]; if (Array.isArray(beforeNewLine)) { beforeNewLine = beforeNewLine.flat(); } - let afterNewLine = yield calculateTextWidthHeightAux(element[2], style); + let afterNewLine = (yield calculateTextWidthHeightAux(element[2], style, styleCache, fontCache))[0]; if (Array.isArray(afterNewLine)) { afterNewLine = afterNewLine.flat(); } @@ -302,18 +318,66 @@ function calculateTextWidthHeightAux(element, style) { original: beforeNewLine, newLined: afterNewLine, }; - return breakPointNode; + return [breakPointNode, styleCache, fontCache]; + // hglue } else if (element[0] == "hglue" && !Array.isArray(element[1])) { - let hGlue = { stretchFactor: parseFloat(element[1]) }; - return hGlue; + let hGlue = { + isHorizonalGlue: true, + stretchFactor: parseFloat(element[1]) + }; + return [hGlue, styleCache, fontCache]; + } + // new line
+ else if (element[0] == "br") { + let brBoxItem = yield calculateTextWidthHeightAux(["hglue", "10000"], style, styleCache, fontCache); + //
+ let BR = { + isBR: true, + original: brBoxItem[0], + newLined: brBoxItem[0] + }; + return [BR, styleCache, fontCache]; } else { - return calculateTextWidthHeight(element, style); + return [yield calculateTextWidthHeight(element, style), styleCache, fontCache]; } }); } exports.calculateTextWidthHeightAux = calculateTextWidthHeightAux; +/** + * put childrenBox inside VBox + */ +function putInVBox(childrenBox, parentBox) { + var voffset = Array(childrenBox.length).fill(0); + for (var i = 0; i < childrenBox.length - 1; i++) { + voffset[i + 1] = voffset[i] + childrenBox[i].height; + } + console.log("~", voffset); + for (var i = 0; i < childrenBox.length; i++) { + childrenBox[i] = applyVOffset(childrenBox[i], voffset[i]); + childrenBox[i].y += voffset[i]; + } + parentBox.content = childrenBox; + return parentBox; +} +exports.putInVBox = putInVBox; +/** + * apply vertical offset to a box + * @param box the box to be applied + * @param voffset the vertical offset + * @returns applied box + */ +function applyVOffset(box, voffset) { + if (box.y !== null) { + box.y += voffset; + } + if (Array.isArray(box.content)) { + box.content = box.content.map((x) => applyVOffset(x, voffset)); + } + return box; +} +exports.applyVOffset = applyVOffset; /** * whole document-representing class */ @@ -360,51 +424,91 @@ class Clo { } // generate the width and height of the stream let defaultFontStyle = this.attrs.defaultFrameStyle.textStyle; - let a = yield calculateTextWidthHeight(preprocessed, defaultFontStyle); + // calculate the width and height of each chars + let calculated = yield calculateTextWidthHeight(preprocessed, defaultFontStyle); + // + let paragraphized = this.paragraphize(calculated); let breakLineAlgorithms = new breakLines.BreakLineAlgorithm(); - // TODO - //console.log(breakLineAlgorithms.totalCost(a,70)); - let segmentedNodes = breakLineAlgorithms.segmentedNodes(a, this.attrs.defaultFrameStyle.width); - console.log(this.attrs.defaultFrameStyle.width); - let segmentedNodesToBox = this.segmentedNodesToFrameBox(segmentedNodes, this.attrs.defaultFrameStyle); - let boxesFixed = this.fixenBoxesPosition(segmentedNodesToBox); - // generate pdf7 + let segmentedNodes = paragraphized.map((x) => breakLineAlgorithms.segmentedNodes(x, this.attrs.defaultFrameStyle.width)); + let segmentedNodesToBox = segmentedNodes.map((x) => this.segmentedNodesToFrameBoxAux(x, this.attrs.defaultFrameStyle)); + let boxWithParagraph = putInVBox(segmentedNodesToBox, this.attrs.defaultFrameStyle); + console.log(boxWithParagraph); + // fix the bug of main Frame x & y + if (boxWithParagraph.x !== null) { + boxWithParagraph.x *= 0.75; + } + if (boxWithParagraph.y !== null) { + boxWithParagraph.y *= 0.75; + } + let boxesFixed = this.fixenBoxesPosition(boxWithParagraph); + boxesFixed.content.map((e) => { console.log(e.y); }); + // generate pdf const doc = new PDFDocument({ size: 'A4' }); - doc.pipe(fs.createWriteStream('output.pdf')); + // let fsMemory = memfs(); + doc.pipe(memfs_1.vol.createWriteStream('output.pdf')); this.grid(doc); - yield this.putText(doc, boxesFixed); + let styleCache = {}; + let fontPairCache = { path: "", psName: "" }; + yield this.putText(doc, boxesFixed, styleCache, fontPairCache); // putChar doc.end(); }); } - putText(doc, box) { + paragraphize(calculated) { + var res = [[]]; + for (var i = 0; i < calculated.length; i++) { + if ("isBR" in (calculated[i])) { + res[res.length - 1] = res[res.length - 1].concat(calculated[i]); + res.push([]); + } + else { + res[res.length - 1] = res[res.length - 1].concat(calculated[i]); + } + } + res = res.filter((x) => x.length !== 0); + return res; + } + putText(doc, box, styleCache, fontPairCache) { return __awaiter(this, void 0, void 0, function* () { + var fontPair; if (box.textStyle !== null) { - let fontInfo = (0, canva_1.fontStyleTofont)(box.textStyle); - if (fontInfo.path.match(/\.ttc$/g)) { - doc - .font(fontInfo.path, fontInfo.psName) - .fontSize(box.textStyle.size * 0.75); + if (box.textStyle == styleCache) { + fontPair = fontPairCache; } else { - doc - .font(fontInfo.path) - .fontSize(box.textStyle.size * 0.75); + fontPair = (0, canva_1.fontStyleTofont)(box.textStyle); + styleCache = box.textStyle; + fontPairCache = fontPair; + let textColor = box.textStyle.color; + if (fontPair.path.match(/\.ttc$/g)) { + doc + .fillColor(textColor !== undefined ? textColor : "#000000") + .font(fontPair.path, fontPair.psName) + .fontSize(box.textStyle.size * 0.75); + } + else { + doc + .fillColor(textColor !== undefined ? textColor : "#000000") + .font(fontPair.path) + .fontSize(box.textStyle.size * 0.75); // 0.75 must added! + } } if (box.textStyle.color !== undefined) { doc.fill(box.textStyle.color); } if (Array.isArray(box.content)) { for (var k = 0; k < box.content.length; k++) { - doc = yield this.putText(doc, box.content[k]); + let tmp = yield this.putText(doc, box.content[k], styleCache, fontPairCache); + doc = tmp[0]; + styleCache = tmp[1]; + fontPairCache = tmp[2]; } } else if (box.content !== null) { - console.log(box.content, box.x, box.y); yield doc.text(box.content, (box.x !== null ? box.x : undefined), (box.y !== null ? box.y : undefined)); } } - return doc; + return [doc, styleCache, fontPairCache]; }); } ; @@ -461,7 +565,6 @@ class Clo { * @returns the fixed boxes */ fixenBoxesPosition(box) { - console.log("~~~~~", box); var currX = (box.x !== null ? box.x : 0); // current x var currY = (box.y !== null ? box.y : 0); // current y if (Array.isArray(box.content)) { @@ -493,12 +596,12 @@ class Clo { * @param frame the frame to be layed out. * @returns the big `Box`. */ - segmentedNodesToFrameBox(segmentedNodes, frame) { + segmentedNodesToFrameBoxAux(segmentedNodes, frame) { let baseLineskip = frame.baseLineskip; let boxArrayEmpty = []; let bigBox = { - x: frame.x, - y: frame.y, + x: (frame.x !== null ? frame.x * 0.75 : null), + y: (frame.y !== null ? frame.y * 0.75 : null), textStyle: frame.textStyle, direction: frame.direction, width: frame.width, @@ -526,6 +629,8 @@ class Clo { bigBoxContent.push(currentLineBox); } bigBox.content = bigBoxContent; + let bigBoxHeight = bigBoxContent.map((x) => x.height).reduce((x, y) => x + y, 0); + bigBox.height = bigBoxHeight; return bigBox; } /** @@ -562,7 +667,6 @@ class Clo { } }) .reduce((acc, cur) => acc + cur, 0); let offset = frame.width * 0.75 - glueRemovedWidth; - console.log("OFFSET", offset); var res = []; for (var i = 0; i < nodeLine.length; i++) { var ele = nodeLine[i]; @@ -572,6 +676,7 @@ class Clo { y: null, textStyle: null, direction: frame.directionInsideLine, + //width : 0, // ragged width: ele.stretchFactor / sumStretchFactor * offset, height: 0, content: "",