Please bookmark this page to avoid losing your image tool!

Image Of Mayan Stone Tablet Creator

(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, stoneColorStr = "160,140,120", embossOffset = 1, embossIntensity = 1.0, noiseAmount = 0.15, contrast = 30) {
    // Ensure embossOffset is an integer and non-negative
    embossOffset = Math.max(0, Math.floor(embossOffset));

    // Clamp contrast to a safe range to avoid division by zero or extreme factors
    contrast = Math.max(-254, Math.min(254, contrast));

    const canvas = document.createElement('canvas');
    // Add willReadFrequently hint for potential performance improvement
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Ensure the image is loaded, otherwise width/height might be 0
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (imgWidth === 0 || imgHeight === 0) {
        console.error("Image not loaded or has zero dimensions. Returning a 1x1 canvas.");
        canvas.width = 1;
        canvas.height = 1;
        // Optionally, fill with a default color or throw an error
        // ctx.fillStyle = 'red';
        // ctx.fillRect(0,0,1,1);
        return canvas;
    }

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

    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data; // This is a Uint8ClampedArray
    const width = canvas.width;
    const height = canvas.height;

    // Parse stoneColorStr into normalized (0-1) R,G,B components
    // Gracefully handles potential malformed strings by defaulting to black if NaN.
    const stoneColorParts = stoneColorStr.split(',');
    const stoneR_norm = (parseInt(stoneColorParts[0]?.trim(), 10) || 0) / 255.0;
    const stoneG_norm = (parseInt(stoneColorParts[1]?.trim(), 10) || 0) / 255.0;
    const stoneB_norm = (parseInt(stoneColorParts[2]?.trim(), 10) || 0) / 255.0;


    // Intermediate arrays for processing
    const originalGrayData = new Uint8ClampedArray(width * height); // Stores original grayscale values (0-255)
    const processedGray = new Float32Array(width * height); // Stores intermediate float values for precision

    // 1. Convert to Grayscale and initialize processedGray
    // This loop populates originalGrayData and initializes processedGray with these values.
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const i = (y * width + x) * 4; // Index for imageData.data
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            // Standard luminance calculation for grayscale
            const gray = 0.299 * r + 0.587 * g + 0.114 * b;
            
            originalGrayData[y * width + x] = gray; // Store clamped 0-255 gray value
            processedGray[y * width + x] = gray;    // Initialize processedGray with this (float but effectively 0-255)
        }
    }

    // 2. Emboss Effect
    // This modifies processedGray. It operates on originalGrayData for source values.
    // Pixels not processed by this loop (borders if embossOffset > 0) will retain their original gray values from initialization.
    if (embossOffset > 0) {
        for (let y = embossOffset; y < height; y++) { // Start from y = embossOffset to have a valid neighbor
            for (let x = embossOffset; x < width; x++) { // Start from x = embossOffset
                const pixelIdx = y * width + x;
                const currentGray = originalGrayData[pixelIdx];
                // Get gray value of the pixel at (x - offset, y - offset)
                const neighborGray = originalGrayData[(y - embossOffset) * width + (x - embossOffset)];
                
                const diff = currentGray - neighborGray;
                // Base of 128 for neutral gray, difference scaled by intensity creates light/shadow
                let embossedValue = 128 + diff * embossIntensity;
                processedGray[pixelIdx] = embossedValue; // Store float value, will be clamped later
            }
        }
    }

    // 3. Apply Contrast, Noise, and then Color Tint to each pixel in processedGray
    // The contrast factor is calculated once for efficiency.
    const contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast));

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const pixelIdx = y * width + x;
            let value = processedGray[pixelIdx]; // Get the (potentially embossed) gray value

            // 3a. Clamp 'value' if it came from an emboss operation, as it might be outside [0,255]
            // This check ensures that only values modified by emboss (and thus potentially out of 0-255 range)
            // are clamped here. Original gray values (borders or if embossOffset=0) are already 0-255.
            if (embossOffset > 0 && y >= embossOffset && x >= embossOffset) {
                 value = Math.max(0, Math.min(255, value));
            }

            // 3b. Contrast adjustment
            if (contrast !== 0) { // Apply contrast if it's not neutral zero
                value = contrastFactor * (value - 128) + 128;
                value = Math.max(0, Math.min(255, value)); // Clamp after contrast
            }

            // 3c. Add Noise
            if (noiseAmount > 0) {
                // Generate noise: range is roughly [-noiseAmount * 128, +noiseAmount * 128)
                const randomNoise = (Math.random() - 0.5) * 2 * noiseAmount * 128;
                value += randomNoise;
                value = Math.max(0, Math.min(255, value)); // Clamp after adding noise
            }
            
            // At this point, 'value' is the final grayscale intensity (0-255) for the pixel.
            
            // 4. Color Tinting: Apply the stone color by modulating the grayscale value.
            const i = pixelIdx * 4; // Index for the final imageData.data array
            data[i]     = value * stoneR_norm; // Uint8ClampedArray handles flooring & clamping
            data[i + 1] = value * stoneG_norm;
            data[i + 2] = value * stoneB_norm;
            data[i + 3] = 255; // Alpha channel remains fully opaque
        }
    }

    ctx.putImageData(imageData, 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 Of Mayan Stone Tablet Creator allows users to transform regular images into stylized representations resembling ancient Mayan stone tablets. This tool effectively applies an embossing effect, enhances the image’s contrast, and adds a noise texture to simulate the appearance of stone. Users can customize the stone color and intensity of the emboss effect, making it useful for creating artistic designs, educational materials, or themed graphics that evoke historical artifacts. Ideal for graphic designers, artists, and anyone interested in unique image modifications.

Leave a Reply

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