You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, strength = 1.0, direction = "top-left") {
const canvas = document.createElement('canvas');
// Use willReadFrequently for potential performance gain with multiple getImageData/putImageData calls
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Ensure the originalImg is loaded, otherwise width/height might be 0.
// For this function's contract, we assume originalImg is a loaded Image object.
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
console.error("Image has zero dimensions. Ensure it is loaded.");
// Return an empty or error canvas
canvas.width = 100; // Default small size
canvas.height = 50;
ctx.font = "12px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("Error: Image not loaded or zero dimensions.", canvas.width / 2, canvas.height / 2);
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let imageData;
try {
imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error getting image data for Welded Seam effect: ", e);
// In case of error (e.g. tainted canvas from cross-origin image), return a canvas with an error message.
ctx.clearRect(0,0,canvas.width, canvas.height); // Clear previous drawImage
ctx.font = "14px Arial";
ctx.fillStyle = "black"; // Use black for visibility on typical white backgrounds
ctx.textAlign = "center";
const message = e.name === 'SecurityError' ? "Error: Cannot process cross-origin image." : "Error: Could not get image data.";
ctx.fillText(message, canvas.width / 2, canvas.height / 2, canvas.width * 0.9); // Add max width for text
return canvas;
}
const data = imageData.data;
const width = imgWidth;
const height = imgHeight;
const originalAlpha = new Uint8Array(width * height); // Store original alpha values
const grayData = new Float32Array(width * height); // Store grayscale values with precision
// 1. Convert image to grayscale and store original alpha values
// Using Rec. 709 luma coefficients for grayscale conversion (common for digital displays).
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const alpha = data[i + 3];
const grayVal = 0.2126 * r + 0.7152 * g + 0.0722 * b;
const pixelIndex = i / 4;
grayData[pixelIndex] = grayVal;
originalAlpha[pixelIndex] = alpha;
}
// Determine displacement (dx, dy) for sampling based on 'direction' parameter.
// This displacement simulates a light source: dx, dy define the offset for sampling.
// Light is effectively from the direction (-dx, -dy).
// E.g., if dx=1, dy=1, light comes from top-left.
let dx = 0, dy = 0;
switch (String(direction).toLowerCase()) { // Ensure direction is treated as a string
case "top": dx = 0; dy = 1; break;
case "top-right": dx = -1; dy = 1; break;
case "left": dx = 1; dy = 0; break;
case "right": dx = -1; dy = 0; break;
case "bottom-left": dx = 1; dy = -1; break;
case "bottom": dx = 0; dy = -1; break;
case "bottom-right":dx = -1; dy = -1; break;
case "top-left": // Default direction
default: dx = 1; dy = 1; break;
}
// Helper function to get a grayscale value from grayData, handling image boundaries by clamping coordinates.
function getGrayClamped(x, y, sourceGrayData, w, h) {
const clampedX = Math.max(0, Math.min(w - 1, x));
const clampedY = Math.max(0, Math.min(h - 1, y));
return sourceGrayData[clampedY * w + clampedX];
}
// 2. Apply the emboss-like effect (welded seam)
// This iterates through each pixel, calculating its new value based on neighbors.
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// Sample two points: val_a from "uphill" (towards light), val_b from "downhill" (away from light).
const val_a = getGrayClamped(x - dx, y - dy, grayData, width, height);
const val_b = getGrayClamped(x + dx, y + dy, grayData, width, height);
// Calculate the difference, scale by strength, and offset by 128 (mid-gray).
// Ensure 'strength' is treated as a number.
let finalPixelVal = 128 + (val_a - val_b) * Number(strength);
// Clamp the final pixel value to the 0-255 range for RGB channels.
finalPixelVal = Math.max(0, Math.min(255, finalPixelVal));
const dataIndex = (y * width + x) * 4;
data[dataIndex] = finalPixelVal; // Red channel
data[dataIndex + 1] = finalPixelVal; // Green channel
data[dataIndex + 2] = finalPixelVal; // Blue channel
// Restore the original alpha value for the pixel.
data[dataIndex + 3] = originalAlpha[dataIndex / 4];
}
}
// Put the modified pixel data back onto the canvas.
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Welded Seam Filter Effect Application allows users to apply an artistic effect simulating a welded seam look to their images. By processing images through a canvas, the tool utilizes grayscale values and directional sampling to create a visually striking, embossed effect. This effect can enhance the texture of images for creative projects, such as graphic design, digital art, or personal photography enhancement. Users can adjust parameters like strength and direction of the light source to customize the final appearance of the effect.