You can edit the below JavaScript code to customize the image tool.
Apply Changes
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;
}
Apply Changes