You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
bgColor = "#283593", // Indigo-like blue for background
lineColor = "#E1F5FE", // Light Cyan for lines
lineThreshold = 80, // 0-255; defines how dark original part (after inversion) becomes a line
enableGrid = "true",
gridSpacing = 30, // Pixels
gridColor = "rgba(176,190,197,0.2)", // Faint Blue Grey for grid
enableBorder = "true",
borderWidth = 5, // Pixels for border stroke
borderColor = "#B0BEC5", // Blue Grey for border lines
borderTextColor = "#CFD8DC", // Lighter Blue Grey for text in border
enableVignette = "true",
vignetteIntensity = 0.6 // 0-1; controls darkness of vignette edges
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
canvas.width = width;
canvas.height = height;
// Parse string "true"/"false" to boolean
const E_GRID = String(enableGrid).toLowerCase() === "true";
const E_BORDER = String(enableBorder).toLowerCase() === "true";
const E_VIGNETTE = String(enableVignette).toLowerCase() === "true";
// Convert numeric parameters from string if necessary, or use as number
const numLineThreshold = parseFloat(lineThreshold);
const numGridSpacing = parseFloat(gridSpacing);
const numBorderWidth = parseFloat(borderWidth);
const numVignetteIntensity = parseFloat(vignetteIntensity);
// 1. Fill Background Color
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, width, height);
// 2. Draw Grid Lines (if enabled)
if (E_GRID && numGridSpacing > 0) {
ctx.strokeStyle = gridColor;
ctx.lineWidth = 1; // Grid lines are thin
for (let x = numGridSpacing; x < width; x += numGridSpacing) {
ctx.beginPath();
ctx.moveTo(x + 0.5, 0); // +0.5 for sharper lines
ctx.lineTo(x + 0.5, height);
ctx.stroke();
}
for (let y = numGridSpacing; y < height; y += numGridSpacing) {
ctx.beginPath();
ctx.moveTo(0, y + 0.5);
ctx.lineTo(width, y + 0.5);
ctx.stroke();
}
}
// 3. Draw Processed Image Lines
// Use a temporary canvas to draw the original image and access its pixel data
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); // Important for getImageData performance
tempCtx.drawImage(originalImg, 0, 0, width, height);
const imgData = tempCtx.getImageData(0, 0, width, height);
const pixels = imgData.data;
ctx.fillStyle = lineColor; // Set fill style for the blueprint lines
for (let i = 0; i < pixels.length; i += 4) {
const r = pixels[i];
const g = pixels[i + 1];
const b = pixels[i + 2];
const a = pixels[i + 3];
if (a < 128) { // Skip transparent or mostly transparent pixels from original
continue;
}
// Convert pixel to grayscale
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
// Invert grayscale (darker original parts become lighter in inverted scale)
const invertedGray = 255 - gray;
// If inverted gray value is above threshold, draw it as part of the "line"
if (invertedGray > numLineThreshold) {
const x = (i / 4) % width;
const y = Math.floor((i / 4) / width);
ctx.fillRect(x, y, 1, 1); // Draw a 1x1 pixel for the line
}
}
// 4. Draw Border and Title Block (if enabled)
if (E_BORDER && numBorderWidth > 0) {
ctx.strokeStyle = borderColor;
ctx.lineWidth = numBorderWidth;
const bwHalf = numBorderWidth / 2;
// Outer border rectangle
ctx.strokeRect(bwHalf, bwHalf, width - numBorderWidth, height - numBorderWidth);
// Simple title block area at the bottom
const titleBlockHeight = Math.min(80, Math.max(40, height * 0.15)); // Responsive height
const titleBlockY = height - titleBlockHeight - bwHalf;
// Draw dividing line for title block from main content
ctx.beginPath();
ctx.moveTo(bwHalf, titleBlockY);
ctx.lineTo(width - bwHalf, titleBlockY);
ctx.stroke();
// Placeholder text for Title Block
ctx.fillStyle = borderTextColor;
let fontSize = Math.floor(titleBlockHeight * 0.22); // Base font size on block height
fontSize = Math.min(fontSize, Math.floor(width / 20)); // Limit by width also
fontSize = Math.max(8, Math.min(18, fontSize)); // Clamp font size (8px to 18px)
ctx.font = `bold ${fontSize}px 'Courier New', monospace`;
ctx.textBaseline = "middle";
const textVPadding = titleBlockHeight * 0.33; // Vertical padding for text lines
const textHPadding = numBorderWidth + fontSize * 0.8; // Horizontal padding from border edge
const randomId = "ID-" + Math.floor(Math.random() * 8999 + 1000);
const randomRev = String.fromCharCode(65 + Math.floor(Math.random() * 5)); // Revision A-E
ctx.textAlign = "left";
ctx.fillText(randomId, textHPadding, titleBlockY + textVPadding);
ctx.fillText("TYPE: SCHEMATIC", textHPadding, titleBlockY + titleBlockHeight - textVPadding);
ctx.textAlign = "right";
const currentDate = new Date();
const dateString = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(currentDate.getDate()).padStart(2, '0')}`;
ctx.fillText(`REV: ${randomRev}`, width - textHPadding, titleBlockY + textVPadding);
ctx.fillText(`DATE: ${dateString}`, width - textHPadding, titleBlockY + titleBlockHeight - textVPadding);
}
// 5. Draw Vignette (if enabled)
if (E_VIGNETTE && numVignetteIntensity > 0) {
const vigIntensity = Math.min(1, Math.max(0, numVignetteIntensity)); // Clamp 0-1
const centerX = width / 2;
const centerY = height / 2;
const outerRadius = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
// Vignette starts fading further from the center if intensity is lower
const innerRadiusRatio = Math.max(0.1, 1 - vigIntensity);
const innerRadius = outerRadius * innerRadiusRatio;
const gradient = ctx.createRadialGradient(
centerX, centerY, innerRadius,
centerX, centerY, outerRadius
);
gradient.addColorStop(0, "rgba(0,0,0,0)"); // Center is transparent
gradient.addColorStop(1, `rgba(0,0,0,${vigIntensity})`); // Edge is dark
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
}
return canvas;
}
Apply Changes