Please bookmark this page to avoid losing your image tool!

Photo Popsicle Melt 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, dripChanceParam = "0.005", minDripLengthParam = "10", maxDripLengthParam = "50") {
    // 1. Parameter parsing and sanitization
    // Parameters from the function signature might be strings (if default) or could be numbers/strings if passed by user.
    // parseFloat/parseInt conveniently handle both numbers and string representations of numbers.

    let dripChance = parseFloat(dripChanceParam);
    // Validate dripChance: should be a probability between 0 and 1.
    if (isNaN(dripChance) || dripChance < 0 || dripChance > 1) {
        dripChance = 0.005; // Default value if parsing fails or value is out of range.
    }

    let minDripLength = parseInt(minDripLengthParam);
    // Validate minDripLength: should be at least 1.
    if (isNaN(minDripLength) || minDripLength < 1) {
        minDripLength = 10; // Default value if parsing fails or value is less than 1.
    }

    let maxDripLength = parseInt(maxDripLengthParam);
    // Validate maxDripLength: should be a number.
    if (isNaN(maxDripLength)) {
        maxDripLength = 50; // Default value if parsing fails.
    }
    
    // Ensure maxDripLength is not less than minDripLength.
    if (maxDripLength < minDripLength) {
        maxDripLength = minDripLength; // Adjust maxDripLength if it's smaller than the (potentially adjusted) minDripLength.
    }

    // 2. Canvas setup
    const canvas = document.createElement('canvas');
    // Add willReadFrequently attribute for potential performance optimization on repeated getImageData calls.
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); 
    
    // Use naturalWidth/naturalHeight to get the original image dimensions, not CSS-scaled dimensions.
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    // Handle cases where the image might not have loaded or has zero dimensions.
    if (width === 0 || height === 0) {
        canvas.width = 0;
        canvas.height = 0;
        return canvas; // Return an empty, zero-size canvas.
    }

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

    // 3. Image data processing
    // Draw the original image onto the canvas. This is the surface we'll read pixels from.
    ctx.drawImage(originalImg, 0, 0, width, height);
    
    let sourceImageData;
    try {
        // Attempt to get the pixel data from the canvas.
        sourceImageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // This error can occur if the image is loaded from a different origin (CORS issue)
        // and the server's CORS policy doesn't allow cross-origin data access.
        console.error("Failed to get image data, possibly due to CORS policy. The effect cannot be applied.", e);
        // In this scenario, return the canvas with only the original image drawn, as the effect cannot proceed.
        return canvas;
    }
    
    // Create a new ImageData object to store the pixels of the modified image.
    const targetImageData = ctx.createImageData(width, height);
    
    // Initialize targetImageData by copying all pixels from sourceImageData.
    // This ensures that pixels not affected by a "drip" will retain their original color from the source image.
    targetImageData.data.set(sourceImageData.data);

    const sourceData = sourceImageData.data; // A Uint8ClampedArray view of the source image's pixel data.
    const targetData = targetImageData.data; // A Uint8ClampedArray view for the target image's pixel data.

    // 4. Apply the "Popsicle Melt" (drip) effect
    // Iterate over each column of pixels in the image.
    for (let x = 0; x < width; x++) {
        // Iterate over each row of pixels in the current column.
        for (let y = 0; y < height; y++) {
            // With a certain probability (dripChance), a drip will start from the current pixel (x, y).
            if (Math.random() < dripChance) {
                // Calculate a random length for this specific drip, within the min/max bounds.
                const currentDripLength = Math.floor(Math.random() * (maxDripLength - minDripLength + 1)) + minDripLength;
                
                // Get the color (RGBA) of the source pixel that initiates this drip.
                // The index calculation maps 2D (x,y) coordinates to a 1D array index. Each pixel uses 4 array elements (R,G,B,A).
                const srcPixelIndex = (y * width + x) * 4; 
                const r = sourceData[srcPixelIndex];     // Red component
                const g = sourceData[srcPixelIndex + 1]; // Green component
                const b = sourceData[srcPixelIndex + 2]; // Blue component
                const a = sourceData[srcPixelIndex + 3]; // Alpha (transparency) component

                // "Paint" the drip downwards from the current pixel (x,y) using its color.
                for (let offsetY = 0; offsetY < currentDripLength; offsetY++) {
                    const dripY = y + offsetY; // Calculate the Y-coordinate for the current segment of the drip.
                    
                    // Ensure the drip segment is still within the image's vertical bounds.
                    if (dripY < height) {
                        const targetPixelIndex = (dripY * width + x) * 4;
                        targetData[targetPixelIndex]     = r;
                        targetData[targetPixelIndex + 1] = g;
                        targetData[targetPixelIndex + 2] = b;
                        targetData[targetPixelIndex + 3] = a;
                    } else {
                        // The drip has extended beyond the bottom edge of the image; stop this drip.
                        break; 
                    }
                }
            }
        }
    }

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

    // 6. Return the canvas element with the applied effect.
    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 Photo Popsicle Melt Filter Effect Tool allows users to apply a unique melting effect to their images, simulating the appearance of a popsicle gradually melting and dripping. This tool is useful for artists and designers looking to create visually striking effects for social media posts, digital art, or promotional materials. Users can customize the drip effect by adjusting parameters such as the chance for a drip to occur, as well as the minimum and maximum lengths of the drips, providing flexibility in achieving the desired aesthetic.

Leave a Reply

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