Please bookmark this page to avoid losing your image tool!

Stone Block Image Generator

(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, carvingDepthStr = "15", stoneColorHex = "#8f979c", roughnessStr = "45", contrastStr = "1.5", blurStr = "0") {
    const carvingDepth = parseFloat(carvingDepthStr);
    const roughness = parseFloat(roughnessStr);
    const contrast = parseFloat(contrastStr);
    let blurAmt = parseFloat(blurStr);

    const w = originalImg.width;
    const h = originalImg.height;

    // Helper to safely extract RGB from Hex snippet
    function hexToRgb(hex) {
        let r=143, g=151, b=156;
        if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
            hex = hex.substring(1);
            if(hex.length === 3) hex = hex.split('').map(x => x + x).join('');
            r = parseInt(hex.substring(0, 2), 16);
            g = parseInt(hex.substring(2, 4), 16);
            b = parseInt(hex.substring(4, 6), 16);
        }
        return [r, g, b];
    }
    const [bR, bG, bB] = hexToRgb(stoneColorHex);

    // Auto-calculate appropriate blur based on image dimensions for a smooth carving slope if not set
    if (blurAmt === 0) {
        blurAmt = Math.max(2, Math.min(w, h) * 0.006);
    }

    // Step 1: Blur initial image to generate a bump map (Z map)
    const blurCanvas = document.createElement('canvas');
    blurCanvas.width = w; 
    blurCanvas.height = h;
    const bCtx = blurCanvas.getContext('2d', { willReadFrequently: true });
    
    // Draw with slight Gaussian blur to enable steep smooth slopes instead of jagged edges
    bCtx.filter = `blur(${blurAmt}px)`;
    bCtx.drawImage(originalImg, 0, 0, w, h);
    
    let bData;
    try {
        bData = bCtx.getImageData(0, 0, w, h);
    } catch(e) {
        // Fallback for CORS tainted images in strict environments, removes the filter so they can potentially fail natively or pass if policy changes
        bCtx.filter = 'none';
        bCtx.drawImage(originalImg, 0, 0, w, h);
        bData = bCtx.getImageData(0, 0, w, h); 
    }

    // Step 2: Build the 3D surface map array (Z-coordinates)
    const Z = new Float32Array(w * h);
    const margin = Math.floor(Math.min(w, h) * 0.04); // the size of the outer tablet bevel
    
    for (let y = 0; y < h; y++) {
        for (let x = 0; x < w; x++) {
            const i = y * w + x;
            const r = bData.data[i*4];
            const g = bData.data[i*4+1];
            const b = bData.data[i*4+2];
            const a = bData.data[i*4+3] / 255;
            
            // Calculate lightness and map it to a displacement elevation map (-100 to +100 roughly)
            const lum = (r * 0.299 + g * 0.587 + b * 0.114); 
            const elevate = (lum - 128) * a * 0.7; // Bright carves outwards, Dark carves inwards
            
            // Generate the outer 3D stone block bevel (dips down at canvas edges)
            const distToEdge = Math.min(x, w - 1 - x, y, h - 1 - y);
            let blockZ = 120; // flat rock surface baseline height
            if (distToEdge < margin) {
                const t = distToEdge / margin; // smoothstep beveling
                const smoothT = t * t * (3 - 2 * t);
                blockZ = smoothT * 120;
            }
            // Final Combined Height
            Z[i] = blockZ + elevate;
        }
    }

    // Step 3: Generate detailed multi-octave Stone Perlin-like Noise structure
    function generateNoise(w, h, scale) {
        const noise = new Float32Array(w * h);
        const sw = Math.ceil(w / scale) + 1;
        const sh = Math.ceil(h / scale) + 1;
        const smallNoise = new Float32Array(sw * sh);
        
        for(let i = 0; i < sw * sh; i++) smallNoise[i] = Math.random();
        
        for(let y = 0; y < h; y++) {
            const sy = y / scale;
            const y0 = Math.floor(sy);
            const ty = sy - y0;
            const fy = ty * ty * (3 - 2 * ty);
            const row0 = y0 * sw;
            const row1 = (y0 + 1) * sw;
            
            for(let x = 0; x < w; x++) {
                const sx = x / scale;
                const x0 = Math.floor(sx);
                const tx = sx - x0;
                const fx = tx * tx * (3 - 2 * tx);
                
                const nx0 = smallNoise[row0 + x0] + (smallNoise[row0 + x0 + 1] - smallNoise[row0 + x0]) * fx;
                const nx1 = smallNoise[row1 + x0] + (smallNoise[row1 + x0 + 1] - smallNoise[row1 + x0]) * fx;
                noise[y*w + x] = nx0 + (nx1 - nx0) * fy;
            }
        }
        return noise;
    }

    const dim = Math.min(w, h);
    const noise32 = generateNoise(w, h, Math.max(16, dim * 0.1));
    const noise16 = generateNoise(w, h, Math.max(8, dim * 0.05));
    const noise8  = generateNoise(w, h, Math.max(4, dim * 0.025));
    const noise4  = generateNoise(w, h, Math.max(2, dim * 0.0125));

    const stoneTex = new Float32Array(w * h);
    for(let i = 0; i < w * h; i++) {
        stoneTex[i] = noise32[i] * 0.4 + noise16[i] * 0.3 + noise8[i] * 0.2 + noise4[i] * 0.1;
    }

    // Step 4: Shading, Bump Mapping & Final Composing Phase
    const finalCanvas = document.createElement('canvas');
    finalCanvas.width = w;
    finalCanvas.height = h;
    const fCtx = finalCanvas.getContext('2d');
    const fData = fCtx.createImageData(w, h);
    
    // Virtual Light pointing diagonally Top-Left 
    let lx = -1.0, ly = -1.5, lz = 1.2;
    const llen = Math.sqrt(lx*lx + ly*ly + lz*lz);
    lx /= llen; ly /= llen; lz /= llen;
    const flatDiffuseBase = lz; 

    for(let y = 0; y < h; y++) {
        for(let x = 0; x < w; x++) {
            const i = y * w + x;
            
            // To compute surface normals properly (Central Difference)
            const xPrev = x > 0 ? x - 1 : x;
            const xNext = x < w - 1 ? x + 1 : x;
            const yPrev = y > 0 ? y - 1 : y;
            const yNext = y < h - 1 ? y + 1 : y;

            // Height-map differentials
            let dx = (Z[y * w + xNext] - Z[y * w + xPrev]) / 2.0 * carvingDepth * 0.1;
            let dy = (Z[yNext * w + x] - Z[yPrev * w + x]) / 2.0 * carvingDepth * 0.1;

            // Micro-roughness differentials
            const sdx = (stoneTex[y * w + xNext] - stoneTex[y * w + xPrev]) / 2.0;
            const sdy = (stoneTex[yNext * w + x] - stoneTex[yPrev * w + x]) / 2.0;
            
            // Blend image normals with natural stone bumping bumps
            dx += sdx * roughness * 0.3;
            dy += sdy * roughness * 0.3;

            // Normalize vector direction
            const nlen = Math.sqrt(dx*dx + dy*dy + 1.0);
            const nx = -dx / nlen; 
            const ny = -dy / nlen; 
            const nz = 1.0 / nlen;

            // Lambertian Illumination with baseline adjustments
            const diffuse = Math.max(0, nx*lx + ny*ly + nz*lz);
            let shadowIntensity = diffuse / flatDiffuseBase; 

            // Vignette calculation to fake 3D depth towards corners
            const vDistX = Math.abs(x - w / 2) / (w / 2);
            const vDistY = Math.abs(y - h / 2) / (h / 2);
            const vignette = 1.0 - (vDistX * vDistX + vDistY * vDistY) * 0.12;

            // Contrast modifier
            shadowIntensity = Math.pow(shadowIntensity, contrast) * vignette;

            // Compute Final Tint and Color
            const texOffset = (stoneTex[i] - 0.5) * roughness;
            
            fData.data[i*4]     = Math.min(255, Math.max(0, (bR + texOffset) * shadowIntensity));
            fData.data[i*4 + 1] = Math.min(255, Math.max(0, (bG + texOffset) * shadowIntensity));
            fData.data[i*4 + 2] = Math.min(255, Math.max(0, (bB + texOffset) * shadowIntensity));
            fData.data[i*4 + 3] = 255; // Rendered output is an entirely solid stone slab block
        }
    }

    fCtx.putImageData(fData, 0, 0);
    return finalCanvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Stone Block Image Generator transforms any uploaded image into a digital stone carving. By analyzing the luminance of the original image, the tool creates a simulated 3D relief effect, making bright areas appear carved outward and dark areas appear recessed. Users can customize the final look by adjusting the carving depth, stone color, surface roughness, contrast, and blur levels. This tool is ideal for game developers looking to create stone tablet textures, graphic designers creating weathered signage, or anyone wanting to give logos and photos a rustic, masonry-etched appearance.

Leave a Reply

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