Please bookmark this page to avoid losing your image tool!

Image Retina Scan 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,
    scanLineYPercent = 50,
    scanLineWidthPx = 40,
    scanLineBrightnessFactor = 1.8,
    overallTint = "rgba(0, 255, 0, 0.1)",
    scanLineCoreColor = "rgba(170, 255, 170, 0.9)", // Light green, high alpha
    scanLineCoreHeightPx = 3,
    scanLineCoreBlurPx = 10,
    glitchIntensity = 4
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Ensure width and height are from the loaded image
    // For HTMLImageElement, naturalWidth/Height are intrinsic, width/height can be styled.
    // For Image objects created in JS, width/height are typically the decoded dimensions after load.
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;
    
    if (width === 0 || height === 0) {
        // Handle cases where image might not be fully loaded or is invalid
        console.error("Image has zero dimensions. Ensure the image is loaded before processing.");
        // Return a minimal canvas or throw an error, based on desired behavior.
        canvas.width = 1; 
        canvas.height = 1;
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;

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

    // 2. Get image data for pixel manipulation
    let sourceImageData;
    try {
        sourceImageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // This can happen due to CORS issues if the image is drawn from another domain
        // and the canvas becomes tainted, preventing getImageData.
        console.error("Could not getImageData (possibly CORS issue with the image source):", e);
        // Fallback: return the canvas with just the original image drawn.
        // The filter effect requiring pixel access cannot be applied.
        return canvas; 
    }
    
    const outputImageData = ctx.createImageData(width, height);
    
    const sourceData = sourceImageData.data;
    const outputData = outputImageData.data;

    // Calculate properties for the scan line effect band
    const scanLineCenterY = height * (scanLineYPercent / 100);
    // Ensure scanEffectHalfWidth is non-negative
    const scanEffectHalfWidth = Math.max(0, scanLineWidthPx / 2); 

    // 3. Pixel manipulation loop: apply brightness changes and glitch effect within the scan band
    for (let y = 0; y < height; y++) {
        const distanceFromScanCenter = Math.abs(y - scanLineCenterY);
        let effectIntensity = 0; // 0 for no effect, 1 for max effect at scan line center
        
        // Calculate effectIntensity only if within the band and the band has a positive width
        if (distanceFromScanCenter <= scanEffectHalfWidth && scanEffectHalfWidth > 0) {
            // Using a power of 2 for a sharper falloff from the center of the scan line
            effectIntensity = Math.pow(1 - (distanceFromScanCenter / scanEffectHalfWidth), 2);
        }

        let currentPixelBrightnessFactor = 1.0; // Default: no brightness change
        let currentGlitchOffsetX = 0;         // Default: no horizontal glitch

        if (effectIntensity > 0) {
            // Apply brightness factor based on proximity to scan line center
            currentPixelBrightnessFactor = 1 + (scanLineBrightnessFactor - 1) * effectIntensity;
            
            // Apply glitch if intensity is positive
            if (glitchIntensity > 0) {
                // Random horizontal offset for glitch, scaled by effectIntensity and glitchIntensity parameter
                currentGlitchOffsetX = Math.round((Math.random() - 0.5) * 2 * glitchIntensity * effectIntensity);
            }
        }

        for (let x = 0; x < width; x++) {
            const destIdx = (y * width + x) * 4; // Index for the current pixel in the 1D outputData array
            
            // Determine source pixel x-coordinate for glitching, clamping to image bounds
            const srcX = Math.max(0, Math.min(width - 1, x - currentGlitchOffsetX));
            const srcIdx = (y * width + srcX) * 4; // Index for source pixel in 1D sourceData array

            // Get RGBA components from the (possibly glitched) source pixel
            const r = sourceData[srcIdx + 0];
            const g = sourceData[srcIdx + 1];
            const b = sourceData[srcIdx + 2];
            const a = sourceData[srcIdx + 3];

            // Apply brightness modification and write to outputData
            outputData[destIdx + 0] = Math.min(255, r * currentPixelBrightnessFactor); // Red
            outputData[destIdx + 1] = Math.min(255, g * currentPixelBrightnessFactor); // Green
            outputData[destIdx + 2] = Math.min(255, b * currentPixelBrightnessFactor); // Blue
            outputData[destIdx + 3] = a; // Preserve original alpha
        }
    }

    // 4. Put the modified image data (with scan band effects) back onto the canvas
    ctx.putImageData(outputImageData, 0, 0);

    // 5. Apply overall tint layer if specified (and not fully transparent)
    // This tint is applied on top of the pixel-processed image.
    if (overallTint && overallTint !== "rgba(0,0,0,0)" && overallTint !== "transparent") {
        ctx.fillStyle = overallTint;
        ctx.fillRect(0, 0, width, height); // Uses default 'source-over' globalCompositeOperation
    }

    // 6. Draw the bright core scan line on top of everything
    // This line is drawn if its height parameter is positive.
    if (scanLineCoreHeightPx > 0) {
        // Calculate actual Y position of the line's center
        const coreLineActualY = height * (scanLineYPercent / 100);
        
        ctx.lineCap = 'butt'; // Style for line endings ('butt', 'round', 'square')
        ctx.strokeStyle = scanLineCoreColor;
        ctx.lineWidth = scanLineCoreHeightPx;

        // Apply a glow effect using shadow if blur radius is positive
        if (scanLineCoreBlurPx > 0) {
            ctx.shadowColor = scanLineCoreColor; // Shadow color can be the same as the line or different
            ctx.shadowBlur = scanLineCoreBlurPx;
        }

        // Draw the horizontal line
        ctx.beginPath();
        ctx.moveTo(0, coreLineActualY);
        ctx.lineTo(width, coreLineActualY);
        ctx.stroke();

        // Reset shadow properties to avoid affecting subsequent drawing operations on this context
        ctx.shadowColor = 'transparent'; // Or a specific non-shadow color like 'rgba(0,0,0,0)'
        ctx.shadowBlur = 0;
        ctx.lineCap = 'butt'; // Reset to default if necessary
    }

    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 Retina Scan Filter Effect Tool allows users to apply a unique scan line effect to images, simulating a futuristic scanning or glitch effect. Users can customize various parameters such as the position and width of the scan line, brightness adjustments, and overall tint. This tool is useful for enhancing visual materials in digital art, creating stylized effects for graphic design, or adding a distinct aesthetic to images for presentations and social media content.

Leave a Reply

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