forked from tkrkt/text2png
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
85 lines (73 loc) · 2.43 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
'use strict';
const Canvas = require('canvas-prebuilt');
/**
* Convert text to PNG image.
* @param text
* @param [option]
* @param [option.font='30px sans-serif']
* @param [option.textColor='black']
* @param [option.bgColor]
* @param [option.lineSpacing=0]
* @param [option.ypadding=0]
* @param [option.output='buffer'] 'buffer', 'stream', 'dataURL', 'canvas'
* @returns {string} png image buffer
*/
module.exports = (text, option) => {
option = option || {};
option.font = option.font || '30px sans-serif';
option.textColor = option.textColor || 'black';
option.lineSpacing = option.lineSpacing || 0;
option.xpadding = option.xpadding || 0;
option.ypadding = option.ypadding || 0;
option.output = option.output || 'buffer';
const canvas = new Canvas(0, 0);
const ctx = canvas.getContext('2d');
const max = {
left: 0,
right: 0,
ascent: 0,
descent: 0
};
let lastDescent;
const lineProps = text.split('\n').map(line => {
ctx.font = option.font;
const metrics = ctx.measureText(line);
const left = -1 * metrics.actualBoundingBoxLeft;
const right = metrics.actualBoundingBoxRight;
const ascent = metrics.actualBoundingBoxAscent;
const descent = metrics.actualBoundingBoxDescent;
max.left = Math.max(max.left, left);
max.right = Math.max(max.right, right);
max.ascent = Math.max(max.ascent, ascent);
max.descent = Math.max(max.descent, descent);
lastDescent = descent;
return {line, left, ascent};
});
const lineHeight = max.ascent + max.descent + option.lineSpacing;
canvas.width = max.left + max.right + option.xpadding * 2;
canvas.height = lineHeight * lineProps.length + option.ypadding * 2 - option.lineSpacing - (max.descent - lastDescent);
if (option.bgColor) {
ctx.fillStyle = option.bgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx.font = option.font;
ctx.fillStyle = option.textColor;
ctx.antialias = 'gray';
let offsetY = option.ypadding;
lineProps.forEach(lineProp => {
ctx.fillText(lineProp.line, lineProp.left + option.xpadding, max.ascent + offsetY);
offsetY += lineHeight;
});
switch (option.output) {
case 'buffer':
return canvas.toBuffer();
case 'stream':
return canvas.createPNGStream();
case 'dataURL':
return canvas.toDataURL('image/png');
case 'canvas':
return canvas;
default:
throw new Error(`output type:${option.output} is not supported.`)
}
};