加上量字功能
This commit is contained in:
parent
90fd2d0d5c
commit
0ccf7a2fa2
4 changed files with 143 additions and 42 deletions
47
src/index.js
47
src/index.js
|
@ -44,7 +44,8 @@ var TokenKind;
|
|||
TokenKind[TokenKind["SpaceNL"] = 9] = "SpaceNL";
|
||||
TokenKind[TokenKind["BSlash"] = 10] = "BSlash";
|
||||
TokenKind[TokenKind["Apos"] = 11] = "Apos";
|
||||
TokenKind[TokenKind["Other"] = 12] = "Other";
|
||||
TokenKind[TokenKind["Cmt"] = 12] = "Cmt";
|
||||
TokenKind[TokenKind["Other"] = 13] = "Other";
|
||||
})(TokenKind || (TokenKind = {}));
|
||||
var ItemType;
|
||||
(function (ItemType) {
|
||||
|
@ -71,16 +72,16 @@ const tokenizer = (0, typescript_parsec_1.buildLexer)([
|
|||
[true, /^'/g, TokenKind.Apos],
|
||||
[true, /^(\s|\t|\r?\n)+/g, TokenKind.SpaceNL],
|
||||
[true, /^\\/g, TokenKind.BSlash],
|
||||
[false, /^\/\/[^\/\r\n]+(\r?\n)/g, TokenKind.Cmt],
|
||||
[true, /^([^+\-*/a-zA-Z_0-9\[\]()'\s\t\r\n\\]+)/g, TokenKind.Other],
|
||||
]);
|
||||
/*
|
||||
* ## BNF
|
||||
LISP = UNIT | LISPS | CON_STR
|
||||
LISP = SINGLE | LISPS | CON_STR
|
||||
LISPS = "(" LISP ")" | "'" "(" LISP ")"
|
||||
SINGLE = "{" CONSTR_INNR | LISP "}"
|
||||
UNIT = INT | NUMBER | STRING | ID
|
||||
CONSTR = "[" (CONSTR_INNER "]"
|
||||
CONSTR_INNER = ([^\\\[\][]] | [\\][{}\[\]]) | LISPS)*
|
||||
SINGLE = INT | NUMBER | STRING | ID
|
||||
CON_STR = "[" CONSTR_INNER "]"
|
||||
CONSTR_INNER = ([^\\\[\]{}] | [\\][{}\[\]]) | LISPS)*
|
||||
*/
|
||||
const SINGLE = (0, typescript_parsec_1.rule)();
|
||||
const LISPS = (0, typescript_parsec_1.rule)();
|
||||
|
@ -151,7 +152,7 @@ function applyStrings(value) {
|
|||
return merged;
|
||||
}
|
||||
/** for convinence to omit the spaces and newlines */
|
||||
const __ = (0, typescript_parsec_2.opt)((0, typescript_parsec_2.tok)(TokenKind.SpaceNL));
|
||||
const __ = (0, typescript_parsec_2.rep_sc)((0, typescript_parsec_2.tok)(TokenKind.SpaceNL));
|
||||
LISP.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.kleft)(SINGLE, __), (0, typescript_parsec_2.kleft)(LISPS, __), (0, typescript_parsec_2.kleft)(CON_STR, __)));
|
||||
SINGLE.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Id), applyId), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Int), applyInt), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Flo), applyFlo), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Str), applyStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Bool), applyBool)));
|
||||
LISPS.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.apply)((0, typescript_parsec_2.kmid)((0, typescript_parsec_2.seq)((0, typescript_parsec_2.str)("("), __), (0, typescript_parsec_2.rep_sc)(LISP), (0, typescript_parsec_2.str)(")")), applyList), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.str)("'"), (0, typescript_parsec_2.kmid)((0, typescript_parsec_2.seq)((0, typescript_parsec_2.str)("("), __), (0, typescript_parsec_2.rep_sc)(LISP), (0, typescript_parsec_2.str)(")"))), applyQuoted)));
|
||||
|
@ -175,7 +176,7 @@ async function measureWidthPx(inputString, fontFamily, fontSizePt) {
|
|||
var blob = hb.createBlob(fontdata); // Load the font data into something Harfbuzz can use
|
||||
var face = hb.createFace(blob, 0); // Select the first font in the file (there's normally only one!)
|
||||
var font = hb.createFont(face); // Create a Harfbuzz font object from the face
|
||||
font.setScale(fontSizePt * 4 / 3 * 1000, fontSizePt * 4 / 3 * 1000);
|
||||
font.setScale(fontSizePt * 1000, fontSizePt * 1000);
|
||||
var buffer = hb.createBuffer(); // Make a buffer to hold some text
|
||||
buffer.addText(inputString); // Fill it with some stuff
|
||||
buffer.guessSegmentProperties(); // Set script, language and direction
|
||||
|
@ -401,21 +402,21 @@ function cons(h, t) {
|
|||
}
|
||||
/* PDF manipulation */
|
||||
async function drawText(pageIndex, fontFamily, textSize, color, x, y, text) {
|
||||
let currentPage = pdfDoc.getPages()[0];
|
||||
let pdfPages = pdfDoc.getPages();
|
||||
let currentPage = pdfPages[pageIndex];
|
||||
const fcMatch = await (0, child_process_1.spawnSync)('fc-match', ['--format=%{file}', fontFamily]);
|
||||
const path = fcMatch.stdout.toString();
|
||||
pdfDoc.registerFontkit(fontkit_1.default);
|
||||
const fontBytes = fs.readFileSync(path);
|
||||
const customFont = await pdfDoc.embedFont(fontBytes);
|
||||
const rgbColor = await hexColorToRGB(color);
|
||||
let a = await pdfDoc.getPage(0).drawText(text, {
|
||||
let _ = await currentPage.drawText(text, {
|
||||
x: x,
|
||||
y: y,
|
||||
size: textSize,
|
||||
font: customFont,
|
||||
color: rgbColor,
|
||||
});
|
||||
await pdfDoc.save();
|
||||
}
|
||||
async function hexColorToRGB(hex) {
|
||||
let rgbHex = /[#]?([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})/.exec(hex);
|
||||
|
@ -825,7 +826,7 @@ async function interp(prog, env) {
|
|||
throw new Error("the type of replace and variable should be the same.");
|
||||
}
|
||||
else {
|
||||
env[vari.id][0].value = prog[2];
|
||||
env[vari.id][0].value = replacer;
|
||||
return { type: ItemType.Unit };
|
||||
}
|
||||
}
|
||||
|
@ -850,7 +851,7 @@ async function interp(prog, env) {
|
|||
}
|
||||
else {
|
||||
const fontFamily = argsMapped[0].str;
|
||||
const textSize = argsMapped[1].int;
|
||||
const textSize = argsMapped[1].flo;
|
||||
const color = argsMapped[2].str;
|
||||
const x = argsMapped[3].flo;
|
||||
const y = argsMapped[4].flo;
|
||||
|
@ -861,6 +862,26 @@ async function interp(prog, env) {
|
|||
};
|
||||
}
|
||||
}
|
||||
// print to the console
|
||||
else if (op.id === "print") {
|
||||
if (prog.length !== 2) {
|
||||
throw invalidLengthException('print', 1);
|
||||
}
|
||||
else {
|
||||
let data = argsMapped[0];
|
||||
let dataString;
|
||||
if (data.hasOwnProperty("list")) {
|
||||
dataString = astToString(data, true);
|
||||
}
|
||||
else {
|
||||
dataString = astToString(data, false);
|
||||
}
|
||||
console.log(dataString);
|
||||
return {
|
||||
type: ItemType.Unit,
|
||||
};
|
||||
}
|
||||
}
|
||||
// procedures returning the last called command
|
||||
else if (op.id === "begin") {
|
||||
const rtn = argsMapped[argsMapped.length - 1];
|
||||
|
|
48
src/index.ts
48
src/index.ts
|
@ -39,7 +39,8 @@ enum TokenKind {
|
|||
RBrack,
|
||||
SpaceNL,
|
||||
BSlash,
|
||||
Apos,
|
||||
Apos, // Apostrophe
|
||||
Cmt, // comment
|
||||
Other,
|
||||
}
|
||||
|
||||
|
@ -124,17 +125,17 @@ const tokenizer = buildLexer([
|
|||
[true, /^'/g, TokenKind.Apos],
|
||||
[true, /^(\s|\t|\r?\n)+/g, TokenKind.SpaceNL],
|
||||
[true, /^\\/g, TokenKind.BSlash],
|
||||
[false, /^\/\/[^\/\r\n]+(\r?\n)/g, TokenKind.Cmt], // omit the comment
|
||||
[true, /^([^+\-*/a-zA-Z_0-9\[\]()'\s\t\r\n\\]+)/g, TokenKind.Other],
|
||||
]);
|
||||
|
||||
/*
|
||||
* ## BNF
|
||||
LISP = UNIT | LISPS | CON_STR
|
||||
LISP = SINGLE | LISPS | CON_STR
|
||||
LISPS = "(" LISP ")" | "'" "(" LISP ")"
|
||||
SINGLE = "{" CONSTR_INNR | LISP "}"
|
||||
UNIT = INT | NUMBER | STRING | ID
|
||||
CONSTR = "[" (CONSTR_INNER "]"
|
||||
CONSTR_INNER = ([^\\\[\][]] | [\\][{}\[\]]) | LISPS)*
|
||||
SINGLE = INT | NUMBER | STRING | ID
|
||||
CON_STR = "[" CONSTR_INNER "]"
|
||||
CONSTR_INNER = ([^\\\[\]{}] | [\\][{}\[\]]) | LISPS)*
|
||||
*/
|
||||
|
||||
const SINGLE = rule<TokenKind, AST>();
|
||||
|
@ -216,7 +217,7 @@ function applyStrings(value: AST[]): AST {
|
|||
}
|
||||
|
||||
/** for convinence to omit the spaces and newlines */
|
||||
const __ = opt(tok(TokenKind.SpaceNL));
|
||||
const __ = rep_sc(tok(TokenKind.SpaceNL));
|
||||
|
||||
LISP.setPattern(alt(kleft(SINGLE, __), kleft(LISPS, __), kleft(CON_STR, __)));
|
||||
|
||||
|
@ -286,7 +287,7 @@ async function measureWidthPx(inputString: string, fontFamily : string, fontSize
|
|||
var blob = hb.createBlob(fontdata); // Load the font data into something Harfbuzz can use
|
||||
var face = hb.createFace(blob, 0); // Select the first font in the file (there's normally only one!)
|
||||
var font = hb.createFont(face); // Create a Harfbuzz font object from the face
|
||||
font.setScale(fontSizePt * 4/3* 1000 , fontSizePt*4/3 * 1000 );
|
||||
font.setScale(fontSizePt * 1000 , fontSizePt * 1000 );
|
||||
var buffer = hb.createBuffer(); // Make a buffer to hold some text
|
||||
buffer.addText(inputString); // Fill it with some stuff
|
||||
buffer.guessSegmentProperties(); // Set script, language and direction
|
||||
|
@ -309,7 +310,7 @@ async function measureWidthPx(inputString: string, fontFamily : string, fontSize
|
|||
face.destroy();
|
||||
blob.destroy();
|
||||
|
||||
return totalX / 1000;
|
||||
return totalX / 1000;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -523,7 +524,8 @@ async function drawText(pageIndex : number,
|
|||
x : number,
|
||||
y : number,
|
||||
text : string){
|
||||
let currentPage = pdfDoc.getPages()[0];
|
||||
let pdfPages = pdfDoc.getPages();
|
||||
let currentPage = pdfPages[pageIndex];
|
||||
|
||||
const fcMatch = await spawnSync('fc-match', ['--format=%{file}', fontFamily]);
|
||||
const path = fcMatch.stdout.toString();
|
||||
|
@ -534,14 +536,14 @@ const path = fcMatch.stdout.toString();
|
|||
|
||||
const rgbColor = await hexColorToRGB(color);
|
||||
|
||||
let a = await pdfDoc.getPage(0).drawText(text, {
|
||||
let _ = await currentPage.drawText(text, {
|
||||
x: x,
|
||||
y: y,
|
||||
size: textSize,
|
||||
font: customFont,
|
||||
color: rgbColor,
|
||||
});
|
||||
await pdfDoc.save();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -918,7 +920,7 @@ async function interp(prog: AST, env: Env): Promise<AST> {
|
|||
|| (env[vari.id][0].value as Item).type != replacer.type ){
|
||||
throw new Error("the type of replace and variable should be the same.")
|
||||
}else{
|
||||
env[vari.id][0].value = prog[2];
|
||||
env[vari.id][0].value = replacer;
|
||||
return {type:ItemType.Unit};
|
||||
}
|
||||
}
|
||||
|
@ -940,7 +942,7 @@ async function interp(prog: AST, env: Env): Promise<AST> {
|
|||
throw invalidLengthException('drawText', 6);
|
||||
}else{
|
||||
const fontFamily = (argsMapped[0] as ItemStr).str;
|
||||
const textSize = (argsMapped[1] as ItemInt).int;
|
||||
const textSize = (argsMapped[1] as ItemFlo).flo;
|
||||
const color = (argsMapped[2] as ItemStr).str;
|
||||
const x = (argsMapped[3] as ItemFlo).flo;
|
||||
const y = (argsMapped[4] as ItemFlo).flo;
|
||||
|
@ -958,6 +960,24 @@ async function interp(prog: AST, env: Env): Promise<AST> {
|
|||
}
|
||||
}
|
||||
}
|
||||
// print to the console
|
||||
else if (op.id === "print"){
|
||||
if (prog.length !== 2){
|
||||
throw invalidLengthException('print', 1);
|
||||
}else{
|
||||
let data = argsMapped[0];
|
||||
let dataString;
|
||||
if (data.hasOwnProperty("list")){
|
||||
dataString = astToString(data, true);
|
||||
}else{
|
||||
dataString = astToString(data, false);
|
||||
}
|
||||
console.log(dataString);
|
||||
return {
|
||||
type:ItemType.Unit,
|
||||
}
|
||||
}
|
||||
}
|
||||
// procedures returning the last called command
|
||||
else if (op.id === "begin"){
|
||||
const rtn = argsMapped[argsMapped.length-1];
|
||||
|
|
90
text.lisp
90
text.lisp
|
@ -1,8 +1,8 @@
|
|||
(begin
|
||||
(define defaultFontFormat
|
||||
'(("fontFamily" "Gentium")
|
||||
'(("fontFamily" "FreeSerif")
|
||||
("color" "#ff0000")
|
||||
("fontSize" 12)
|
||||
("fontSize" 12.0)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -23,6 +23,13 @@
|
|||
(setDictItemAux dict '() key data)
|
||||
)))
|
||||
|
||||
(define addDictItem (lambda (dict key data)
|
||||
(if (= (dictRef dict key) false)
|
||||
(extendDict dict key data)
|
||||
dict
|
||||
)
|
||||
))
|
||||
|
||||
(define setDictItemAux (lambda (oldDict newDict key data)
|
||||
(if (= oldDict '()) newDict
|
||||
(if (= (car(car oldDict)) key)
|
||||
|
@ -30,36 +37,89 @@
|
|||
(setDictItemAux (cdr oldDict) (cons (car oldDict) newDict) key data)
|
||||
))))
|
||||
|
||||
|
||||
(addPDFPage '())
|
||||
(addPDFPage '())
|
||||
(define text2boxAux2 (lambda (format text)
|
||||
(if (isList text)
|
||||
// set font size
|
||||
(if (= (listRef text 0) "fontSize")
|
||||
(let ((newFormat (setDictItem format "fontSize" (listRef text 1)))) (text2boxAux1 newFormat (listRef text 2)))
|
||||
text)
|
||||
(cons format (cons text '())))
|
||||
(cons (cons "content" (cons text '())) format)
|
||||
)
|
||||
))
|
||||
|
||||
(define text2boxAux1 (lambda (format txt)
|
||||
(if (isList txt)
|
||||
(map (lambda (x) (text2boxAux2 format x)) txt)
|
||||
(cons format (cons txt '()))
|
||||
(cons (cons "content" (cons txt '())) format)
|
||||
)))
|
||||
|
||||
(define text2box (lambda (txt) (text2boxAux1 defaultFontFormat txt)))
|
||||
// (measureWidthPx "1314abc" "Gentium" 12.0)
|
||||
|
||||
(define measureBoxItem (lambda (boxList) (map measureBoxItemAux boxList)))
|
||||
(define measureBoxItemAux (lambda (boxDict)
|
||||
(let
|
||||
((fontFamily (dictRef boxDict "fontFamily"))
|
||||
(fontSize (dictRef boxDict "fontSize"))
|
||||
(content (dictRef boxDict "content")))
|
||||
(let
|
||||
((measuredWidthPx (measureWidthPx content fontFamily fontSize)))
|
||||
(addDictItem boxDict "widthPx" measuredWidthPx)
|
||||
)
|
||||
)))
|
||||
|
||||
(define text2box (lambda (txt)
|
||||
(let ((tmp1 (text2boxAux1 defaultFontFormat txt)))
|
||||
(let ((res (measureBoxItem tmp1))) res)
|
||||
)))
|
||||
|
||||
|
||||
|
||||
|
||||
(drawText
|
||||
(dictRef defaultFontFormat "fontFamily")
|
||||
(dictRef defaultFontFormat "fontSize")
|
||||
(dictRef defaultFontFormat "color")
|
||||
40.0
|
||||
50.0
|
||||
"blah"
|
||||
|
||||
//(drawText
|
||||
//(dictRef defaultFontFormat "fontFamily")
|
||||
//(dictRef defaultFontFormat "fontSize")
|
||||
//(dictRef defaultFontFormat "color")
|
||||
//40.0
|
||||
//50.0
|
||||
//"blah"
|
||||
//)
|
||||
(define x 0.0)
|
||||
|
||||
(define text '("abracabra" ("fontSize" 18.0 "cat") "foo"))
|
||||
|
||||
(define putOnChar (lambda (boxDict x)
|
||||
(let
|
||||
((content (dictRef boxDict "content"))
|
||||
(fontFamily (dictRef boxDict "fontFamily"))
|
||||
(fontSize (dictRef boxDict "fontSize"))
|
||||
(color (dictRef boxDict "color"))
|
||||
(widthPx (dictRef boxDict "widthPx"))
|
||||
)
|
||||
(begin
|
||||
(drawText fontFamily fontSize color x 100.0 content)
|
||||
(+ x widthPx)) // return an updated x
|
||||
|
||||
)))
|
||||
|
||||
(define putOnChars (lambda (ls x)
|
||||
(if (= ls '())
|
||||
'()
|
||||
(let
|
||||
((newX (putOnChar (car ls) x)))
|
||||
(putOnChars (cdr ls) newX))
|
||||
))
|
||||
)
|
||||
(define text '("abracabra" ("fontSize" 18 "貓") "foo"))
|
||||
(text2box text)
|
||||
(measureWidthPx "1314abc" "Gentium" 12.0)
|
||||
|
||||
(let ((boxOfText (text2box text)))
|
||||
(putOnChars boxOfText 0.0)
|
||||
)
|
||||
|
||||
|
||||
|
||||
(text2box text)
|
||||
// (measureWidthPx "1314abc" "Gentium" 12.0)
|
||||
)
|
BIN
text.lisp.pdf
BIN
text.lisp.pdf
Binary file not shown.
Loading…
Reference in a new issue