Please bookmark this page to avoid losing your image tool!

Image Cubism 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, numShapes = 1000, shapeType = 'triangle', minShapeSize = 10, maxShapeSize = 50, strokeColor = 'rgba(0,0,0,0.1)', strokeWidth = 1) {
    
    // Parameter sanitization and normalization
    let currentNumShapes = parseInt(String(numShapes), 10);
    if (isNaN(currentNumShapes) || currentNumShapes <= 0) {
        currentNumShapes = 1000; // Fallback to default from signature or a hardcoded one
    }

    let currentMinShapeSize = parseFloat(String(minShapeSize));
    if (isNaN(currentMinShapeSize) || currentMinShapeSize <= 0) {
        currentMinShapeSize = 10;
    }

    let currentMaxShapeSize = parseFloat(String(maxShapeSize));
    if (isNaN(currentMaxShapeSize) || currentMaxShapeSize <= 0) {
        currentMaxShapeSize = 50;
    }

    if (currentMinShapeSize > currentMaxShapeSize) {
        // Swap if min > max to maintain logical order
        [currentMinShapeSize, currentMaxShapeSize] = [currentMaxShapeSize, currentMinShapeSize];
    }

    let currentStrokeWidth = parseFloat(String(strokeWidth));
    if (isNaN(currentStrokeWidth) || currentStrokeWidth < 0) {
        currentStrokeWidth = 1; 
    }

    const currentShapeType = String(shapeType).toLowerCase();
    const currentStrokeColor = String(strokeColor);

    // Canvas setup
    const outputCanvas = document.createElement('canvas');
    const ctx = outputCanvas.getContext('2d');
    
    // Use naturalWidth/Height for intrinsic image dimensions
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (imgWidth === 0 || imgHeight === 0) {
        // If image is not loaded or has no dimensions, return an empty canvas
        outputCanvas.width = 0;
        outputCanvas.height = 0;
        return outputCanvas; 
    }

    outputCanvas.width = imgWidth;
    outputCanvas.height = imgHeight;

    // Temporary canvas for color sampling from the original image
    // Using willReadFrequently hint for potential performance improvement with getImageData
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
    tempCanvas.width = imgWidth;
    tempCanvas.height = imgHeight;
    tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    function getColorAtPoint(x, y, sourceContext, canvasWidth, canvasHeight) {
        // Clamp coordinates to be within the canvas bounds
        const clampedX = Math.max(0, Math.min(Math.floor(x), canvasWidth - 1));
        const clampedY = Math.max(0, Math.min(Math.floor(y), canvasHeight - 1));
        
        try {
            const pixel = sourceContext.getImageData(clampedX, clampedY, 1, 1).data;
            return `rgba(${pixel[0]}, ${pixel[1]}, ${pixel[2]}, ${pixel[3] / 255})`;
        } catch (e) {
            // getImageData can fail for various reasons (e.g. tainted canvas from cross-origin image)
            // Silently fail to a default color (transparent black)
            return 'rgba(0,0,0,0)'; 
        }
    }

    function generateShapePoints(cx, cy, characteristicSize, numVertices) {
        const points = [];
        const angleIncrement = (2 * Math.PI) / numVertices;
        for (let i = 0; i < numVertices; i++) {
            const baseAngle = i * angleIncrement;
            // Randomize angle slightly for irregularity
            const angleRandomness = (Math.random() - 0.5) * angleIncrement * 0.8; // +/- 40% of sector
            const angle = baseAngle + angleRandomness;
            
            // Randomize radius to vary vertex distance from center
            // This creates shapes with an average 'diameter' related to characteristicSize
            const radius = (characteristicSize / 2) * (0.6 + Math.random() * 0.8); // Radius is 30% to 70% of characteristicSize
            
            points.push({
                x: cx + radius * Math.cos(angle),
                y: cy + radius * Math.sin(angle)
            });
        }
        return points;
    }
    
    // ------ Main drawing loop ------
    for (let i = 0; i < currentNumShapes; i++) {
        // Pick a random center point for the shape
        const centerX = Math.random() * imgWidth;
        const centerY = Math.random() * imgHeight;
        
        // Determine a random size for the current shape within the specified range
        const shapeSize = currentMinShapeSize + Math.random() * (currentMaxShapeSize - currentMinShapeSize);
        
        // Sample color from the original image at the shape's center
        const fillColor = getColorAtPoint(centerX, centerY, tempCtx, imgWidth, imgHeight);
        ctx.fillStyle = fillColor;
        
        // Setup stroke if width is positive
        if (currentStrokeWidth > 0) {
            ctx.strokeStyle = currentStrokeColor;
            ctx.lineWidth = currentStrokeWidth;
        }

        ctx.beginPath();
        let points = null; // To hold vertices for polygonal shapes
        
        if (currentShapeType === 'triangle') {
            points = generateShapePoints(centerX, centerY, shapeSize, 3);
        } else if (currentShapeType === 'rectangle') { // 'rectangle' is interpreted as a quadrilateral
            points = generateShapePoints(centerX, centerY, shapeSize, 4);
        } else if (currentShapeType === 'circle') {
            ctx.arc(centerX, centerY, shapeSize / 2, 0, 2 * Math.PI); // Draw a circle path
        } else { 
            // Default to triangle if shapeType is unknown
            points = generateShapePoints(centerX, centerY, shapeSize, 3);
        }

        if (points) { // If points were generated (for polygons)
            ctx.moveTo(points[0].x, points[0].y);
            for (let k = 1; k < points.length; k++) {
                ctx.lineTo(points[k].x, points[k].y);
            }
        }
        
        ctx.closePath(); // Close the path (connects last point to first for polygons)
        ctx.fill();      // Fill the shape
        
        if (currentStrokeWidth > 0) {
            ctx.stroke(); // Stroke the shape's border
        }
    }

    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 Cubism Filter Effect Tool allows users to transform images into artistic renditions using a cubist style. By applying geometric shapes such as triangles, rectangles, or circles, it generates a vibrant reinterpretation of the original image. Users can customize parameters such as the number of shapes, size ranges, and stroke colors to create unique effects. This tool is ideal for artists, designers, and anyone looking to add a distinctive visual flair to their images for social media, design projects, or personal use.

Leave a Reply

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