Please bookmark this page to avoid losing your image tool!

Image Paper Cut Filter

(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, colorLevels = 4, outlineColorStr = "black", outlineThickness = 2, shadowOffset = 2, shadowColorStr = "rgba(0,0,0,0.3)") {
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    if (width === 0 || height === 0) {
        console.error("Image has zero dimensions. Ensure it is loaded correctly before processing.");
        const errCanvas = document.createElement('canvas');
        errCanvas.width = 1; 
        errCanvas.height = 1;
        return errCanvas; // Return a minimal canvas
    }

    // Ensure colorLevels is an integer and at least 2
    const numLevels = Math.max(2, parseInt(colorLevels, 10) || 2);

    // Output canvas
    const outCanvas = document.createElement('canvas');
    outCanvas.width = width;
    outCanvas.height = height;
    const outCtx = outCanvas.getContext('2d');

    if (!outCtx) {
        console.error("Could not get 2D context for the output canvas.");
        return document.createElement('canvas'); // Return an empty canvas
    }

    // Temporary canvas for posterization
    const postCanvas = document.createElement('canvas');
    postCanvas.width = width;
    postCanvas.height = height;
    const postCtx = postCanvas.getContext('2d');

    if (!postCtx) {
        console.error("Could not get 2D context for the posterization canvas.");
        // Fallback: draw original image on outCanvas and return
        outCtx.drawImage(originalImg, 0, 0, width, height);
        return outCanvas;
    }

    postCtx.drawImage(originalImg, 0, 0, width, height);
    
    let imageData;
    try {
        imageData = postCtx.getImageData(0, 0, width, height);
    } catch (e) {
        console.error("Could not get image data. This might be due to cross-origin restrictions if the image is not hosted on the same domain or if appropriate CORP/CORS headers are not set.", e);
        // Fallback: draw original image and return
        outCtx.drawImage(originalImg, 0, 0, width, height);
        return outCanvas;
    }
    
    const data = imageData.data;
    const factor = 255 / (numLevels - 1);

    for (let i = 0; i < data.length; i += 4) {
        data[i]     = Math.round(data[i] / factor) * factor;     // R
        data[i+1]   = Math.round(data[i+1] / factor) * factor; // G
        data[i+2]   = Math.round(data[i+2] / factor) * factor; // B
        // Alpha (data[i+3]) is preserved
    }
    postCtx.putImageData(imageData, 0, 0); // postCanvas now holds the posterized image

    // 1. Draw Shadow Layer
    const sOffset = parseFloat(shadowOffset);
    if (sOffset > 0) {
        const shadowCanvas = document.createElement('canvas');
        shadowCanvas.width = width;
        shadowCanvas.height = height;
        const shadowCtx = shadowCanvas.getContext('2d');
        
        if (shadowCtx) {
            shadowCtx.drawImage(postCanvas, 0, 0); // Draw posterized image (with its alpha)
            shadowCtx.globalCompositeOperation = 'source-in'; // Keep existing alpha, fill color
            shadowCtx.fillStyle = shadowColorStr;
            shadowCtx.fillRect(0, 0, width, height);
            
            // Draw this shadow silhouette offset on the output canvas
            outCtx.drawImage(shadowCanvas, sOffset, sOffset);
            // Reset composite operation for outCtx is not needed as it was not set on outCtx
        } else {
            console.warn("Could not create shadow canvas context. Skipping shadow.");
        }
    }

    // 2. Draw Outline Layer
    const oThickness = parseFloat(outlineThickness);
    if (oThickness > 0) {
        const outlineShapeCanvas = document.createElement('canvas');
        outlineShapeCanvas.width = width;
        outlineShapeCanvas.height = height;
        const outlineShapeCtx = outlineShapeCanvas.getContext('2d');

        if (outlineShapeCtx) {
            outlineShapeCtx.drawImage(postCanvas, 0, 0); // Posterized image (with its alpha)
            outlineShapeCtx.globalCompositeOperation = 'source-in'; // Keep existing alpha, fill color
            outlineShapeCtx.fillStyle = outlineColorStr;
            outlineShapeCtx.fillRect(0, 0, width, height); 
            // outlineShapeCanvas now contains the posterized shapes, filled with outlineColorStr, preserving alpha

            // Define offsets for drawing the outline shape to create thickness
            const directions = [
                [-oThickness, -oThickness], [0, -oThickness], [oThickness, -oThickness],
                [-oThickness, 0],                             [oThickness, 0],
                [-oThickness, oThickness], [0, oThickness], [oThickness, oThickness]
            ];

            for (const [dx, dy] of directions) {
                outCtx.drawImage(outlineShapeCanvas, dx, dy);
            }
        } else {
            console.warn("Could not create outline shape canvas context. Skipping outlines.");
        }
    }

    // 3. Draw Main Posterized Image on top
    // This will draw the colored posterized image over the shadow and outlines
    outCtx.drawImage(postCanvas, 0, 0);

    return outCanvas;
}

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 Paper Cut Filter applies a creative effect to your images, transforming them into stylized paper cut designs. By posterizing the image into a specified number of color levels, the tool enhances the visual appeal while allowing users to customize outline color, thickness, and shadow effects. This filter is ideal for creating unique artwork, social media graphics, or personalized gifts by adding a handcrafted look to digital images. Whether for professional design projects or personal use, this tool offers a simple way to enhance visual content.

Leave a Reply

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