You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Converts a single image into a "Two Photo to Music Track Search Topic" layout.
* It dynamically generates a dual-photo collage (using filtering for the second photo),
* layered with a Glassmorphism search and music player UI.
*
* @param {HTMLImageElement} originalImg - The input image object.
* @param {string} searchTopic - The topic text to put into the search bar.
* @param {string} musicTrack - The title of the music track.
* @param {string} artistName - The artist name for the music player.
* @param {string} secondPhotoEffect - CSS filter effect for the second auto-generated photo (e.g. 'hue-rotate(180deg)', 'grayscale(100%)', 'sepia(100%)').
* @returns {HTMLCanvasElement} A drawn canvas with the combined layout.
*/
async function processImage(
originalImg,
searchTopic = "Vaporwave Aesthetics",
musicTrack = "Midnight City Vibes",
artistName = "Unknown Explorer",
secondPhotoEffect = "hue-rotate(140deg)"
) {
const canvas = document.createElement('canvas');
const width = 1200;
const height = 630;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Utility: Draw a rectangle with rounded corners
function drawRoundRect(x, y, w, h, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + w - radius, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + radius);
ctx.lineTo(x + w, y + h - radius);
ctx.quadraticCurveTo(x + w, y + h, x + w - radius, y + h);
ctx.lineTo(x + radius, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
// Utility: Draw an image covering a bounding box (similar to object-fit: cover)
function drawCover(img, x, y, w, h, filter = 'none') {
const imgAspect = img.width / img.height;
const boxAspect = w / h;
let renderW = w;
let renderH = h;
let offsetX = 0;
let offsetY = 0;
if (imgAspect > boxAspect) {
renderW = h * imgAspect;
offsetX = (w - renderW) / 2;
} else {
renderH = w / imgAspect;
offsetY = (h - renderH) / 2;
}
ctx.save();
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.clip();
if (filter !== 'none') {
ctx.filter = filter;
}
ctx.drawImage(img, x + offsetX, y + offsetY, renderW, renderH);
ctx.restore();
}
// 1. Draw "Two Photos" Background (Left: Original, Right: Stylized version)
drawCover(originalImg, 0, 0, width / 2, height, 'none');
drawCover(originalImg, width / 2, 0, width / 2, height, secondPhotoEffect);
// 2. Center Glassmorphism Overlay (The "Search Topic & Music Track" module)
const overlayW = 860;
const overlayH = 420;
const overlayX = (width - overlayW) / 2;
const overlayY = (height - overlayH) / 2;
ctx.save();
// Shadow for depth
ctx.shadowColor = 'rgba(0, 0, 0, 0.6)';
ctx.shadowBlur = 40;
ctx.shadowOffsetY = 15;
// Draw glassy card
drawRoundRect(overlayX, overlayY, overlayW, overlayH, 24);
ctx.fillStyle = 'rgba(25, 25, 30, 0.85)';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
ctx.stroke();
ctx.restore();
// 3. Search Topic Bar inside the overlay
const searchBarW = overlayW - 80;
const searchBarH = 65;
const searchBarX = overlayX + 40;
const searchBarY = overlayY + 40;
ctx.fillStyle = 'rgba(255, 255, 255, 0.08)';
drawRoundRect(searchBarX, searchBarY, searchBarW, searchBarH, searchBarH / 2);
ctx.fill();
ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
ctx.lineWidth = 1;
ctx.stroke();
// Search Topic Text
ctx.fillStyle = '#ffffff';
ctx.font = '500 26px "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText("🔍 " + searchTopic, searchBarX + 30, searchBarY + searchBarH / 2 + 2);
// Add a trailing mic/search icon abstraction
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.textAlign = 'right';
ctx.fillText("🎙️", searchBarX + searchBarW - 30, searchBarY + searchBarH / 2 + 2);
// 4. Music Player Section
const musicAreaY = searchBarY + searchBarH + 50;
const albumImgSize = 180;
const albumImgX = overlayX + 40;
const albumImgY = musicAreaY;
// Mini Album Art Cover
ctx.save();
drawRoundRect(albumImgX, albumImgY, albumImgSize, albumImgSize, 16);
ctx.clip();
drawCover(originalImg, albumImgX, albumImgY, albumImgSize, albumImgSize, 'none');
ctx.restore();
// Track Title and Artist Strings
const trackTextX = albumImgX + albumImgSize + 40;
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'left';
ctx.textBaseline = 'alphabetic';
ctx.font = 'bold 38px "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
ctx.fillText(musicTrack, trackTextX, albumImgY + 45);
ctx.fillStyle = '#b3b3b3';
ctx.font = '24px "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
ctx.fillText(artistName, trackTextX, albumImgY + 85);
// Progress Bar
const progressX = trackTextX;
const progressY = albumImgY + 135;
const progressW = overlayW - albumImgSize - 120;
const progressH = 6;
// Track background
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
drawRoundRect(progressX, progressY, progressW, progressH, 3);
ctx.fill();
// Track progress (fill up to ~45%)
ctx.fillStyle = '#1DB954'; // Sleek player green
drawRoundRect(progressX, progressY, progressW * 0.45, progressH, 3);
ctx.fill();
// Time Indicators
ctx.textBaseline = 'top';
ctx.fillStyle = '#b3b3b3';
ctx.font = '14px "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
ctx.textAlign = 'left';
ctx.fillText("1:42", progressX, progressY + 12);
ctx.textAlign = 'right';
ctx.fillText("3:55", progressX + progressW, progressY + 12);
// Playback Controls
const controlY = albumImgY + albumImgSize - 20;
const controlX = progressX + progressW / 2;
// Pause button background (Circle)
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(controlX, controlY, 28, 0, Math.PI * 2);
ctx.fill();
// Pause bars
ctx.fillStyle = '#1e1e23';
ctx.fillRect(controlX - 8, controlY - 10, 5, 20);
ctx.fillRect(controlX + 3, controlY - 10, 5, 20);
// Previous Button
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(controlX - 50, controlY);
ctx.lineTo(controlX - 68, controlY - 12);
ctx.lineTo(controlX - 68, controlY + 12);
ctx.fill();
ctx.fillRect(controlX - 72, controlY - 12, 4, 24);
// Next Button
ctx.beginPath();
ctx.moveTo(controlX + 50, controlY);
ctx.lineTo(controlX + 68, controlY - 12);
ctx.lineTo(controlX + 68, controlY + 12);
ctx.fill();
ctx.fillRect(controlX + 68, controlY - 12, 4, 24);
// 5. Watermark / Tool Identifier in bottom right corner
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
ctx.font = 'italic 16px sans-serif';
ctx.fillText("Two Photo To Music Track Space", width - 20, height - 15);
return canvas;
}
Apply Changes