]> git.kianting.info Git - clo/commitdiff
optimize the speed
authorTan Kian-ting <chenjt30@gmail.com>
Mon, 20 Nov 2023 15:23:56 +0000 (23:23 +0800)
committerTan Kian-ting <chenjt30@gmail.com>
Mon, 20 Nov 2023 15:23:56 +0000 (23:23 +0800)
output.pdf
src/libclo/breakLines.js
src/libclo/breakLines.ts
src/libclo/index.js
src/libclo/index.ts

index 14c2d0a1620fd37abbcf87e13c1239a1d1b706b6..11d94c0b40653cf2cf6c77dd8a94c05fdd197d9e 100644 (file)
Binary files a/output.pdf and b/output.pdf differ
index cdd4f6e99d3d25f1ee90cb24cf4bfa4ba2d50f2b..14a7836178190690f79c86f462067fa58022a4aa 100644 (file)
@@ -1,13 +1,4 @@
 "use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.BreakLineAlgorithm = void 0;
 /**
@@ -81,27 +72,23 @@ class BreakLineAlgorithm {
      * check all the total cost of paragraphes of the segnemt
      */
     totalCost(items, lineWidth) {
-        return __awaiter(this, void 0, void 0, function* () {
-            let lineWidthFixed = lineWidth * 0.75;
-            let itemsLength = items.length;
-            this.lineCostStorage = Array(itemsLength);
-            this.prevNodes = Array(itemsLength).fill(null);
-            for (var i = 0; i < itemsLength; i++) {
-                this.lineCostStorage[i] = Array(itemsLength).fill(null);
-            }
-            this.totalCostAuxStorage = Array(itemsLength).fill(null);
-            let a = Infinity;
-            for (var k = itemsLength - 2; (yield this.lineCost(items, k + 1, itemsLength - 1, lineWidthFixed)) < Infinity; k--) {
-                let tmp = yield this.totalCostAux(items, k, lineWidthFixed);
-                if (a > tmp) {
-                    this.prevNodes[itemsLength - 1] = k;
-                    a = tmp;
-                }
+        let lineWidthFixed = lineWidth * 0.75;
+        let itemsLength = items.length;
+        this.lineCostStorage = Array(itemsLength);
+        this.prevNodes = Array(itemsLength).fill(null);
+        for (var i = 0; i < itemsLength; i++) {
+            this.lineCostStorage[i] = Array(itemsLength).fill(null);
+        }
+        this.totalCostAuxStorage = Array(itemsLength).fill(null);
+        let a = Infinity;
+        for (var k = itemsLength - 2; this.lineCost(items, k + 1, itemsLength - 1, lineWidthFixed) < Infinity; k--) {
+            let tmp = this.totalCostAux(items, k, lineWidthFixed);
+            if (a > tmp) {
+                this.prevNodes[itemsLength - 1] = k;
+                a = tmp;
             }
-            console.log("~~~", lineWidth);
-            console.log(items[itemsLength - 2]);
-            return a;
-        });
+        }
+        return a;
     }
     /**
      * check the total cost item[0..j].
@@ -110,29 +97,26 @@ class BreakLineAlgorithm {
      * @param lineWidth
      */
     totalCostAux(items, j, lineWidth) {
-        return __awaiter(this, void 0, void 0, function* () {
-            if (this.totalCostAuxStorage[j] !== null) {
-                return this.totalCostAuxStorage[j];
-            }
-            let rawLineCost = yield this.lineCost(items, 0, j, lineWidth);
-            if (rawLineCost != Infinity) {
-                this.totalCostAuxStorage[j] = rawLineCost ** 3.0;
-                return rawLineCost ** 3.0;
-            }
-            else {
-                var returnCost = Infinity;
-                for (var k = 0; k < j; k++) {
-                    let tmp1 = yield Promise.all([this.totalCostAux(items, k, lineWidth), this.lineCost(items, k + 1, j, lineWidth)]);
-                    let tmp = tmp1[0] + tmp1[1] ** 3;
-                    if (returnCost > tmp) {
-                        this.prevNodes[j] = k;
-                        returnCost = tmp;
-                    }
+        if (this.totalCostAuxStorage[j] !== null) {
+            return this.totalCostAuxStorage[j];
+        }
+        let rawLineCost = this.lineCost(items, 0, j, lineWidth);
+        if (rawLineCost != Infinity) {
+            this.totalCostAuxStorage[j] = rawLineCost ** 3.0;
+            return rawLineCost ** 3.0;
+        }
+        else {
+            var returnCost = Infinity;
+            for (var k = 0; k < j; k++) {
+                let tmp = this.totalCostAux(items, k, lineWidth) + this.lineCost(items, k + 1, j, lineWidth) ** 3.0;
+                if (returnCost > tmp) {
+                    this.prevNodes[j] = k;
+                    returnCost = tmp;
                 }
-                this.totalCostAuxStorage[j] = returnCost;
-                return returnCost;
             }
-        });
+            this.totalCostAuxStorage[j] = returnCost;
+            return returnCost;
+        }
     }
     /**
      * check the line cost of a line containing items[i..j]
@@ -142,31 +126,30 @@ class BreakLineAlgorithm {
      * @param lineWidth line width
      */
     lineCost(items, i, j, lineWidth) {
-        return __awaiter(this, void 0, void 0, function* () {
-            if (this.lineCostStorage[i] !== null && this.lineCostStorage[i][j] !== null) {
-                return this.lineCostStorage[i][j];
+        if (this.lineCostStorage[i][j] !== null) {
+            console.log("AA");
+            return this.lineCostStorage[i][j];
+        }
+        if (!this.isBreakPoint(items[j])) {
+            this.lineCostStorage[i][j] = Infinity;
+            return Infinity;
+        }
+        else {
+            var tmpItemWidth = 0;
+            for (var k = i; k < j; k++) {
+                tmpItemWidth += this.origWidth(items[k]);
             }
-            if (!this.isBreakPoint(items[j])) {
+            tmpItemWidth += this.newLineWidth(items[j]);
+            if (tmpItemWidth > lineWidth) {
                 this.lineCostStorage[i][j] = Infinity;
                 return Infinity;
             }
             else {
-                var tmpItemWidth = 0;
-                for (var k = i; k < j; k++) {
-                    tmpItemWidth += this.origWidth(items[k]);
-                }
-                tmpItemWidth += this.newLineWidth(items[j]);
-                if (tmpItemWidth > lineWidth) {
-                    this.lineCostStorage[i][j] = Infinity;
-                    return Infinity;
-                }
-                else {
-                    let returnValue = (lineWidth - tmpItemWidth);
-                    this.lineCostStorage[i][j] = returnValue;
-                    return returnValue;
-                }
+                let returnValue = (lineWidth - tmpItemWidth);
+                this.lineCostStorage[i][j] = returnValue;
+                return returnValue;
             }
-        });
+        }
     }
 }
 exports.BreakLineAlgorithm = BreakLineAlgorithm;
index f761b1868525b52e2e76b491110e1a2d98b82ac6..7ab8c0d70bf0c68cd951a3feb89b3536722b345b 100644 (file)
@@ -51,6 +51,7 @@ export class BreakLineAlgorithm {
     }
 
     segmentedNodes(items : BoxesItem[], lineWidth : number) : BoxesItem[][]{
+
         let lineWidthFixed = lineWidth;
         this.totalCost(items ,lineWidthFixed);
         let nodeList = this.generateBreakLineNodeList();
@@ -64,6 +65,8 @@ export class BreakLineAlgorithm {
             up = nodeList[i+1];
 
         }
+
+
         return res;
     }
 
@@ -105,16 +108,15 @@ export class BreakLineAlgorithm {
 
         let a = Infinity;
         for(var k=itemsLength-2; this.lineCost(items, k+1,itemsLength-1, lineWidthFixed) < Infinity; k--){
+            
             let tmp = this.totalCostAux(items, k, lineWidthFixed);
-
+            
             if (a > tmp){
                 this.prevNodes[itemsLength-1] = k
                 a = tmp;
             }
+            
         }
-
-        console.log("~~~", lineWidth);
-        console.log((<CharBox>items[itemsLength-2]));
         return a;
 
     }
@@ -163,7 +165,8 @@ export class BreakLineAlgorithm {
      * @param lineWidth line width
      */
     lineCost(items : BoxesItem[], i : number, j : number, lineWidth: number) : number{
-        if (this.lineCostStorage[i] !== null && this.lineCostStorage[i][j] !== null){
+        if (this.lineCostStorage[i][j] !== null){
+            console.log("AA")
             return this.lineCostStorage[i][j];
         }
 
index 2840b3d07f529131196341ba164538b064321326..9d9e8a8ccad312a1d0ac40bbc6c07e02c4e83970 100644 (file)
@@ -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");
@@ -287,14 +302,14 @@ function calculateTextWidthHeightAux(element, style) {
                 };
                 result.push(item);
             }
-            return result;
+            return [result, styleCache, fontCache];
         }
         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,14 +317,14 @@ function calculateTextWidthHeightAux(element, style) {
                 original: beforeNewLine,
                 newLined: afterNewLine,
             };
-            return breakPointNode;
+            return [breakPointNode, styleCache, fontCache];
         }
         else if (element[0] == "hglue" && !Array.isArray(element[1])) {
             let hGlue = { stretchFactor: parseFloat(element[1]) };
-            return hGlue;
+            return [hGlue, styleCache, fontCache];
         }
         else {
-            return calculateTextWidthHeight(element, style);
+            return [yield calculateTextWidthHeight(element, style), styleCache, fontCache];
         }
     });
 }
@@ -362,47 +377,58 @@ class Clo {
             let defaultFontStyle = this.attrs.defaultFrameStyle.textStyle;
             let a = yield calculateTextWidthHeight(preprocessed, defaultFontStyle);
             let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
-            // TODO
-            //console.log(breakLineAlgorithms.totalCost(a,70));
             let segmentedNodes = breakLineAlgorithms.segmentedNodes(a, this.attrs.defaultFrameStyle.width);
             let segmentedNodesToBox = this.segmentedNodesToFrameBox(segmentedNodes, this.attrs.defaultFrameStyle);
             let boxesFixed = this.fixenBoxesPosition(segmentedNodesToBox);
-            // generate pdf7
+            // generate pdf
             const doc = new PDFDocument({ size: 'A4' });
             doc.pipe(fs.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) {
+    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); // 0.75 must added!  
+                    fontPair = (0, canva_1.fontStyleTofont)(box.textStyle);
+                    styleCache = box.textStyle;
+                    fontPairCache = fontPair;
+                    if (fontPair.path.match(/\.ttc$/g)) {
+                        doc
+                            .font(fontPair.path, fontPair.psName)
+                            .fontSize(box.textStyle.size * 0.75);
+                    }
+                    else {
+                        doc
+                            .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) {
                     yield doc.text(box.content, (box.x !== null ? box.x : undefined), (box.y !== null ? box.y : undefined));
                 }
             }
-            return doc;
+            return [doc, styleCache, fontPairCache];
         });
     }
     ;
index e5c2108442e2deae04678c9a11e261f70f6f5ed7..f48f448d9bcabebaeaba7d0b21a60923bf4baf8b 100644 (file)
@@ -1,9 +1,11 @@
 import {tkTree} from "../parser";
-import {FontStyle, TextStyle, TextWeight, fontStyleTofont} from "../canva";
+import {FontStyle, TextStyle, TextWeight, fontStyleTofont, fontPathPSNamePair} from "../canva";
 import * as fontkit from "fontkit";
 import * as breakLines from "./breakLines";
 const PDFDocument = require('pdfkit');
 import * as fs from "fs";
+import { Style } from "util";
+import { time } from "console";
 
 
 /**
@@ -279,6 +281,8 @@ export function hyphenTkTree(arr : tkTree, lang: string) : tkTree{
     return result;
 }
 
+
+
 /**
  * calculate the text width and Height with a given `TextStyle` 
  * @param preprocessed 
@@ -286,9 +290,14 @@ export function hyphenTkTree(arr : tkTree, lang: string) : tkTree{
  */
 export async function calculateTextWidthHeight(element : tkTree, style : TextStyle): Promise<BoxesItem[]> {
     var res = [];
+    var styleCache = {};
+    var fontCache = {};
     
     for (var i=0; i<element.length; i++){
-        res.push(await calculateTextWidthHeightAux(element[i], style));
+        let item = await calculateTextWidthHeightAux(element[i], style, <TextStyle>styleCache, <fontkit.Font>fontCache);
+        styleCache = item[1];
+        fontCache = item[2];
+        res.push(item[0]);
     }
 
     res = res.flat();
@@ -302,18 +311,37 @@ export async function calculateTextWidthHeight(element : tkTree, style : TextSty
  * @param preprocessed 
  * @param defaultFontStyle 
  */
-export async function calculateTextWidthHeightAux(element : tkTree, style : TextStyle): Promise<BoxesItem> {
+export async function calculateTextWidthHeightAux(element : tkTree,
+                                                    style : TextStyle,
+                                                    styleCache : TextStyle,
+                                                    fontCache :  fontkit.Font): Promise<[BoxesItem, TextStyle, fontkit.Font] > {
     var result : BoxesItem = [];
-    
+    var font;
+
+    if (style === styleCache){
+        font = fontCache;
+    }else {
 
 
     let fontPair = fontStyleTofont(style);
+
     if (fontPair.path.match(/\.ttc$/)){
-        var font = await fontkit.openSync(fontPair.path, fontPair.psName);
+        font = await fontkit.openSync(fontPair.path, fontPair.psName);
+        styleCache = style;
+        fontCache = font;
+
     }
     else{
-        var font = await fontkit.openSync(fontPair.path);
+        font = await fontkit.openSync(fontPair.path);
+        styleCache = style;
+        fontCache = font;
+    }
+
+    
+
     }
+
+
     if (!Array.isArray(element)){
         var run = font.layout(element, undefined, undefined, undefined, "ltr");
 
@@ -340,19 +368,20 @@ export async function calculateTextWidthHeightAux(element : tkTree, style : Text
             result.push(item);
 
         }
-    return result;
+    return [result, styleCache, fontCache];
 
 
         
 
     }else if(element[0] == "bp"){
 
-        var beforeNewLine = await calculateTextWidthHeightAux(element[1], style);
+
+        var beforeNewLine = (await calculateTextWidthHeightAux(element[1], style, styleCache, fontCache))[0];
         if (Array.isArray(beforeNewLine)){
             beforeNewLine = beforeNewLine.flat();
         }
 
-        let afterNewLine = await calculateTextWidthHeightAux(element[2], style);
+        let afterNewLine = (await calculateTextWidthHeightAux(element[2], style, styleCache, fontCache))[0];
         if (Array.isArray(afterNewLine)){
             afterNewLine = afterNewLine.flat();
         }
@@ -362,13 +391,13 @@ export async function calculateTextWidthHeightAux(element : tkTree, style : Text
             newLined : afterNewLine,
         }
 
-        return breakPointNode;
+        return [breakPointNode, styleCache, fontCache];
     }else if(element[0] == "hglue" && !Array.isArray(element[1])){
         let hGlue : HGlue = {stretchFactor : parseFloat(element[1])}
-        return hGlue;
+        return [hGlue, styleCache, fontCache];
     }
     else{
-        return calculateTextWidthHeight(element, style);
+        return [await calculateTextWidthHeight(element, style), styleCache, fontCache];
     }
 }
 
@@ -428,56 +457,72 @@ export class Clo{
     }
 
     public async generatePdf(){
+
         // preprocessed
         var preprocessed = this.mainStream;
         for (var i = 0; i<this.preprocessors.length; i++){
             preprocessed = this.preprocessors[i](preprocessed, this);
         }
+
         // generate the width and height of the stream
 
         let defaultFontStyle : TextStyle = this.attrs.defaultFrameStyle.textStyle;
+
+
         let a = await calculateTextWidthHeight(preprocessed, defaultFontStyle);
 
         let breakLineAlgorithms = new breakLines.BreakLineAlgorithm();
-        // TODO
-        //console.log(breakLineAlgorithms.totalCost(a,70));
+
         let segmentedNodes = breakLineAlgorithms.segmentedNodes(a, this.attrs.defaultFrameStyle.width);
 
         let segmentedNodesToBox =
             this.segmentedNodesToFrameBox(segmentedNodes, <FrameBox>this.attrs.defaultFrameStyle);
 
 
-
         let boxesFixed = this.fixenBoxesPosition(segmentedNodesToBox);
 
         
 
 
-        // generate pdf7
+        // generate pdf
         const doc = new PDFDocument({size: 'A4'});
         doc.pipe(fs.createWriteStream('output.pdf'));
         this.grid(doc);
 
-        await this.putText(doc, boxesFixed);
+        let styleCache : any = {};
+        let fontPairCache : fontPathPSNamePair = {path : "", psName : ""};
+        await this.putText(doc, boxesFixed, <TextStyle>styleCache, fontPairCache);
         // putChar
         doc.end();
 
+
     }
 
-    async putText(doc : PDFKit.PDFDocument, box : Box): Promise<PDFKit.PDFDocument>{
+    async putText(doc : PDFKit.PDFDocument, box : Box, styleCache : TextStyle,
+        fontPairCache : fontPathPSNamePair):
+        Promise<[PDFKit.PDFDocument, TextStyle, fontPathPSNamePair]>{
+            var fontPair;
+        
     
         if (box.textStyle !== null){
-            let fontInfo = fontStyleTofont(box.textStyle);
-        
-            if (fontInfo.path.match(/\.ttc$/g)){
-                doc
-                .font(fontInfo.path, fontInfo.psName)
-                .fontSize(box.textStyle.size * 0.75);}
-            else{
-                doc
-                .font(fontInfo.path)
-                .fontSize(box.textStyle.size * 0.75); // 0.75 must added!  
-            }
+            
+            if(box.textStyle == styleCache){
+                fontPair = fontPairCache;
+            }else{
+                fontPair = fontStyleTofont(box.textStyle);
+                styleCache = box.textStyle;
+                fontPairCache = fontPair;
+
+                if (fontPair.path.match(/\.ttc$/g)){
+                    doc
+                    .font(fontPair.path, fontPair.psName)
+                    .fontSize(box.textStyle.size * 0.75);}
+                else{
+                    doc
+                    .font(fontPair.path)
+                    .fontSize(box.textStyle.size * 0.75); // 0.75 must added!  
+                }
+        }
         
             if (box.textStyle.color !== undefined){
                 doc.fill(box.textStyle.color);
@@ -486,7 +531,10 @@ export class Clo{
             if (Array.isArray(box.content)){
                 for (var k=0; k<box.content.length; k++){
 
-                    doc = await this.putText(doc, box.content[k]);
+                    let tmp = await this.putText(doc, box.content[k], styleCache, fontPairCache);
+                    doc = tmp[0];
+                    styleCache = tmp[1];
+                    fontPairCache = tmp[2];
                 }
             }else if (box.content !== null){
                 await doc.text(box.content,
@@ -495,7 +543,9 @@ export class Clo{
             }
         
         }
-        return doc;
+
+
+        return [doc, styleCache, fontPairCache];
     };