You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, title = 'В МАСТЕРСКУЮ!', backgroundColor = '#002244', lineColor = '#FFFFFF', threshold = 50, addGrid = 'true', gridSize = 50) {
/**
* Dynamically loads a Google Font if it's not already available.
* @param {string} fontName The name of the font to load.
*/
const loadFont = async (fontName) => {
const fontUrl = `https://fonts.googleapis.com/css2?family=${fontName.replace(/ /g, '+')}&display=swap`;
if (!document.querySelector(`link[href="${fontUrl}"]`)) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontUrl;
document.head.appendChild(link);
try {
await document.fonts.load(`1em "${fontName}"`);
} catch (err) {
console.error(`Font ${fontName} could not be loaded:`, err);
}
}
};
/**
* Converts a HEX color string to an RGB object.
* @param {string} hex The hex color string (e.g., '#FF5733').
* @returns {{r: number, g: number, b: number}|null}
*/
const hexToRgb = (hex) => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
};
await loadFont('Share Tech Mono');
const canvas = document.createElement('canvas');
const width = originalImg.naturalWidth;
const height = originalImg.naturalHeight;
canvas.width = width;
canvas.height = height;
// The 'willReadFrequently' hint can optimize repeated getImageData/putImageData calls.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Draw the original image to a temporary canvas to get its pixel data.
ctx.drawImage(originalImg, 0, 0);
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
const bgRgb = hexToRgb(backgroundColor);
const lineRgb = hexToRgb(lineColor);
if (!bgRgb || !lineRgb) {
console.error("Invalid background or line color provided.");
return canvas; // Return empty canvas on error
}
// Convert the image to grayscale for edge detection.
const grayscaleData = new Uint8ClampedArray(width * height);
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
grayscaleData[i / 4] = gray;
}
// Apply the Sobel operator to detect edges.
const sobelData = new Float32Array(width * height);
const Gx = [
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]
];
const Gy = [
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]
];
for (let y = 1; y < height - 1; y++) {
for (let x = 1; x < width - 1; x++) {
let sumX = 0;
let sumY = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
const gray = grayscaleData[(y + i) * width + (x + j)];
sumX += gray * Gx[i + 1][j + 1];
sumY += gray * Gy[i + 1][j + 1];
}
}
const magnitude = Math.sqrt(sumX * sumX + sumY * sumY);
sobelData[y * width + x] = magnitude;
}
}
// Create the final blueprint image data.
const outputImageData = ctx.createImageData(width, height);
const outputData = outputImageData.data;
for (let i = 0; i < sobelData.length; i++) {
const magnitude = sobelData[i];
const pixelIndex = i * 4;
const color = magnitude > threshold ? lineRgb : bgRgb;
outputData[pixelIndex] = color.r;
outputData[pixelIndex + 1] = color.g;
outputData[pixelIndex + 2] = color.b;
outputData[pixelIndex + 3] = 255;
}
ctx.putImageData(outputImageData, 0, 0);
// Add optional grid lines for a more technical look.
if (addGrid === 'true' && gridSize > 0) {
ctx.strokeStyle = lineColor;
ctx.globalAlpha = 0.2;
ctx.lineWidth = 1;
for (let x = Number(gridSize); x < width; x += Number(gridSize)) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = Number(gridSize); y < height; y += Number(gridSize)) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
ctx.globalAlpha = 1.0;
}
// Add an optional title block in the corner.
if (title) {
const fontSize = Math.max(16, Math.min(width / 25, height / 25));
const padding = fontSize * 0.5;
ctx.font = `${fontSize}px "Share Tech Mono", monospace`;
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
const textMetrics = ctx.measureText(title);
const boxWidth = textMetrics.width + 2 * padding;
const boxHeight = fontSize + 2 * padding;
const boxX = width - boxWidth - padding;
const boxY = height - boxHeight - padding;
ctx.strokeStyle = lineColor;
ctx.fillStyle = backgroundColor;
ctx.lineWidth = 2;
ctx.fillRect(boxX, boxY, boxWidth, boxHeight);
ctx.strokeRect(boxX, boxY, boxWidth, boxHeight);
ctx.fillStyle = lineColor;
ctx.fillText(title, width - 2 * padding, height - 2 * padding);
}
return canvas;
}
Apply Changes