Please bookmark this page to avoid losing your image tool!

Image Penrose Tiling Filter 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.
function processImage(originalImg, subdivisions = 4, lineWidth = 1, lineColor = "rgba(0,0,0,0.5)") {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    if (canvas.width === 0 || canvas.height === 0) {
        // Handle cases where image dimensions are not available or invalid
        console.error("Invalid image dimensions.");
        return canvas; // Return an empty or minimal canvas
    }

    const phi = (1 + Math.sqrt(5)) / 2;
    const TYPE_THICK = 'thick'; // Robinson Triangle Type P (Acute: 36, 72, 72 degrees)
    const TYPE_THIN = 'thin';   // Robinson Triangle Type Q (Obtuse: 108, 36, 36 degrees)

    // Point/vector operations
    // Interpolates between p1 and p2 by a factor t
    // p1 + t * (p2 - p1)
    function interpolate(p1, p2, t) {
        return {
            x: p1.x * (1 - t) + p2.x * t,
            y: p1.y * (1 - t) + p2.y * t
        };
    }

    let tiles = [];

    // Initial tiles: a wheel of 10 thick triangles
    // v0 is the apex (36 degrees for Thick, 108 for Thin)
    // v1, v2 are base vertices
    const center = { x: canvas.width / 2, y: canvas.height / 2 };
    
    // Calculate R so the initial decagon (formed by bases of the 10 triangles)
    // has its apothem (distance from center to midpoint of a side)
    // equal to max(width/2, height/2), plus a small margin.
    // Apothem = R * cos(PI/10) for a decagon of triangles with apex at center.
    const apothem = Math.max(canvas.width / 2, canvas.height / 2);
    let R = apothem / Math.cos(Math.PI / 10);
    R *= 1.05; // Add a 5% margin to ensure full coverage, especially for non-square images

    for (let i = 0; i < 10; i++) {
        // Calculate vertices for the base of each initial thick triangle.
        // The angular placement is shifted by -PI/10 to make the pattern
        // symmetric around the y-axis if desired (one flat edge of the decagon at top).
        const angle1 = i * 2 * Math.PI / 10 - Math.PI / 10;
        const angle2 = (i + 1) * 2 * Math.PI / 10 - Math.PI / 10;

        const p1 = {
            x: center.x + R * Math.cos(angle1),
            y: center.y + R * Math.sin(angle1)
        };
        const p2 = {
            x: center.x + R * Math.cos(angle2),
            y: center.y + R * Math.sin(angle2)
        };
        // Initial triangles are Thick: (v0=apex, v1, v2 are base points)
        // Apex is center (angle PI/5 = 36 deg), v1 and v2 are points on the circle.
        tiles.push({ type: TYPE_THICK, v: [center, p1, p2] });
    }
    
    // Cap subdivisions to prevent excessive computation time / memory usage.
    // Max 10 subdivisions mean 10 * 2^10 = 10240 tiles which is generally manageable.
    const actualSubdivisions = Math.max(0, Math.min(subdivisions, 10));

    for (let s = 0; s < actualSubdivisions; s++) {
        const next_tiles = [];
        for (const tile of tiles) {
            const v0 = tile.v[0]; // Apex
            const v1 = tile.v[1]; // Base vertex 1
            const v2 = tile.v[2]; // Base vertex 2

            if (tile.type === TYPE_THICK) { // Apex v0 is PI/5 (36 deg)
                // Subdivision rule for Thick triangle (v0, v1, v2):
                // Point P divides edge v0-v1 by golden ratio: P = v0 + (v1-v0)/phi
                const P = interpolate(v0, v1, 1 / phi);
                // Children: Thick(P, v2, v0) and Thin(v2, P, v1)
                // Child Thick: New apex P, base v2-v0
                next_tiles.push({ type: TYPE_THICK, v: [P, v2, v0] });
                // Child Thin: New apex v2, base P-v1
                next_tiles.push({ type: TYPE_THIN, v: [v2, P, v1] });
            } else { // TYPE_THIN, Apex v0 is 3*PI/5 (108 deg)
                // Subdivision rule for Thin triangle (v0, v1, v2):
                // Point P divides edge v1-v0 by golden ratio: P = v1 + (v0-v1)/phi
                const P = interpolate(v1, v0, 1 / phi);
                // Children: Thin(P, v2, v0) and Thick(v2, P, v1)
                // Child Thin: New apex P, base v2-v0
                next_tiles.push({ type: TYPE_THIN, v: [P, v2, v0] });
                // Child Thick: New apex v2, base P-v1
                next_tiles.push({ type: TYPE_THICK, v: [v2, P, v1] });
            }
        }
        tiles = next_tiles;
    }

    // Drawing
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas for fresh drawing
    for (const tile of tiles) {
        ctx.save(); // Save context state (clip path, styles)
        
        ctx.beginPath();
        ctx.moveTo(tile.v[0].x, tile.v[0].y);
        ctx.lineTo(tile.v[1].x, tile.v[1].y);
        ctx.lineTo(tile.v[2].x, tile.v[2].y);
        ctx.closePath();

        // Draw border if lineWidth is positive
        if (lineWidth > 0) {
            ctx.strokeStyle = lineColor;
            ctx.lineWidth = lineWidth;
            ctx.stroke();
        }
        
        // Use the triangle as a clipping mask
        ctx.clip();
        
        // Draw the original image, clipped by the current tile path
        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
        
        ctx.restore(); // Restore context state (removes clipping mask for next tile)
    }

    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 Penrose Tiling Filter Effect Generator is a tool that applies a Penrose tiling effect to your images. By subdividing the image into intricate geometric patterns resembling Penrose tiles, this utility allows users to create visually striking designs. This tool can be used for various applications, including enhancing artwork, creating unique backgrounds, or generating distinctive visuals for web design and digital media. Users can customize the level of detail through subdivisions, line width, and color, making it versatile for both artistic experimentation and professional projects.

Leave a Reply

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