♻️ switching to typescript
This commit is contained in:
@@ -1,26 +1,38 @@
|
||||
import Node from '../Node';
|
||||
import {waitForMedia} from '../../utils';
|
||||
import {waitForMedia, merge} from '../../utils';
|
||||
import {canvasPool2D} from '../../canvas/CanvasPool';
|
||||
import {
|
||||
Variables,
|
||||
ImageVar,
|
||||
BooleanVar,
|
||||
NumberVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
export default class Canvas2d extends Node {
|
||||
constructor(name, inputDefinition, outputDefiniton, options) {
|
||||
const inputs = {
|
||||
image: {
|
||||
type: 'Image',
|
||||
} as ImageVar,
|
||||
};
|
||||
|
||||
const outputs = {
|
||||
image: {
|
||||
type: 'Image',
|
||||
} as ImageVar,
|
||||
width: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
height: {
|
||||
type: 'Number',
|
||||
} as NumberVar
|
||||
};
|
||||
|
||||
|
||||
|
||||
export default class Canvas2d<I extends Variables, O extends Variables> extends Node<I & (typeof inputs), O & (typeof outputs)> {
|
||||
constructor(name, inputDefinition: I, outputDefiniton: O, options) {
|
||||
super(name,
|
||||
Object.assign({
|
||||
image: {
|
||||
type: 'Image',
|
||||
},
|
||||
}, inputDefinition),
|
||||
Object.assign({
|
||||
image: {
|
||||
type: 'Image',
|
||||
},
|
||||
width: {
|
||||
type: 'Number',
|
||||
},
|
||||
height: {
|
||||
type: 'Number',
|
||||
}
|
||||
}, outputDefiniton),
|
||||
merge(inputs, inputDefinition),
|
||||
merge(outputs, outputDefiniton),
|
||||
options
|
||||
);
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
|
||||
export default class Compose extends Canvas2d {
|
||||
|
||||
constructor(options) {
|
||||
super('Compose', {
|
||||
image: null,
|
||||
fg: {
|
||||
type: 'Image'
|
||||
},
|
||||
fgX: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
},
|
||||
fgY: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
},
|
||||
bg: {
|
||||
type: 'Image',
|
||||
},
|
||||
bgX: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
},
|
||||
bgY: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
},
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
step: 1,
|
||||
min: 1
|
||||
},
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
step: 1,
|
||||
min: 1,
|
||||
},
|
||||
mode: {
|
||||
type: 'String',
|
||||
default: 'source-over',
|
||||
enum: [
|
||||
'source-over',
|
||||
'source-in',
|
||||
'source-out',
|
||||
'source-atop',
|
||||
'destination-over',
|
||||
'destination-in',
|
||||
'destination-out',
|
||||
'destination-atop',
|
||||
'lighter',
|
||||
'copy',
|
||||
'xor',
|
||||
'multiply',
|
||||
'screen',
|
||||
'overlay',
|
||||
'darken',
|
||||
'lighten',
|
||||
'color-dodge',
|
||||
'color-burn',
|
||||
'hard-light',
|
||||
'soft-light',
|
||||
'difference',
|
||||
'exclusion',
|
||||
'hue',
|
||||
'saturation',
|
||||
'color',
|
||||
'luminosity',
|
||||
]
|
||||
}
|
||||
}, {
|
||||
image: {
|
||||
type: 'Image'
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.__in.width.value;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.__in.height.value;
|
||||
}
|
||||
|
||||
get fg() {
|
||||
if (!this.__in.fg.value) {
|
||||
return null;
|
||||
} else {
|
||||
const {width, height} = this.__in.fg.value;
|
||||
return {
|
||||
image: this.__in.fg.value,
|
||||
top: this.__in.fgY.value || 0,
|
||||
left: this.__in.fgX.value || 0,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get bg() {
|
||||
if (!this.__in.bg.value) {
|
||||
return null;
|
||||
} else {
|
||||
const {width, height} = this.__in.bg.value;
|
||||
return {
|
||||
image: this.__in.bg.value,
|
||||
top: this.__in.bgY.value || 0,
|
||||
left: this.__in.bgX.value || 0,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} values
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
*/
|
||||
async render({width, height, mode}, canvas, ctx) {
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
if (!this.bg && !this.fg) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
if (this.bg) {
|
||||
paintToCanvas(canvas, this.bg.image, this.bg);
|
||||
}
|
||||
|
||||
ctx.globalCompositeOperation = mode;
|
||||
|
||||
if (this.fg) {
|
||||
paintToCanvas(canvas, this.fg.image, this.fg);
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
163
src/nodes/Canvas2d/Compose.ts
Normal file
163
src/nodes/Canvas2d/Compose.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
import {
|
||||
ImageVar,
|
||||
StringVar,
|
||||
NumberVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
const inputs = {
|
||||
image: null,
|
||||
fg: {
|
||||
type: 'Image'
|
||||
} as ImageVar,
|
||||
fgX: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
} as NumberVar,
|
||||
fgY: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
} as NumberVar,
|
||||
bg: {
|
||||
type: 'Image',
|
||||
} as ImageVar,
|
||||
bgX: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
} as NumberVar,
|
||||
bgY: {
|
||||
type: 'Number',
|
||||
default: 0,
|
||||
step: 1,
|
||||
} as NumberVar,
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
step: 1,
|
||||
min: 1
|
||||
} as NumberVar,
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
step: 1,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
mode: {
|
||||
type: 'String',
|
||||
default: 'source-over',
|
||||
enum: [
|
||||
'source-over',
|
||||
'source-in',
|
||||
'source-out',
|
||||
'source-atop',
|
||||
'destination-over',
|
||||
'destination-in',
|
||||
'destination-out',
|
||||
'destination-atop',
|
||||
'lighter',
|
||||
'copy',
|
||||
'xor',
|
||||
'multiply',
|
||||
'screen',
|
||||
'overlay',
|
||||
'darken',
|
||||
'lighten',
|
||||
'color-dodge',
|
||||
'color-burn',
|
||||
'hard-light',
|
||||
'soft-light',
|
||||
'difference',
|
||||
'exclusion',
|
||||
'hue',
|
||||
'saturation',
|
||||
'color',
|
||||
'luminosity',
|
||||
]
|
||||
} as StringVar
|
||||
}
|
||||
|
||||
const outputs = {
|
||||
image: {
|
||||
type: 'Image'
|
||||
} as ImageVar
|
||||
}
|
||||
|
||||
export default class Compose extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor(options={}) {
|
||||
super('Compose', inputs, outputs, options);
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.__in.width.value;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.__in.height.value;
|
||||
}
|
||||
|
||||
get fg() {
|
||||
if (!this.__in.fg.value) {
|
||||
return null;
|
||||
} else {
|
||||
const {width, height} = this.__in.fg.value;
|
||||
return {
|
||||
image: this.__in.fg.value,
|
||||
top: this.__in.fgY.value || 0,
|
||||
left: this.__in.fgX.value || 0,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get bg() {
|
||||
if (!this.__in.bg.value) {
|
||||
return null;
|
||||
} else {
|
||||
const {width, height} = this.__in.bg.value;
|
||||
return {
|
||||
image: this.__in.bg.value,
|
||||
top: this.__in.bgY.value || 0,
|
||||
left: this.__in.bgX.value || 0,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} values
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
*/
|
||||
async render({width, height, mode}, canvas, ctx) {
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
if (!this.bg && !this.fg) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
if (this.bg) {
|
||||
paintToCanvas(canvas, this.bg.image, this.bg);
|
||||
}
|
||||
|
||||
ctx.globalCompositeOperation = mode;
|
||||
|
||||
if (this.fg) {
|
||||
paintToCanvas(canvas, this.fg.image, this.fg);
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,35 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
import {
|
||||
NumberVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
export default class EmptySpace extends Canvas2d {
|
||||
const inputs = {};
|
||||
const outputs = {
|
||||
w: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
h: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
top: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
right: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
bottom: {
|
||||
type: 'Number',
|
||||
} as NumberVar,
|
||||
left: {
|
||||
type: 'Number',
|
||||
} as NumberVar
|
||||
};
|
||||
|
||||
export default class EmptySpace extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor() {
|
||||
super('EmptySpace', {
|
||||
}, {
|
||||
w: {
|
||||
type: 'Number',
|
||||
},
|
||||
h: {
|
||||
type: 'Number',
|
||||
},
|
||||
top: {
|
||||
type: 'Number',
|
||||
},
|
||||
right: {
|
||||
type: 'Number',
|
||||
},
|
||||
bottom: {
|
||||
type: 'Number',
|
||||
},
|
||||
left: {
|
||||
type: 'Number',
|
||||
}
|
||||
});
|
||||
super('EmptySpace', inputs, outputs, {});
|
||||
this._update();
|
||||
}
|
||||
|
||||
@@ -42,22 +47,23 @@ export default class EmptySpace extends Canvas2d {
|
||||
canvas.height = height;
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const imageData = ctx.getImageData(0, 0, width, height)
|
||||
for (let offset=0; offset<imageData.data.length; offset+=4) {
|
||||
const x = (offset/4) % width;
|
||||
const y = Math.floor((offset/4) / width)
|
||||
const [r,g,b,a] = imageData.data.slice(offset, offset+4);
|
||||
if (a < 1) {
|
||||
let x = 0, y = 0, a, offset;
|
||||
let length = imageData.data.length/4;
|
||||
for (offset=0; offset<length; offset+=1) {
|
||||
x = (offset) % width;
|
||||
y = Math.floor(offset / width)
|
||||
a = imageData.data[offset * 4 + 3];
|
||||
if (a < 254) {
|
||||
top = Math.min(top, y);
|
||||
right = Math.max(right, x);
|
||||
bottom = Math.max(bottom, y);
|
||||
left = Math.min(left, x);
|
||||
}
|
||||
imageData.data[offset] = a;
|
||||
imageData.data[offset + 1] = a;
|
||||
imageData.data[offset + 2] = a;
|
||||
imageData.data[offset + 3] = a;
|
||||
|
||||
if (x === left && y == bottom && x < right) {
|
||||
offset += (right - left) -1;
|
||||
}
|
||||
}
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
this.out.top.value = top;
|
||||
this.out.right.value = right;
|
||||
this.out.bottom.value = bottom;
|
||||
@@ -1,33 +0,0 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
|
||||
export default class Fill extends Canvas2d {
|
||||
|
||||
constructor() {
|
||||
super('Fill', {
|
||||
image: null,
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
color: {
|
||||
type: 'Color',
|
||||
default: '#FFFFFF'
|
||||
}
|
||||
}, {});
|
||||
this._update();
|
||||
}
|
||||
|
||||
async render({color, width, height}, canvas, ctx) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
40
src/nodes/Canvas2d/Fill.ts
Normal file
40
src/nodes/Canvas2d/Fill.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {
|
||||
NumberVar,
|
||||
ColorVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
const inputs = {
|
||||
image: null,
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
color: {
|
||||
type: 'Color',
|
||||
default: '#FFFFFF'
|
||||
} as ColorVar
|
||||
};
|
||||
const outputs = {};
|
||||
|
||||
export default class Fill extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor() {
|
||||
super('Fill', inputs, outputs);
|
||||
this._update();
|
||||
}
|
||||
|
||||
async render({color, width, height}, canvas, ctx) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,26 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
import {
|
||||
BooleanVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
export default class Flip extends Canvas2d {
|
||||
const inputs = {
|
||||
horizontal: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
} as BooleanVar,
|
||||
vertical: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
} as BooleanVar,
|
||||
}
|
||||
|
||||
const outputs = {};
|
||||
|
||||
export default class Flip extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor() {
|
||||
super('Flip', {
|
||||
horizontal: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
},
|
||||
vertical: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
},
|
||||
}, {});
|
||||
super('Flip', inputs, outputs, {});
|
||||
this._update();
|
||||
}
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {waitForMedia} from '../../utils';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
import {
|
||||
ImageVar,
|
||||
StringVar,
|
||||
NumberVar
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
export default class Resize extends Canvas2d {
|
||||
|
||||
|
||||
const inputs = {
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
};
|
||||
|
||||
const outputs = {};
|
||||
|
||||
export default class Resize extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor() {
|
||||
super('Resize', {
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
}, {});
|
||||
super('Resize', inputs, outputs, {});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,91 +0,0 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {waitForMedia} from '../../utils';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
|
||||
const isEmpty = (x) => !x || Object.keys(x).length === 0;
|
||||
|
||||
export default class Resize extends Canvas2d {
|
||||
|
||||
constructor() {
|
||||
super('Text', {
|
||||
image: null,
|
||||
text: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
},
|
||||
fontSize: {
|
||||
type: 'Number',
|
||||
min: 1,
|
||||
default: 50,
|
||||
},
|
||||
fontStyle: {
|
||||
type: 'String',
|
||||
default: 'normal',
|
||||
enum: [
|
||||
'normal',
|
||||
'bold',
|
||||
'italic',
|
||||
'bold italic',
|
||||
]
|
||||
},
|
||||
font: {
|
||||
type: 'Font', // {name, url, fontface}
|
||||
default: 'Arial',
|
||||
},
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
},
|
||||
color: {
|
||||
type: 'Color',
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
textAlign: {
|
||||
type: 'String',
|
||||
default: 'center',
|
||||
enum: [
|
||||
'left',
|
||||
'center',
|
||||
'right',
|
||||
]
|
||||
}
|
||||
}, {});
|
||||
this._update();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{name: string, url: string, fontface: FontFace, type: 'font'}} font
|
||||
*/
|
||||
async loadFont(font) {
|
||||
if (typeof font === 'string') {
|
||||
return font;
|
||||
} else if (!font) {
|
||||
return;
|
||||
} else {
|
||||
return font.name;
|
||||
}
|
||||
}
|
||||
|
||||
async render({font, fontSize, text, color, width, height, textAlign, fontStyle}, canvas, ctx) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.font = `${fontStyle} ${fontSize}px "${(await this.loadFont(font)) || ''}"`;
|
||||
// ctx.font = `${fontStyle} ${fontSize}px "Arial"`;
|
||||
ctx.fillStyle = color;
|
||||
ctx.textAlign = textAlign;
|
||||
const x = textAlign === 'center' ? canvas.width /2 :
|
||||
textAlign === 'left' ? 0 : canvas.width;
|
||||
text.split('\\n').forEach((line, index) => {
|
||||
ctx.fillText(line, x, fontSize * (1 + index));
|
||||
});
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
101
src/nodes/Canvas2d/Text.ts
Normal file
101
src/nodes/Canvas2d/Text.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import Canvas2d from './Canvas2d';
|
||||
import {waitForMedia} from '../../utils';
|
||||
import {createCanvas, mediaSize, paintToCanvas} from '../canvas';
|
||||
import {
|
||||
NumberVar,
|
||||
StringVar,
|
||||
FontVar,
|
||||
ColorVar,
|
||||
} from '../io/AbstractIOSet';
|
||||
|
||||
const isEmpty = (x) => !x || Object.keys(x).length === 0;
|
||||
|
||||
const inputs = {
|
||||
image: null,
|
||||
text: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
} as StringVar,
|
||||
fontSize: {
|
||||
type: 'Number',
|
||||
min: 1,
|
||||
default: 50,
|
||||
} as NumberVar,
|
||||
fontStyle: {
|
||||
type: 'String',
|
||||
default: 'normal',
|
||||
enum: [
|
||||
'normal',
|
||||
'bold',
|
||||
'italic',
|
||||
'bold italic',
|
||||
]
|
||||
} as StringVar,
|
||||
font: {
|
||||
type: 'Font', // {name, url, fontface}
|
||||
default: 'Arial',
|
||||
} as FontVar,
|
||||
width: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
height: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
min: 1,
|
||||
} as NumberVar,
|
||||
color: {
|
||||
type: 'Color',
|
||||
default: '#FFFFFF'
|
||||
} as ColorVar,
|
||||
textAlign: {
|
||||
type: 'String',
|
||||
default: 'center',
|
||||
enum: [
|
||||
'left',
|
||||
'center',
|
||||
'right',
|
||||
]
|
||||
} as StringVar
|
||||
};
|
||||
|
||||
const outputs = {};
|
||||
|
||||
export default class Resize extends Canvas2d<typeof inputs, typeof outputs> {
|
||||
|
||||
constructor() {
|
||||
super('Text', inputs, outputs, {});
|
||||
this._update();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{name: string, url: string, fontface: FontFace, type: 'font'}} font
|
||||
*/
|
||||
async loadFont(font) {
|
||||
if (typeof font === 'string') {
|
||||
return font;
|
||||
} else if (!font) {
|
||||
return;
|
||||
} else {
|
||||
return font.name;
|
||||
}
|
||||
}
|
||||
|
||||
async render({font, fontSize, text, color, width, height, textAlign, fontStyle}, canvas, ctx) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.font = `${fontStyle} ${fontSize}px "${(await this.loadFont(font)) || ''}"`;
|
||||
// ctx.font = `${fontStyle} ${fontSize}px "Arial"`;
|
||||
ctx.fillStyle = color;
|
||||
ctx.textAlign = textAlign;
|
||||
const x = textAlign === 'center' ? canvas.width /2 :
|
||||
textAlign === 'left' ? 0 : canvas.width;
|
||||
text.split('\\n').forEach((line, index) => {
|
||||
ctx.fillText(line, x, fontSize * (1 + index));
|
||||
});
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user