Please bookmark this page to avoid losing your image tool!

Image Tie-Dye Filter 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, 
    colorsStr = "FF0000,FFFF00,00FF00,0000FF,FF00FF,00FFFF", 
    numSwirlsParam = 3, 
    swirlStrengthParam = 10, 
    bandFrequencyParam = 0.03, 
    irregularityParam = 0.2, 
    blendMode = "overlay"
) {

    function hexToRgb(hex) {
        const originalHex = hex;
        // Ensure '#' prefix
        hex = hex.startsWith('#') ? hex : '#' + hex;
        
        // Validate hex color format (#RGB, #RRGGBB)
        if (!/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(hex)) {
            // console.warn(`Invalid hex color: ${originalHex}`);
            return null; 
        }

        let r = 0, g = 0, b = 0;
        if (hex.length === 4) { // #RGB shorthand
            r = parseInt(hex[1] + hex[1], 16);
            g = parseInt(hex[2] + hex[2], 16);
            b = parseInt(hex[3] + hex[3], 16);
        } else if (hex.length === 7) { // #RRGGBB
            r = parseInt(hex.substring(1, 3), 16);
            g = parseInt(hex.substring(3, 5), 16);
            b = parseInt(hex.substring(5, 7), 16);
        }
        return { r, g, b };
    }

    const width = originalImg.width;
    const height = originalImg.height;

    if (width === 0 || height === 0) {
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = Math.max(1, width); 
        emptyCanvas.height = Math.max(1, height);
        // console.warn("Original image has zero dimension. Returning small empty canvas.");
        return emptyCanvas;
    }
    
    // Sanitize and validate numeric parameters
    let numSwirls = typeof numSwirlsParam === 'string' ? parseFloat(numSwirlsParam) : numSwirlsParam;
    numSwirls = (Number.isFinite(numSwirls) && numSwirls >= 1) ? Math.floor(numSwirls) : 3;

    let swirlStrength = typeof swirlStrengthParam === 'string' ? parseFloat(swirlStrengthParam) : swirlStrengthParam;
    swirlStrength = Number.isFinite(swirlStrength) ? swirlStrength : 10;

    let bandFrequency = typeof bandFrequencyParam === 'string' ? parseFloat(bandFrequencyParam) : bandFrequencyParam;
    bandFrequency = Number.isFinite(bandFrequency) ? bandFrequency : 0.03;

    let irregularity = typeof irregularityParam === 'string' ? parseFloat(irregularityParam) : irregularityParam;
    irregularity = (Number.isFinite(irregularity) && irregularity >= 0) ? irregularity : 0.2;
    const irregularityRadianFactor = irregularity * Math.PI;

    // Parse colors
    const colorHexArray = colorsStr.split(',').map(c => c.trim()).filter(c => c.length > 0);
    let parsedColors = colorHexArray.map(hex => hexToRgb(hex)).filter(color => color !== null);
    if (parsedColors.length === 0) {
        // Fallback to a default set of vibrant colors if input is empty or all invalid
        parsedColors = ["FF5733", "FFC300", "33FF57", "3357FF", "C70039"].map(hex => hexToRgb(hex));
    }

    // Canvas setup
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // Generate swirl centers
    const swirlCenters = [];
    for (let i = 0; i < numSwirls; i++) {
        swirlCenters.push({
            x: Math.random() * width,
            y: Math.random() * height,
            // Add random phase offsets for more variety per center's distortion pattern
            phaseOffset1: Math.random() * 2 * Math.PI, // For distance-based part of distortion
            phaseOffset2: Math.random() * 2 * Math.PI  // For angle-based part of distortion
        });
    }

    // Create ImageData for the tie-dye pattern
    const patternData = ctx.createImageData(width, height);
    const data = patternData.data;

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            let totalValue = 0;

            for (let i = 0; i < numSwirls; i++) {
                const sc = swirlCenters[i];
                const dx = x - sc.x;
                const dy = y - sc.y;
                
                const angle = Math.atan2(dy, dx);
                const dist = Math.sqrt(dx * dx + dy * dy);

                const basePhase = angle * swirlStrength + dist * bandFrequency;
                
                // Applying irregularity as a phase distortion.
                // The distortion term uses a combination of sines based on distance and angle,
                // with random phase offsets for each swirl center to make patterns more varied.
                const distFactorForIrregularity = 0.015; // Controls frequency of irregularity based on distance
                const angleFactorForIrregularity = Math.abs(swirlStrength / 4) + 1; // Controls frequency of irregularity based on angle/swirlStrength
                
                const distortion = irregularityRadianFactor * 
                                 Math.sin(dist * distFactorForIrregularity + sc.phaseOffset1) *
                                 Math.cos(angle * angleFactorForIrregularity + sc.phaseOffset2); 
                
                totalValue += Math.sin(basePhase + distortion);
            }
            
            // Normalize totalValue: Math.sin sums numSwirls times, so range can be [-numSwirls, numSwirls]
            let normalizedValue = (totalValue / numSwirls + 1) / 2; // Expected range [0, 1]
            normalizedValue = Math.max(0, Math.min(1, normalizedValue)); // Clamp to [0,1] to be safe

            const colorIndex = Math.floor(normalizedValue * parsedColors.length) % parsedColors.length;
            const selectedColor = parsedColors[colorIndex];

            const pixelIndex = (y * width + x) * 4;
            data[pixelIndex]     = selectedColor.r;
            data[pixelIndex + 1] = selectedColor.g;
            data[pixelIndex + 2] = selectedColor.b;
            data[pixelIndex + 3] = 255; // Alpha (fully opaque)
        }
    }

    // Drawing logic
    const safeBlendMode = typeof blendMode === 'string' ? blendMode.toLowerCase() : "overlay";

    if (safeBlendMode === "patternonly") {
        ctx.putImageData(patternData, 0, 0);
    } else {
        // Draw original image first
        ctx.drawImage(originalImg, 0, 0, width, height);
        
        // Create a temporary canvas to hold the pattern. This is necessary for
        // globalCompositeOperation to apply correctly when drawing generated pixel data.
        const tempCanvas = document.createElement('canvas');
        tempCanvas.width = width;
        tempCanvas.height = height;
        const tempCtx = tempCanvas.getContext('2d');
        tempCtx.putImageData(patternData, 0, 0);

        // Set blend mode. Browsers usually default to "source-over" for invalid modes.
        // A try-catch is defensive but often not strictly needed for this property.
        try {
            ctx.globalCompositeOperation = safeBlendMode;
        } catch(e) {
            // console.warn(`Invalid blend mode: '${safeBlendMode}'. Defaulting to 'overlay'.`);
            ctx.globalCompositeOperation = "overlay"; // Fallback blend mode
        }
        
        ctx.drawImage(tempCanvas, 0, 0, width, height);
        
        // Reset globalCompositeOperation to default for good practice
        ctx.globalCompositeOperation = "source-over"; 
    }

    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 Tie-Dye Filter Application allows users to apply a vibrant tie-dye effect to their images, creating unique and colorful patterns. Users can customize the colors, number of swirls, and swirl strength to generate various artistic effects. This tool is ideal for enhancing personal photographs, creating eye-catching social media content, designing graphics for events or crafts, and adding a playful touch to digital art projects.

Leave a Reply

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