Please bookmark this page to avoid losing your image tool!

Image Chain Link Fence Filter Effect 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, cellSize = 30, lineWidth = 2, lineColor = "gray", lineOpacity = 0.7, linkStyle = "dots", dotColor = "darkgray", dotOpacity = 0.8, dotSizeFactor = 2) {
    const canvas = document.createElement('canvas');
    const W = originalImg.width;
    const H = originalImg.height;
    canvas.width = W;
    canvas.height = H;

    if (W === 0 || H === 0) { // Handle zero-dimension images
        return canvas;
    }

    const ctx = canvas.getContext('2d');

    // Draw the original image
    ctx.drawImage(originalImg, 0, 0, W, H);

    // Helper function to remove duplicate points using a Set for unique keys
    // and sort them to ensure consistent line drawing order.
    function _removeDuplicatePoints(points) {
        if (points.length < 2) return points;
        const unique = [];
        const seenKeys = new Set();
        for (const p of points) {
            // Quantize to handle floating point inaccuracies, especially at corners
            const key = `${p.x.toFixed(3)},${p.y.toFixed(3)}`;
            if (!seenKeys.has(key)) {
                unique.push(p);
                seenKeys.add(key);
            }
        }
        // Sort points by x, then by y
        unique.sort((a, b) => {
            if (Math.abs(a.x - b.x) > 1e-4) return a.x - b.x; // Compare with tolerance for float
            if (Math.abs(a.y - b.y) > 1e-4) return a.y - b.y;
            return 0;
        });
        return unique;
    }

    // cellSize is the perpendicular distance between parallel wires.
    // spacingConstant is the shift along the x or y axis for the line equation constant.
    const spacingConstant = cellSize * Math.sqrt(2);
    ctx.lineWidth = lineWidth;
    const originalGlobalAlpha = ctx.globalAlpha; // Save current globalAlpha

    // --- Draw lines ---
    ctx.strokeStyle = lineColor;
    ctx.globalAlpha = lineOpacity;

    // Family 1: lines of the form x + y = k
    // k ranges from 0 (passing through origin) to W+H (passing through W,H)
    ctx.beginPath();
    // Iterate kVal. Start slightly before 0 and end slightly after W+H to ensure coverage.
    // The loop starts from `kValInit1` and goes up to `kValEnd1`.
    const kValInit1 = Math.min(0, W + H) - spacingConstant; // Ensure it covers from a bit less than smallest sum
    const kValEnd1 = Math.max(0, W + H) + spacingConstant;   // To a bit more than largest sum

    for (let kVal = kValInit1; kVal <= kValEnd1; kVal += spacingConstant) {
        const pts = [];
        // Intersection with y-axis (x=0): y = kVal. Point (0, kVal)
        if (kVal >= -lineWidth && kVal <= H + lineWidth) pts.push({ x: 0, y: kVal });
        // Intersection with x-axis (y=0): x = kVal. Point (kVal, 0)
        if (kVal >= -lineWidth && kVal <= W + lineWidth) pts.push({ x: kVal, y: 0 });
        // Intersection with x=W: y = kVal - W. Point (W, kVal - W)
        if ((kVal - W) >= -lineWidth && (kVal - W) <= H + lineWidth) pts.push({ x: W, y: kVal - W });
        // Intersection with y=H: x = kVal - H. Point (kVal - H, H)
        if ((kVal - H) >= -lineWidth && (kVal - H) <= W + lineWidth) pts.push({ x: kVal - H, y: H });

        const validPts = pts.filter(p =>
            p.x >= -lineWidth && p.x <= W + lineWidth && p.y >= -lineWidth && p.y <= H + lineWidth
        );
        const uniquePts = _removeDuplicatePoints(validPts);

        if (uniquePts.length >= 2) {
             // Draw line between the first and last points (covers cases where line might be on edge)
            ctx.moveTo(uniquePts[0].x, uniquePts[0].y);
            ctx.lineTo(uniquePts[uniquePts.length - 1].x, uniquePts[uniquePts.length - 1].y);
        }
    }
    ctx.stroke();

    // Family 2: lines of the form x - y = k (or y - x = -k)
    // k ranges from 0-H = -H (passing through 0,H) to W-0 = W (passing through W,0)
    ctx.beginPath();
    const kValInit2 = Math.min(-H, W) - spacingConstant;
    const kValEnd2 = Math.max(-H, W) + spacingConstant;

    for (let kVal = kValInit2; kVal <= kValEnd2; kVal += spacingConstant) {
        const pts = [];
        // Intersection with y-axis (x=0): y = -kVal. Point (0, -kVal)
        if ((-kVal) >= -lineWidth && (-kVal) <= H + lineWidth) pts.push({ x: 0, y: -kVal });
        // Intersection with x-axis (y=0): x = kVal. Point (kVal, 0)
        if (kVal >= -lineWidth && kVal <= W + lineWidth) pts.push({ x: kVal, y: 0 });
        // Intersection with x=W: y = W - kVal. Point (W, W - kVal)
        if ((W - kVal) >= -lineWidth && (W - kVal) <= H + lineWidth) pts.push({ x: W, y: W - kVal });
        // Intersection with y=H: x = kVal + H. Point (kVal + H, H)
        if ((kVal + H) >= -lineWidth && (kVal + H) <= W + lineWidth) pts.push({ x: kVal + H, y: H });

        const validPts = pts.filter(p =>
            p.x >= -lineWidth && p.x <= W + lineWidth && p.y >= -lineWidth && p.y <= H + lineWidth
        );
        const uniquePts = _removeDuplicatePoints(validPts);
        if (uniquePts.length >= 2) {
            ctx.moveTo(uniquePts[0].x, uniquePts[0].y);
            ctx.lineTo(uniquePts[uniquePts.length-1].x, uniquePts[uniquePts.length-1].y);
        }
    }
    ctx.stroke();

    // --- Draw intersection dots if specified ---
    if (linkStyle === "dots" && lineWidth > 0) { // Also ensure lineWidth is positive for dotSize calc
        ctx.fillStyle = dotColor;
        ctx.globalAlpha = dotOpacity;
        const dotDiameter = lineWidth * dotSizeFactor;
        const dotRadius = dotDiameter / 2;

        if (dotRadius > 0) { // Only draw dots if they have a positive size
            const k1_values = [];
            for (let kVal = kValInit1; kVal <= kValEnd1; kVal += spacingConstant) {
                k1_values.push(kVal);
            }
            const k2_values = [];
            for (let kVal = kValInit2; kVal <= kValEnd2; kVal += spacingConstant) {
                k2_values.push(kVal);
            }

            k1_values.forEach(k1 => {
                k2_values.forEach(k2 => {
                    // Intersection of x+y=k1 and x-y=k2
                    const intersectX = (k1 + k2) / 2;
                    const intersectY = (k1 - k2) / 2;

                    // Check if intersection is within canvas bounds (or close enough for dot to be visible)
                    if (intersectX >= -dotRadius && intersectX <= W + dotRadius &&
                        intersectY >= -dotRadius && intersectY <= H + dotRadius) {
                        ctx.beginPath();
                        ctx.arc(intersectX, intersectY, dotRadius, 0, 2 * Math.PI);
                        ctx.fill();
                    }
                });
            });
        }
    }

    // Restore original globalAlpha
    ctx.globalAlpha = originalGlobalAlpha;

    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 Chain Link Fence Filter Effect Tool allows users to apply a unique chain link fence effect to images. This effect creates a pattern of overlapping lines and optional dots, mimicking the appearance of a chain link fence. Users can customize various parameters, including the size of the cells in the pattern, the color and opacity of the lines, as well as the style and appearance of the dots. This tool can be used for artistic purposes, graphic design, or to add textured effects to images, making it ideal for artists, designers, and anyone looking to creatively enhance their photos.

Leave a Reply

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