Please bookmark this page to avoid losing your image tool!

Image Ultra Realistic Skin Texture Pore Emulation 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.
async function processImage(originalImg, poreDensity = 0.5, poreSize = 1.0, poreDarkness = 0.3, skinRoughness = 0.15, effectStrength = 0.5) {
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    // Helper to create a new canvas
    const createCanvas = (w, h) => {
        const canvas = document.createElement('canvas');
        canvas.width = w;
        canvas.height = h;
        return canvas;
    };

    // --- Step 1: Create a Skin Mask ---
    // This mask will isolate the effect to skin-toned areas.
    const maskCanvas = createCanvas(width, height);
    const maskCtx = maskCanvas.getContext('2d', {
        willReadFrequently: true
    });
    maskCtx.drawImage(originalImg, 0, 0, width, height);

    const imageData = maskCtx.getImageData(0, 0, width, height);
    const data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];

        // A common method for skin detection is to convert RGB to a color space
        // like YCbCr and check for values within a specific range.
        const y = 0.299 * r + 0.587 * g + 0.114 * b;
        const cb = 128 - 0.168736 * r - 0.331264 * g + 0.5 * b;
        const cr = 128 + 0.5 * r - 0.418688 * g - 0.081312 * b;

        // Thresholds for skin tones in YCbCr space.
        const isSkin = (y > 80 && cb > 85 && cb < 135 && cr > 135 && cr < 180);

        // Set pixel to white for skin, black for non-skin.
        const value = isSkin ? 255 : 0;
        data[i] = data[i + 1] = data[i + 2] = value;
    }
    maskCtx.putImageData(imageData, 0, 0);

    // Feather the mask edges for a smooth transition.
    // A blur radius relative to image size scales well.
    const blurRadius = Math.max(1, Math.min(width, height) * 0.01);
    maskCtx.filter = `blur(${blurRadius}px)`;
    maskCtx.drawImage(maskCanvas, 0, 0, width, height); // Re-draw to apply filter
    maskCtx.filter = 'none'; // Reset filter


    // --- Step 2: Create a Texture Layer ---
    const textureCanvas = createCanvas(width, height);
    const textureCtx = textureCanvas.getContext('2d');

    // Fill with neutral gray (#808080), which is neutral for 'overlay' blend mode.
    textureCtx.fillStyle = '#808080';
    textureCtx.fillRect(0, 0, width, height);

    // Add fine-grained noise for general skin roughness.
    if (skinRoughness > 0) {
        const roughnessData = textureCtx.getImageData(0, 0, width, height);
        const roughData = roughnessData.data;
        for (let i = 0; i < roughData.length; i += 4) {
            // Add or subtract a small random value from the gray.
            const noise = (Math.random() - 0.5) * 50 * skinRoughness;
            roughData[i] += noise;
            roughData[i + 1] += noise;
            roughData[i + 2] += noise;
        }
        textureCtx.putImageData(roughnessData, 0, 0);
    }

    // Add pores.
    if (poreDensity > 0) {
        const numPores = Math.floor(width * height * 0.005 * poreDensity);
        for (let i = 0; i < numPores; i++) {
            const x = Math.random() * width;
            const y = Math.random() * height;

            // Randomize pore characteristics for a more natural look.
            const currentPoreSize = poreSize * (0.5 + Math.random() * 0.75);
            const currentPoreAlpha = poreDarkness * (0.7 + Math.random() * 0.6);

            // A radial gradient simulates a pore's depth better than a flat circle.
            const gradient = textureCtx.createRadialGradient(x, y, 0, x, y, currentPoreSize);
            gradient.addColorStop(0, `rgba(0, 0, 0, ${currentPoreAlpha})`); // Dark center
            gradient.addColorStop(0.6, `rgba(0, 0, 0, ${currentPoreAlpha * 0.3})`);
            gradient.addColorStop(1, 'rgba(128, 128, 128, 0)'); // Fade to transparent neutral gray

            textureCtx.fillStyle = gradient;
            // Use fillRect as it's often faster than drawing arcs.
            textureCtx.fillRect(x - currentPoreSize, y - currentPoreSize, currentPoreSize * 2, currentPoreSize * 2);
        }
    }

    // --- Step 3: Mask the Texture Layer ---
    // This uses the skin mask to "cut out" the texture, leaving it only in skin areas.
    textureCtx.globalCompositeOperation = 'destination-in';
    textureCtx.drawImage(maskCanvas, 0, 0);


    // --- Step 4: Composite the Final Image ---
    const resultCanvas = createCanvas(width, height);
    const resultCtx = resultCanvas.getContext('2d');

    // Start with the original image.
    resultCtx.drawImage(originalImg, 0, 0, width, height);

    // Set blend mode and opacity, then overlay the masked texture.
    resultCtx.globalAlpha = Math.max(0, Math.min(1, effectStrength));
    resultCtx.globalCompositeOperation = 'overlay';
    resultCtx.drawImage(textureCanvas, 0, 0);

    // Reset context properties for safety.
    resultCtx.globalAlpha = 1.0;
    resultCtx.globalCompositeOperation = 'source-over';

    return resultCanvas;
}

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 Ultra Realistic Skin Texture Pore Emulation Tool allows users to enhance images of skin by adding realistic texture features such as pores and skin roughness. This tool can be valuable for artists, photographers, and designers looking to improve the portrayal of skin in their work by simulating natural skin characteristics. It is also useful in the beauty and skincare industry for producing realistic images that showcase skin textures effectively.

Leave a Reply

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