]> git.kianting.info Git - clo/blob - src/canva.ts
92650c66a80a84e68f3ed1afb5b572b31adb2272
[clo] / src / canva.ts
1 const { execSync } = require('child_process');
2 import { PDFDocument, RGB, ColorTypes } from "pdf-lib";
3 import { readFileSync, writeFileSync } from "fs";
4 import fontkit from '@pdf-lib/fontkit';
5
6
7 export interface CloCommand {
8 cmdName : string,
9 args : TextStreamUnit[],
10 }
11
12 export type TextStreamUnit = string | CloCommand;
13
14 /**
15 * a clo document
16 */
17 export interface Clo{
18 mainText : TextStreamUnit[],
19 mainFontStyle? : FontStyle,
20 PDFCanvas : PDFDocument,
21
22 }
23
24 /**
25 * Font Style Interface
26 * name : eg. "FreeSans"
27 * size : in px, not in pt.
28 * textWeight : TextWeight.REGULAR ,etc
29 * textWeight : TextStyle.ITALIC ,etc
30 */
31 export interface FontStyle{
32 name : string,
33 size : number,
34 textWeight : TextWeight,
35 textStyle : TextStyle,
36 color? : string,
37 };
38
39 export enum TextWeight {
40 REGULAR,
41 BOLD,
42 };
43
44 export enum TextStyle{
45 NORMAL,
46 ITALIC,
47 OBLIQUE,
48 };
49
50 /**
51 * guess the font path of a font style with fontconfig's commands
52 * @param style the font style
53 * @returns the font path in string, if found none or .ttc, return a empty string.
54 */
55 export function fontStyleTofontPath(style : FontStyle) : string{
56 try {
57 let fcMatchOut = execSync(
58 `fc-match "${style.name}":${TextWeight[style.textWeight]}:`+
59 `${TextStyle[style.textStyle]}`);
60
61 let fontFileName : string = fcMatchOut.toString().match(/^[^:]+/g)[0];
62
63 if (fontFileName.match(/[.]ttc$/g)){
64 console.log("WARNING: the program doesn't support .ttc font format!\n"+
65 "Font file name: "+
66 fontFileName);
67 return "";
68 }
69
70 let fcListOut = execSync(
71 `fc-list | grep ${fontFileName}`);
72 let fontPath : string = fcListOut.toString().match(/^[^:]+/g)[0];
73 return fontPath;
74 } catch (error) {
75 console.log("WARNING: You should install `fontconfig` to select the font.");
76 return "";
77 }
78 };
79
80 export function hexToRGB(hex : string) : RGB{
81 let matched = hex.match(/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
82
83 var result : RGB ;
84 if (!matched){
85 console.log("WARNING: the hex color code is not valid. set to #000000")
86 result = {
87 type : ColorTypes.RGB,
88 red: 0,
89 green: 0,
90 blue: 0,
91 }
92 }else{
93 result = {
94 type : ColorTypes.RGB,
95 red: parseInt(matched[1], 16),
96 green: parseInt(matched[2], 16),
97 blue: parseInt(matched[3], 16)
98 };
99 }
100
101 return result;
102 }
103
104 /**
105 * put text in a clo canva.
106 * @param clo : the clo object
107 * @param str input string
108 * @param sty input fontstyle
109 * @param PageNo : the input page, 0-indexed.
110 * @param x base x-point from left
111 * @param y base y-point from top
112 * @returns a new updated clo object
113 */
114 export async function putText(clo : Clo, str : string, sty : FontStyle,
115 pageNo : number, x : number, y : number): Promise<Clo>{
116
117 clo.PDFCanvas.registerFontkit(fontkit);
118 let canvaPage = clo.PDFCanvas.getPage(pageNo);
119
120
121 const fontBytes = readFileSync(fontStyleTofontPath(sty));
122 const fontEmbed = await clo.PDFCanvas.embedFont(fontBytes);
123
124 var textColor : RGB;
125 if (sty.color === undefined){
126 textColor = hexToRGB("#000000");
127 }else{
128 textColor = hexToRGB(sty.color);
129 }
130
131 let drawTextOptions = {
132 x : x,
133 y : canvaPage.getHeight() - y,
134 font : fontEmbed,
135 size : sty.size,
136 color : textColor};
137
138 canvaPage.drawText(str, drawTextOptions);
139
140 return clo;
141 };