2 var __createBinding
= (this && this.__createBinding
) || (Object
.create
? (function(o
, m
, k
, k2
) {
3 if (k2
=== undefined) k2
= k
;
4 var desc
= Object
.getOwnPropertyDescriptor(m
, k
);
5 if (!desc
|| ("get" in desc
? !m
.__esModule
: desc
.writable
|| desc
.configurable
)) {
6 desc
= { enumerable
: true, get: function() { return m
[k
]; } };
8 Object
.defineProperty(o
, k2
, desc
);
9 }) : (function(o
, m
, k
, k2
) {
10 if (k2
=== undefined) k2
= k
;
13 var __setModuleDefault
= (this && this.__setModuleDefault
) || (Object
.create
? (function(o
, v
) {
14 Object
.defineProperty(o
, "default", { enumerable
: true, value
: v
});
18 var __importStar
= (this && this.__importStar
) || function (mod
) {
19 if (mod
&& mod
.__esModule
) return mod
;
21 if (mod
!= null) for (var k
in mod
) if (k
!== "default" && Object
.prototype.hasOwnProperty
.call(mod
, k
)) __createBinding(result
, mod
, k
);
22 __setModuleDefault(result
, mod
);
25 var __awaiter
= (this && this.__awaiter
) || function (thisArg
, _arguments
, P
, generator
) {
26 function adopt(value
) { return value
instanceof P
? value
: new P(function (resolve
) { resolve(value
); }); }
27 return new (P
|| (P
= Promise
))(function (resolve
, reject
) {
28 function fulfilled(value
) { try { step(generator
.next(value
)); } catch (e
) { reject(e
); } }
29 function rejected(value
) { try { step(generator
["throw"](value
)); } catch (e
) { reject(e
); } }
30 function step(result
) { result
.done
? resolve(result
.value
) : adopt(result
.value
).then(fulfilled
, rejected
); }
31 step((generator
= generator
.apply(thisArg
, _arguments
|| [])).next());
34 Object
.defineProperty(exports
, "__esModule", { value
: true });
35 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;
36 const canva_1
= require("../canva");
37 const fontkit
= __importStar(require("fontkit"));
38 const breakLines
= __importStar(require("./breakLines"));
40 const pdf_lib_1
= require("pdf-lib");
41 const fs
= __importStar(require("fs"));
52 (function (Direction
) {
53 Direction
[Direction
["LTR"] = 0] = "LTR";
54 Direction
[Direction
["RTL"] = 1] = "RTL";
55 Direction
[Direction
["TTB"] = 2] = "TTB";
56 Direction
[Direction
["BTT"] = 3] = "BTT";
57 })(Direction
|| (exports
.Direction
= Direction
= {}));
61 exports
.A4_IN_PX
= { "width": 793.7,
63 exports
.defaultTextStyle
= {
66 textWeight
: canva_1
.TextWeight
.REGULAR
,
67 fontStyle
: canva_1
.FontStyle
.ITALIC
,
69 exports
.defaultFrameStyle
= {
70 directionInsideLine
: Direction
.LTR
,
71 direction
: Direction
.TTB
,
72 baseLineskip
: ptToPx(15),
73 textStyle
: exports
.defaultTextStyle
,
74 x
: exports
.A4_IN_PX
.width
* 0.10,
75 y
: exports
.A4_IN_PX
.height
* 0.10,
76 width
: exports
.A4_IN_PX
.width
* 0.80,
77 height
: exports
.A4_IN_PX
.height
* 0.80,
81 * definition for cjk scripts
82 * - Hani : Han Character
88 exports
.cjkvBlocksInRegex
= ["Hani", "Hang", "Bopo", "Kana", "Hira"];
89 exports
.cjkvRegexPattern
= new RegExp("((?:" +
90 exports
.cjkvBlocksInRegex
.map((x
) => "\\p{Script_Extensions=" + x
+ "}").join("|") + ")+)", "gu");
96 * @param pt pt size value
97 * @returns the corresponding px value
100 return pt
* 4.0 / 3.0;
102 exports
.ptToPx
= ptToPx
;
107 * convert '\n\n' to newline command ["nl"]
108 * @param arr the input `tkTree`
109 * @param clo the `Clo` object
110 * @returns the input tktree
112 function twoReturnsToNewline(arr
, clo
) {
114 for (let i
= 0; i
< arr
.length
; i
++) {
116 if (!Array
.isArray(item
)) {
117 middle
= middle
.concat(item
.split(/(\n\n)/g));
124 for (let j
= 0; j
< middle
.length
; j
++) {
125 var item
= middle
[j
];
126 if (!Array
.isArray(item
) && item
== "\n\n") {
127 result
.push(["nl"]); // push a newline command to the result `tkTree`
130 result
.push(middle
[j
]);
135 exports
.twoReturnsToNewline
= twoReturnsToNewline
;
137 * split CJKV and non-CJKV
139 * @param arr : input tkTree
140 * @returns a splitted tkTree (by CJK and NonCJK)
143 * [`many臺中daylight`] => [`many`, `臺中`, `dahylight`]
146 function splitCJKV(arr
, clo
) {
148 for (let i
= 0; i
< arr
.length
; i
++) {
150 if (!Array
.isArray(item
)) {
151 result
= result
.concat(item
.split(exports
.cjkvRegexPattern
));
159 exports
.splitCJKV
= splitCJKV
;
161 * hyphenation for a clo document
162 * @param arr the array for a `tkTree`
163 * @param clo the Clo object
165 function hyphenForClo(arr
, clo
) {
166 let hyphenLanguage
= clo
.attrs
["hyphenLanguage"];
167 let res
= hyphenTkTree(arr
, hyphenLanguage
);
170 exports
.hyphenForClo
= hyphenForClo
;
172 * convert spaces to Breakpoint
173 * \s+ => ["bp" [\s+] ""]
174 * @param arr the tkTree input text stream
175 * @param clo the Clo object
176 * @returns the converted object
178 function spacesToBreakpoint(arr
, clo
) {
179 let spacePattern
= /^([ \t]+)$/g;
181 for (let i
= 0; i
< arr
.length
; i
++) {
183 if (!Array
.isArray(item
) && item
.match(spacePattern
)) {
184 // push a breakpoint command to the result `tkTree`
185 result
.push(['bp', [["hglue", "0.1"], item
], ""]);
193 exports
.spacesToBreakpoint
= spacesToBreakpoint
;
195 * remove all the `` (empty string) in the arr
196 * @param arr the tkTree to be filtered
197 * @param clo the Clo file
199 function filterEmptyString(arr
, clo
) {
200 if (Array
.isArray(arr
)) {
201 arr
.filter((x
) => { return x
!= ``; });
205 exports
.filterEmptyString
= filterEmptyString
;
210 * hyphenate for a tkTree
211 * - hyphenation => ["bp", "", "-"]
212 * @param arr the tkTree array
213 * @param lang ISO 639 code for the language
215 function hyphenTkTree(arr
, lang
) {
216 // import corresponding hyphen language data and function
217 let hyphen
= require("hyphen/" + lang
);
219 for (let i
= 0; i
< arr
.length
; i
++) {
220 let element
= arr
[i
];
221 let splitter
= "分"; // a CJKV
222 if (!Array
.isArray(element
)) {
223 let hyphenatedElement
= hyphen
.hyphenateSync(element
, { hyphenChar
: splitter
});
224 let hyphenatedSplitted
= hyphenatedElement
.split(splitter
);
225 var newSplitted
= [];
226 for (var j
= 0; j
< hyphenatedSplitted
.length
- 1; j
++) {
227 newSplitted
.push(hyphenatedSplitted
[j
]);
228 // "bp" for breakpoint
229 newSplitted
.push(["bp", "", "-"]); //insert a breakable point (bp) mark
231 newSplitted
.push(hyphenatedSplitted
[hyphenatedSplitted
.length
- 1]);
232 result
= result
.concat(newSplitted
);
235 result
.push(element
);
240 exports
.hyphenTkTree
= hyphenTkTree
;
242 * calculate the text width and Height with a given `TextStyle`
243 * @param preprocessed
244 * @param defaultFontStyle
246 function calculateTextWidthHeight(element
, style
) {
247 return __awaiter(this, void 0, void 0, function* () {
249 for (var i
= 0; i
< element
.length
; i
++) {
250 res
.push(yield calculateTextWidthHeightAux(element
[i
], style
));
256 exports
.calculateTextWidthHeight
= calculateTextWidthHeight
;
258 * calculate the text width and Height with a given `TextStyle`
259 * @param preprocessed
260 * @param defaultFontStyle
262 function calculateTextWidthHeightAux(element
, style
) {
263 return __awaiter(this, void 0, void 0, function* () {
265 let fontPair
= (0, canva_1
.fontStyleTofont
)(style
);
266 if (fontPair
.path
.match(/\.ttc$/)) {
267 var font
= yield fontkit
.openSync(fontPair
.path
, fontPair
.psName
);
270 var font
= yield fontkit
.openSync(fontPair
.path
);
272 if (!Array
.isArray(element
)) {
273 var run
= font
.layout(element
, undefined, undefined, undefined, "ltr");
274 for (var j
= 0; j
< run
.glyphs
.length
; j
++) {
275 let runGlyphsItem
= run
.glyphs
[j
];
280 direction
: Direction
.LTR
,
281 width
: (runGlyphsItem
.advanceWidth
) * (style
.size
) / 1000,
282 height
: (runGlyphsItem
.bbox
.maxY
- runGlyphsItem
.bbox
.minY
) * (style
.size
) / 1000,
284 minX
: runGlyphsItem
.bbox
.minX
,
285 maxX
: runGlyphsItem
.bbox
.maxX
,
286 minY
: runGlyphsItem
.bbox
.minY
,
287 maxY
: runGlyphsItem
.bbox
.maxY
293 else if (element
[0] == "bp") {
294 var beforeNewLine
= yield calculateTextWidthHeightAux(element
[1], style
);
295 if (Array
.isArray(beforeNewLine
)) {
296 beforeNewLine
= beforeNewLine
.flat();
298 let afterNewLine
= yield calculateTextWidthHeightAux(element
[2], style
);
299 if (Array
.isArray(afterNewLine
)) {
300 afterNewLine
= afterNewLine
.flat();
302 let breakPointNode
= {
303 original
: beforeNewLine
,
304 newLined
: afterNewLine
,
306 return breakPointNode
;
308 else if (element
[0] == "hglue" && !Array
.isArray(element
[1])) {
309 let hGlue
= { stretchFactor
: parseFloat(element
[1]) };
313 return calculateTextWidthHeight(element
, style
);
317 exports
.calculateTextWidthHeightAux
= calculateTextWidthHeightAux
;
319 * whole document-representing class
323 this.preprocessors
= [];
324 this.mainStream
= [];
326 "page": exports
.A4_IN_PX
,
327 "defaultFrameStyle": exports
.defaultFrameStyle
,
328 "hyphenLanguage": 'en' // hyphenated in the language (in ISO 639)
330 // register the precessor functions
331 this.preprocessorRegister(splitCJKV
);
332 this.preprocessorRegister(hyphenForClo
);
333 this.preprocessorRegister(twoReturnsToNewline
);
334 this.preprocessorRegister(spacesToBreakpoint
);
335 this.preprocessorRegister(filterEmptyString
);
338 Object
.assign(this.attrs
, attr
, val
);
341 if (Object
.keys(this.attrs
).length
=== 0) {
342 return this.attrs
[attr
];
349 * register a function of preprocessor
350 * @param f a function
352 preprocessorRegister(f
) {
353 this.preprocessors
.push(f
);
356 return __awaiter(this, void 0, void 0, function* () {
358 var preprocessed
= this.mainStream
;
359 for (var i
= 0; i
< this.preprocessors
.length
; i
++) {
360 preprocessed
= this.preprocessors
[i
](preprocessed
, this);
362 // generate the width and height of the stream
363 let defaultFontStyle
= this.attrs
["defaultFrameStyle"].textStyle
;
364 let a
= yield calculateTextWidthHeight(preprocessed
, defaultFontStyle
);
365 let breakLineAlgorithms
= new breakLines
.BreakLineAlgorithm();
367 //console.log(breakLineAlgorithms.totalCost(a,70));
368 let segmentedNodes
= breakLineAlgorithms
.segmentedNodes(a
, 70);
369 console
.log(this.segmentedNodesToFrameBox(segmentedNodes
, this.attrs
["defaultFrameStyle"]));
371 const pdfDoc
= yield pdf_lib_1
.PDFDocument
.create();
372 var page
= pdfDoc
.addPage();
373 page
.drawText('You can create PDFs!');
374 for (var j
= 0; j
< 1000; j
+= 5) {
376 page
.drawText(j
.toString(), { x
: 50, y
: j
});
379 start
: { x
: 0, y
: j
},
380 end
: { x
: 1000, y
: j
},
382 color
: (0, pdf_lib_1
.rgb
)(0.75, 0.2, 0.2),
386 for (var i
= 0; i
< 1000; i
+= 5) {
388 page
.drawText(i
.toString(), { x
: i
, y
: 50 });
391 start
: { x
: i
, y
: 0 },
392 end
: { x
: i
, y
: 1000 },
394 color
: (0, pdf_lib_1
.rgb
)(0.75, 0.2, 0.2),
399 const pdfBytes
= yield pdfDoc
.save();
400 fs
.writeFileSync("blank.pdf", pdfBytes
);
403 segmentedNodesToFrameBox(segmentedNodes
, frame
) {
404 let baseLineskip
= frame
.baseLineskip
;
405 let boxArrayEmpty
= [];
409 textStyle
: frame
.textStyle
,
410 direction
: frame
.direction
,
412 height
: frame
.height
,
413 content
: boxArrayEmpty
,
415 var bigBoxContent
= boxArrayEmpty
;
416 let segmentedNodesFixed
= segmentedNodes
.map((x
) => this.removeBreakPoints(x
).flat());
417 let segmentedNodeUnglue
= segmentedNodesFixed
.map((x
) => this.removeGlue(x
, frame
).flat());
418 for (var i
= 0; i
< segmentedNodesFixed
.length
- 1; i
++) {
419 var currentLineSkip
= baseLineskip
;
420 var glyphMaxHeight
= this.getGlyphMaxHeight(segmentedNodesFixed
[i
]);
421 if (currentLineSkip
=== null || glyphMaxHeight
> currentLineSkip
) {
422 currentLineSkip
= glyphMaxHeight
;
424 var currentLineBox
= {
427 textStyle
: exports
.defaultTextStyle
,
428 direction
: frame
.directionInsideLine
,
430 height
: currentLineSkip
,
431 content
: segmentedNodeUnglue
[i
],
433 bigBoxContent
.push(currentLineBox
);
435 bigBox
.content
= bigBoxContent
;
439 * get the max height of the glyph`[a, b, c]`
440 * @param nodeLine the node line [a, b, c, ...]
443 getGlyphMaxHeight(nodeLine
) {
444 let segmentedNodeLineHeight
= nodeLine
.map((x
) => { if ("height" in x
&& x
.height
> 0.0) {
450 let maxHeight
= Math
.max(...segmentedNodeLineHeight
);
453 removeGlue(nodeLine
, frame
) {
454 let breakLineAlgorithms
= new breakLines
.BreakLineAlgorithm();
455 let glueRemoved
= nodeLine
.filter((x
) => !breakLineAlgorithms
.isHGlue(x
));
456 let onlyGlue
= nodeLine
.filter((x
) => breakLineAlgorithms
.isHGlue(x
));
457 let sumStretchFactor
= onlyGlue
.map((x
) => { if ("stretchFactor" in x
) {
458 return x
.stretchFactor
;
463 .reduce((acc
, cur
) => acc
+ cur
, 0);
464 let glueRemovedWidth
= glueRemoved
.map((x
) => { if ("width" in x
) {
470 .reduce((acc
, cur
) => acc
+ cur
, 0);
471 let offset
= frame
.width
- glueRemovedWidth
;
473 for (var i
= 0; i
< nodeLine
.length
; i
++) {
474 var ele
= nodeLine
[i
];
475 if (breakLineAlgorithms
.isHGlue(ele
)) {
480 direction
: frame
.directionInsideLine
,
481 width
: ele
.stretchFactor
/ sumStretchFactor
* offset
,
495 * @param boxitemline boxitem in a line with a breakpoint
496 * @returns boxitemline with break points removed
498 removeBreakPoints(boxitemline
) {
500 let breakLineAlgorithms
= new breakLines
.BreakLineAlgorithm();
501 for (var i
= 0; i
< boxitemline
.length
; i
++) {
502 let ele
= boxitemline
[i
];
503 if (breakLineAlgorithms
.isBreakPoint(ele
)) {
504 if (i
== boxitemline
.length
- 1) {
505 res
.push(ele
.newLined
);
508 res
.push(ele
.original
);
520 export let a = new Clo();