You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, threshold = 220, numSpikes = 4, baseSpikeLength = 30, spikeThickness = 1.5, spikeColor = "rgba(255, 255, 230, 0.6)", sampleRate = 1) {
// Sanitize numeric parameters
threshold = Math.max(0, Math.min(255, Number(threshold)));
numSpikes = Math.max(0, Math.floor(Number(numSpikes)));
baseSpikeLength = Math.max(0, Number(baseSpikeLength));
spikeThickness = Math.max(0.1, Number(spikeThickness)); // Minimum thickness of 0.1
sampleRate = Math.max(1, Math.floor(Number(sampleRate)));
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Create a temporary canvas to get image data
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);
let imageData;
try {
imageData = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error getting image data (CORS issue?):", e);
// Fallback: return a canvas with the original image and an error message
const errorCanvas = document.createElement('canvas');
errorCanvas.width = imgWidth;
errorCanvas.height = imgHeight;
const errorCtx = errorCanvas.getContext('2d');
errorCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
errorCtx.font = "bold 16px Arial";
errorCtx.fillStyle = "red";
errorCtx.textAlign = "center";
errorCtx.fillText("Error: Could not process image data.", imgWidth / 2, imgHeight / 2);
return errorCanvas;
}
const data = imageData.data;
// Create the output canvas
const outputCanvas = document.createElement('canvas');
outputCanvas.width = imgWidth;
outputCanvas.height = imgHeight;
const ctx = outputCanvas.getContext('2d');
// Draw the original image onto the output canvas
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// If no spikes to draw, or no length, return early
if (numSpikes === 0 || baseSpikeLength === 0) {
return outputCanvas;
}
// Set spike drawing properties
ctx.strokeStyle = spikeColor;
ctx.lineWidth = spikeThickness;
ctx.lineCap = 'round'; // For softer spike ends
const angleStep = (Math.PI * 2) / numSpikes;
// Iterate through pixels (with sampling)
for (let y = 0; y < imgHeight; y += sampleRate) {
for (let x = 0; x < imgWidth; x += sampleRate) {
const i = (y * imgWidth + x) * 4; // Calculate index in pixel array
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// const a = data[i+3]; // Alpha not used for luminance calculation
// Simple luminance calculation
const luminance = (r + g + b) / 3;
if (luminance > threshold) {
const centerX = x + 0.5; // Center of the (sampled) pixel
const centerY = y + 0.5;
// Modulate spike length by how much luminance exceeds threshold
let lengthFactor = 1.0;
const denominator = 255 - threshold;
if (denominator > 0) { // Avoid division by zero if threshold is 255
lengthFactor = (luminance - threshold) / denominator;
}
// Clamp lengthFactor to [0, 1] in case luminance somehow exceeds 255 or threshold is tricky
lengthFactor = Math.min(1.0, Math.max(0.0, lengthFactor));
const minLengthFactor = 0.3; // Spikes are at least 30% of baseSpikeLength
const dynamicSpikeLength = baseSpikeLength * (minLengthFactor + (1 - minLengthFactor) * lengthFactor);
if (dynamicSpikeLength <= 0) continue; // No need to draw if no length
for (let k = 0; k < numSpikes; k++) {
const currentAngle = k * angleStep;
const endX = centerX + dynamicSpikeLength * Math.cos(currentAngle);
const endY = centerY + dynamicSpikeLength * Math.sin(currentAngle);
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
}
}
}
return outputCanvas;
}
Apply Changes