You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Converts an image into a "contemporary shape drawing" by sampling the image colors
* and redrawing it using a collection of geometric shapes.
*
* @param {Image} originalImg The original source image object.
* @param {number} [shapeSize=20] The base size of the shapes in pixels.
* @param {number} [strokeWidth=1] The width of the outline for each shape. Set to 0 for no outline.
* @param {string} [strokeColor='rgba(0,0,0,0.5)'] The color of the shape outlines.
* @param {string} [backgroundColor='white'] The background color of the output canvas.
* @param {string} [shapeTypes='circle,triangle,rectangle'] A comma-separated string of shapes to use. Options: 'circle', 'triangle', 'rectangle'.
* @param {number} [randomness=10] A factor controlling the randomness of shape placement and size. Higher values increase randomness.
* @returns {HTMLCanvasElement} A canvas element with the generated drawing.
*/
function processImage(originalImg, shapeSize = 20, strokeWidth = 1, strokeColor = 'rgba(0,0,0,0.5)', backgroundColor = 'white', shapeTypes = 'circle,triangle,rectangle', randomness = 10) {
// --- Helper function to draw a circle centered at (x, y) ---
const drawCircle = (ctx, x, y, radius) => {
ctx.beginPath();
ctx.arc(x, y, Math.abs(radius), 0, Math.PI * 2);
ctx.closePath();
if (ctx.fillStyle !== 'transparent') ctx.fill();
if (ctx.lineWidth > 0) ctx.stroke();
};
// --- Helper function to draw a rectangle centered at (x, y) ---
const drawRectangle = (ctx, x, y, width, height) => {
const startX = x - width / 2;
const startY = y - height / 2;
ctx.beginPath();
ctx.rect(startX, startY, width, height);
ctx.closePath();
if (ctx.fillStyle !== 'transparent') ctx.fill();
if (ctx.lineWidth > 0) ctx.stroke();
};
// --- Helper function to draw a rotated equilateral triangle centered at (x, y) ---
const drawTriangle = (ctx, x, y, size) => {
const h = size * (Math.sqrt(3) / 2); // Height of the equilateral triangle
const angle = Math.random() * Math.PI * 2; // Random rotation angle
// Vertices relative to the center (0,0) before rotation
const p1 = { x: 0, y: -h * 2 / 3 };
const p2 = { x: -size / 2, y: h / 3 };
const p3 = { x: size / 2, y: h / 3 };
// Rotation formula: x' = x*cos(a) - y*sin(a), y' = x*sin(a) + y*cos(a)
const rotate = (p, a) => ({
x: p.x * Math.cos(a) - p.y * Math.sin(a),
y: p.x * Math.sin(a) + p.y * Math.cos(a)
});
const r1 = rotate(p1, angle);
const r2 = rotate(p2, angle);
const r3 = rotate(p3, angle);
ctx.beginPath();
ctx.moveTo(x + r1.x, y + r1.y);
ctx.lineTo(x + r2.x, y + r2.y);
ctx.lineTo(x + r3.x, y + r3.y);
ctx.closePath();
if (ctx.fillStyle !== 'transparent') ctx.fill();
if (ctx.lineWidth > 0) ctx.stroke();
};
// 1. Setup final canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
// 2. Get pixel data from the original image
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = w;
tempCanvas.height = h;
tempCtx.drawImage(originalImg, 0, 0, w, h);
const imageData = tempCtx.getImageData(0, 0, w, h);
const data = imageData.data;
// 3. Draw background
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, w, h);
// 4. Prepare for drawing
const availableShapes = shapeTypes.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
if (availableShapes.length === 0) {
return canvas; // Return empty canvas if no valid shapes are provided
}
const step = Math.max(1, Math.floor(shapeSize));
// 5. Iterate over the image in steps to sample colors and draw shapes
for (let y = 0; y < h; y += step) {
for (let x = 0; x < w; x += step) {
const index = (y * w + x) * 4;
const r = data[index];
const g = data[index + 1];
const b = data[index + 2];
const a = data[index + 3];
// Skip transparent pixels
if (a === 0) continue;
const color = `rgba(${r},${g},${b},${a / 255})`;
// Choose a random shape from the provided list
const shape = availableShapes[Math.floor(Math.random() * availableShapes.length)];
// Calculate randomized properties for the shape
const posOffsetX = (Math.random() - 0.5) * randomness;
const posOffsetY = (Math.random() - 0.5) * randomness;
const centerX = x + posOffsetX;
const centerY = y + posOffsetY;
// Size variation based on randomness parameter (e.g., randomness=10 -> +/-10% size)
const sizeVariation = (Math.random() - 0.5) * (randomness / 50);
const currentSize = shapeSize * (1 + sizeVariation);
// Set drawing styles
ctx.fillStyle = color;
ctx.strokeStyle = strokeColor;
ctx.lineWidth = strokeWidth;
// Draw the chosen shape
switch (shape) {
case 'circle':
drawCircle(ctx, centerX, centerY, currentSize / 2);
break;
case 'rectangle':
drawRectangle(ctx, centerX, centerY, currentSize, currentSize);
break;
case 'triangle':
drawTriangle(ctx, centerX, centerY, currentSize);
break;
}
}
}
// 6. Return the final canvas
return canvas;
}
Apply Changes