You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, segments = "12", zoom = "1.5", angle = "0", glow = "0.7", sparkles = "30", offsetX = "0.5", offsetY = "0.5") {
// Parse parameters
const segCount = parseInt(segments, 10) || 12;
const zoomLevel = parseFloat(zoom) || 1.5;
const rotAngle = parseFloat(angle) || 0;
const glowOp = Math.max(0, Math.min(1, parseFloat(glow) || 0.7));
const sparkleCount = parseInt(sparkles, 10) || 30;
let ox = parseFloat(offsetX);
if (isNaN(ox)) ox = 0.5;
let oy = parseFloat(offsetY);
if (isNaN(oy)) oy = 0.5;
const canvas = document.createElement('canvas');
// Generating a square output based on the largest dimension of the image
const size = Math.max(originalImg.width, originalImg.height);
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
// Fill with black background
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, size, size);
const cx = size / 2;
const cy = size / 2;
const numSegments = Math.max(2, segCount);
const sliceAngle = (2 * Math.PI) / numSegments;
const imgCx = originalImg.width * ox;
const imgCy = originalImg.height * oy;
// 1. Draw Kaleidoscope Pattern
for (let i = 0; i < numSegments; i++) {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(i * sliceAngle);
// Clip to the wedge shape
ctx.beginPath();
ctx.moveTo(0, 0);
// A tiny overlap (0.002) is added to avoid anti-aliasing gaps between slices
ctx.arc(0, 0, size * 1.5, -sliceAngle / 2 - 0.002, sliceAngle / 2 + 0.002);
ctx.closePath();
ctx.clip();
// Mirror odd slices across local X-axis to create perfect seamless symmetry
if (i % 2 !== 0) {
ctx.scale(1, -1);
}
// Apply user zoom and rotation
ctx.rotate(rotAngle * Math.PI / 180);
ctx.scale(zoomLevel, zoomLevel);
// Draw the image, centered on the target offset point
ctx.drawImage(originalImg, -imgCx, -imgCy);
ctx.restore();
}
// 2. Add Dreamy Bloom/Glow Effect
if (glowOp > 0) {
const offscreen = document.createElement('canvas');
offscreen.width = size;
offscreen.height = size;
const offCtx = offscreen.getContext('2d');
offCtx.drawImage(canvas, 0, 0);
ctx.save();
ctx.globalAlpha = glowOp;
ctx.globalCompositeOperation = 'screen';
// Scale the blur radiuses relative to the output size
ctx.filter = `blur(${size * 0.03}px)`;
ctx.drawImage(offscreen, 0, 0);
ctx.filter = `blur(${size * 0.01}px)`;
ctx.drawImage(offscreen, 0, 0);
ctx.restore();
}
// 3. Add Magical Sparkles
if (sparkleCount > 0) {
// Simple deterministic PRNG for consistent sparkle placement
let seed = 1337;
function random() {
seed = (seed * 16807) % 2147483647;
return (seed - 1) / 2147483646;
}
const drawSparkle = (x, y, radius) => {
ctx.save();
ctx.translate(x, y);
ctx.fillStyle = '#ffffff';
ctx.shadowColor = '#ffffff';
ctx.shadowBlur = radius;
ctx.beginPath();
const points = 4;
const innerRadius = radius * 0.15;
for (let j = 0; j < points * 2; j++) {
const r = (j % 2 === 0) ? radius : innerRadius;
const a = j * Math.PI / points;
ctx.lineTo(Math.cos(a) * r, Math.sin(a) * r);
}
ctx.closePath();
ctx.fill();
ctx.restore();
};
for (let i = 0; i < sparkleCount; i++) {
const sx = random() * size;
const sy = random() * size;
const sRadius = random() * (size * 0.025) + (size * 0.005);
ctx.globalAlpha = random() * 0.6 + 0.4;
ctx.save();
ctx.translate(sx, sy);
ctx.rotate(random() * Math.PI / 2); // Random initial rotation for each star
ctx.translate(-sx, -sy);
drawSparkle(sx, sy, sRadius);
ctx.restore();
}
ctx.globalAlpha = 1.0;
}
return canvas;
}
Apply Changes