Please bookmark this page to avoid losing your image tool!

Image To Polar Coordinates Converter

(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, mode = "RectToPolar", shape = "ellipse", edgeBehavior = "transparent", centerMap = "top") {
    const width = originalImg.width;
    const height = originalImg.height;

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

    const srcData = ctx.getImageData(0, 0, width, height);
    const dstData = ctx.createImageData(width, height);

    const cx = width / 2;
    const cy = height / 2;

    const w1 = width - 1;
    const h1 = height - 1;

    let R_fit = Math.min(cx, cy);
    let R_fill = Math.sqrt(cx * cx + cy * cy);

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            let sx, sy;
            let wrapX = false;

            if (mode === "RectToPolar") {
                // Converting rectangular image into circular/elliptical shape
                const dx = x - cx;
                const dy = y - cy;
                
                let r_norm;
                if (shape === "ellipse") {
                    r_norm = Math.sqrt((dx / cx) ** 2 + (dy / cy) ** 2);
                } else if (shape === "circle_fill") {
                    r_norm = Math.sqrt(dx * dx + dy * dy) / R_fill;
                } else { 
                    // "circle_fit"
                    r_norm = Math.sqrt(dx * dx + dy * dy) / R_fit;
                }

                // Make the 12 o'clock position (top) match angle 0
                let theta = Math.atan2(dy, dx) + Math.PI / 2;
                if (theta < 0) theta += 2 * Math.PI;

                // Scale angle to source image width
                sx = (theta / (2 * Math.PI)) * width;
                
                // Scale radius to source image height
                if (centerMap === "top") {
                    sy = r_norm * h1;
                } else {
                    sy = (1 - r_norm) * h1;
                }
                wrapX = true; // Angle wraps around horizontally 0 -> 2pi
            } else {
                // "PolarToRect": Unwrapping an existing circular/elliptical image to rectangular
                const theta = (x / width) * 2 * Math.PI - Math.PI / 2;
                
                let r_norm;
                if (centerMap === "top") {
                    r_norm = y / h1;
                } else {
                    r_norm = 1 - (y / h1);
                }
                
                // Map the normalized radius and angle back to Cartesian coordinates of the source
                if (shape === "ellipse") {
                    sx = cx + (r_norm * cx) * Math.cos(theta);
                    sy = cy + (r_norm * cy) * Math.sin(theta);
                } else if (shape === "circle_fill") {
                    sx = cx + (r_norm * R_fill) * Math.cos(theta);
                    sy = cy + (r_norm * R_fill) * Math.sin(theta);
                } else { 
                    // "circle_fit"
                    sx = cx + (r_norm * R_fit) * Math.cos(theta);
                    sy = cy + (r_norm * R_fit) * Math.sin(theta);
                }
                wrapX = false; // Cartesian coordinates shouldn't wrap horizontally
            }

            const dstIdx = (y * width + x) * 4;

            // Coordinate bounds checking and interpolation treatment
            if (wrapX) {
                if (sy < 0 || sy > h1) {
                    if (edgeBehavior === "clamp") {
                        sy = Math.max(0, Math.min(h1, sy));
                    } else {
                        dstData.data[dstIdx + 3] = 0; // transparent edge
                        continue;
                    }
                }
                sx = sx % width;
                if (sx < 0) sx += width;
            } else {
                if (sx < 0 || sx > w1 || sy < 0 || sy > h1) {
                    if (edgeBehavior === "clamp") {
                        sx = Math.max(0, Math.min(w1, sx));
                        sy = Math.max(0, Math.min(h1, sy));
                    } else {
                        dstData.data[dstIdx + 3] = 0; // transparent edge
                        continue;
                    }
                }
            }

            // Bilinear Interpolation
            const x1 = Math.floor(sx);
            const y1 = Math.floor(sy);
            
            let x2, y2;
            if (wrapX) {
                x2 = (x1 + 1) % width; // Smooth seamlessly horizontally 
                y2 = Math.min(h1, y1 + 1);
            } else {
                x2 = Math.min(w1, x1 + 1);
                y2 = Math.min(h1, y1 + 1);
            }

            const fx = sx - x1;
            const fy = sy - y1;

            const p11 = (y1 * width + x1) * 4;
            const p21 = (y1 * width + x2) * 4;
            const p12 = (y2 * width + x1) * 4;
            const p22 = (y2 * width + x2) * 4;

            // Apply calculated ratios for RGBA channels
            for (let c = 0; c < 4; c++) {
                const val = (srcData.data[p11 + c] * (1 - fx) + srcData.data[p21 + c] * fx) * (1 - fy) +
                            (srcData.data[p12 + c] * (1 - fx) + srcData.data[p22 + c] * fx) * fy;
                dstData.data[dstIdx + c] = val;
            }
        }
    }

    ctx.putImageData(dstData, 0, 0);
    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

This tool allows you to convert images between rectangular and polar coordinate systems. It can transform a standard rectangular image into a circular or elliptical shape, or conversely, ‘unwrap’ a circular/elliptical image into a flat rectangular layout. This is useful for specialized graphic design tasks, such as creating circular textures, radial patterns, or preparing panoramic-style data from circular captures for easier analysis and editing.

Leave a Reply

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