You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
outputSize = 600,
titleText = "ALBUM TITLE",
artistText = "ARTIST NAME",
textColor = "white",
fontFamily = "Arial Black, Gadget, sans-serif",
titleFontSizeRatio = 0.08,
artistFontSizeRatio = 0.05,
textBlockPosition = "bottom", // "top", "bottom", "none"
textAlign = "center", // "left", "center", "right"
textPaddingRatio = 0.05, // Padding for text block from canvas edges & PA label margin
textShadowEnabled = 1, // 0 for false, 1 for true
showParentalAdvisory = 0, // 0 for false, 1 for true
parentalAdvisoryType = "explicit_content", // "explicit_content", "explicit_lyrics"
parentalAdvisoryPosition = "bottom-right", // "bottom-right", "bottom-left", "top-right", "top-left"
parentalAdvisoryWidthRatio = 0.3, // Width of PA label as ratio of outputSize
parentalAdvisoryFontFamily = "Impact, Arial Black, sans-serif"
) {
const canvas = document.createElement('canvas');
canvas.width = outputSize;
canvas.height = outputSize;
const ctx = canvas.getContext('2d');
// 1. Draw the image (cover mode)
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
// Draw a placeholder if image is not loaded or invalid
ctx.fillStyle = '#cccccc';
ctx.fillRect(0, 0, outputSize, outputSize);
ctx.fillStyle = '#333333';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = `${outputSize * 0.05}px Arial`;
ctx.fillText("Image Error", outputSize / 2, outputSize / 2 - outputSize * 0.03);
ctx.fillText("(No image loaded or image is empty)", outputSize / 2, outputSize / 2 + outputSize * 0.03);
return canvas;
}
const canvasAspect = 1; // outputSize / outputSize (square)
const imgAspect = imgWidth / imgHeight;
let sx = 0, sy = 0, sWidth = imgWidth, sHeight = imgHeight;
if (imgAspect > canvasAspect) { // Image is wider than target aspect (e.g., landscape image on square canvas)
sWidth = imgHeight * canvasAspect; // Crop width
sx = (imgWidth - sWidth) / 2; // Center horizontally
} else if (imgAspect < canvasAspect) { // Image is taller than target aspect (e.g., portrait image on square canvas)
sHeight = imgWidth / canvasAspect; // Crop height
sy = (imgHeight - sHeight) / 2; // Center vertically
}
// If imgAspect === canvasAspect, sx, sy, sWidth, sHeight are already correct for full image.
ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, 0, 0, outputSize, outputSize);
// 2. Draw Text (Title and Artist)
const cleanTitleText = titleText.trim();
const cleanArtistText = artistText.trim();
if (textBlockPosition !== "none" && (cleanTitleText || cleanArtistText)) {
const titleFontSize = outputSize * titleFontSizeRatio;
const artistFontSize = outputSize * artistFontSizeRatio;
const padding = outputSize * textPaddingRatio;
// Min 2px or 1.5% of outputSize for line spacing.
const mainTextLineSpacing = Math.max(2, outputSize * 0.015);
if (textShadowEnabled === 1) {
ctx.shadowColor = 'rgba(0,0,0,0.7)';
// Min 3px blur or 1% of outputSize for shadow blur.
ctx.shadowBlur = Math.max(3, outputSize * 0.01);
// Min 1px offset or 0.3% of outputSize for shadow offset.
ctx.shadowOffsetX = Math.max(1, outputSize * 0.003);
ctx.shadowOffsetY = Math.max(1, outputSize * 0.003);
}
ctx.fillStyle = textColor;
let textX;
if (textAlign === "left") {
ctx.textAlign = "left";
textX = padding;
} else if (textAlign === "right") {
ctx.textAlign = "right";
textX = outputSize - padding;
} else { // Default to center
ctx.textAlign = "center";
textX = outputSize / 2;
}
if (textBlockPosition === "bottom") {
ctx.textBaseline = 'bottom';
let currentY = outputSize - padding;
if (cleanArtistText) {
ctx.font = `${artistFontSize}px ${fontFamily}`;
ctx.fillText(cleanArtistText, textX, currentY);
currentY -= (artistFontSize + mainTextLineSpacing);
}
if (cleanTitleText) {
ctx.font = `${titleFontSize}px ${fontFamily}`;
ctx.fillText(cleanTitleText, textX, currentY);
}
} else if (textBlockPosition === "top") {
ctx.textBaseline = 'top';
let currentY = padding;
if (cleanTitleText) {
ctx.font = `${titleFontSize}px ${fontFamily}`;
ctx.fillText(cleanTitleText, textX, currentY);
currentY += (titleFontSize + mainTextLineSpacing);
}
if (cleanArtistText) {
ctx.font = `${artistFontSize}px ${fontFamily}`;
ctx.fillText(cleanArtistText, textX, currentY);
}
}
// Clear shadow for subsequent drawing operations
if (textShadowEnabled === 1) {
ctx.shadowColor = 'transparent'; // Or 'rgba(0,0,0,0)'
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
}
}
// 3. Draw Parental Advisory Label
if (showParentalAdvisory === 1) {
const paLabelWidth = outputSize * parentalAdvisoryWidthRatio;
// Standard-ish aspect ratio is ~2.6:1 for the PA label.
const paLabelHeight = paLabelWidth / 2.6;
// Use textPaddingRatio for PA label's margin from canvas edge.
const paLabelMarginFromEdge = outputSize * textPaddingRatio;
let palX, palY; // Top-left corner of the PA label
if (parentalAdvisoryPosition === "bottom-left") {
palX = paLabelMarginFromEdge;
palY = outputSize - paLabelHeight - paLabelMarginFromEdge;
} else if (parentalAdvisoryPosition === "top-left") {
palX = paLabelMarginFromEdge;
palY = paLabelMarginFromEdge;
} else if (parentalAdvisoryPosition === "top-right") {
palX = outputSize - paLabelWidth - paLabelMarginFromEdge;
palY = paLabelMarginFromEdge;
} else { // Default to "bottom-right"
palX = outputSize - paLabelWidth - paLabelMarginFromEdge;
palY = outputSize - paLabelHeight - paLabelMarginFromEdge;
}
// Draw black background for PA label
ctx.fillStyle = "black";
ctx.fillRect(palX, palY, paLabelWidth, paLabelHeight);
// PA Text
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
const paTextTop = "PARENTAL ADVISORY";
const paTextBottom = parentalAdvisoryType === "explicit_lyrics" ? "EXPLICIT LYRICS" : "EXPLICIT CONTENT";
// Horizontal padding inside the PA label (e.g., 5% of label width on each side)
const paLabelPaddingHorizontal = paLabelWidth * 0.05;
const paUsableTextWidth = paLabelWidth - 2 * paLabelPaddingHorizontal;
// Top Text: PARENTAL ADVISORY
// Target font size ~32% of label height for this line. Make it bold.
let paFontSizeTop = paLabelHeight * 0.32;
ctx.font = `bold ${paFontSizeTop}px ${parentalAdvisoryFontFamily}`;
let textMetricsTop = ctx.measureText(paTextTop);
if (textMetricsTop.width > paUsableTextWidth) {
paFontSizeTop *= (paUsableTextWidth / textMetricsTop.width);
ctx.font = `bold ${paFontSizeTop}px ${parentalAdvisoryFontFamily}`;
}
// Position text in the top ~35% of the label's vertical space
ctx.fillText(paTextTop, palX + paLabelWidth / 2, palY + paLabelHeight * 0.35);
// Bottom Text: EXPLICIT CONTENT/LYRICS
// Target font size ~28% of label height. Font choice determines boldness.
let paFontSizeBottom = paLabelHeight * 0.28;
ctx.font = `${paFontSizeBottom}px ${parentalAdvisoryFontFamily}`;
let textMetricsBottom = ctx.measureText(paTextBottom);
if (textMetricsBottom.width > paUsableTextWidth) {
paFontSizeBottom *= (paUsableTextWidth / textMetricsBottom.width);
ctx.font = `${paFontSizeBottom}px ${parentalAdvisoryFontFamily}`;
}
// Position text in the bottom ~75% of the label's vertical space
ctx.fillText(paTextBottom, palX + paLabelWidth / 2, palY + paLabelHeight * 0.75);
}
return canvas;
}
Apply Changes