Please bookmark this page to avoid losing your image tool!

Image Persian Carpet 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, pixelSize = 8, paletteColorsStr = "maroon,darkblue,beige,saddlebrown,darkgreen,black") {
    // Ensure originalImg is valid and loaded
    if (!originalImg || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
        console.error("Persian Carpet Filter: Invalid image or image not loaded properly.");
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = 1; 
        errorCanvas.height = 1;
        // Optionally, draw a small indicator on the error canvas
        // const errCtx = errorCanvas.getContext('2d');
        // errCtx.fillStyle = 'red';
        // errCtx.fillRect(0,0,1,1);
        return errorCanvas;
    }

    pixelSize = Math.max(1, Math.floor(pixelSize));

    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    // 1. Parse palette colors
    let parsedPalette = [];
    // Temporary canvas for converting color strings to RGB values
    const tempColorCanvas = document.createElement('canvas');
    tempColorCanvas.width = 1;
    tempColorCanvas.height = 1;
    // Use willReadFrequently for performance optimization if available, though for few colors it's minor.
    const tempColorCtx = tempColorCanvas.getContext('2d', { willReadFrequently: true });

    if (paletteColorsStr && typeof paletteColorsStr === 'string' && paletteColorsStr.trim() !== "") {
        const colorStrings = paletteColorsStr.split(',').map(s => s.trim()).filter(s => s.length > 0);
        for (const colorStr of colorStrings) {
            // Clear previous color draw (important for transparent colors or if fillStyle fails silently)
            tempColorCtx.clearRect(0, 0, 1, 1); 
            tempColorCtx.fillStyle = colorStr;
            tempColorCtx.fillRect(0, 0, 1, 1);
            const data = tempColorCtx.getImageData(0, 0, 1, 1).data;
            // data will be [R, G, B, A]. We only need R, G, B.
            // If colorStr is invalid, fillStyle usually defaults to black.
            parsedPalette.push([data[0], data[1], data[2]]);
        }
    }

    // If palette is empty after parsing (e.g., empty string, only commas, or all colors unparseable - though latter is unlikely)
    // Fallback to a predefined default palette
    if (parsedPalette.length === 0) {
        console.warn("Persian Carpet Filter: Palette is empty or invalid. Using a default internal palette.");
        parsedPalette = [
            [128, 0, 0],    // maroon
            [0, 0, 139],   // darkblue
            [245, 245, 220], // beige
            [139, 69, 19],  // saddlebrown
            [0, 100, 0],   // darkgreen
            [0, 0, 0]      // black
        ];
    }

    // 2. Input canvas to get pixel data from the original image
    const inputCanvas = document.createElement('canvas');
    inputCanvas.width = imgWidth;
    inputCanvas.height = imgHeight;
    const inputCtx = inputCanvas.getContext('2d', { willReadFrequently: true });
    inputCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    
    let imageData;
    try {
        imageData = inputCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Persian Carpet Filter: Could not getImageData. This might be due to a tainted canvas (cross-origin image without CORS).", e);
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = imgWidth || 1;
        errorCanvas.height = imgHeight || 1;
        return errorCanvas; // Return an empty canvas of original size or 1x1
    }
    const data = imageData.data;

    // 3. Output canvas (the one to be returned)
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = imgWidth;
    outputCanvas.height = imgHeight;
    const outputCtx = outputCanvas.getContext('2d');
    // Ensure sharp, pixelated blocks without anti-aliasing from browser defaults
    outputCtx.imageSmoothingEnabled = false; 


    // 4. Process image in blocks
    for (let y = 0; y < imgHeight; y += pixelSize) {
        for (let x = 0; x < imgWidth; x += pixelSize) {
            let sumR = 0, sumG = 0, sumB = 0, count = 0;

            // Define the actual block dimensions, handling edges
            const blockWidth = Math.min(pixelSize, imgWidth - x);
            const blockHeight = Math.min(pixelSize, imgHeight - y);

            // Calculate average color of the block in the original image
            for (let blockY = 0; blockY < blockHeight; blockY++) {
                for (let blockX = 0; blockX < blockWidth; blockX++) {
                    const currentY = y + blockY;
                    const currentX = x + blockX;
                    
                    const i = (currentY * imgWidth + currentX) * 4;
                    sumR += data[i];
                    sumG += data[i+1];
                    sumB += data[i+2];
                    count++;
                }
            }

            if (count === 0) continue; // Should not happen with correct blockWidth/Height logic

            const avgR = sumR / count;
            const avgG = sumG / count;
            const avgB = sumB / count;

            // Find the closest color in the palette
            let closestColor = parsedPalette[0]; // Default to first palette color
            let minDist = Infinity;

            for (const paletteRgb of parsedPalette) {
                // Euclidean distance in RGB space
                const dist = Math.sqrt(
                    Math.pow(avgR - paletteRgb[0], 2) +
                    Math.pow(avgG - paletteRgb[1], 2) +
                    Math.pow(avgB - paletteRgb[2], 2)
                );
                if (dist < minDist) {
                    minDist = dist;
                    closestColor = paletteRgb;
                }
            }

            // Fill the block on the output canvas with the closest palette color
            outputCtx.fillStyle = `rgb(${closestColor[0]},${closestColor[1]},${closestColor[2]})`;
            outputCtx.fillRect(x, y, blockWidth, blockHeight);
        }
    }

    return outputCanvas;
}

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 Persian Carpet Filter Effect Tool allows users to apply a unique pixelated effect to uploaded images, mimicking the intricate patterns of traditional Persian carpets. By adjusting parameters such as pixel size and customizable color palettes, users can transform their photographs into artful representations suitable for various applications, including digital art projects, social media posts, or personal collections. This tool is particularly useful for those looking to create visually striking images with a cultural flair.

Leave a Reply

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