@shibam/sticker-maker 1.1.12 → 1.1.13

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/index.js CHANGED
@@ -42,6 +42,7 @@ class Sticker {
42
42
  this.metaInfo.category = this.metaInfo.category ?? [];
43
43
  this.metaInfo.type = this.metaInfo.type ?? StickerTypes.DEFAULT;
44
44
  this.metaInfo.quality = this.metaInfo?.quality ?? this.utils.getQuality(this.buffer);
45
+ this.metaInfo.text = this.metaInfo.text ?? '';
45
46
  }
46
47
  catch (error) {
47
48
  throw new Error(`Initialization error: ${error}`);
@@ -1,6 +1,8 @@
1
1
  import sharp from 'sharp';
2
2
  import { StickerTypes } from '../types/StickerTypes.js';
3
3
  import toGif from './toGif.js';
4
+ import TextOnImg from './textOnImg.js';
5
+ const textOnImg = new TextOnImg();
4
6
  /**
5
7
  * Converts a given buffer to WebP format with optional transformations.
6
8
  *
@@ -15,8 +17,8 @@ const ToWebp = async (buffer, metaInfo, mimeExt, mimeType) => {
15
17
  if (mimeExt === 'webp')
16
18
  return buffer;
17
19
  let data = mimeType?.includes('video')
18
- ? await toGif(buffer, mimeExt, metaInfo.type || StickerTypes.DEFAULT)
19
- : buffer;
20
+ ? await toGif(buffer, mimeExt, metaInfo.type || StickerTypes.DEFAULT, metaInfo.text ?? '')
21
+ : (metaInfo.text ? await textOnImg.drawText(buffer, metaInfo.text) : buffer);
20
22
  let isAnimated = mimeType?.includes('video') || mimeExt?.includes('gif');
21
23
  const res = sharp(data, { animated: isAnimated });
22
24
  if (metaInfo.type === StickerTypes.CIRCLE) {
@@ -0,0 +1,24 @@
1
+ import TextOnGif from 'text-on-gif';
2
+ const textOnGif = async (fileName, text) => {
3
+ return new Promise(async (resolve, reject) => {
4
+ try {
5
+ const gif = new TextOnGif({
6
+ file_path: fileName,
7
+ font_size: "18px",
8
+ font_color: "white",
9
+ font_family: "Arial",
10
+ stroke_color: "black",
11
+ stroke_width: 3,
12
+ });
13
+ const buff = await gif.textOnGif({
14
+ text,
15
+ get_as_buffer: true,
16
+ });
17
+ resolve(buff);
18
+ }
19
+ catch (error) {
20
+ reject(error);
21
+ }
22
+ });
23
+ };
24
+ export default textOnGif;
@@ -0,0 +1,54 @@
1
+ import { createCanvas, loadImage } from 'canvas';
2
+ export default class TextOnImage {
3
+ fontSize;
4
+ maxCharsPerLine;
5
+ constructor(maxCharsPerLine = 33) {
6
+ this.fontSize = 65;
7
+ this.maxCharsPerLine = maxCharsPerLine;
8
+ }
9
+ wrapText(ctx, text) {
10
+ const words = text.split(' ');
11
+ let lines = [];
12
+ let currentLine = words[0];
13
+ for (let i = 1; i < words.length; i++) {
14
+ const word = words[i];
15
+ const testLine = `${currentLine} ${word}`;
16
+ if (testLine.length > this.maxCharsPerLine) {
17
+ lines.push(currentLine);
18
+ currentLine = word;
19
+ }
20
+ else {
21
+ currentLine = testLine;
22
+ }
23
+ }
24
+ lines.push(currentLine);
25
+ return lines;
26
+ }
27
+ async drawText(imageBuffer, text, padding = { x: 10, y: 10 }) {
28
+ const image = await loadImage(imageBuffer);
29
+ const canvas = createCanvas(image.width, image.height);
30
+ const ctx = canvas.getContext('2d');
31
+ ctx.drawImage(image, 0, 0);
32
+ ctx.font = `bold ${this.fontSize}px Arial`;
33
+ ctx.fillStyle = 'white';
34
+ ctx.textAlign = 'center';
35
+ ctx.textBaseline = 'top';
36
+ ctx.lineWidth = 4;
37
+ ctx.strokeStyle = 'black';
38
+ const lines = this.wrapText(ctx, text);
39
+ const lineHeight = this.fontSize * 1.2;
40
+ const totalTextHeight = lines.length * lineHeight;
41
+ if (totalTextHeight + (2 * padding.y) > canvas.height) {
42
+ this.fontSize = (canvas.height - (2 * padding.y)) / (lines.length * 1.2);
43
+ ctx.font = `bold ${this.fontSize}px Arial`;
44
+ }
45
+ let y = canvas.height - totalTextHeight - padding.y;
46
+ lines.forEach(line => {
47
+ let x = canvas.width / 2;
48
+ ctx.strokeText(line, x, y);
49
+ ctx.fillText(line, x, y);
50
+ y += lineHeight;
51
+ });
52
+ return canvas.toBuffer('image/png');
53
+ }
54
+ }
package/dist/lib/toGif.js CHANGED
@@ -4,12 +4,14 @@ import { tmpdir } from 'os';
4
4
  import { writeFile, readFile, unlink } from 'fs/promises';
5
5
  import { join } from 'path';
6
6
  import { StickerTypes } from '../types/StickerTypes.js';
7
+ import TextOnGif from './textOnGif.js';
7
8
  ffmpeg.setFfmpegPath(ffmpegInstaller.path);
8
- const videoToGif = (buffer, extType, type, retries = 3) => {
9
+ const videoToGif = (buffer, extType, type, text = '') => {
9
10
  return new Promise(async (resolve, reject) => {
10
11
  const execute = async (attempt) => {
11
12
  const filename = join(tmpdir(), `${Math.random().toString(36)}.${extType}`);
12
13
  const outputFilename = join(tmpdir(), `${Math.random().toString(36)}.gif`);
14
+ const retries = 3;
13
15
  try {
14
16
  await writeFile(filename, buffer);
15
17
  const shape = type === StickerTypes.SQUARE
@@ -24,7 +26,7 @@ const videoToGif = (buffer, extType, type, retries = 3) => {
24
26
  .on('end', resolveFfmpeg)
25
27
  .on('error', rejectFfmpeg);
26
28
  });
27
- const gifBuffer = await readFile(outputFilename);
29
+ const gifBuffer = text ? await TextOnGif(outputFilename, text) : await readFile(outputFilename);
28
30
  await Promise.all([unlink(filename), unlink(outputFilename)]);
29
31
  resolve(gifBuffer);
30
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shibam/sticker-maker",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "A package for creating stickers",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -35,10 +35,12 @@
35
35
  "dependencies": {
36
36
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
37
37
  "@types/fluent-ffmpeg": "^2.1.24",
38
+ "canvas": "^2.11.2",
38
39
  "file-type": "^19.4.0",
39
40
  "fluent-ffmpeg": "^2.1.3",
40
41
  "node-webpmux": "^3.2.0",
41
- "sharp": "^0.33.4"
42
+ "sharp": "^0.33.4",
43
+ "text-on-gif": "^2.0.13"
42
44
  },
43
45
  "devDependencies": {
44
46
  "@types/node": "^20.10.0",