You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
shadowColorStr = "10,20,10",
baseGreenColorStr = "0,70,0",
lightGreenColorStr = "0,100,0",
traceColorStr = "170,130,40",
highlightColorStr = "192,192,192",
threshold1 = 50,
threshold2 = 100,
threshold3 = 150,
threshold4 = 200
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
// Create a small placeholder canvas indicating an issue with the input image
console.warn("Image has zero width or height. Returning a placeholder.");
canvas.width = 100;
canvas.height = 30;
ctx.fillStyle = '#FAA';
ctx.fillRect(0,0,canvas.width, canvas.height);
ctx.font = '10px Arial';
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.fillText('Invalid Image', canvas.width / 2, canvas.height / 2 + 4);
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
try {
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
} catch (e) {
// This can happen if the image isn't fully loaded or is invalid
console.error("Error drawing image to canvas: ", e);
ctx.fillStyle = '#FAA'; // Light red
ctx.fillRect(0,0,canvas.width, canvas.height);
ctx.font = '16px Arial';
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.fillText('Error drawing image.', canvas.width / 2, canvas.height / 2);
return canvas;
}
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
// This is common due to tainted canvas (CORS issues if image is from another domain)
console.error("Could not get image data (CORS issue?): ", e);
// Draw an error message on the canvas
ctx.fillStyle = 'rgba(128, 128, 128, 0.8)'; // Semi-transparent grey
ctx.fillRect(0,0,canvas.width, canvas.height);
ctx.font = Math.min(24, canvas.width / 10) + 'px Arial';
ctx.fillStyle = 'white';
ctx.textAlign = 'center';
const message = 'Error: Cannot process image.';
const message2 = '(Possibly CORS issue)';
ctx.fillText(message, canvas.width / 2, canvas.height / 2 - 10);
ctx.fillText(message2, canvas.width / 2, canvas.height / 2 + 20);
return canvas;
}
const data = imageData.data;
const parseColor = (colorStr, defaultColor = [0, 0, 0]) => {
try {
const parts = colorStr.split(',').map(s => parseInt(s.trim(), 10));
if (parts.length === 3 && parts.every(p => !isNaN(p) && p >= 0 && p <= 255)) {
return parts;
}
} catch (ex) {
// Error during parsing
}
console.warn(`Invalid color string: "${colorStr}". Defaulting to [${defaultColor.join(',')}].`);
return defaultColor;
};
const shadowColor = parseColor(shadowColorStr, [10,20,10]);
const baseGreenColor = parseColor(baseGreenColorStr, [0,70,0]);
const lightGreenColor = parseColor(lightGreenColorStr, [0,100,0]);
const traceColor = parseColor(traceColorStr, [170,130,40]);
const highlightColor = parseColor(highlightColorStr, [192,192,192]);
const parseNumericThreshold = (val, defaultValue) => {
const num = Number(val);
return isNaN(num) ? defaultValue : num;
};
// Thresholds define the upper boundary (exclusive) of each brightness band.
// t1 (shadows) < t2 (baseGreen) < t3 (lightGreen) < t4 (traces) < 255 (highlights)
let th1 = parseNumericThreshold(threshold1, 50);
let th2 = parseNumericThreshold(threshold2, 100);
let th3 = parseNumericThreshold(threshold3, 150);
let th4 = parseNumericThreshold(threshold4, 200);
// Ensure thresholds are sorted and within [0, 255] range
const sortedThresholds = [th1, th2, th3, th4]
.map(t => Math.max(0, Math.min(255, t))) // Clamp each threshold
.sort((a, b) => a - b); // Sort them
// Remove duplicates that might arise from clamping or identical inputs
const uniqueSortedThresholds = [...new Set(sortedThresholds)];
// Assign to t1-t4; if fewer than 4 unique thresholds, some color bands might be skipped.
const t_eff = [0,0,0,0]; // effective thresholds
for(let i=0; i<4; i++) {
t_eff[i] = uniqueSortedThresholds[i] !== undefined ? uniqueSortedThresholds[i] : (i > 0 ? t_eff[i-1] : 0);
if (i > 0 && t_eff[i] < t_eff[i-1]) t_eff[i] = t_eff[i-1]; // ensure non-decreasing
}
[th1, th2, th3, th4] = t_eff;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const avg = (r + g + b) / 3; // Brightness (0-255)
let newR, newG, newB;
if (avg < th1) {
[newR, newG, newB] = shadowColor;
} else if (avg < th2) {
[newR, newG, newB] = baseGreenColor;
} else if (avg < th3) {
[newR, newG, newB] = lightGreenColor;
} else if (avg < th4) {
[newR, newG, newB] = traceColor;
} else {
[newR, newG, newB] = highlightColor;
}
data[i] = newR;
data[i + 1] = newG;
data[i + 2] = newB;
// Alpha channel (data[i + 3]) is preserved
}
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Apply Changes