Please bookmark this page to avoid losing your image tool!

Whale Image Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, whaleSize = "15", backgroundColor = "#021226", whaleDirection = "left", colorMode = "original") {
    const w = originalImg.width;
    const h = originalImg.height;

    // Parse the size and enforce a safety limit to prevent the browser from freezing on huge images
    let size = parseFloat(whaleSize);
    if (isNaN(size) || size <= 0) size = 15;
    
    // Dynamic minimum size calculated based on total image pixels, capping out at roughly ~100,000 whales max.
    const minSize = Math.max(4, Math.sqrt((w * h) / 100000));
    if (size < minSize) {
        size = Math.ceil(minSize);
    }

    const canvas = document.createElement('canvas');
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Draw the image first to grab the original pixel data
    ctx.drawImage(originalImg, 0, 0, w, h);
    const imgData = ctx.getImageData(0, 0, w, h);
    const data = imgData.data;

    // Fill the background context
    if (backgroundColor.toLowerCase() === 'transparent' || backgroundColor === '') {
        ctx.clearRect(0, 0, w, h);
    } else {
        ctx.fillStyle = backgroundColor;
        ctx.fillRect(0, 0, w, h);
    }

    const dir = String(whaleDirection).toLowerCase();
    const style = String(colorMode).toLowerCase();

    // Determine mosaic spacing structure
    const spacingX = size;
    const spacingY = size * 0.6; // Packed tightly to accommodate the whale's vertical structure
    let row = 0;

    for (let y = spacingY / 2; y < h + spacingY; y += spacingY) {
        // Staggered honeycomb-like offset
        const offsetX = (row % 2 === 1) ? spacingX / 2 : 0;
        
        for (let x = spacingX / 2 + offsetX; x < w + spacingX; x += spacingX) {
            
            // Constrain pixel coordinates safely inside the canvas bounds
            const px = Math.max(0, Math.min(Math.floor(x), w - 1));
            const py = Math.max(0, Math.min(Math.floor(y), h - 1));
            
            const offset = (py * w + px) * 4;
            let r = data[offset];
            let g = data[offset + 1];
            let b = data[offset + 2];
            const a = data[offset + 3];

            // Skip largely transparent pixels
            if (a < 128) continue;

            if (style === "oceanblue") {
                // Mix the original color with a deep, oceanic cyan/blue
                r = Math.min(255, Math.floor(r * 0.3 + 10));
                g = Math.min(255, Math.floor(g * 0.5 + 80));
                b = Math.min(255, Math.floor(b * 0.7 + 140));
            }

            const color = `rgb(${r}, ${g}, ${b})`;
            const brightness = (r * 0.299 + g * 0.587 + b * 0.114);

            // Determine swimming direction randomness 
            let flip = false;
            if (dir === "right") {
                flip = true;
            } else if (dir === "random" || dir === "both") {
                flip = Math.random() > 0.5;
            }

            ctx.save();
            ctx.translate(x, y);

            let s = size / 100; // Whales are designed in roughly 100x100 space coords
            if (flip) {
                ctx.scale(-s, s);
            } else {
                ctx.scale(s, s);
            }

            // Draw organic, aesthetic whale shape
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.moveTo(-40, 0); // Nose
            ctx.bezierCurveTo(-40, -30, 20, -30, 30, -10); // Forehead and back
            ctx.quadraticCurveTo(40, -10, 50, -20); // Upper tail 
            ctx.lineTo(45, 0); // V-cleft of the tail fin
            ctx.lineTo(50, 20); // Bottom tail
            ctx.quadraticCurveTo(40, 10, 30, 10); // Lower tail curve
            ctx.bezierCurveTo(20, 30, -20, 30, -40, 10); // Belly 
            ctx.quadraticCurveTo(-30, 5, -40, 0); // Friendly mouth indent
            ctx.fill();

            // Draw the eye (contrast dynamically adjusted heavily against lightness limit)
            if (brightness > 128) {
                // Light-colored whale -> Dark eye with a white sparkle
                ctx.fillStyle = '#000000';
                ctx.beginPath(); ctx.arc(-20, -5, 4, 0, Math.PI * 2); ctx.fill();
                ctx.fillStyle = '#ffffff';
                ctx.beginPath(); ctx.arc(-21, -6, 1.5, 0, Math.PI * 2); ctx.fill();
            } else {
                // Dark-colored whale -> White eye with a dark pupil
                ctx.fillStyle = '#ffffff';
                ctx.beginPath(); ctx.arc(-20, -5, 4, 0, Math.PI * 2); ctx.fill();
                ctx.fillStyle = '#000000';
                ctx.beginPath(); ctx.arc(-19, -5, 2, 0, Math.PI * 2); ctx.fill();
            }

            ctx.restore();
        }
        row++;
    }

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Whale Image Tool is a creative mosaic generator that transforms your photos into artistic patterns made of small whale shapes. By sampling colors from your original image, the tool recreates the picture using a dense arrangement of whales, allowing you to customize the size of the whales, the background color, and their swimming direction. You can also apply an ‘oceanblue’ color mode to give your mosaic a themed, aquatic aesthetic. This tool is ideal for creating unique digital art, themed social media profile pictures, or whimsical wallpapers.

Leave a Reply

Your email address will not be published. Required fields are marked *