xpict 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effects/blur.d.ts +3 -0
- package/dist/effects/blur.js +8 -0
- package/dist/effects/grayscale.d.ts +2 -0
- package/dist/effects/grayscale.js +8 -0
- package/dist/effects/index.d.ts +3 -0
- package/dist/effects/index.js +19 -0
- package/dist/effects/negative.d.ts +2 -0
- package/dist/effects/negative.js +8 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +25 -1
- package/dist/layers/circle-layer.d.ts +3 -4
- package/dist/layers/circle-layer.js +18 -6
- package/dist/layers/group-layer.d.ts +3 -4
- package/dist/layers/group-layer.js +19 -4
- package/dist/layers/image-layer.d.ts +20 -5
- package/dist/layers/image-layer.js +37 -10
- package/dist/layers/layer.d.ts +15 -3
- package/dist/layers/layer.js +1 -1
- package/dist/layers/line-layer.d.ts +3 -4
- package/dist/layers/line-layer.js +32 -8
- package/dist/layers/rectangle-layer.d.ts +3 -4
- package/dist/layers/rectangle-layer.js +16 -6
- package/dist/layers/repeat-layer.d.ts +9 -5
- package/dist/layers/repeat-layer.js +21 -6
- package/dist/layers/text-layer.d.ts +9 -5
- package/dist/layers/text-layer.js +21 -10
- package/dist/template.d.ts +7 -2
- package/dist/template.js +19 -9
- package/dist/utils/commit-frame.js +1 -1
- package/dist/utils/font-config.d.ts +1 -1
- package/dist/utils/font-config.js +1 -1
- package/dist/utils/resolve-axis.d.ts +13 -2
- package/dist/utils/resolve-axis.js +2 -2
- package/package.json +7 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
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]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./blur"), exports);
|
|
18
|
+
__exportStar(require("./grayscale"), exports);
|
|
19
|
+
__exportStar(require("./negative"), exports);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { GroupLayer, RepeatLayer, GroupLayerOptions, ImageLayer, ImageLayerOptions, LineLayer, LineLayerOptions, RectangleLayer, RectangleLayerOptions, RepeatLayerOptions, TextLayer, TextLayerOptions, CircleLayerOptions, CircleLayer } from "./layers";
|
|
2
|
-
import {
|
|
2
|
+
import { negativeEffect, blurEffect, grayscaleEffect } from "./effects";
|
|
3
|
+
import { Template, InputTemplateOptions } from "./template";
|
|
3
4
|
import { fontConfig } from "./utils/font-config";
|
|
5
|
+
export * from "./layers";
|
|
6
|
+
export * from "./effects";
|
|
7
|
+
export * from "./template";
|
|
8
|
+
export * from "./utils/font-config";
|
|
4
9
|
declare const xpict: {
|
|
5
10
|
rectangle<Data>(options: RectangleLayerOptions<Data>): RectangleLayer<Data>;
|
|
6
11
|
circle<Data>(options: CircleLayerOptions<Data>): CircleLayer<Data>;
|
|
@@ -9,7 +14,12 @@ declare const xpict: {
|
|
|
9
14
|
repeat<Data, Item>(options: RepeatLayerOptions<Data, Item>): RepeatLayer<Data, Item>;
|
|
10
15
|
group<Data>(options: GroupLayerOptions<Data>): GroupLayer<Data>;
|
|
11
16
|
line<Data>(options: LineLayerOptions<Data>): LineLayer<Data>;
|
|
12
|
-
template<Data>(options:
|
|
17
|
+
template<Data>(options: InputTemplateOptions<Data>): Template<Data>;
|
|
13
18
|
fontConfig: typeof fontConfig;
|
|
19
|
+
effects: {
|
|
20
|
+
negative: typeof negativeEffect;
|
|
21
|
+
blur: typeof blurEffect;
|
|
22
|
+
grayscale: typeof grayscaleEffect;
|
|
23
|
+
};
|
|
14
24
|
};
|
|
15
25
|
export default xpict;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
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]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
const layers_1 = require("./layers");
|
|
18
|
+
const effects_1 = require("./effects");
|
|
4
19
|
const template_1 = require("./template");
|
|
5
20
|
const font_config_1 = require("./utils/font-config");
|
|
21
|
+
__exportStar(require("./layers"), exports);
|
|
22
|
+
__exportStar(require("./effects"), exports);
|
|
23
|
+
__exportStar(require("./template"), exports);
|
|
24
|
+
__exportStar(require("./utils/font-config"), exports);
|
|
6
25
|
const xpict = {
|
|
7
26
|
rectangle(options) {
|
|
8
27
|
return new layers_1.RectangleLayer(options);
|
|
@@ -28,6 +47,11 @@ const xpict = {
|
|
|
28
47
|
template(options) {
|
|
29
48
|
return new template_1.Template(options);
|
|
30
49
|
},
|
|
31
|
-
fontConfig: font_config_1.fontConfig
|
|
50
|
+
fontConfig: font_config_1.fontConfig,
|
|
51
|
+
effects: {
|
|
52
|
+
negative: effects_1.negativeEffect,
|
|
53
|
+
blur: effects_1.blurEffect,
|
|
54
|
+
grayscale: effects_1.grayscaleEffect,
|
|
55
|
+
},
|
|
32
56
|
};
|
|
33
57
|
exports.default = xpict;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
+
import { Layer, RenderOptions, WhenOptions } from "./layer";
|
|
1
2
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
import { RenderContext } from "../render-context";
|
|
3
|
-
import { Layer } from "./layer";
|
|
4
3
|
export type CircleLayerOptions<Data> = {
|
|
5
4
|
x: Axis<Data>;
|
|
6
5
|
y: Axis<Data>;
|
|
7
6
|
radius: number;
|
|
8
7
|
fill: string;
|
|
9
|
-
when?: (
|
|
8
|
+
when?: (options: WhenOptions<Data>) => boolean;
|
|
10
9
|
};
|
|
11
10
|
export declare class CircleLayer<Data> extends Layer<Data> {
|
|
12
11
|
private readonly options;
|
|
13
12
|
constructor(options: CircleLayerOptions<Data>);
|
|
14
|
-
render(
|
|
13
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
15
14
|
}
|
|
@@ -2,20 +2,32 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CircleLayer = void 0;
|
|
4
4
|
const canvas_1 = require("canvas");
|
|
5
|
-
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
6
5
|
const layer_1 = require("./layer");
|
|
6
|
+
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
7
7
|
class CircleLayer extends layer_1.Layer {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
super(options.when);
|
|
10
10
|
this.options = options;
|
|
11
11
|
}
|
|
12
|
-
async render(ctx, data, index = 0) {
|
|
12
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
13
13
|
const image = ctx.image;
|
|
14
14
|
const metadata = await image.metadata();
|
|
15
15
|
const canvasWidth = metadata.width;
|
|
16
16
|
const canvasHeight = metadata.height;
|
|
17
|
-
const x = ctx.offsetX +
|
|
18
|
-
|
|
17
|
+
const x = ctx.offsetX +
|
|
18
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
19
|
+
axis: this.options.x,
|
|
20
|
+
data: data,
|
|
21
|
+
index: index,
|
|
22
|
+
templateConfig: templateConfig,
|
|
23
|
+
});
|
|
24
|
+
const y = ctx.offsetY +
|
|
25
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
26
|
+
axis: this.options.y,
|
|
27
|
+
data: data,
|
|
28
|
+
index: index,
|
|
29
|
+
templateConfig: templateConfig,
|
|
30
|
+
});
|
|
19
31
|
const { radius, fill } = this.options;
|
|
20
32
|
const canvas = (0, canvas_1.createCanvas)(canvasWidth, canvasHeight);
|
|
21
33
|
const context = canvas.getContext("2d");
|
|
@@ -29,8 +41,8 @@ class CircleLayer extends layer_1.Layer {
|
|
|
29
41
|
{
|
|
30
42
|
input: circleBuffer,
|
|
31
43
|
top: 0,
|
|
32
|
-
left: 0
|
|
33
|
-
}
|
|
44
|
+
left: 0,
|
|
45
|
+
},
|
|
34
46
|
]);
|
|
35
47
|
}
|
|
36
48
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { Layer } from "./layer";
|
|
1
|
+
import { Layer, RenderOptions, WhenOptions } from "./layer";
|
|
2
2
|
import { Axis } from "../utils/resolve-axis";
|
|
3
|
-
import { RenderContext } from "../render-context";
|
|
4
3
|
export type GroupLayerOptions<Data> = {
|
|
5
4
|
layers: Layer<Data>[];
|
|
6
5
|
x: Axis<Data>;
|
|
7
6
|
y: Axis<Data>;
|
|
8
|
-
when?: (
|
|
7
|
+
when?: (options: WhenOptions<Data>) => boolean;
|
|
9
8
|
};
|
|
10
9
|
export declare class GroupLayer<Data> extends Layer<Data> {
|
|
11
10
|
private readonly options;
|
|
12
11
|
constructor(options: GroupLayerOptions<Data>);
|
|
13
|
-
render(
|
|
12
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
14
13
|
}
|
|
@@ -9,9 +9,19 @@ class GroupLayer extends layer_1.Layer {
|
|
|
9
9
|
super(options.when);
|
|
10
10
|
this.options = options;
|
|
11
11
|
}
|
|
12
|
-
async render(ctx, data, index = 0) {
|
|
13
|
-
const dx = (0, resolve_axis_1.resolveAxis)(
|
|
14
|
-
|
|
12
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
13
|
+
const dx = (0, resolve_axis_1.resolveAxis)({
|
|
14
|
+
axis: this.options.x,
|
|
15
|
+
data: data,
|
|
16
|
+
index: index,
|
|
17
|
+
templateConfig: templateConfig,
|
|
18
|
+
});
|
|
19
|
+
const dy = (0, resolve_axis_1.resolveAxis)({
|
|
20
|
+
axis: this.options.y,
|
|
21
|
+
data: data,
|
|
22
|
+
index: index,
|
|
23
|
+
templateConfig: templateConfig,
|
|
24
|
+
});
|
|
15
25
|
const prevX = ctx.offsetX;
|
|
16
26
|
const prevY = ctx.offsetY;
|
|
17
27
|
ctx.offsetX += dx;
|
|
@@ -19,7 +29,12 @@ class GroupLayer extends layer_1.Layer {
|
|
|
19
29
|
for (const layer of this.options.layers) {
|
|
20
30
|
if (!layer.shouldRender(data))
|
|
21
31
|
continue;
|
|
22
|
-
await layer.render(
|
|
32
|
+
await layer.render({
|
|
33
|
+
context: ctx,
|
|
34
|
+
data: data,
|
|
35
|
+
index: index,
|
|
36
|
+
templateConfig: templateConfig,
|
|
37
|
+
});
|
|
23
38
|
ctx.image = await (0, commit_frame_1.commitFrame)(ctx.image);
|
|
24
39
|
}
|
|
25
40
|
ctx.offsetX = prevX;
|
|
@@ -1,16 +1,31 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
import { Layer, RenderOptions, WhenFunction } from "./layer";
|
|
1
3
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
+
export type TransformOptions<Data> = {
|
|
5
|
+
data: Data;
|
|
6
|
+
index: number;
|
|
7
|
+
image: sharp.Sharp;
|
|
8
|
+
};
|
|
9
|
+
export type ImageTransformFunction<Data> = (options: TransformOptions<Data>) => sharp.Sharp | Promise<sharp.Sharp>;
|
|
10
|
+
export type ImageImageSrcOptions<Data> = {
|
|
11
|
+
data: Data;
|
|
12
|
+
index: number;
|
|
13
|
+
};
|
|
14
|
+
export type ImageSrcFunction<Data> = (options: ImageImageSrcOptions<Data>) => string | Buffer;
|
|
4
15
|
export type ImageLayerOptions<Data> = {
|
|
5
|
-
src:
|
|
16
|
+
src: string | ImageSrcFunction<Data>;
|
|
6
17
|
x: Axis<Data>;
|
|
7
18
|
y: Axis<Data>;
|
|
8
19
|
width?: number;
|
|
9
20
|
height?: number;
|
|
10
|
-
|
|
21
|
+
flipX?: boolean;
|
|
22
|
+
flipY?: boolean;
|
|
23
|
+
rotate?: number;
|
|
24
|
+
when?: WhenFunction<Data>;
|
|
25
|
+
transform?: ImageTransformFunction<Data>[];
|
|
11
26
|
};
|
|
12
27
|
export declare class ImageLayer<Data> extends Layer<Data> {
|
|
13
28
|
private options;
|
|
14
29
|
constructor(options: ImageLayerOptions<Data>);
|
|
15
|
-
render(
|
|
30
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
16
31
|
}
|
|
@@ -5,24 +5,51 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ImageLayer = void 0;
|
|
7
7
|
const sharp_1 = __importDefault(require("sharp"));
|
|
8
|
-
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
9
8
|
const layer_1 = require("./layer");
|
|
9
|
+
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
10
10
|
class ImageLayer extends layer_1.Layer {
|
|
11
11
|
constructor(options) {
|
|
12
12
|
super(options.when);
|
|
13
13
|
this.options = options;
|
|
14
14
|
}
|
|
15
|
-
async render(ctx, data, index = 0) {
|
|
16
|
-
const localX = (0, resolve_axis_1.resolveAxis)(
|
|
17
|
-
|
|
15
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
16
|
+
const localX = (0, resolve_axis_1.resolveAxis)({
|
|
17
|
+
axis: this.options.x,
|
|
18
|
+
data: data,
|
|
19
|
+
index: index,
|
|
20
|
+
templateConfig: templateConfig,
|
|
21
|
+
});
|
|
22
|
+
const localY = (0, resolve_axis_1.resolveAxis)({
|
|
23
|
+
axis: this.options.y,
|
|
24
|
+
data: data,
|
|
25
|
+
index: index,
|
|
26
|
+
templateConfig: templateConfig,
|
|
27
|
+
});
|
|
18
28
|
const x = ctx.offsetX + localX;
|
|
19
29
|
const y = ctx.offsetY + localY;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
const src = this.options.src;
|
|
31
|
+
const resolvedImageSource = typeof src === "string" ? src : src({ data: data, index: index });
|
|
32
|
+
let img = (0, sharp_1.default)(resolvedImageSource).resize(this.options.width, this.options.height);
|
|
33
|
+
if (this.options.flipX) {
|
|
34
|
+
img = img.flop();
|
|
35
|
+
}
|
|
36
|
+
if (this.options.flipY) {
|
|
37
|
+
img = img.flip();
|
|
38
|
+
}
|
|
39
|
+
if (this.options.rotate !== undefined) {
|
|
40
|
+
img = img.rotate(this.options.rotate);
|
|
41
|
+
}
|
|
42
|
+
if (this.options.transform && this.options.transform.length > 0) {
|
|
43
|
+
for (const transform of this.options.transform) {
|
|
44
|
+
img = await transform({
|
|
45
|
+
data: data,
|
|
46
|
+
index: index,
|
|
47
|
+
image: img,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const buffer = await img.toBuffer();
|
|
52
|
+
ctx.image = ctx.image.composite([{ input: buffer, left: x, top: y }]);
|
|
26
53
|
}
|
|
27
54
|
}
|
|
28
55
|
exports.ImageLayer = ImageLayer;
|
package/dist/layers/layer.d.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { RenderContext } from "../render-context";
|
|
2
|
+
import { TemplateConfig } from "../template";
|
|
3
|
+
export type WhenOptions<Data> = {
|
|
4
|
+
data: Data;
|
|
5
|
+
index: number;
|
|
6
|
+
};
|
|
7
|
+
export type WhenFunction<Data> = (options: WhenOptions<Data>) => boolean;
|
|
8
|
+
export type RenderOptions<Data> = {
|
|
9
|
+
context: RenderContext;
|
|
10
|
+
data: Data;
|
|
11
|
+
index?: number;
|
|
12
|
+
templateConfig: TemplateConfig;
|
|
13
|
+
};
|
|
2
14
|
export declare abstract class Layer<Data = any> {
|
|
3
|
-
protected readonly when?:
|
|
4
|
-
constructor(when?:
|
|
15
|
+
protected readonly when?: WhenFunction<Data> | undefined;
|
|
16
|
+
constructor(when?: WhenFunction<Data> | undefined);
|
|
5
17
|
shouldRender(data: Data, index?: number): boolean;
|
|
6
|
-
abstract render(
|
|
18
|
+
abstract render(options: RenderOptions<Data>): Promise<void>;
|
|
7
19
|
}
|
package/dist/layers/layer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { Layer, RenderOptions, WhenFunction } from "./layer";
|
|
1
2
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
import { RenderContext } from "../render-context";
|
|
3
|
-
import { Layer } from "./layer";
|
|
4
3
|
export type LineLayerOptions<Data> = {
|
|
5
4
|
from: {
|
|
6
5
|
x: Axis<Data>;
|
|
@@ -12,10 +11,10 @@ export type LineLayerOptions<Data> = {
|
|
|
12
11
|
};
|
|
13
12
|
color: string;
|
|
14
13
|
width: number;
|
|
15
|
-
when?:
|
|
14
|
+
when?: WhenFunction<Data>;
|
|
16
15
|
};
|
|
17
16
|
export declare class LineLayer<Data> extends Layer<Data> {
|
|
18
17
|
private readonly options;
|
|
19
18
|
constructor(options: LineLayerOptions<Data>);
|
|
20
|
-
render(
|
|
19
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
21
20
|
}
|
|
@@ -2,22 +2,46 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LineLayer = void 0;
|
|
4
4
|
const canvas_1 = require("canvas");
|
|
5
|
-
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
6
5
|
const layer_1 = require("./layer");
|
|
6
|
+
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
7
7
|
class LineLayer extends layer_1.Layer {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
super(options.when);
|
|
10
10
|
this.options = options;
|
|
11
11
|
}
|
|
12
|
-
async render(ctx, data, index = 0) {
|
|
12
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
13
13
|
const image = ctx.image;
|
|
14
14
|
const metadata = await image.metadata();
|
|
15
15
|
const canvasWidth = metadata.width;
|
|
16
16
|
const canvasHeight = metadata.height;
|
|
17
|
-
const x1 = ctx.offsetX +
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const x1 = ctx.offsetX +
|
|
18
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
19
|
+
axis: this.options.from.x,
|
|
20
|
+
data: data,
|
|
21
|
+
index: index,
|
|
22
|
+
templateConfig: templateConfig,
|
|
23
|
+
});
|
|
24
|
+
const y1 = ctx.offsetY +
|
|
25
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
26
|
+
axis: this.options.from.y,
|
|
27
|
+
data: data,
|
|
28
|
+
index: index,
|
|
29
|
+
templateConfig: templateConfig,
|
|
30
|
+
});
|
|
31
|
+
const x2 = ctx.offsetX +
|
|
32
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
33
|
+
axis: this.options.to.x,
|
|
34
|
+
data: data,
|
|
35
|
+
index: index,
|
|
36
|
+
templateConfig: templateConfig,
|
|
37
|
+
});
|
|
38
|
+
const y2 = ctx.offsetY +
|
|
39
|
+
(0, resolve_axis_1.resolveAxis)({
|
|
40
|
+
axis: this.options.to.y,
|
|
41
|
+
data: data,
|
|
42
|
+
index: index,
|
|
43
|
+
templateConfig: templateConfig,
|
|
44
|
+
});
|
|
21
45
|
const canvas = (0, canvas_1.createCanvas)(canvasWidth, canvasHeight);
|
|
22
46
|
const context = canvas.getContext("2d");
|
|
23
47
|
context.strokeStyle = this.options.color;
|
|
@@ -32,8 +56,8 @@ class LineLayer extends layer_1.Layer {
|
|
|
32
56
|
{
|
|
33
57
|
input: lineBuffer,
|
|
34
58
|
top: 0,
|
|
35
|
-
left: 0
|
|
36
|
-
}
|
|
59
|
+
left: 0,
|
|
60
|
+
},
|
|
37
61
|
]);
|
|
38
62
|
}
|
|
39
63
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { Layer, RenderOptions, WhenFunction } from "./layer";
|
|
1
2
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
import { RenderContext } from "../render-context";
|
|
3
|
-
import { Layer } from "./layer";
|
|
4
3
|
export type RectangleLayerOptions<Data> = {
|
|
5
4
|
x: Axis<Data>;
|
|
6
5
|
y: Axis<Data>;
|
|
@@ -11,6 +10,6 @@ export type RectangleLayerOptions<Data> = {
|
|
|
11
10
|
};
|
|
12
11
|
export declare class RectangleLayer<Data> extends Layer<Data> {
|
|
13
12
|
private readonly options;
|
|
14
|
-
constructor(options: RectangleLayerOptions<Data>, when?:
|
|
15
|
-
render(
|
|
13
|
+
constructor(options: RectangleLayerOptions<Data>, when?: WhenFunction<Data>);
|
|
14
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
16
15
|
}
|
|
@@ -2,20 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RectangleLayer = void 0;
|
|
4
4
|
const canvas_1 = require("canvas");
|
|
5
|
-
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
6
5
|
const layer_1 = require("./layer");
|
|
6
|
+
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
7
7
|
class RectangleLayer extends layer_1.Layer {
|
|
8
8
|
constructor(options, when) {
|
|
9
9
|
super(when);
|
|
10
10
|
this.options = options;
|
|
11
11
|
}
|
|
12
|
-
async render(ctx, data, index = 0) {
|
|
12
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
13
13
|
const image = ctx.image;
|
|
14
14
|
const metadata = await image.metadata();
|
|
15
15
|
const canvasWidth = metadata.width;
|
|
16
16
|
const canvasHeight = metadata.height;
|
|
17
|
-
const localX = (0, resolve_axis_1.resolveAxis)(
|
|
18
|
-
|
|
17
|
+
const localX = (0, resolve_axis_1.resolveAxis)({
|
|
18
|
+
axis: this.options.x,
|
|
19
|
+
data: data,
|
|
20
|
+
index: index,
|
|
21
|
+
templateConfig: templateConfig,
|
|
22
|
+
});
|
|
23
|
+
const localY = (0, resolve_axis_1.resolveAxis)({
|
|
24
|
+
axis: this.options.y,
|
|
25
|
+
data: data,
|
|
26
|
+
index: index,
|
|
27
|
+
templateConfig: templateConfig,
|
|
28
|
+
});
|
|
19
29
|
const x = ctx.offsetX + localX;
|
|
20
30
|
const y = ctx.offsetY + localY;
|
|
21
31
|
const { width, height, fill, borderRadius } = this.options;
|
|
@@ -45,8 +55,8 @@ class RectangleLayer extends layer_1.Layer {
|
|
|
45
55
|
{
|
|
46
56
|
input: rectangleBuffer,
|
|
47
57
|
top: 0,
|
|
48
|
-
left: 0
|
|
49
|
-
}
|
|
58
|
+
left: 0,
|
|
59
|
+
},
|
|
50
60
|
]);
|
|
51
61
|
}
|
|
52
62
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import { Layer, RenderOptions, WhenFunction } from "./layer";
|
|
1
2
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
export type EachOptions<Data> = {
|
|
4
|
+
data: Data;
|
|
5
|
+
index: number;
|
|
6
|
+
};
|
|
7
|
+
export type EachFunction<Data> = (options: EachOptions<Data>) => any[];
|
|
4
8
|
export type RepeatLayerOptions<Data, Item> = {
|
|
5
|
-
each:
|
|
9
|
+
each: EachFunction<Data>;
|
|
6
10
|
layer: (item: Item, index: number) => Layer<Data>;
|
|
7
|
-
when?:
|
|
11
|
+
when?: WhenFunction<Data>;
|
|
8
12
|
x: Axis<Data>;
|
|
9
13
|
y: Axis<Data>;
|
|
10
14
|
};
|
|
11
15
|
export declare class RepeatLayer<Data, Item> extends Layer<Data> {
|
|
12
16
|
private readonly options;
|
|
13
17
|
constructor(options: RepeatLayerOptions<Data, Item>);
|
|
14
|
-
render(
|
|
18
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
15
19
|
}
|
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RepeatLayer = void 0;
|
|
4
|
+
const layer_1 = require("./layer");
|
|
4
5
|
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
5
6
|
const commit_frame_1 = require("../utils/commit-frame");
|
|
6
|
-
const layer_1 = require("./layer");
|
|
7
7
|
class RepeatLayer extends layer_1.Layer {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
super(options.when);
|
|
10
10
|
this.options = options;
|
|
11
11
|
}
|
|
12
|
-
async render(ctx, data) {
|
|
13
|
-
const items = this.options.each(data);
|
|
12
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
13
|
+
const items = this.options.each({ data: data, index: index });
|
|
14
14
|
if (!items || items.length === 0)
|
|
15
15
|
return;
|
|
16
16
|
for (let index = 0; index < items.length; index++) {
|
|
17
17
|
const item = items[index];
|
|
18
|
-
const dx = (0, resolve_axis_1.resolveAxis)(
|
|
19
|
-
|
|
18
|
+
const dx = (0, resolve_axis_1.resolveAxis)({
|
|
19
|
+
axis: this.options.x,
|
|
20
|
+
data: data,
|
|
21
|
+
index: index,
|
|
22
|
+
templateConfig: templateConfig,
|
|
23
|
+
});
|
|
24
|
+
const dy = (0, resolve_axis_1.resolveAxis)({
|
|
25
|
+
axis: this.options.y,
|
|
26
|
+
data: data,
|
|
27
|
+
index: index,
|
|
28
|
+
templateConfig: templateConfig,
|
|
29
|
+
});
|
|
20
30
|
const prevX = ctx.offsetX;
|
|
21
31
|
const prevY = ctx.offsetY;
|
|
22
32
|
ctx.offsetX += dx;
|
|
23
33
|
ctx.offsetY += dy;
|
|
24
34
|
const layer = this.options.layer(item, index);
|
|
25
|
-
await layer.render(
|
|
35
|
+
await layer.render({
|
|
36
|
+
context: ctx,
|
|
37
|
+
data: data,
|
|
38
|
+
index: index,
|
|
39
|
+
templateConfig: templateConfig,
|
|
40
|
+
});
|
|
26
41
|
ctx.image = await (0, commit_frame_1.commitFrame)(ctx.image);
|
|
27
42
|
ctx.offsetX = prevX;
|
|
28
43
|
ctx.offsetY = prevY;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { Layer, RenderOptions, WhenFunction } from "./layer";
|
|
1
2
|
import { Axis } from "../utils/resolve-axis";
|
|
2
|
-
import { RenderContext } from "../render-context";
|
|
3
|
-
import { Layer } from "./layer";
|
|
4
3
|
export type FontOptions = {
|
|
5
4
|
size: number;
|
|
6
5
|
color?: string;
|
|
@@ -12,8 +11,13 @@ export type Stroke = {
|
|
|
12
11
|
fill: string;
|
|
13
12
|
width: number;
|
|
14
13
|
};
|
|
14
|
+
export type TextFunctionOptions<Data> = {
|
|
15
|
+
data: Data;
|
|
16
|
+
index: number;
|
|
17
|
+
};
|
|
18
|
+
export type StringFunction<Data> = (options: TextFunctionOptions<Data>) => string;
|
|
15
19
|
export type TextLayerOptions<Data> = {
|
|
16
|
-
text:
|
|
20
|
+
text: StringFunction<Data> | string;
|
|
17
21
|
font: FontOptions;
|
|
18
22
|
x: Axis<Data>;
|
|
19
23
|
y: Axis<Data>;
|
|
@@ -21,10 +25,10 @@ export type TextLayerOptions<Data> = {
|
|
|
21
25
|
anchor?: TextAnchor;
|
|
22
26
|
stroke?: Stroke;
|
|
23
27
|
rotation?: number;
|
|
24
|
-
when?:
|
|
28
|
+
when?: WhenFunction<Data>;
|
|
25
29
|
};
|
|
26
30
|
export declare class TextLayer<Data> extends Layer<Data> {
|
|
27
31
|
private readonly options;
|
|
28
32
|
constructor(options: TextLayerOptions<Data>);
|
|
29
|
-
render(
|
|
33
|
+
render({ context: ctx, data, index, templateConfig }: RenderOptions<Data>): Promise<void>;
|
|
30
34
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TextLayer = void 0;
|
|
4
4
|
const canvas_1 = require("canvas");
|
|
5
|
-
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
6
5
|
const layer_1 = require("./layer");
|
|
6
|
+
const resolve_axis_1 = require("../utils/resolve-axis");
|
|
7
7
|
const anchorOffsets = {
|
|
8
8
|
"top-left": (w, h) => ({ x: 0, y: 0 }),
|
|
9
9
|
"top-center": (w, h) => ({ x: -w / 2, y: 0 }),
|
|
@@ -13,19 +13,22 @@ const anchorOffsets = {
|
|
|
13
13
|
"middle-right": (w, h) => ({ x: -w, y: -h / 2 }),
|
|
14
14
|
"bottom-left": (w, h) => ({ x: 0, y: -h }),
|
|
15
15
|
"bottom-center": (w, h) => ({ x: -w / 2, y: -h }),
|
|
16
|
-
"bottom-right": (w, h) => ({ x: -w, y: -h })
|
|
16
|
+
"bottom-right": (w, h) => ({ x: -w, y: -h }),
|
|
17
17
|
};
|
|
18
18
|
class TextLayer extends layer_1.Layer {
|
|
19
19
|
constructor(options) {
|
|
20
20
|
super(options.when);
|
|
21
21
|
this.options = options;
|
|
22
22
|
}
|
|
23
|
-
async render(ctx, data) {
|
|
23
|
+
async render({ context: ctx, data, index = 0, templateConfig }) {
|
|
24
24
|
var _a, _b;
|
|
25
25
|
const imageMetadata = await ctx.image.metadata();
|
|
26
26
|
const width = imageMetadata.width;
|
|
27
27
|
const height = imageMetadata.height;
|
|
28
|
-
const { text, font, x: initialX, y: initialY, backgroundColor = "transparent", anchor = "top-left", stroke, rotation = 0 } = this.options;
|
|
28
|
+
const { text, font, x: initialX, y: initialY, backgroundColor = "transparent", anchor = "top-left", stroke, rotation = 0, } = this.options;
|
|
29
|
+
if (!font.name) {
|
|
30
|
+
throw new Error("Font name is required");
|
|
31
|
+
}
|
|
29
32
|
if (font.filePath) {
|
|
30
33
|
(0, canvas_1.registerFont)(font.filePath, { family: font.name });
|
|
31
34
|
}
|
|
@@ -37,13 +40,23 @@ class TextLayer extends layer_1.Layer {
|
|
|
37
40
|
}
|
|
38
41
|
context.font = `${font.size}px ${(_a = font.name) !== null && _a !== void 0 ? _a : "Arial"}`;
|
|
39
42
|
context.fillStyle = (_b = font.color) !== null && _b !== void 0 ? _b : "#000";
|
|
40
|
-
const content = text(data);
|
|
43
|
+
const content = typeof text === "string" ? text : text({ data: data, index: index });
|
|
41
44
|
const metrics = context.measureText(content);
|
|
42
45
|
const textWidth = metrics.width;
|
|
43
46
|
const textHeight = font.size;
|
|
44
47
|
const offset = anchorOffsets[anchor](textWidth, textHeight);
|
|
45
|
-
const localX = (0, resolve_axis_1.resolveAxis)(
|
|
46
|
-
|
|
48
|
+
const localX = (0, resolve_axis_1.resolveAxis)({
|
|
49
|
+
axis: initialX,
|
|
50
|
+
data: data,
|
|
51
|
+
index: index,
|
|
52
|
+
templateConfig: templateConfig,
|
|
53
|
+
});
|
|
54
|
+
const localY = (0, resolve_axis_1.resolveAxis)({
|
|
55
|
+
axis: initialY,
|
|
56
|
+
data: data,
|
|
57
|
+
index: index,
|
|
58
|
+
templateConfig: templateConfig,
|
|
59
|
+
});
|
|
47
60
|
const x = ctx.offsetX + localX;
|
|
48
61
|
const y = ctx.offsetY + localY;
|
|
49
62
|
const adjustedX = x + offset.x;
|
|
@@ -60,9 +73,7 @@ class TextLayer extends layer_1.Layer {
|
|
|
60
73
|
context.fillText(content, 0, 0);
|
|
61
74
|
context.restore();
|
|
62
75
|
const buffer = canvas.toBuffer();
|
|
63
|
-
ctx.image = ctx.image.composite([
|
|
64
|
-
{ input: buffer, top: 0, left: 0 }
|
|
65
|
-
]);
|
|
76
|
+
ctx.image = ctx.image.composite([{ input: buffer, top: 0, left: 0 }]);
|
|
66
77
|
}
|
|
67
78
|
}
|
|
68
79
|
exports.TextLayer = TextLayer;
|
package/dist/template.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type TemplateConfig = {
|
|
|
5
5
|
height: number;
|
|
6
6
|
fill?: Color;
|
|
7
7
|
};
|
|
8
|
-
export type
|
|
8
|
+
export type InputTemplateOptions<Data> = {
|
|
9
9
|
imagePath?: undefined;
|
|
10
10
|
config: TemplateConfig;
|
|
11
11
|
layers: Layer<Data>[];
|
|
@@ -14,8 +14,13 @@ export type TemplateOptions<Data> = {
|
|
|
14
14
|
imagePath: string;
|
|
15
15
|
layers: Layer<Data>[];
|
|
16
16
|
};
|
|
17
|
+
export type TemplateOptions<Data> = {
|
|
18
|
+
imagePath?: string;
|
|
19
|
+
config?: TemplateConfig;
|
|
20
|
+
layers: Layer<Data>[];
|
|
21
|
+
};
|
|
17
22
|
export declare class Template<Data> {
|
|
18
23
|
readonly options: TemplateOptions<Data>;
|
|
19
|
-
constructor(options:
|
|
24
|
+
constructor(options: InputTemplateOptions<Data>);
|
|
20
25
|
render(data: Data): Promise<sharp.Sharp>;
|
|
21
26
|
}
|
package/dist/template.js
CHANGED
|
@@ -6,6 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Template = void 0;
|
|
7
7
|
const sharp_1 = __importDefault(require("sharp"));
|
|
8
8
|
const commit_frame_1 = require("./utils/commit-frame");
|
|
9
|
+
const transparentFill = {
|
|
10
|
+
r: 0,
|
|
11
|
+
g: 0,
|
|
12
|
+
b: 0,
|
|
13
|
+
alpha: 0,
|
|
14
|
+
};
|
|
9
15
|
class Template {
|
|
10
16
|
constructor(options) {
|
|
11
17
|
this.options = options;
|
|
@@ -19,27 +25,31 @@ class Template {
|
|
|
19
25
|
width: width,
|
|
20
26
|
height: height,
|
|
21
27
|
channels: 4,
|
|
22
|
-
background: fill !== null && fill !== void 0 ? fill :
|
|
23
|
-
|
|
24
|
-
g: 0,
|
|
25
|
-
b: 0,
|
|
26
|
-
alpha: 0
|
|
27
|
-
}
|
|
28
|
-
}
|
|
28
|
+
background: fill !== null && fill !== void 0 ? fill : transparentFill,
|
|
29
|
+
},
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
33
|
image = (0, sharp_1.default)(this.options.imagePath);
|
|
34
|
+
const metadata = await image.metadata();
|
|
35
|
+
this.options.config = {
|
|
36
|
+
width: metadata.width,
|
|
37
|
+
height: metadata.height,
|
|
38
|
+
};
|
|
33
39
|
}
|
|
34
40
|
const ctx = {
|
|
35
41
|
image: image,
|
|
36
42
|
offsetX: 0,
|
|
37
|
-
offsetY: 0
|
|
43
|
+
offsetY: 0,
|
|
38
44
|
};
|
|
39
45
|
for (const layer of this.options.layers) {
|
|
40
46
|
if (!layer.shouldRender(data))
|
|
41
47
|
continue;
|
|
42
|
-
await layer.render(
|
|
48
|
+
await layer.render({
|
|
49
|
+
context: ctx,
|
|
50
|
+
data: data,
|
|
51
|
+
templateConfig: this.options.config,
|
|
52
|
+
});
|
|
43
53
|
ctx.image = await (0, commit_frame_1.commitFrame)(ctx.image);
|
|
44
54
|
}
|
|
45
55
|
return ctx.image;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { TemplateConfig } from "../template";
|
|
2
|
+
export type ComputeAxisOptions<Data> = {
|
|
3
|
+
data: Data;
|
|
4
|
+
index: number;
|
|
5
|
+
};
|
|
6
|
+
export type ComputeAxis<Data> = (options: ComputeAxisOptions<Data>) => number;
|
|
2
7
|
export type Axis<Data> = ComputeAxis<Data> | number;
|
|
3
|
-
export
|
|
8
|
+
export type ResolveAxisOptions<Data> = {
|
|
9
|
+
axis: Axis<Data>;
|
|
10
|
+
data: Data;
|
|
11
|
+
index: number;
|
|
12
|
+
templateConfig: TemplateConfig;
|
|
13
|
+
};
|
|
14
|
+
export declare function resolveAxis<Data>({ axis, ...params }: ResolveAxisOptions<Data>): number;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveAxis = resolveAxis;
|
|
4
|
-
function resolveAxis(axis,
|
|
4
|
+
function resolveAxis({ axis, ...params }) {
|
|
5
5
|
if (typeof axis === "function") {
|
|
6
|
-
return axis(
|
|
6
|
+
return axis(params);
|
|
7
7
|
}
|
|
8
8
|
return axis;
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xpict",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Xpict é uma biblioteca para a geração de imagens padronizadas a partir de modelos declarativos.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"playground:heroic-race": "ts-node ./playground/heroic-race.ts",
|
|
14
14
|
"test": "jest",
|
|
15
|
-
"build": "tsc"
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"format": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\""
|
|
16
17
|
},
|
|
17
18
|
"keywords": [
|
|
18
19
|
"xpict",
|
|
@@ -27,6 +28,10 @@
|
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/jest": "^30.0.0",
|
|
29
30
|
"@types/node": "^25.0.3",
|
|
31
|
+
"eslint-config-prettier": "^10.1.8",
|
|
32
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
33
|
+
"prettier": "^3.7.4",
|
|
34
|
+
"prettier-plugin-sort-imports": "^1.8.9",
|
|
30
35
|
"ts-jest": "^29.4.6",
|
|
31
36
|
"ts-node": "^10.9.2",
|
|
32
37
|
"typescript": "^5.9.3"
|