Please bookmark this page to avoid losing your image tool!

Image Low Poly Effect 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.
async function processImage(originalImg, pointCount = 1500, wireframe = 'false', strokeColor = 'rgba(0,0,0,0.1)', strokeWidth = 1) {
    /**
     * Dynamically imports the Delaunator library for triangulation.
     * Caches it on the window object to prevent re-downloads on subsequent calls.
     */
    if (typeof window.Delaunator === 'undefined') {
        try {
            // Using a reliable CDN link for the ES module.
            const module = await import('https://unpkg.com/delaunator@5.0.0/index.js');
            window.Delaunator = module.default;
        } catch (error) {
            console.error("Failed to load Delaunator library:", error);
            // Fallback: return the original image on a canvas if the library fails to load.
            const canvas = document.createElement('canvas');
            canvas.width = originalImg.naturalWidth;
            canvas.height = originalImg.naturalHeight;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(originalImg, 0, 0);
            return canvas;
        }
    }
    const Delaunator = window.Delaunator;

    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;

    // Create a temporary canvas to access the image's pixel data efficiently.
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = w;
    tempCanvas.height = h;
    const tempCtx = tempCanvas.getContext('2d');
    tempCtx.drawImage(originalImg, 0, 0, w, h);
    const imageData = tempCtx.getImageData(0, 0, w, h);
    const data = imageData.data;

    /**
     * Helper function to get the RGBA color at a specific coordinate from the image data.
     * @param {number} x - The x-coordinate.
     * @param {number} y - The y-coordinate.
     * @returns {string} The CSS rgba color string.
     */
    const getColorAt = (x, y) => {
        const roundedX = Math.max(0, Math.min(Math.floor(x), w - 1));
        const roundedY = Math.max(0, Math.min(Math.floor(y), h - 1));
        const index = (roundedY * w + roundedX) * 4;
        const r = data[index];
        const g = data[index + 1];
        const b = data[index + 2];
        const a = data[index + 3] / 255;
        return `rgba(${r}, ${g}, ${b}, ${a})`;
    };

    // Create the final destination canvas.
    const canvas = document.createElement('canvas');
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');

    // Generate vertices for the triangulation.
    const points = [];

    // Add points at corners and edge midpoints to preserve the image boundary.
    points.push([0, 0], [w, 0], [0, h], [w, h], [w / 2, 0], [w / 2, h], [0, h / 2], [w, h / 2]);

    // Add a specified number of random points.
    const numPoints = Number(pointCount) || 1500;
    for (let i = 0; i < numPoints; i++) {
        points.push([Math.random() * w, Math.random() * h]);
    }

    // Perform Delaunay triangulation on the points.
    const delaunay = Delaunator.from(points);
    const triangles = delaunay.triangles;

    // Render each triangle by filling it with the color from its centroid.
    for (let i = 0; i < triangles.length; i += 3) {
        const p1_idx = triangles[i];
        const p2_idx = triangles[i + 1];
        const p3_idx = triangles[i + 2];

        const [x1, y1] = points[p1_idx];
        const [x2, y2] = points[p2_idx];
        const [x3, y3] = points[p3_idx];

        // Calculate the centroid of the triangle to sample the color from the original image.
        const cx = (x1 + x2 + x3) / 3;
        const cy = (y1 + y2 + y3) / 3;
        const color = getColorAt(cx, cy);

        // Draw the filled triangle.
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.lineTo(x3, y3);
        ctx.closePath();
        ctx.fillStyle = color;
        ctx.fill();
    }

    // Optionally draw the wireframe on top in a separate loop for a clean look.
    const drawWireframe = wireframe.toString().toLowerCase() === 'true';
    if (drawWireframe) {
        ctx.strokeStyle = strokeColor;
        ctx.lineWidth = Number(strokeWidth) || 1;
        for (let i = 0; i < triangles.length; i += 3) {
            const p1_idx = triangles[i];
            const p2_idx = triangles[i + 1];
            const p3_idx = triangles[i + 2];

            const [x1, y1] = points[p1_idx];
            const [x2, y2] = points[p2_idx];
            const [x3, y3] = points[p3_idx];
            
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.lineTo(x3, y3);
            ctx.closePath();
            ctx.stroke();
        }
    }

    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 Low Poly Effect Generator transforms standard images into stylized low poly artwork. By applying a triangulation technique, users can create a unique artistic effect reminiscent of polygonal graphics. This tool is ideal for graphic designers, artists, and hobbyists looking to enhance their images for digital art projects, social media content, or creative presentations. Users can customize the number of triangles, add a wireframe overlay, and select stroke colors and widths to achieve their desired aesthetic.

Leave a Reply

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