X-Git-Url: https://git.kianting.info/?a=blobdiff_plain;f=src%2Flibclo%2Findex.ts;h=f48f448d9bcabebaeaba7d0b21a60923bf4baf8b;hb=9548c51651d010ec8fd8fbf0213a2d7c60e051ce;hp=53b837c63572ddbc503bb4f69d3ba0fe581364c7;hpb=a4f79a3761539f45ac7d86fe919bdc32cf290db0;p=clo diff --git a/src/libclo/index.ts b/src/libclo/index.ts index 53b837c..f48f448 100644 --- a/src/libclo/index.ts +++ b/src/libclo/index.ts @@ -1,10 +1,12 @@ -import { isBoxedPrimitive, isKeyObject, isStringObject } from "util/types"; import {tkTree} from "../parser"; -import {FontStyle, TextStyle, TextWeight, fontStyleTofont} from "../canva"; -import { JSDOM } from "jsdom"; +import {FontStyle, TextStyle, TextWeight, fontStyleTofont, fontPathPSNamePair} from "../canva"; import * as fontkit from "fontkit"; -import * as util from "node:util"; import * as breakLines from "./breakLines"; +const PDFDocument = require('pdfkit'); +import * as fs from "fs"; +import { Style } from "util"; +import { time } from "console"; + /** * TYPES @@ -58,11 +60,11 @@ export interface CharBox extends Box{ /** * a basic Box - * - x : - * - y : + * - x : pt + * - y : pt * - textStyle : * - direction : - * - width : x_advance + * - width : x_advance pt * - content : */ export interface Box{ @@ -94,10 +96,10 @@ export const defaultFrameStyle : FrameBox = { direction : Direction.TTB, baseLineskip : ptToPx(15), textStyle : defaultTextStyle, - x : A4_IN_PX.width * 0.10, - y : A4_IN_PX.height * 0.10, - width : A4_IN_PX.width * 0.80, - height : A4_IN_PX.height * 0.80, + x : A4_IN_PX.width * 0.10 , + y : A4_IN_PX.height * 0.10 , + width : A4_IN_PX.width * 0.80 , + height : A4_IN_PX.height * 0.80 , content : null, }; @@ -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 { var res = []; + var styleCache = {}; + var fontCache = {}; for (var i=0; istyleCache, 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 { +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"); @@ -328,8 +356,8 @@ export async function calculateTextWidthHeightAux(element : tkTree, style : Text y : null, textStyle : style, direction : Direction.LTR, - width : (runGlyphsItem.advanceWidth)*(style.size)/1000, - height : (runGlyphsItem.bbox.maxY - runGlyphsItem.bbox.minY)*(style.size)/1000, + width : (runGlyphsItem.advanceWidth)*(style.size)/1000 * 0.75, // in pt + height : (runGlyphsItem.bbox.maxY - runGlyphsItem.bbox.minY)*(style.size)/1000 * 0.75, // in pt content : element[j], minX : runGlyphsItem.bbox.minX, maxX : runGlyphsItem.bbox.maxX, @@ -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,24 +457,314 @@ export class Clo{ } public async generatePdf(){ + // preprocessed var preprocessed = this.mainStream; for (var i = 0; ithis.attrs.defaultFrameStyle); + + + let boxesFixed = this.fixenBoxesPosition(segmentedNodesToBox); + + + + + // generate pdf + const doc = new PDFDocument({size: 'A4'}); + doc.pipe(fs.createWriteStream('output.pdf')); + this.grid(doc); + + let styleCache : any = {}; + let fontPairCache : fontPathPSNamePair = {path : "", psName : ""}; + await this.putText(doc, boxesFixed, styleCache, fontPairCache); + // putChar + doc.end(); + + + } + + async putText(doc : PDFKit.PDFDocument, box : Box, styleCache : TextStyle, + fontPairCache : fontPathPSNamePair): + Promise<[PDFKit.PDFDocument, TextStyle, fontPathPSNamePair]>{ + var fontPair; + + + if (box.textStyle !== null){ + + 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); + } + + if (Array.isArray(box.content)){ + for (var k=0; kthis.removeBreakPoints +(x).flat()); + let segmentedNodeUnglue = segmentedNodesFixed.map((x)=>this.removeGlue(x, frame).flat()); + + for (var i=0; icurrentLineSkip ){ + currentLineSkip = glyphMaxHeight; + } + + var currentLineBox : Box = { + x : null, + y : null, + textStyle : defaultTextStyle, + direction : frame.directionInsideLine, + width : frame.width, + height : currentLineSkip, + content : segmentedNodeUnglue[i], + } + + bigBoxContent.push(currentLineBox); + + } + + bigBox.content = bigBoxContent; + + return bigBox; + } + + /** + * get the max height of the glyph`[a, b, c]` + * @param nodeLine the node line [a, b, c, ...] + * @returns + */ + getGlyphMaxHeight(nodeLine : BoxesItem[]) : number{ + let segmentedNodeLineHeight = nodeLine.map((x : BoxesItem)=>{if ("height" in x && x.height > 0.0){return x.height}else{return 0.0}}); + let maxHeight = Math.max(...segmentedNodeLineHeight); + return maxHeight; + } + + removeGlue(nodeLine : BoxesItem[], frame : FrameBox) : BoxesItem[]{ + let breakLineAlgorithms = new breakLines.BreakLineAlgorithm(); + let glueRemoved = nodeLine.filter((x)=>!breakLineAlgorithms.isHGlue(x)); + let onlyGlue = nodeLine.filter((x)=>breakLineAlgorithms.isHGlue(x)); + let sumStretchFactor = onlyGlue.map((x)=>{if("stretchFactor" in x){ return x.stretchFactor} else{return 0;}}) + .reduce((acc, cur)=>acc+cur , 0); + + let glueRemovedWidth = glueRemoved.map((x)=>{if("width" in x){ return x.width} else{return 0;}}) + .reduce((acc, cur)=>acc+cur , 0); + let offset = frame.width * 0.75 - glueRemovedWidth; + var res = []; + for (var i=0; i