Please bookmark this page to avoid losing your image tool!

Image Custom Polygon Cropper

(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.
/**
 * Crops an image to a custom polygon shape.
 *
 * @param {Image} originalImg The original HTMLImageElement (must be loaded, e.g., originalImg.complete should be true).
 * @param {string} [pointsStr=""] A string representing the polygon points, e.g., "x1,y1 x2,y2 x3,y3 ...".
 *                                Points are separated by spaces, coordinates (x,y) by a comma.
 *                                If empty, invalid, or defines less than 3 points,
 *                                it defaults to a rectangle covering the entire image.
 * @returns {HTMLCanvasElement} A new canvas element containing the cropped image.
 *                              The canvas dimensions will be the bounding box of the polygon.
 *                              If the polygon (or the original image, in default mode) has zero area,
 *                              an empty canvas of the corresponding dimensions (e.g., 0xH, Wx0, or 0x0) is returned.
 */
function processImage(originalImg, pointsStr = "") {
    // Validate originalImg
    // An Image object has width/height properties. If not loaded, these are often 0.
    // The problem implies it's a usable JavaScript Image object.
    if (!originalImg || typeof originalImg.width === 'undefined' || typeof originalImg.height === 'undefined') {
        console.error("Invalid originalImg provided. It must be an Image object with width and height properties.");
        const errCanvas = document.createElement('canvas');
        errCanvas.width = 0;
        errCanvas.height = 0;
        return errCanvas;
    }
    // A further check could be `if (!originalImg.complete || originalImg.naturalWidth === 0)`
    // but assuming `originalImg` is ready as per typical usage of such a function.

    // 1. Parse pointsStr
    let points = [];
    if (typeof pointsStr === 'string' && pointsStr.trim() !== "") {
        const stringPairs = pointsStr.trim().split(/\s+/); // Split by one or more spaces
        for (const pair of stringPairs) {
            const coords = pair.split(',');
            if (coords.length === 2) {
                const x = parseFloat(coords[0]);
                const y = parseFloat(coords[1]);
                if (!isNaN(x) && !isNaN(y)) {
                    points.push({ x, y });
                } else {
                    points = []; // Invalidate all parsed points if one coordinate pair is bad
                    console.warn("Invalid coordinate value in pointsStr pair:", pair, "- NaN found after parsing.");
                    break; 
                }
            } else {
                points = []; // Invalidate all parsed points if pair format is bad
                console.warn("Invalid point pair format in pointsStr (expected 'x,y'):", pair);
                break;
            }
        }
    }

    // 2. Handle default or insufficient points for a polygon
    let isDefaultApplied = false;
    if (points.length < 3) {
        // Check if user actually provided a non-empty pointsStr which turned out insufficient/invalid
        if (typeof pointsStr === 'string' && pointsStr.trim() !== "") {
            if (points.length > 0) { // Some points parsed, but not enough
                console.warn(`Provided pointsStr ("${pointsStr}") resulted in ${points.length} valid points. A polygon requires at least 3. Defaulting to full image crop.`);
            } else { // No points parsed from the provided string (all invalid or format issues)
                console.warn(`Provided pointsStr ("${pointsStr}") could not be parsed into any valid points. A polygon requires at least 3. Defaulting to full image crop.`);
            }
        }
        // Apply default: a rectangle covering the entire image
        points = [
            { x: 0, y: 0 },
            { x: originalImg.width, y: 0 },
            { x: originalImg.width, y: originalImg.height },
            { x: 0, y: originalImg.height }
        ];
        isDefaultApplied = true; // Mark that default points are now in use
    }

    // 3. Calculate the bounding box of the polygon
    // This uses the finalized `points` array (either parsed or defaulted).
    let minX = points[0].x;
    let minY = points[0].y;
    let maxX = points[0].x;
    let maxY = points[0].y;

    for (let i = 1; i < points.length; i++) {
        minX = Math.min(minX, points[i].x);
        minY = Math.min(minY, points[i].y);
        maxX = Math.max(maxX, points[i].x);
        maxY = Math.max(maxY, points[i].y);
    }

    // Ensure non-negative dimensions for bounding box.
    const boundingBoxWidth = Math.max(0, maxX - minX);
    const boundingBoxHeight = Math.max(0, maxY - minY);

    // Create the output canvas with dimensions of the_polygon's bounding box
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = boundingBoxWidth;
    outputCanvas.height = boundingBoxHeight;
    
    // If the bounding box has zero area (e.g., width or height is 0),
    // no drawing is needed. Return the (potentially 0-dimension) canvas.
    if (boundingBoxWidth === 0 || boundingBoxHeight === 0) {
        // Warn if user's specific points led to this, not if default logic for a 0-dim image did.
        if (!isDefaultApplied) { 
            console.warn("Polygon results in zero area (e.g., all points collinear, or covers zero width/height). Returning an empty canvas of the calculated size.");
        }
        return outputCanvas; 
    }
    
    const outputCtx = outputCanvas.getContext('2d');

    // 4. Draw the polygon shape on the output canvas to use as a mask
    outputCtx.beginPath();
    // Path points must be translated to be relative to the bounding box's top-left corner (minX, minY),
    // which becomes (0,0) on the outputCanvas.
    outputCtx.moveTo(points[0].x - minX, points[0].y - minY);
    for (let i = 1; i < points.length; i++) {
        outputCtx.lineTo(points[i].x - minX, points[i].y - minY);
    }
    outputCtx.closePath();
    
    // Fill the path. This filled shape will serve as the mask for the image.
    // Any opaque color works; 'black' is conventional.
    outputCtx.fillStyle = 'black'; 
    outputCtx.fill(); // Uses non-zero winding rule by default for complex polygons

    // 5. Use 'source-in' global composite operation.
    // This operation means the "new" drawing (the originalImg) will only be visible 
    // where it overlaps with the "existing" content (the filled polygon mask).
    // Effectively, the filled polygon becomes transparent, and the image is shown through it.
    outputCtx.globalCompositeOperation = 'source-in';

    // 6. Draw the original image onto the output canvas.
    // The image is drawn offset by (-minX, -minY). This aligns the
    // part of the original image corresponding to the polygon's bounding box
    // with the output canvas. The 'source-in' operation then performs the "crop".
    outputCtx.drawImage(originalImg, -minX, -minY, originalImg.width, originalImg.height);

    // 7. Reset globalCompositeOperation to default (optional, but good practice if context were reused).
    // outputCtx.globalCompositeOperation = 'source-over'; 

    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 Custom Polygon Cropper allows users to crop images into custom polygon shapes. By specifying the vertices of the polygon through a string of coordinates, users can create unique crop shapes beyond standard rectangles. This tool is particularly useful for graphic designers, artists, or anyone looking to create custom visuals for presentations, social media content, or other digital formats. If fewer than three points are provided, the tool defaults to cropping the image as a rectangle. The resulting cropped image is returned in a canvas format, ready for further use.

Leave a Reply

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

Other Image Tools:

Image Rule Of Thirds Grid Overlay Tool

Image Resizer for Social Media Platforms

Image Circular Crop Tool

Image Date Stamp Adder

Image Circular Guides Adder

Image Center Cropper

Image Petzval Lens Swirly Bokeh Effect Creator

Image Mimiya 645 Medium Format Filter Effect Tool

Photo Fujifilm Klasse W Filter Effect Application

Image Deardorff Large Format Filter Effect Application

Image Lomo LC-A Filter Effect Tool

Image Large Format Filter Effect Application

Image Zone Plate Lens Effect Creator

Photo Kodak Retina Filter Effect Tool

Image Polaroid 600 Filter Effect Tool

Photo Black and White Yellow Filter Effect Tool

Image Contax G2 Film Camera Render Effect Applicator

Image 110 Film Format Filter Effect Tool

Photo Jupiter-9 Portrait Lens Filter Effect

Image Fujifilm GW690 Texas Leica Filter Effect Application

Image Zeiss T* Coating Filter Effect Tool

Image Hoya R72 Infrared Filter Effect Tool

Image Filter Effect for Zeiss Ikon Contaflex

Photo Olympus Mju-II/Stylus Epic Filter Effect Tool

Image NiSi Nano IR ND Filter Effect Tool

Image Polaroid SX-70 Filter Effect Tool

Image Linhof Technika Filter Effect Tool

Image Lee Big Stopper 10-Stop ND Filter Effect Tool

Image Minolta X-700 Film Camera Render Effect Creator

Image ORWO UN54 Motion Picture Film Effect Applicator

Image Shen-Hao Large Format Filter Effect Tool

Image Impossible Project Polaroid Filter Effect Tool

Photo Foma Retropan 320 Film Filter Effect Tool

Image Fuji QuickSnap Disposable Filter Effect Application

Image 220 Film Format Filter Effect

Image Black and White with Green #61 Filter Effect Tool

See All →