You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, maxIterations = 100, zoom = 1.0, centerX = -0.7, centerY = 0.0, colorPaletteStr = "hsv_cycle", blendMode = "multiply") {
const W = originalImg.width;
const H = originalImg.height;
// Ensure width and height are valid
if (W === 0 || H === 0) {
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = W;
emptyCanvas.height = H;
console.warn("Original image has zero width or height.");
return emptyCanvas;
}
// Ensure zoom is positive
if (zoom <= 0) {
zoom = 1.0; // Default to 1.0 if zoom is invalid
console.warn("Zoom must be positive. Resetting to 1.0.");
}
if (maxIterations <= 0) {
maxIterations = 1; // Ensure at least one iteration
}
const outputCanvas = document.createElement('canvas');
outputCanvas.width = W;
outputCanvas.height = H;
const outCtx = outputCanvas.getContext('2d');
// Draw the original image first onto the output canvas
outCtx.drawImage(originalImg, 0, 0, W, H);
// Create ImageData for the fractal
const fractalImageData = outCtx.createImageData(W, H);
// Complex plane parameters:
// Standard Mandelbrot view is roughly Real:[-2.5, 1.0], Imaginary:[-1.0, 1.0] (Width 3.5, Height 2.0)
// Or more tightly, Real:[-2.0, 1.0], Imaginary:[-1.0, 1.0] (Width 3.0, Height 2.0)
// We'll use the 3.0x2.0 base view.
// Adjust the view window to match canvas aspect ratio, centered at (centerX, centerY) and scaled by zoom.
let realRange, imaginaryRange;
const canvasAspectRatio = W / H;
const fractalBaseAspectRatio = 3.0 / 2.0;
if (canvasAspectRatio > fractalBaseAspectRatio) {
// Canvas is wider than the base fractal view. Fit height, expand width.
imaginaryRange = 2.0 / zoom;
realRange = imaginaryRange * canvasAspectRatio;
} else {
// Canvas is taller or has the same aspect ratio. Fit width, expand height.
realRange = 3.0 / zoom;
imaginaryRange = realRange / canvasAspectRatio;
}
const realMin = centerX - realRange / 2.0;
// Canvas Y=0 is top row. Complex Im values usually increase upwards.
// So, map canvas row 0 to top of complex window (imaginaryMax).
const imaginaryMax = centerY + imaginaryRange / 2.0;
// Helper function for HSV to RGB conversion (defined inside to keep the function self-contained)
function HSVtoRGB(h, s, v) {
let r, g, b, i, f, p, q, t;
if (s === 0) {
r = g = b = v; // achromatic
} else {
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
default: r = 0; g = 0; b = 0; // Should not happen
}
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
// Mandelbrot calculation loop
for (let r_px = 0; r_px < H; r_px++) { // Current row in pixels
for (let c_px = 0; c_px < W; c_px++) { // Current column in pixels
// Map pixel coordinate to complex number c = cr + i * ci
const cr = realMin + (c_px / W) * realRange;
const ci = imaginaryMax - (r_px / H) * imaginaryRange; // Y-axis inversion for complex plane
let zr = 0; // Real part of z
let zi = 0; // Imaginary part of z
let zr2 = 0; // zr^2
let zi2 = 0; // zi^2
let n = 0; // Iteration count
// Iterate z_{k+1} = z_k^2 + c
for (; n < maxIterations; n++) {
// z_i_new = 2*z_r*z_i + c_i
// z_r_new = z_r^2 - z_i^2 + c_r
// Important: use z_r from _this_ iteration for z_i calculation before z_r is updated.
// zr2 and zi2 are from the *previous* iteration state (z_k)^2
zi = 2 * zr * zi + ci;
zr = zr2 - zi2 + cr;
// Update squares for next iteration's escape check and calculation
zr2 = zr * zr;
zi2 = zi * zi;
// Check escape condition: |z|^2 > 4 (escape radius 2)
if (zr2 + zi2 > 4) {
break;
}
}
const pixelIdx = (r_px * W + c_px) * 4;
let r_col = 0, g_col = 0, b_col = 0; // Default to black (inside the set)
if (n < maxIterations) { // Point escaped (outside the set)
// Smooth coloring based on n and final |z|
// nu = log_2(log_escape_radius(|Z_n|))
const log_zn = Math.log(Math.sqrt(zr2 + zi2)); // log(|Z_n|)
const nu = Math.log(log_zn / Math.log(2)) / Math.log(2); // log_2(log_base_2(|Z_n|))
let smooth_n = n + 1 - nu;
if (smooth_n < 0 || !isFinite(smooth_n)) { // handles NaN/Infinity from log args
smooth_n = 0;
}
switch (colorPaletteStr.toLowerCase()) {
case "hsv_cycle":
const hue_factor = 0.05; // Controls frequency of color cycling
const hue = (smooth_n * hue_factor) % 1.0;
[r_col, g_col, b_col] = HSVtoRGB(hue, 1.0, 1.0);
break;
case "grayscale":
// Map smooth_n to a grayscale value. Normalize by maxIterations or a fraction of it.
let gray_val = (smooth_n / (maxIterations * 0.3)) % 1.0; // Modulo for cycling effect
gray_val = Math.min(1.0, gray_val); // Clamp
const gray = Math.floor(gray_val * 255);
r_col = g_col = b_col = gray;
break;
default: // Fallback to hsv_cycle if palette name is unknown
const default_hue_factor = 0.05;
const default_hue = (smooth_n * default_hue_factor) % 1.0;
[r_col, g_col, b_col] = HSVtoRGB(default_hue, 1.0, 1.0);
break;
}
}
// Else (n == maxIterations), point is in the set. Color remains black.
fractalImageData.data[pixelIdx] = r_col;
fractalImageData.data[pixelIdx + 1] = g_col;
fractalImageData.data[pixelIdx + 2] = b_col;
fractalImageData.data[pixelIdx + 3] = 255; // Fully opaque
}
}
// To blend, draw the fractalData onto a temporary canvas, then draw that canvas onto the outputCanvas.
const fractalCanvas = document.createElement('canvas');
fractalCanvas.width = W;
fractalCanvas.height = H;
const fractalCtx = fractalCanvas.getContext('2d');
fractalCtx.putImageData(fractalImageData, 0, 0);
// Apply blend mode
outCtx.globalCompositeOperation = blendMode;
outCtx.drawImage(fractalCanvas, 0, 0);
// Optional: Reset globalCompositeOperation if outCtx might be used further by caller
// outCtx.globalCompositeOperation = 'source-over';
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Fractal Mandelbrot Filter Application allows users to generate stunning Mandelbrot fractal visuals applied to existing images. This tool enables customization such as adjusting the zoom level, changing the center point of the fractal, and selecting from various color palettes. It is particularly useful for artists, designers, and digital creators looking to enhance their images with unique fractal effects, making it ideal for digital art projects, graphic design, and creative visual experimentation.