You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, threshold = 30, outlineColor = "black", fillColor = "transparent") {
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
console.error("Image has zero width or height.");
const errCanvas = document.createElement('canvas');
// Ensure minimum visible size for the error message canvas
errCanvas.width = Math.max(150, width || 150);
errCanvas.height = Math.max(50, height || 50);
const errCtx = errCanvas.getContext('2d');
if (errCtx) {
errCtx.fillStyle = "#f0f0f0"; // Light gray background for error message
errCtx.fillRect(0,0, errCanvas.width, errCanvas.height);
errCtx.font = "12px Arial";
errCtx.fillStyle = "red";
errCtx.textAlign = "center";
errCtx.textBaseline = "middle";
errCtx.fillText("Error: Image is empty.", errCanvas.width / 2, errCanvas.height / 2);
}
return errCanvas;
}
const workingCanvas = document.createElement('canvas');
workingCanvas.width = width;
workingCanvas.height = height;
// Use willReadFrequently hint for potential performance improvement with getImageData
const workingCtx = workingCanvas.getContext('2d', { willReadFrequently: true });
if (!workingCtx) {
console.error("Failed to get 2D context for working canvas.");
// Fallback: return a simple canvas indicating context failure.
// Drawing the original image might not be possible if context creation failed.
const errCanvas = document.createElement('canvas');
errCanvas.width = width;
errCanvas.height = height;
// Optionally, try to draw a text message here too if context can be obtained for errCanvas
return errCanvas;
}
workingCtx.drawImage(originalImg, 0, 0, width, height);
let imageData;
try {
imageData = workingCtx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Error getting image data (CORS issue likely):", e);
const errorCanvas = document.createElement('canvas');
errorCanvas.width = width;
errorCanvas.height = height;
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
errCtx.drawImage(originalImg, 0, 0); // Draw original image as fallback
// Style for error text overlay
errCtx.font = "bold 14px Arial";
errCtx.textAlign = "center";
errCtx.textBaseline = "middle";
const text = "Processing Error (CORS?). Original shown.";
// Measure text to draw a semi-transparent background for better readability
const textMetrics = errCtx.measureText(text);
// Ensure textMetrics properties are numbers, provide fallbacks
const textAscent = typeof textMetrics.actualBoundingBoxAscent === 'number' ? textMetrics.actualBoundingBoxAscent : 14;
const textDescent = typeof textMetrics.actualBoundingBoxDescent === 'number' ? textMetrics.actualBoundingBoxDescent : 4;
const textWidthPadding = textMetrics.width + 20;
const textHeightPadding = textAscent + textDescent + 10;
// Draw semi-transparent background for the text
errCtx.fillStyle = "rgba(0, 0, 0, 0.6)";
errCtx.fillRect((width - textWidthPadding) / 2, (height - textHeightPadding) / 2, textWidthPadding, textHeightPadding);
// Draw the error text
errCtx.fillStyle = "white";
errCtx.fillText(text, width / 2, height / 2);
}
return errorCanvas;
}
const data = imageData.data;
const outputCanvas = document.createElement('canvas');
outputCanvas.width = width;
outputCanvas.height = height;
const outputCtx = outputCanvas.getContext('2d');
if (!outputCtx){
console.error("Failed to get 2D context for output canvas.");
// Return the workingCanvas which has the original image drawn on it.
// This is a reasonable fallback as it contains the original unfilterd image content.
return workingCanvas;
}
// Fill the output canvas with the specified fill color.
// "transparent" is a valid CSS color string that results in rgba(0,0,0,0).
outputCtx.fillStyle = fillColor;
outputCtx.fillRect(0, 0, width, height);
// Set the fill style for drawing the outlines
outputCtx.fillStyle = outlineColor;
function getLuminance(r, g, b) {
// Standard luminance calculation
return 0.299 * r + 0.587 * g + 0.114 * b;
}
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const idx = (y * width + x) * 4;
const r = data[idx];
const g = data[idx+1];
const b = data[idx+2];
// Alpha component (data[idx+3]) is not used in luminance calculation
const lumCurrent = getLuminance(r, g, b);
// Luminance of the pixel to the right
let lumRight = lumCurrent; // Default to current pixel's luminance if at the right edge
if (x < width - 1) {
const idxRight = (y * width + (x + 1)) * 4;
lumRight = getLuminance(data[idxRight], data[idxRight+1], data[idxRight+2]);
}
// Luminance of the pixel below
let lumBottom = lumCurrent; // Default to current pixel's luminance if at the bottom edge
if (y < height - 1) {
const idxBottom = ((y + 1) * width + x) * 4;
lumBottom = getLuminance(data[idxBottom], data[idxBottom+1], data[idxBottom+2]);
}
// Calculate the difference in luminance
const deltaX = Math.abs(lumCurrent - lumRight);
const deltaY = Math.abs(lumCurrent - lumBottom);
// Magnitude of the gradient (using Manhattan distance for simplicity and speed)
const magnitude = deltaX + deltaY;
if (magnitude > threshold) {
// This pixel is considered part of an edge, draw it with outlineColor
outputCtx.fillRect(x, y, 1, 1);
}
}
}
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Outline Filter Tool allows users to enhance images by applying an outline effect based on luminance differences. By adjusting a customizable threshold, users can emphasize the edges of subjects in photos, making them stand out. This tool is particularly useful for graphic designers, artists, and hobbyists looking to highlight features in images or prepare graphics for presentations and social media. Options for outline color and fill color provide further control over the visual output, enabling creative experimentation with image aesthetics.