Please bookmark this page to avoid losing your image tool!

Image Heart Monitor 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, lineColorStr = "0,255,0", lineWidth = 3, intensity = 1.5, scanHeight = 0.5, beatFrequency = 5, amplitude = 50, tintAmount = 0.3) {
    // 1. Setup main canvas
    const canvas = document.createElement('canvas');
    // Use { willReadFrequently: true } for potential performance optimization if available/supported
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    if (canvas.width === 0 || canvas.height === 0) {
        console.error("Image dimensions are zero or invalid.");
        // Optionally draw a small indicator on the canvas
        canvas.width = canvas.width || 100; // Ensure some size for error message
        canvas.height = canvas.height || 30;
        ctx.font = "12px Arial";
        ctx.fillStyle = "red";
        ctx.fillText("Invalid image dimensions", 5, 15);
        return canvas; // Return (Potentially small) canvas
    }

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

    // 2. Get original image data
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Could not get ImageData. This might be due to CORS policy if the image is from an external domain.", e);
        // Fallback: return the canvas with the original image and an error message
        // The original image is already drawn. Add text warning.
        ctx.font = "bold 16px Arial";
        ctx.fillStyle = "red";
        ctx.textAlign = "center";
        ctx.strokeStyle = "black";
        ctx.lineWidth = 2;
        const errText = "Error: Cannot process image (CORS issue or insecure canvas).";
        ctx.strokeText(errText, canvas.width / 2, canvas.height / 2);
        ctx.fillText(errText, canvas.width / 2, canvas.height / 2);
        return canvas;
    }
    const data = imageData.data;

    // 3. Parse and validate parameters
    let [rStr, gStr, bStr] = lineColorStr.split(',');
    let lr = parseInt(rStr, 10);
    let lg = parseInt(gStr, 10);
    let lb = parseInt(bStr, 10);

    if (isNaN(lr) || isNaN(lg) || isNaN(lb) || lr < 0 || lr > 255 || lg < 0 || lg > 255 || lb < 0 || lb > 255) {
        [lr, lg, lb] = [0, 255, 0]; // Default to green on parse error or invalid color values
    }

    lineWidth = Math.max(1, Number(lineWidth));
    intensity = Math.max(1.0, Number(intensity));
    scanHeight = Math.max(0.0, Math.min(1.0, Number(scanHeight)));
    beatFrequency = Math.max(1, Number(beatFrequency));
    amplitude = Math.max(0, Number(amplitude));
    tintAmount = Math.max(0.0, Math.min(1.0, Number(tintAmount)));

    const baselineY = canvas.height * scanHeight;

    // 4. ECG Y-coordinate function
    function getEcgY(xPos, currentCanvasWidth, currentBaselineY, currentAmplitude, currentBeatFrequency) {
        const period = currentCanvasWidth / currentBeatFrequency;
        const xInPeriod = xPos % period;
        const currentPhase = xInPeriod / period; // Normalized phase within a beat cycle (0 to 1)
        
        let yOffset = 0; // Positive yOffset means upward deflection from baseline

        // P-wave: Example phase 0.1 to 0.2
        if (currentPhase >= 0.1 && currentPhase < 0.2) {
            const pPhase = (currentPhase - 0.1) / 0.1; // Normalize phase for P-wave duration
            yOffset = currentAmplitude * 0.2 * Math.sin(pPhase * Math.PI); // Sine curve for P-wave
        }
        // QRS complex (simplified as R-spike): Example phase 0.25 to 0.35
        else if (currentPhase >= 0.25 && currentPhase < 0.35) {
            const qrsPhase = (currentPhase - 0.25) / 0.1; // Normalize phase for QRS duration
            const rPeakPhase = 0.5; // R-spike peak is at midpoint of QRS phase
            if (qrsPhase < rPeakPhase) { // Rising edge of R-spike
                yOffset = currentAmplitude * (qrsPhase / rPeakPhase);
            } else { // Falling edge of R-spike
                yOffset = currentAmplitude * (1 - (qrsPhase - rPeakPhase) / (1 - rPeakPhase));
            }
        }
        // T-wave: Example phase 0.4 to 0.6
        else if (currentPhase >= 0.4 && currentPhase < 0.6) {
            const tPhase = (currentPhase - 0.4) / 0.2; // Normalize phase for T-wave duration
            yOffset = currentAmplitude * 0.3 * Math.sin(tPhase * Math.PI); // Sine curve for T-wave
        }
        
        return Math.round(currentBaselineY - yOffset); // Canvas Y is downwards, so subtract offset
    }
    
    // 5. Create an offscreen canvas to draw the ECG line
    const lineCanvas = document.createElement('canvas');
    lineCanvas.width = canvas.width;
    lineCanvas.height = canvas.height;
    const lineCtx = lineCanvas.getContext('2d', { willReadFrequently: true });

    // Draw the ECG line on the offscreen canvas
    if (canvas.width > 0) {
        lineCtx.beginPath();
        lineCtx.moveTo(0, getEcgY(0, canvas.width, baselineY, amplitude, beatFrequency));
        for (let x = 1; x < canvas.width; x++) {
            lineCtx.lineTo(x, getEcgY(x, canvas.width, baselineY, amplitude, beatFrequency));
        }
        lineCtx.lineWidth = lineWidth;
        lineCtx.strokeStyle = `rgb(${lr},${lg},${lb})`;
        lineCtx.lineCap = 'round';
        lineCtx.lineJoin = 'round';
        
        // Add a glow effect to the line for a softer filter application
        lineCtx.shadowColor = `rgba(${lr},${lg},${lb},0.7)`;
        lineCtx.shadowBlur = Math.max(1, lineWidth * 1.5); // Ensure blur is at least 1
        
        lineCtx.stroke();
    }

    // Get image data of the drawn line (this includes the line, its color, glow, and anti-aliasing)
    const lineImageData = lineCtx.getImageData(0, 0, lineCanvas.width, lineCanvas.height);
    const linePixelData = lineImageData.data;

    // 6. Apply the filter effect to the original image data
    // Iterate through each pixel of the original image
    for (let i = 0; i < data.length; i += 4) {
        const lineAlpha = linePixelData[i + 3]; // Alpha value of the ECG line/glow at this pixel
        
        if (lineAlpha > 0) { // If there's any part of the ECG line/glow at this pixel
            const lineStrength = lineAlpha / 255; // Normalized strength (0 to 1)

            let r = data[i];
            let g = data[i + 1];
            let b = data[i + 2];

            // Apply intensity: Brighten the underlying image pixels based on lineStrength
            const intensityFactor = 1 + (intensity - 1) * lineStrength;
            r = Math.min(255, r * intensityFactor);
            g = Math.min(255, g * intensityFactor);
            b = Math.min(255, b * intensityFactor);

            // Apply tint: Shift color towards the specified line color
            if (tintAmount > 0) {
                const currentTintFactor = lineStrength * tintAmount;
                // Blend current (brightened) color with the line color parameters (lr, lg, lb)
                r = Math.min(255, Math.round(r * (1 - currentTintFactor) + lr * currentTintFactor));
                g = Math.min(255, Math.round(g * (1 - currentTintFactor) + lg * currentTintFactor));
                b = Math.min(255, Math.round(b * (1 - currentTintFactor) + lb * currentTintFactor));
            }
            
            // Update pixel data
            data[i] = r;
            data[i + 1] = g;
            data[i + 2] = b;
            // Alpha (data[i+3]) remains unchanged
        }
    }

    // 7. Put the modified image data back onto the main canvas
    ctx.putImageData(imageData, 0, 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 Heart Monitor Filter Effect Tool allows users to apply a stylized ECG filter effect to their images. This tool generates an ECG-like line overlay with customizable colors, thickness, and amplitude, which enhances the original image by incorporating a heartbeat monitoring effect. It can be used for creating visually engaging graphics for health-related content, designing promotional materials for medical services, or adding a creative touch to social media posts. Perfect for artists, designers, and anyone looking to add a unique filter to their images.

Leave a Reply

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