letter-avatar-image
Version:
A simple and lightweight package to generate letter-based avatars with customizable styles and colors, perfect for displaying initials or user profile images in your applications. `letter-avatar-image` is an easy-to-use npm package that allows you to gene
172 lines (147 loc) • 8.89 kB
JavaScript
const { createCanvas } = require('canvas');
const allColors = require('./colors.json');
const Avatar = {
extractHexColors: () => {
return Object.values(allColors).map((color) => color.hex);
},
allConditionCheck: async ({ width, height, letter, font, textColor, textAlign, textBaseline, colors }) => {
return new Promise(async (resolve, reject) => {
try {
if (!letter || letter === null || letter === undefined || letter == '') {
throw new Error(`Please provide the 'letter' configuration for the specified text. The first letter will be converted into an avatar image.`);
}
if (!colors?.length || colors == [] || colors === null || colors === undefined || colors === '') {
throw new Error(`Invalid input: The colors array cannot be empty. Please provide at least one color in the array.`);
}
if (!width || width === null || width === undefined || width === '') {
throw new Error(`Invalid input: The width field cannot be empty. Please provide a valid width value.`);
}
if (!height || height === null || height === undefined || height === '') {
throw new Error(`Invalid input: The height field cannot be empty. Please provide a valid height value.`);
}
if (!font || font === null || font === undefined || font === '') {
throw new Error(`Invalid input: The font field cannot be empty. Please provide a valid font value.`);
}
if (!textColor || textColor === null || textColor === undefined || textColor === '') {
throw new Error(`Invalid input: The textColor field cannot be empty. Please provide a valid textColor value.`);
}
if (!textAlign || textAlign === null || textAlign === undefined || textAlign === '') {
throw new Error(`Invalid input: The textAlign field cannot be empty. Please provide a valid textAlign value.`);
}
if (!textBaseline || textBaseline === null || textBaseline === undefined || textBaseline === '') {
throw new Error(`Invalid input: The textAlign field cannot be empty. Please provide a valid textAlign value.`);
}
resolve(true);
} catch (error) {
reject(error);
}
});
},
LetterAvatar: async ({ width = 100, height = 100, letter = 'A', font = 'bold 60pt Graphiks', textColor = '#ffffff', textAlign = 'center', textBaseline = 'middle', strokeColor = '#000000', isStroke = false, strokeWidth = 1, isTextStroke = false, textStrokeColor = '#000000', textStrokeWidth = 1, colors = Avatar.extractHexColors(), singleColor = '', isRounded = false, roundedStrokeWidth = 1, isUpperCase = true, textCharacter = 0 }) => {
const isNode = typeof window === 'undefined';
return new Promise(async (resolve, reject) => {
try {
await Avatar.allConditionCheck({ width, height, letter, font, textColor, textAlign, textBaseline, colors });
const character = textCharacter === 0 ? letter?.charAt(textCharacter) : letter?.slice(0, textCharacter);
let text = isUpperCase ? character?.toUpperCase() : character;
const adjustedFont = isRounded ? font.replace(/\d+pt/, `${Math.floor(parseInt(font.match(/\d+/)[0]) * 0.8)}pt`) : font;
const randomColor = singleColor || colors[Math.floor(Math.random() * colors.length)];
if (isNode) {
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
if (isRounded) {
ctx.beginPath();
ctx.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, Math.PI * 2);
ctx.clip();
}
ctx.fillStyle = randomColor;
ctx.fillRect(0, 0, width, height);
ctx.font = adjustedFont;
ctx.fillStyle = textColor;
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
if (isStroke) {
const roundedStroke = roundedStrokeWidth <= 3 ? roundedStrokeWidth : 1;
ctx.strokeStyle = strokeColor;
ctx.lineWidth = isRounded ? roundedStroke : strokeWidth;
if (isRounded) {
ctx.beginPath();
ctx.arc(width / 2, height / 2, Math.min(width, height) / 2 - roundedStroke / 2, 0, Math.PI * 2);
ctx.stroke();
} else {
ctx.strokeRect(0, 0, width, height);
}
}
const textMetrics = ctx.measureText(text);
const textHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
const centerY = height / 2 - textHeight / 2 + textMetrics.actualBoundingBoxAscent;
ctx.fillText(text, width / 2, isRounded ? centerY : height / 2);
if (isTextStroke) {
ctx.strokeStyle = textStrokeColor;
ctx.lineWidth = textStrokeWidth;
ctx.strokeText(text, width / 2, isRounded ? centerY : height / 2);
}
const buffer = canvas.toBuffer('image/png');
resolve(buffer);
} else {
// Browser (Frontend)
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Check for rounded shape
if (isRounded) {
ctx.beginPath();
ctx.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, Math.PI * 2);
ctx.clip();
}
// Set background color
ctx.fillStyle = randomColor;
ctx.fillRect(0, 0, width, height);
// Adjust font size for rounded shapes
ctx.font = adjustedFont;
// Set text properties
ctx.fillStyle = textColor;
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
// Add border/stroke around the shape if needed
if (isStroke) {
const roundedStroke = roundedStrokeWidth <= 3 ? roundedStrokeWidth : 1;
ctx.strokeStyle = strokeColor;
ctx.lineWidth = isRounded ? roundedStroke : strokeWidth;
if (isRounded) {
ctx.beginPath();
ctx.arc(width / 2, height / 2, Math.min(width, height) / 2 - roundedStroke / 2, 0, Math.PI * 2);
ctx.stroke();
} else {
ctx.strokeRect(0, 0, width, height);
}
}
// Measure text for vertical alignment
const textMetrics = ctx.measureText(text);
const textHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
const centerY = height / 2 - textHeight / 2 + textMetrics.actualBoundingBoxAscent;
// Draw text
ctx.fillText(text, width / 2, isRounded ? centerY : height / 2);
// Add stroke to text if required
if (isTextStroke) {
ctx.strokeStyle = textStrokeColor;
ctx.lineWidth = textStrokeWidth;
ctx.strokeText(text, width / 2, isRounded ? centerY : height / 2);
}
// Convert canvas to data URL and resolve
const dataURL = canvas.toDataURL('image/png');
resolve(dataURL);
}
} catch (e) {
console.error('error in LetterAvatar =----->> ', e);
reject(e);
}
});
},
};
// (async () => {
// const avtar = await Avatar.LetterAvatar({ font: 'bold 60pt Graphiks', letter: "tirth", isRounded: false, isUpperCase: true, isStroke: true });
// console.log('avtar :', avtar.toString('base64'));
// })();
module.exports = Avatar;