Please bookmark this page to avoid losing your image tool!

Image Riveted Metal Filter Effect Application

(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, rivetSize = 5, rivetSpacing = 50, rivetColor = '#888888', contrastLevel = 50, brightnessOffset = 10) {

    // --- Start Helper Functions ---
    function _parseHex(hex) {
        hex = hex.replace(/^#/, '');
        if (hex.length === 3) { // Expand shorthand hex (e.g., "03F" -> "0033FF")
            hex = hex.split('').map(char => char + char).join('');
        }
        const bigint = parseInt(hex, 16);
        const r = (bigint >> 16) & 255;
        const g = (bigint >> 8) & 255;
        const b = bigint & 255;
        return [r, g, b];
    }

    function _componentToHex(c) {
        const hex = Math.round(c).toString(16); // Ensure c is an integer before converting
        return hex.length == 1 ? "0" + hex : hex;
    }

    function _rgbToHex(r, g, b) {
        return "#" + _componentToHex(r) + _componentToHex(g) + _componentToHex(b);
    }

    function _adjustHexColor(hex, amount) {
        let [r, g, b] = _parseHex(hex);
        r = Math.max(0, Math.min(255, r + amount));
        g = Math.max(0, Math.min(255, g + amount));
        b = Math.max(0, Math.min(255, b + amount));
        return _rgbToHex(r, g, b);
    }
    // --- End Helper Functions ---

    const canvas = document.createElement('canvas');
    // Use naturalWidth/Height for images that might have been scaled via CSS width/height attributes
    // but fall back to width/height if naturalWidth/Height are 0 (e.g. not an HTMLImageElement or not loaded)
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;
    
    // If image dimensions are invalid, return an empty (or error indicating) canvas
    if (canvas.width === 0 || canvas.height === 0) {
        console.error("Image has no dimensions or is not fully loaded. Cannot process.");
        // Optionally draw an error message on the canvas
        // const errorCtx = canvas.getContext('2d');
        // if(errorCtx) {
        //    canvas.width = canvas.width || 100; canvas.height = canvas.height || 30; // Min size for error
        //    errorCtx.font = "12px Arial";
        //    errorCtx.fillText("Error: Image not loaded", 5, 15);
        // }
        return canvas; 
    }

    const ctx = canvas.getContext('2d');
    if (!ctx) {
        console.error("Could not get 2D rendering context for canvas.");
        return canvas; // Return empty canvas if context cannot be obtained
    }

    // 1. Draw original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // 2. Process image data for metallic effect (Grayscale, Contrast, Brightness)
    // This block is wrapped to ensure imageData operations only happen on valid canvas area
    if (canvas.width > 0 && canvas.height > 0) {
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;
        
        // Map contrastLevel (0-100) to a factor (1-3)
        // 0   -> factor 1 (no change)
        // 50  -> factor 2
        // 100 -> factor 3
        const contrastFactor = 1 + (contrastLevel / 100) * 2; 

        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];

            // Grayscale conversion using the luminosity method (standard perceptual weights)
            let gray = 0.299 * r + 0.587 * g + 0.114 * b;

            // Contrast adjustment
            // Formula: NewValue = Factor * (OldValue - MidPoint) + MidPoint
            // MidPoint for 8-bit color is 128
            gray = contrastFactor * (gray - 128) + 128;

            // Brightness adjustment (additive offset)
            gray += brightnessOffset;

            // Clamp the resulting gray value to the valid [0, 255] range
            gray = Math.max(0, Math.min(255, gray));

            // Apply the new gray value to R, G, and B channels
            data[i] = gray;
            data[i + 1] = gray;
            data[i + 2] = gray;
            // Alpha channel (data[i+3]) remains unchanged
        }
        ctx.putImageData(imageData, 0, 0);
    }

    // 3. Draw Rivets (if rivetSize and rivetSpacing are positive)
    if (rivetSize > 0 && rivetSpacing > 0) {
        const rivetLighterColor = _adjustHexColor(rivetColor, 40);  // Lighter shade for highlight
        const rivetDarkerColor = _adjustHexColor(rivetColor, -40); // Darker shade for shadow/edge

        // Configure a subtle drop shadow for the rivets to give them depth
        ctx.shadowColor = 'rgba(0, 0, 0, 0.4)'; // Shadow color
        ctx.shadowBlur = Math.max(1, rivetSize * 0.3);   // Blur radius, ensure at least 1px
        ctx.shadowOffsetX = rivetSize * 0.15;             // Horizontal offset
        ctx.shadowOffsetY = rivetSize * 0.15;             // Vertical offset

        // Iterate over the canvas to place rivets based on spacing
        // Start from half spacing to center the grid of rivets
        for (let y = rivetSpacing / 2; y < canvas.height; y += rivetSpacing) {
            for (let x = rivetSpacing / 2; x < canvas.width; x += rivetSpacing) {
                
                // Create a radial gradient for the rivet body to simulate a metallic sheen
                // The gradient is offset slightly to simulate a light source from top-left
                const gradX = x - rivetSize * 0.25; // X-coordinate of gradient start circle
                const gradY = y - rivetSize * 0.25; // Y-coordinate of gradient start circle
                const gradR0 = Math.max(1, rivetSize * 0.1); // Radius of gradient start circle (highlight spot)

                const gradient = ctx.createRadialGradient(
                    gradX, gradY, gradR0, // Inner circle (highlight)
                    x, y, rivetSize       // Outer circle (rivet edge)
                );

                // Define color stops for the gradient
                gradient.addColorStop(0, rivetLighterColor);    // Center of highlight
                gradient.addColorStop(0.7, rivetColor);         // Main rivet color
                gradient.addColorStop(1, rivetDarkerColor);     // Edge of rivet

                ctx.fillStyle = gradient; // Apply the gradient fill
                
                // Draw the rivet
                ctx.beginPath();
                ctx.arc(x, y, rivetSize, 0, 2 * Math.PI); // Full circle
                ctx.fill();
            }
        }

        // Reset shadow properties to avoid affecting subsequent drawing operations (if any)
        ctx.shadowColor = 'transparent';
        ctx.shadowBlur = 0;
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 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

The Image Riveted Metal Filter Effect Application allows users to apply a metallic riveted effect to their images. By adjusting parameters such as rivet size, spacing, color, contrast, and brightness, users can transform their images into a visually striking riveted metal style. This tool is ideal for graphic designers, game developers, or anyone looking to enhance images with a unique metallic texture for use in various projects, including digital art, social media posts, and web design.

Leave a Reply

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