Please bookmark this page to avoid losing your image tool!

Image Rune Carving 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, carveDepth = 1, lightBias = 128, useMonochrome = 1) {
    const canvas = document.createElement('canvas');
    // Use willReadFrequently hint for potential performance improvement if this function is called often
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Use naturalWidth/Height for HTMLImageElement, fallback to width/height
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    let sourceData;
    try {
        sourceData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        // Handle potential security errors (e.g., cross-origin image)
        console.error("Error getting ImageData:", e);
        // Draw an error message on the canvas as feedback
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'rgba(0,0,0,0.7)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '16px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('Error: Could not process image.', canvas.width / 2, canvas.height / 2);
        ctx.fillText('(Possibly cross-origin issue)', canvas.width / 2, canvas.height / 2 + 20);
        return canvas;
    }
    
    const data = sourceData.data;
    const outputData = ctx.createImageData(imgWidth, imgHeight);
    const outData = outputData.data;

    // Validate and prepare parameters
    const d_int = Math.max(1, Math.floor(Number(carveDepth)));
    const bOffset = Math.max(0, Math.min(255, Number(lightBias))); // Bias for the emboss effect, ensure it's 0-255
    const applyMono = Number(useMonochrome) === 1;

    // Create a new data array for potentially grayscaled input.
    // This separation ensures the original 'data' array is not modified if applyMono is false.
    const processedInputData = new Uint8ClampedArray(data.length);

    if (applyMono) {
        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            // Standard luminance calculation for grayscale
            const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
            processedInputData[i]     = gray;
            processedInputData[i + 1] = gray;
            processedInputData[i + 2] = gray;
            processedInputData[i + 3] = data[i + 3]; // Preserve original alpha
        }
    } else {
        // If not applying monochrome, copy original data to processedInputData
        processedInputData.set(data);
    }

    // Main loop for the carving (emboss) effect
    for (let y = 0; y < imgHeight; y++) {
        for (let x = 0; x < imgWidth; x++) {
            const currentIndex = (y * imgWidth + x) * 4;

            const r_current = processedInputData[currentIndex];
            const g_current = processedInputData[currentIndex + 1];
            const b_current = processedInputData[currentIndex + 2];
            const a_current = processedInputData[currentIndex + 3]; // Alpha from (potentially grayscaled) source

            let r_offsetVal, g_offsetVal, b_offsetVal;

            // Check if the offset pixel (top-left) is within image bounds
            if (y >= d_int && x >= d_int) {
                const offsetPixelIndex = ((y - d_int) * imgWidth + (x - d_int)) * 4;
                r_offsetVal = processedInputData[offsetPixelIndex];
                g_offsetVal = processedInputData[offsetPixelIndex + 1];
                b_offsetVal = processedInputData[offsetPixelIndex + 2];

                // Apply emboss formula: current - offset + bias
                // Uint8ClampedArray will automatically clamp values to 0-255,
                // but Math.max/min ensures intermediate values are also conceptually clamped if needed.
                outData[currentIndex]     = Math.max(0, Math.min(255, r_current - r_offsetVal + bOffset));
                outData[currentIndex + 1] = Math.max(0, Math.min(255, g_current - g_offsetVal + bOffset));
                outData[currentIndex + 2] = Math.max(0, Math.min(255, b_current - b_offsetVal + bOffset));
            } else {
                // Handle border pixels: set to the lightBias value for R,G,B
                // This creates a neutral border consistent with the effect's midpoint.
                outData[currentIndex]     = bOffset;
                outData[currentIndex + 1] = bOffset;
                outData[currentIndex + 2] = bOffset;
            }
            outData[currentIndex + 3] = a_current; // Preserve alpha
        }
    }

    // Put the modified image data back onto the canvas
    ctx.putImageData(outputData, 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 Rune Carving Filter Effect Tool allows users to apply a unique carving or emboss effect to their images. By adjusting parameters such as carving depth, light bias, and whether to use monochrome, users can create visually striking interpretations of their photos or artwork. This tool is particularly useful for graphic designers, artists, and hobbyists who want to enhance their images for creative projects, social media, or digital art presentations. It offers a practical way to create textured and dimensional effects that can add interest and enhance the overall aesthetic of images.

Leave a Reply

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