Please bookmark this page to avoid losing your image tool!

Image Of A Ball In Space Generator

(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, starCount = 400, spaceColor = '#050510', lightAngle = 45, atmosphereColor = '#4a90e2') {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Parse and validate parameters
    starCount = parseInt(starCount);
    if (isNaN(starCount) || starCount < 0) starCount = 400;
    lightAngle = parseFloat(lightAngle);
    if (isNaN(lightAngle)) lightAngle = 45;

    // Define dimensions. Cap the maximum radius to prevent memory / performance issues on very large images.
    let R = Math.max(originalImg.width, originalImg.height) / 2;
    if (R > 800) R = 800; // Limit radius to 800px (Canvas max 2400x2400)
    const R_int = Math.floor(R);

    // Canvas size provides ample "space" around the ball
    canvas.width = R_int * 3;
    canvas.height = R_int * 3;
    const cx = canvas.width / 2;
    const cy = canvas.height / 2;

    // --- 1. Draw Deep Space Background ---
    ctx.fillStyle = spaceColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Subtle background nebula/cloud
    const nebulaGrad = ctx.createRadialGradient(cx, cy, R_int * 1.5, cx, cy, canvas.width * 0.8);
    nebulaGrad.addColorStop(0, 'rgba(0, 0, 0, 0)');
    nebulaGrad.addColorStop(1, 'rgba(25, 10, 45, 0.4)');
    ctx.fillStyle = nebulaGrad;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Light source (Distant Sun/Star) in the background
    const radAngle = lightAngle * Math.PI / 180;
    const sunX = cx - Math.cos(radAngle) * canvas.width * 0.4;
    const sunY = cy - Math.sin(radAngle) * canvas.width * 0.4;

    ctx.globalCompositeOperation = 'screen';
    const sunGrad = ctx.createRadialGradient(sunX, sunY, 0, sunX, sunY, canvas.width * 0.3);
    sunGrad.addColorStop(0, 'rgba(255, 255, 255, 1)');
    sunGrad.addColorStop(0.05, 'rgba(200, 220, 255, 0.6)');
    sunGrad.addColorStop(0.3, 'rgba(100, 150, 255, 0.1)');
    sunGrad.addColorStop(1, 'rgba(100, 150, 255, 0)');
    ctx.fillStyle = sunGrad;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = 'source-over';

    // Generate Stars
    for (let i = 0; i < starCount; i++) {
        const x = Math.random() * canvas.width;
        const y = Math.random() * canvas.height;
        const r = Math.random() * 1.2 + 0.3;
        
        let opacity = Math.random() * 0.7 + 0.1;
        // Occasional extra bright star
        if (Math.random() < 0.05) opacity = 1; 
        
        ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
        ctx.beginPath();
        ctx.arc(x, y, r, 0, Math.PI * 2);
        ctx.fill();
    }

    // --- 2. Spherize Target Image (Pixel Manipulation) ---
    const tempCanvas = document.createElement('canvas');
    const tCtx = tempCanvas.getContext('2d');
    const size2R = R_int * 2;
    tempCanvas.width = size2R;
    tempCanvas.height = size2R;

    // Draw standard image over the square target frame
    tCtx.drawImage(originalImg, 0, 0, size2R, size2R);

    // Spherize via mapping Cartesian to spherical coordinates
    const srcData = tCtx.getImageData(0, 0, size2R, size2R);
    const destData = tCtx.createImageData(size2R, size2R);

    for (let y = 0; y < size2R; y++) {
        for (let x = 0; x < size2R; x++) {
            const dy = y - R_int;
            const dx = x - R_int;
            const distance = Math.sqrt(dx * dx + dy * dy);
            const destIdx = (y * size2R + x) * 4;

            if (distance <= R_int) {
                let sx, sy;
                if (distance === 0) {
                   sx = R_int;
                   sy = R_int;
                } else {
                    const d_norm = distance / R_int;
                    // Fisheye mapping gives the illusion of a protruding surface
                    const theta = Math.asin(Math.max(-1, Math.min(1, d_norm)));
                    const d_mapped = (2 * theta / Math.PI);
                    
                    sx = R_int + (dx / distance) * d_mapped * R_int;
                    sy = R_int + (dy / distance) * d_mapped * R_int;
                }
                
                sx = Math.floor(Math.max(0, Math.min(size2R - 1, sx)));
                sy = Math.floor(Math.max(0, Math.min(size2R - 1, sy)));
                const srcIdx = (sy * size2R + sx) * 4;

                destData.data[destIdx] = srcData.data[srcIdx];         // R
                destData.data[destIdx + 1] = srcData.data[srcIdx + 1]; // G
                destData.data[destIdx + 2] = srcData.data[srcIdx + 2]; // B

                // Antialiasing for smooth boundary
                if (distance > R_int - 1) {
                    destData.data[destIdx + 3] = Math.floor(255 * (R_int - distance));
                } else {
                    destData.data[destIdx + 3] = 255;
                }
            } else {
                destData.data[destIdx + 3] = 0; // Transparent outside the ball
            }
        }
    }
    tCtx.putImageData(destData, 0, 0);

    // Place the spherized image into the main space canvas
    ctx.drawImage(tempCanvas, cx - R_int, cy - R_int);

    // --- 3. Apply 3D Shading & Lighting Effects ---
    ctx.save();
    
    // Create a precise clipping mask shaped like the ball so shading doesn't overflow
    ctx.beginPath();
    ctx.arc(cx, cy, R_int - 0.5, 0, Math.PI * 2);
    ctx.clip();

    // Shadow Layer (Ambient Occlusion & Form Shadow)
    const hx = cx - Math.cos(radAngle) * R_int * 0.3;
    const hy = cy - Math.sin(radAngle) * R_int * 0.3;
    const shadowGrad = ctx.createRadialGradient(hx, hy, R_int * 0.1, cx, cy, R_int);
    shadowGrad.addColorStop(0, 'rgba(0, 0, 0, 0)');
    shadowGrad.addColorStop(0.5, 'rgba(0, 0, 0, 0.4)');
    shadowGrad.addColorStop(0.95, 'rgba(0, 0, 0, 0.85)');
    shadowGrad.addColorStop(1, 'rgba(0, 0, 0, 1)'); 
    ctx.fillStyle = shadowGrad;
    ctx.fillRect(cx - R_int, cy - R_int, R_int * 2, R_int * 2);

    // Specular Highlight Layer
    const specX = cx - Math.cos(radAngle) * R_int * 0.7;
    const specY = cy - Math.sin(radAngle) * R_int * 0.7;
    ctx.globalCompositeOperation = 'screen';
    const specGrad = ctx.createRadialGradient(specX, specY, 0, specX, specY, R_int * 0.55);
    specGrad.addColorStop(0, 'rgba(255, 255, 255, 0.7)');
    specGrad.addColorStop(0.3, 'rgba(255, 255, 255, 0.2)');
    specGrad.addColorStop(1, 'rgba(255, 255, 255, 0)');
    ctx.fillStyle = specGrad;
    ctx.fillRect(cx - R_int, cy - R_int, R_int * 2, R_int * 2);

    // Inner Atmosphere Layer (Rim Edge Lighting inside the ball boundary)
    let rimR = 74, rimG = 144, rimB = 226; // Default to #4a90e2
    if (typeof atmosphereColor === 'string' && atmosphereColor.startsWith('#')) {
        let hex = atmosphereColor.replace('#', '');
        if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
        if (hex.length === 6) {
            rimR = parseInt(hex.substring(0, 2), 16);
            rimG = parseInt(hex.substring(2, 4), 16);
            rimB = parseInt(hex.substring(4, 6), 16);
        }
    }
    
    const innerRimGrad = ctx.createRadialGradient(cx, cy, R_int * 0.75, cx, cy, R_int);
    innerRimGrad.addColorStop(0, 'rgba(0,0,0,0)');
    innerRimGrad.addColorStop(1, `rgba(${rimR}, ${rimG}, ${rimB}, 0.5)`);
    ctx.fillStyle = innerRimGrad;
    ctx.fillRect(cx - R_int, cy - R_int, R_int * 2, R_int * 2);

    ctx.restore(); // Release clipping mask

    // --- 4. Outer Atmospheric Blur ---
    // Make sure we only draw on the outside of the ball to leave the edge crisp
    ctx.save();
    ctx.beginPath();
    ctx.rect(0, 0, canvas.width, canvas.height);
    // Draw hole counter-clockwise to subtract from the rect path
    ctx.arc(cx, cy, R_int - 1, 0, Math.PI * 2, true); 
    ctx.clip();

    ctx.globalCompositeOperation = 'screen';
    const outerGlowGrad = ctx.createRadialGradient(cx, cy, R_int, cx, cy, R_int * 1.15);
    outerGlowGrad.addColorStop(0, `rgba(${rimR}, ${rimG}, ${rimB}, 0.7)`);
    outerGlowGrad.addColorStop(1, `rgba(${rimR}, ${rimG}, ${rimB}, 0)`);
    ctx.fillStyle = outerGlowGrad;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    ctx.restore();

    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 Image Of A Ball In Space Generator is a creative tool that transforms any uploaded image into a realistic-looking spherical planet or celestial body floating in deep space. It uses advanced pixel manipulation to spherize your image, giving it a 3D appearance, and then applies professional lighting effects such as shadows, specular highlights, and atmospheric glows. Users can customize the environment by adjusting the star density, the background space color, the light angle, and the color of the planet’s atmosphere. This tool is ideal for creating unique sci-fi artwork, custom textures for digital design, or fun social media avatars and graphics.

Leave a Reply

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