Please bookmark this page to avoid losing your image tool!

Image Caramel Swirl 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.
async function processImage(originalImg, swirlStrength = 0.3, caramelIntensity = 0.5, swirlCenterX = 0.5, swirlCenterY = 0.5) {
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    // Basic check if image has dimensions. If not, it's not loaded or invalid.
    if (width === 0 || height === 0) {
        console.error("Image has zero dimensions or is not loaded properly.");
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = 100; 
        errorCanvas.height = 100; // Small canvas for error message
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = "lightgray"; 
        errorCtx.fillRect(0, 0, 100, 100);
        errorCtx.fillStyle = "red"; 
        errorCtx.textAlign = "center"; 
        errorCtx.textBaseline = "middle";
        errorCtx.font = "12px Arial";
        errorCtx.fillText("Invalid Image", 50, 50);
        return errorCanvas;
    }

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    // Add { willReadFrequently: true } for potential performance optimization if supported
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    ctx.drawImage(originalImg, 0, 0, width, height);
    
    let sourceImageData;
    try {
        sourceImageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // Handle cases like cross-origin image data access restrictions
        console.error("Error getting image data (cross-origin issue?):", e);
        // Return the canvas with the original image drawn and an error message
        ctx.fillStyle = "rgba(255, 0, 0, 0.6)"; // Semi-transparent red overlay for message
        ctx.fillRect(0, 0, width, Math.max(40, height / 8)); // Red bar at top
        ctx.fillStyle = "white";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        const fontSize = Math.min(20, height / 10, width / 15);
        ctx.font = `bold ${fontSize}px Arial`;
        ctx.fillText("Error: Cannot process pixels", width / 2, Math.max(20, height / 16));
        return canvas;
    }
    
    const outputImageData = ctx.createImageData(width, height);
    const sourceDataArray = sourceImageData.data;
    const outputDataArray = outputImageData.data;

    const actualCenterX = swirlCenterX * width;
    const actualCenterY = swirlCenterY * height;
    // referenceRadius helps scale the swirl; using min of width/height ensures it's relative to image size
    const referenceRadius = Math.max(1, Math.min(width, height) / 2); 

    // Helper function to get pixel data with boundary clamp from a data array
    function getColorAt(x, y, dataArr, imgW, imgH) {
        const clampedX = Math.max(0, Math.min(imgW - 1, Math.floor(x)));
        const clampedY = Math.max(0, Math.min(imgH - 1, Math.floor(y)));
        const idx = (clampedY * imgW + clampedX) * 4;
        return {
            r: dataArr[idx],
            g: dataArr[idx+1],
            b: dataArr[idx+2],
            a: dataArr[idx+3]
        };
    }
    
    // Helper function for bilinear interpolation using a data array
    function getInterpolatedColorAt(x, y, dataArr, imgW, imgH) {
        const x_floor = Math.floor(x);
        const y_floor = Math.floor(y);
        const u = x - x_floor; // Fractional part for x
        const v = y - y_floor; // Fractional part for y

        const p00 = getColorAt(x_floor, y_floor, dataArr, imgW, imgH);
        const p10 = getColorAt(x_floor + 1, y_floor, dataArr, imgW, imgH);
        const p01 = getColorAt(x_floor, y_floor + 1, dataArr, imgW, imgH);
        const p11 = getColorAt(x_floor + 1, y_floor + 1, dataArr, imgW, imgH);

        // Interpolate R, G, B, A channels
        const r = p00.r * (1 - u) * (1 - v) + p10.r * u * (1 - v) + p01.r * (1 - u) * v + p11.r * u * v;
        const g = p00.g * (1 - u) * (1 - v) + p10.g * u * (1 - v) + p01.g * (1 - u) * v + p11.g * u * v;
        const b = p00.b * (1 - u) * (1 - v) + p10.b * u * (1 - v) + p01.b * (1 - u) * v + p11.b * u * v;
        const a = p00.a * (1 - u) * (1 - v) + p10.a * u * (1 - v) + p01.a * (1 - u) * v + p11.a * u * v;
        
        return { r, g, b, a };
    }

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const dx = x - actualCenterX;
            const dy = y - actualCenterY;
            const distance = Math.sqrt(dx*dx + dy*dy);
            const originalAngle = Math.atan2(dy, dx); // angle in radians

            let swirledAngle = originalAngle;
            // Only apply swirl if strength is non-zero and distance is >0 (to avoid issues at center)
            if (swirlStrength !== 0 && distance > 0) {
                // swirlStrength defines radians of twist at referenceRadius.
                // Angle offset is proportional to (distance / referenceRadius).
                swirledAngle = originalAngle + swirlStrength * (distance / referenceRadius);
            }

            const sourceX = actualCenterX + distance * Math.cos(swirledAngle);
            const sourceY = actualCenterY + distance * Math.sin(swirledAngle);
            
            const { r: r_swirled, g: g_swirled, b: b_swirled, a: a_swirled } = 
                getInterpolatedColorAt(sourceX, sourceY, sourceDataArray, width, height);

            let r_final = r_swirled;
            let g_final = g_swirled;
            let b_final = b_swirled;

            // Apply Caramel Color Effect if intensity is > 0
            if (caramelIntensity > 0) {
                // Increase red and green, decrease blue for a warm, caramel tone.
                // The caramelIntensity (0 to 1) scales the effect.
                r_final += 60 * caramelIntensity;
                g_final += 30 * caramelIntensity;
                b_final -= 20 * caramelIntensity; 
            }
            
            const dest_idx = (y * width + x) * 4;
            outputDataArray[dest_idx]     = Math.max(0, Math.min(255, r_final));
            outputDataArray[dest_idx + 1] = Math.max(0, Math.min(255, g_final));
            outputDataArray[dest_idx + 2] = Math.max(0, Math.min(255, b_final));
            outputDataArray[dest_idx + 3] = Math.max(0, Math.min(255, a_swirled)); // Preserve alpha
        }
    }

    ctx.putImageData(outputImageData, 0, 0); // Draw the processed image data back to the
    return canvas;                           // canvas and return the 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 Caramel Swirl Filter Effect Tool allows users to apply a unique swirling effect combined with a warm caramel color enhancement to their images. By adjusting the swirl strength and the caramel intensity, users can create visually appealing distortions and color modifications, adding artistic flair to photos. This tool is ideal for enhancing digital artwork, crafting engaging social media visuals, or simply experimenting with image manipulation for creative projects.

Leave a Reply

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