You can edit the below JavaScript code to customize the image tool.
async function processImage(
originalImg,
numContrails = 3,
contrailColorRGB = "255,255,255",
contrailOpacity = 0.7,
maxThickness = 8,
minThickness = 2,
blurStrength = 15
) {
// Helper function to generate random points on the perimeter of an "extended" version of the image canvas.
// The "extended" canvas is larger than the actual image by a margin on all sides.
// This ensures that contrails appear to originate and terminate off-screen, crossing the entire image.
function getRandomPointOnExtendedEdge(W, H, margin) {
const side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
let x, y;
// Calculate dimensions of the effectively larger area from which points are chosen.
// Points can be on segments from (-margin, -margin) to (W+margin, H+margin).
const extendedW = W + 2 * margin; // Full width of the extended area for random selection along an edge
const extendedH = H + 2 * margin; // Full height of the extended area
switch (side) {
case 0: // Point on the top extended edge
x = Math.random() * extendedW - margin; // x coordinate from -margin to W+margin
y = -margin; // y coordinate fixed at -margin (top edge of extended box)
break;
case 1: // Point on the right extended edge
x = W + margin; // x coordinate fixed at W+margin (right edge of extended box)
y = Math.random() * extendedH - margin; // y coordinate from -margin to H+margin
break;
case 2: // Point on the bottom extended edge
x = Math.random() * extendedW - margin;
y = H + margin; // y coordinate fixed at H+margin (bottom edge of extended box)
break;
case 3: // Point on the left extended edge
x = -margin; // x coordinate fixed at -margin (left edge of extended box)
y = Math.random() * extendedH - margin;
break;
}
return { x, y, side }; // Return coordinates and the side chosen
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const W = originalImg.naturalWidth || originalImg.width;
const H = originalImg.naturalHeight || originalImg.height;
canvas.width = W;
canvas.height = H;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, W, H);
// --- Parameter Validation and Sanitization ---
// Validate and parse contrailColorRGB parameter (e.g., "255,0,0" for red)
let r = 255, g = 255, b = 255; // Default to white color
if (typeof contrailColorRGB === 'string') {
const parts = contrailColorRGB.split(',').map(c => parseInt(c.trim(), 10));
if (parts.length === 3 && parts.every(val => !isNaN(val) && val >= 0 && val <= 255)) {
[r, g, b] = parts;
} else {
console.warn(`Invalid contrailColorRGB string: "${contrailColorRGB}". Using default white (255,255,255).`);
}
} else {
console.warn(`contrailColorRGB is not a string: ${contrailColorRGB}. Using default white (255,255,255).`);
}
// Validate contrailOpacity parameter (0.0 to 1.0)
let finalOpacity = parseFloat(contrailOpacity);
if (isNaN(finalOpacity) || finalOpacity < 0 || finalOpacity > 1) {
console.warn(`Invalid contrailOpacity: ${contrailOpacity}. Must be a number between 0 and 1. Using default 0.7.`);
finalOpacity = 0.7;
}
const finalContrailColor = `rgba(${r}, ${g}, ${b}, ${finalOpacity})`;
// Ensure blurStrength is a non-negative number
const actualBlurStrength = Math.max(0, parseFloat(blurStrength) || 0);
// Validate and order thickness parameters, ensuring they are non-negative numbers
// parseFloat will handle string inputs like "5" or "5px" (becomes 5 for "5px")
// Default to 0 if parsing fails (e.g. "abc" string)
let parsedMinThickness = parseFloat(minThickness) || 0;
let parsedMaxThickness = parseFloat(maxThickness) || 0;
let mThick = Math.min(parsedMinThickness, parsedMaxThickness);
let MThick = Math.max(parsedMinThickness, parsedMaxThickness);
if (mThick < 0) mThick = 0;
if (MThick < 0) MThick = 0; // MThick is guaranteed >= mThick, so this checks if both were negative.
// Validate number of contrails (must be a non-negative integer)
const numContrailsToDraw = Math.max(0, parseInt(numContrails, 10) || 0);
// --- Contrail Drawing Loop ---
for (let i = 0; i < numContrailsToDraw; i++) {
// Determine random thickness for the current contrail's core line, within the mThick-MThick range
const currentThickness = (MThick === mThick) ? mThick : (Math.random() * (MThick - mThick) + mThick);
// Define a margin around the canvas. Contrail start/end points will be on the edge of this margin.
// This ensures the blur and line caps of contrails don't abruptly start/end visibly on the canvas.
// The margin size depends on blur strength and maximum possible line thickness.
const margin = actualBlurStrength + MThick;
// Get a random starting point (P1) on one of the extended edges
const P1_info = getRandomPointOnExtendedEdge(W, H, margin);
let P2_info;
// Get a random ending point (P2) on an extended edge.
// The do-while loop ensures P2 is on a different "axis group" (horizontal vs. vertical edges) than P1.
// This strategy promotes contrails that generally cross the image diagonally, rather than short lines
// or lines that might run parallel and close to an edge.
// (side % 2 === 0 for top/bottom edges, side % 2 === 1 for left/right edges)
do {
P2_info = getRandomPointOnExtendedEdge(W, H, margin);
} while (P2_info.side % 2 === P1_info.side % 2);
const x1 = P1_info.x;
const y1 = P1_info.y;
const x2 = P2_info.x;
const y2 = P2_info.y;
// Apply shadow for the blurred part of the contrail (the main visual effect)
ctx.shadowColor = finalContrailColor; // The color of the glow/blur (includes opacity)
ctx.shadowBlur = actualBlurStrength; // How much blur (diffusion)
// Draw the core line of the contrail
// This line itself will be blurred due to the shadow effect.
// Its color can be the same as the shadow to reinforce the center of the blurred area.
ctx.strokeStyle = finalContrailColor;
ctx.lineWidth = currentThickness; // Thickness of the core line segment
ctx.lineCap = 'round'; // Creates soft, rounded ends for the line segment itself
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
// Reset shadow properties after drawing each contrail.
// This prevents the shadow settings from affecting subsequent drawing operations
// (e.g., other contrails in this loop, or any drawing done on the canvas afterwards).
ctx.shadowColor = 'transparent'; // Effectively 'rgba(0,0,0,0)'
ctx.shadowBlur = 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 Airplane Contrail Filter Effect Tool allows users to apply a visually striking airplane contrail effect to their images. Users can customize various parameters such as the number of contrails, their color, opacity, thickness, and blur strength, resulting in unique artistic renditions of their photos. This tool is ideal for graphic designers, digital artists, or anyone looking to enhance images for creative projects, social media posts, or personalized gifts. The contrails add a dynamic, sky-like flair, making images stand out.