Please bookmark this page to avoid losing your image tool!

Image Crystal Drop Effect Applicator

(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, dropCount = "200", minRadius = "15", maxRadius = "50", arrangement = "random") {
    // Parse parameters
    let count = parseInt(dropCount, 10) || 200;
    let minR = parseInt(minRadius, 10) || 15;
    let maxR = parseInt(maxRadius, 10) || 50;

    if (minR > maxR) {
        let temp = minR;
        minR = maxR;
        maxR = temp;
    }

    const width = originalImg.width;
    const height = originalImg.height;
    
    // Create canvas and draw the original image
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0, width, height);

    const imgData = ctx.getImageData(0, 0, width, height);
    const data = imgData.data;

    // Fixed lighting vectors for the 3D crystal/water sphere effect
    // Light coming from top-left
    const Lx = -0.5773, Ly = -0.5773, Lz = 0.5773; 
    // Half vector between light and view (0,0,1) for sharp specular specular highlights
    const Hx = -0.325, Hy = -0.325, Hz = 0.888; 
    // Vector meant for bottom-right internal reflection (caustics)
    const cLx = 0.707, cLy = 0.707, cLz = 0.0; 

    // Generate drop positions
    const drops = [];
    if (typeof arrangement === 'string' && arrangement.toLowerCase() === 'grid') {
        const stepX = maxR * 1.5;
        const stepY = maxR * 1.5;
        for (let y = stepY / 2; y < height + stepY; y += stepY) {
            let offset = (Math.floor(y / stepY) % 2) * (stepX / 2); // Hexagonal layout offset
            for (let x = stepX / 2 - offset; x < width + stepX; x += stepX) {
                let R = minR + Math.random() * (maxR - minR);
                drops.push({ cx: Math.floor(x), cy: Math.floor(y), r: Math.floor(R) });
            }
        }
    } else {
        for (let i = 0; i < count; i++) {
            let cx = Math.floor(Math.random() * width);
            let cy = Math.floor(Math.random() * height);
            let R = minR + Math.random() * (maxR - minR);
            drops.push({ cx, cy, r: Math.floor(R) });
        }
    }

    // Apply drops sequentially over the image
    for (let i = 0; i < drops.length; i++) {
        const cx = drops[i].cx;
        const cy = drops[i].cy;
        const R = drops[i].r;
        const R2 = R * R;

        const shadowCx = cx + R * 0.3;
        const shadowCy = cy + R * 0.3;

        // Bounding box with padding to cover the cast shadow correctly
        const pad = Math.ceil(R * 0.4); 
        const minX = Math.max(0, Math.floor(cx - R - pad));
        const maxX = Math.min(width - 1, Math.ceil(cx + R + pad));
        const minY = Math.max(0, Math.floor(cy - R - pad));
        const maxY = Math.min(height - 1, Math.ceil(cy + R + pad));

        const boxW = maxX - minX + 1;
        const boxH = maxY - minY + 1;
        if (boxW <= 0 || boxH <= 0) continue;

        // Snapshot an isolated bounding box of the current pixels (avoid tearing reflections issue)
        const srcBox = new Uint8ClampedArray(boxW * boxH * 4);
        for (let y = minY; y <= maxY; y++) {
            let srcYOffset = y * width;
            let dstYOffset = (y - minY) * boxW;
            for (let x = minX; x <= maxX; x++) {
                const srcIdx = (srcYOffset + x) * 4;
                const dstIdx = (dstYOffset + x - minX) * 4;
                srcBox[dstIdx] = data[srcIdx];
                srcBox[dstIdx + 1] = data[srcIdx + 1];
                srcBox[dstIdx + 2] = data[srcIdx + 2];
                srcBox[dstIdx + 3] = data[srcIdx + 3];
            }
        }

        // Apply distortions and shadows
        for (let y = minY; y <= maxY; y++) {
            let yOffset = y * width;
            let dy = y - cy;
            let dy2 = dy * dy;
            let sDy = y - shadowCy;
            let sDy2 = sDy * sDy;

            for (let x = minX; x <= maxX; x++) {
                let dx = x - cx;
                let d2 = dx * dx + dy2;

                if (d2 <= R2) {
                    // Inside the drop: Generate spherize + glass effect
                    const d = Math.sqrt(d2);
                    const nd = d / R;
                    const z = Math.sqrt(1 - nd * nd);

                    // Drop point 3D Normal
                    const nx = dx / R;
                    const ny = dy / R;
                    const nz = z;

                    // Refraction Mapping (Magnifies the center nicely)
                    const fraction = nd;
                    const src_x = Math.floor(cx + dx * fraction);
                    const src_y = Math.floor(cy + dy * fraction);

                    const clampX = Math.max(minX, Math.min(maxX, src_x));
                    const clampY = Math.max(minY, Math.min(maxY, src_y));
                    const srcBoxIdx = ((clampY - minY) * boxW + (clampX - minX)) * 4;

                    const r = srcBox[srcBoxIdx];
                    const g = srcBox[srcBoxIdx + 1];
                    const b = srcBox[srcBoxIdx + 2];
                    const a = srcBox[srcBoxIdx + 3];

                    // Standard Diffuse Base
                    let dot = nx * Lx + ny * Ly + nz * Lz;
                    let lightIntensity = 0.6 + Math.max(0, dot) * 0.5;

                    // Shiny Specular Highlight
                    let specular = 0;
                    let specDot = nx * Hx + ny * Hy + nz * Hz;
                    if (specDot > 0) {
                        specular = Math.pow(specDot, 40) * 180;
                    }

                    // Caustic Light Gathering (bottom-right glow)
                    let causticDot = nx * cLx + ny * cLy + nz * cLz;
                    let caustic = Math.pow(Math.max(0, causticDot), 4) * 80;

                    // Render a thick, refractive dark surrounding edge
                    let edgeDarkening = 1.0;
                    if (nd > 0.8) {
                        edgeDarkening = 1.0 - ((nd - 0.8) / 0.2) * 0.4;
                    }

                    const outIdx = (yOffset + x) * 4;
                    data[outIdx]     = Math.min(255, r * lightIntensity * edgeDarkening + specular + caustic);
                    data[outIdx + 1] = Math.min(255, g * lightIntensity * edgeDarkening + specular + caustic);
                    data[outIdx + 2] = Math.min(255, b * lightIntensity * edgeDarkening + specular + caustic);
                    // Force opacity as crystals have physical volume
                    data[outIdx + 3] = 255; 

                } else {
                    // Outside the drop: Generate a soft drop shadow slightly offset downwards
                    let sDx = x - shadowCx;
                    let sDist2 = sDx * sDx + sDy2;

                    if (sDist2 <= R2) {
                        let sd = Math.sqrt(sDist2);
                        let shadowIntensity = 0.6 + 0.4 * (sd / R); // Gradient fade on shadow borders
                        
                        const outIdx = (yOffset + x) * 4;
                        data[outIdx]     = data[outIdx] * shadowIntensity;
                        data[outIdx + 1] = data[outIdx + 1] * shadowIntensity;
                        data[outIdx + 2] = data[outIdx + 2] * shadowIntensity;
                    }
                }
            }
        }
    }

    ctx.putImageData(imgData, 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 Crystal Drop Effect Applicator allows you to overlay realistic, 3D-style crystal or water droplets onto any image. The tool simulates advanced optical properties such as light refraction, specular highlights, caustic light effects, and soft drop shadows to create a convincing glass-like appearance. Users can customize the effect by adjusting the number of drops, their size range, and their arrangement, choosing between a random distribution or a structured grid pattern. This tool is ideal for graphic designers looking to add texture to digital art, creating atmospheric water-on-glass effects for photography, or designing unique visual elements for social media and web graphics.

Leave a Reply

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

Other Image Tools:

Chess Image Generator

Cave Image Generator

Bongo Image Tool

Image Bongo Generator

Birdsong Image Generator

Image Bell Generator

Colorado Driver License Fictional Person Generator

Fake Driver License Image Generator

35mm 2960×1800 Ratio Resolution Image Resizer

The Lion King 1994 IMAX 70mm Movie Trailer Image

Big Hero 6 Character Replacement AI Tool for Video and Image

Big Hero 6 Character Replace AI Image and Video Tool

Big Hero 6 To Big Hero 6 The Series AU Replacement Tool

Big Hero 6 To Big Hero 6 The Series AU Image and Video Replacer

Slow Motion Video and Audio Playback Tool

Image Speed Reduction Tool

YouTube Stats For Nerds Audio Volume Normalization Analysis Tool

YouTube Stats For Nerds Audio Volume Normalization Information Tool

YouTube Stats For Nerds Volume Normalization Analyzer

YouTube Stats For Nerds Audio Volume Normalization Analyzer

YouTube Stats For Nerds Volume Normalization Analysis Tool

YouTube Stats For Nerds Audio Volume Normalization Information Display

YouTube Stats For Nerds Volume Normalization Information Tool

YouTube Stats For Nerds Audio Volume and Codec Information Extractor

YouTube Audio Stats Volume Normalization Tool for Mp2 Mp3 Opus and Ac3

Audio Volume Normalizer for Mp2 Mp3 Opus and Ac3 Formats

YouTube Audio Stats Volume Normalizer For Mp2 Mp3 Opus and Ac3 Formats

United States of America Federal Social Security Card Template Maker

Ukrainian Dub Master Video Voice Actor Information Tool

Ukrainian Dubbed Video Voice Actor Information Tool

YouTube Stats For Nerds Volume Normalizer for Opus and Ac3 Audio

YouTube Audio Volume Normalization Tool for Opus and Ac3 Formats

YouTube Stats For Nerds Volume Normalization Tool

YouTube Video Image and Metadata Stats For Nerds Tool

YouTube Video Image and Stats For Nerds Viewer

Image To I Killed X Losky Effect Color Filter Converter

See All →