Please bookmark this page to avoid losing your image tool!

Image Syrup Pour 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, amplitude = 20, frequency = 3, verticalModulation = 1.0, flowIntensity = 0.3, tintColorHex = "B8860B", tintOpacity = 0.25) {
    const canvas = document.createElement('canvas');
    // Using { willReadFrequently: true } as a hint for performance with getImageData/putImageData
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Use naturalWidth/Height for intrinsic image dimensions for robustness
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    // If image dimensions are invalid, return an empty canvas
    if (canvas.width === 0 || canvas.height === 0) {
        // console.warn("Image has zero width or height. Returning empty canvas.");
        return canvas;
    }

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

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // This can happen due to cross-origin restrictions if the image is not hosted on the same domain.
        // console.error("Could not get image data, possibly due to cross-origin restrictions:", e);
        // Fallback: return canvas with the original image drawn, without the effect.
        return canvas;
    }
    
    const data = imageData.data;
    const outputImageData = ctx.createImageData(canvas.width, canvas.height);
    const outputData = outputImageData.data;

    const width = canvas.width;
    const height = canvas.height;
    const PI2 = Math.PI * 2;

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            // Calculate effective amplitude, which can increase towards the bottom of the image
            const currentEffectiveAmplitude = amplitude * (1 + (y / height) * flowIntensity);
            
            // Calculate the phase for the sine wave.
            // The (x / width) term creates vertical "waves" or "rivulets" (displacement varies with x).
            // The (y / height) term shifts the phase of these waves as y changes, 
            // making the rivulets appear to twist or meander downwards.
            const phase = (x / width) * frequency * PI2 + 
                          (y / height) * verticalModulation * PI2;
            
            const offsetY = currentEffectiveAmplitude * Math.sin(phase);
            
            // Determine the source Y coordinate to sample from.
            // A positive offsetY means pixels are pulled downwards (content from y - offsetY moves to current y).
            let srcY = Math.round(y - offsetY);

            // Clamp srcY to be within image bounds to avoid reading outside the array
            srcY = Math.max(0, Math.min(height - 1, srcY));
            
            const srcX = x; // No horizontal displacement in this particular model

            const srcIndex = (srcY * width + srcX) * 4;
            const destIndex = (y * width + x) * 4;

            // Copy RGBA components from source pixel to destination pixel
            outputData[destIndex]     = data[srcIndex];     // Red
            outputData[destIndex + 1] = data[srcIndex + 1]; // Green
            outputData[destIndex + 2] = data[srcIndex + 2]; // Blue
            outputData[destIndex + 3] = data[srcIndex + 3]; // Alpha (preserve original alpha)
        }
    }

    // Put the modified image data back onto the canvas
    ctx.putImageData(outputImageData, 0, 0);

    // Apply the "syrup" color tint
    if (tintOpacity > 0 && tintColorHex) {
        let sanitizedTintColorHex = tintColorHex;
        if (typeof sanitizedTintColorHex === 'string' && sanitizedTintColorHex.startsWith("#")) {
            sanitizedTintColorHex = sanitizedTintColorHex.substring(1);
        }

        if (typeof sanitizedTintColorHex === 'string' && 
            sanitizedTintColorHex.length === 6 && 
            /^[0-9A-Fa-f]{6}$/.test(sanitizedTintColorHex)) {
            
            const r = parseInt(sanitizedTintColorHex.substring(0, 2), 16);
            const g = parseInt(sanitizedTintColorHex.substring(2, 4), 16);
            const b = parseInt(sanitizedTintColorHex.substring(4, 6), 16);

            // Clamp opacity to be between 0 and 1
            const clampedOpacity = Math.max(0, Math.min(1, tintOpacity));

            ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
            ctx.fillRect(0, 0, width, height);
        } else if (tintOpacity > 0) { // Only warn if tint was intended
            // console.warn(`Invalid tintColorHex ('${tintColorHex}') provided. It should be a 6-digit hex string (e.g., "B8860B"). Skipping tint.`);
        }
    }
    
    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 Syrup Pour Filter Effect Tool provides a unique way to enhance your images by applying a syrup-like flow effect. This tool enables users to manipulate the appearance of their images, creating a visually appealing ‘pouring’ effect that resembles syrup cascading down. Parameters such as amplitude, frequency, vertical modulation, and color tint allow for customized adjustments to achieve the desired artistic effect. This tool is ideal for artists, graphic designers, or hobbyists looking to add dynamic elements to their images for creative projects, social media posts, or promotional materials.

Leave a Reply

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