You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, strokeSize = 20, strokeRatio = 0.4, strokeCountFactor = 10) {
const canvas = document.createElement('canvas');
const w = originalImg.width;
const h = originalImg.height;
// Handle cases where image might not be loaded or has zero dimensions
if (w === 0 || h === 0) {
canvas.width = w; // Potentially 0
canvas.height = h; // Potentially 0
// For a 0x0 canvas, nothing can be meaningfully drawn.
return canvas;
}
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
// Create a temporary canvas to get image data from the originalImg
const tempCanvas = document.createElement('canvas');
tempCanvas.width = w;
tempCanvas.height = h;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(originalImg, 0, 0, w, h);
let originalImageData;
try {
// This can throw a security error if the image is cross-origin and the canvas becomes tainted
originalImageData = tempCtx.getImageData(0, 0, w, h);
} catch (e) {
console.error("Error getting image data (likely cross-origin issue): ", e);
// Draw an error message on the canvas
ctx.fillStyle = '#CCCCCC'; // Light grey background
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = 'red';
// Adjust font size based on canvas size for better visibility
const fontSize = Math.max(12, Math.min(w, h) / 20);
ctx.font = `${fontSize}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const errorMessage1 = "Error processing image.";
const errorMessage2 = e.name === 'SecurityError' ? "Image may be cross-origin." : "Details in console.";
ctx.fillText(errorMessage1, w / 2, h / 2 - fontSize / 2);
ctx.fillText(errorMessage2, w / 2, h / 2 + fontSize / 2 + 5); // +5 for line spacing
return canvas;
}
const originalPixels = originalImageData.data;
// Fill the canvas with white. Palette knife strokes are opaque and will cover this.
// This ensures areas with few strokes still have a defined background.
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, w, h);
// Sanitize input parameters to ensure they are reasonable
const safeStrokeSize = Math.max(1, strokeSize);
const safeStrokeRatio = Math.max(0.01, Math.min(10, strokeRatio)); // Ratio usually between 0.1 and 1
const safeStrokeCountFactor = Math.max(0, strokeCountFactor);
// Calculate the number of strokes to draw
// Average area of a single stroke
const avgStrokeActualLength = safeStrokeSize; // Using safeStrokeSize as the primary dimension reference
const avgStrokeActualWidth = avgStrokeActualLength * safeStrokeRatio;
const avgStrokeArea = avgStrokeActualLength * avgStrokeActualWidth;
let numStrokes;
if (avgStrokeArea <= 0) { // Should not happen with safe parameters, but as a fallback
numStrokes = safeStrokeCountFactor > 0 ? 1 : 0;
} else {
const baseStrokesForFullCoverage = (w * h) / avgStrokeArea;
numStrokes = Math.floor(baseStrokesForFullCoverage * safeStrokeCountFactor);
}
// If strokeCountFactor is positive but numStrokes calculation resulted in 0 (e.g., very large strokesize for small image),
// ensure at least one stroke is drawn to show some effect.
if (safeStrokeCountFactor > 0 && numStrokes === 0) {
numStrokes = 1;
}
for (let i = 0; i < numStrokes; i++) {
// Pick a random central point for the stroke
const randX = Math.random() * w;
const randY = Math.random() * h;
// Determine the color for the stroke by sampling the original image at the stroke's center
// Clamp coordinates to be within image bounds for pixel sampling
const pickX = Math.min(Math.floor(randX), w - 1);
const pickY = Math.min(Math.floor(randY), h - 1);
const pixelIndex = (pickY * w + pickX) * 4; // Each pixel has 4 components (R,G,B,A)
const r = originalPixels[pixelIndex];
const g = originalPixels[pixelIndex + 1];
const b = originalPixels[pixelIndex + 2];
// Alpha component (originalPixels[pixelIndex + 3]) is ignored for opaque palette knife strokes
const color = `rgb(${r}, ${g}, ${b})`;
// Randomize stroke dimensions around the reference size and ratio
// Length varies from 0.75x to 1.25x of safeStrokeSize
const currentLength = safeStrokeSize * (0.75 + Math.random() * 0.5);
// Width is based on this length and strokeRatio, also with variation
const currentWidth = currentLength * safeStrokeRatio * (0.75 + Math.random() * 0.5);
// Ensure minimum dimensions for visibility
const finalLength = Math.max(1, currentLength);
const finalWidth = Math.max(1, currentWidth);
// Randomize stroke angle (0 to PI radians, as rectangles are symmetrical over 180 degrees)
const angle = Math.random() * Math.PI;
// Draw the stroke (a rotated rectangle)
ctx.save(); // Save current canvas state
ctx.translate(randX, randY); // Move canvas origin to the stroke's center
ctx.rotate(angle); // Rotate the canvas for the stroke
ctx.fillStyle = color; // Set the stroke color
// Draw the rectangle centered around the (now translated and rotated) origin
ctx.fillRect(-finalLength / 2, -finalWidth / 2, finalLength, finalWidth);
ctx.restore(); // Restore canvas state to before this stroke
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Palette Knife Filter Effect Tool allows users to apply a unique artistic effect to their images, simulating the appearance of palette knife strokes. This tool is particularly useful for artists, designers, and anyone looking to transform their digital images into stylized artworks. Typical use cases include creating visuals for social media, enhancing photos for creative projects, or generating unique textures for digital illustrations. Users can customize parameters such as stroke size, stroke ratio, and the number of strokes to tailor the effect to their liking, resulting in a diverse range of visual outcomes.