You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Generates a procedural building texture, such as bricks or windows.
* The output dimensions are determined by the input image 'originalImg'.
*
* @param {Image} originalImg - An Image object used to determine the output canvas dimensions.
* @param {string} textureType - The type of texture to generate. Can be 'bricks' or 'windows'. Defaults to 'bricks'.
* @param {string} color1 - The primary color. For 'bricks', this is the brick color. For 'windows', it's the wall color. Defaults to FireBrick '#B22222'.
* @param {string} color2 - The secondary color. For 'bricks', this is the mortar color. For 'windows', it's the frame color. Defaults to LightGray '#D3D3D3'.
* @param {string} color3 - An accent color, primarily used for the glass in the 'windows' texture. Defaults to SkyBlue '#87CEEB'.
* @param {number} horizontalCount - The number of texture elements (bricks, windows) to generate horizontally. Defaults to 15.
* @param {number} verticalCount - The number of texture elements (bricks, windows) to generate vertically. Defaults to 30.
* @param {number} randomness - A value from 0 to 1 that controls the amount of random variation in position, size, and color. Defaults to 0.05.
* @returns {HTMLCanvasElement} A canvas element with the generated texture.
*/
function processImage(originalImg, textureType = 'bricks', color1 = '#B22222', color2 = '#D3D3D3', color3 = '#87CEEB', horizontalCount = 15, verticalCount = 30, randomness = 0.05) {
const width = originalImg.width;
const height = originalImg.height;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// --- Helper Functions ---
/**
* Applies a random variation to a hex color.
* @param {string} hex - The base hex color string (e.g., '#RRGGBB').
* @param {number} variance - A value from 0 to 1 controlling the amount of change.
* @returns {string} The new, slightly varied hex color string.
*/
const varyColor = (hex, variance) => {
if (variance === 0) return hex;
try {
const factor = variance * 255;
let r = parseInt(hex.slice(1, 3), 16);
let g = parseInt(hex.slice(3, 5), 16);
let b = parseInt(hex.slice(5, 7), 16);
const change = (Math.random() - 0.5) * factor;
const clamp = (val) => Math.round(Math.max(0, Math.min(255, val)));
r = clamp(r + change);
g = clamp(g + change);
b = clamp(b + change);
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
} catch (e) {
return hex; // Return original color on parse error
}
};
/**
* Darkens a hex color by a given percentage.
* @param {string} hex - The base hex color string.
* @param {number} percent - The percentage to darken (0 to 1).
* @returns {string} The darkened hex color string.
*/
const darkenColor = (hex, percent) => {
try {
let r = parseInt(hex.slice(1, 3), 16);
let g = parseInt(hex.slice(3, 5), 16);
let b = parseInt(hex.slice(5, 7), 16);
const factor = 1 - percent;
r = Math.floor(r * factor);
g = Math.floor(g * factor);
b = Math.floor(b * factor);
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
} catch(e) {
return hex;
}
};
// --- Texture Generation Logic ---
if (textureType === 'bricks') {
const hCount = Number(horizontalCount);
const vCount = Number(verticalCount);
const rand = Number(randomness);
const brickWidth = width / hCount;
const brickHeight = height / vCount;
const mortarX = Math.max(1, brickWidth * 0.1);
const mortarY = Math.max(1, brickHeight * 0.15);
// Draw mortar background
ctx.fillStyle = color2; // Mortar color
ctx.fillRect(0, 0, width, height);
// Draw bricks
for (let i = 0; i < vCount; i++) {
const y = i * brickHeight;
const rowOffset = (i % 2 === 0) ? 0 : -brickWidth / 2;
for (let j = 0; j <= hCount; j++) { // Loop one extra time to cover offset edge
const x = j * brickWidth + rowOffset;
const rX = (Math.random() - 0.5) * brickWidth * rand;
const rY = (Math.random() - 0.5) * brickHeight * rand;
const rW = (Math.random() - 0.5) * (brickWidth - mortarX) * rand;
const rH = (Math.random() - 0.5) * (brickHeight - mortarY) * rand;
ctx.fillStyle = varyColor(color1, rand); // Brick color
ctx.fillRect(
x + mortarX / 2 + rX,
y + mortarY / 2 + rY,
brickWidth - mortarX + rW,
brickHeight - mortarY + rH
);
}
}
} else if (textureType === 'windows') {
const hCount = Number(horizontalCount);
const vCount = Number(verticalCount);
const rand = Number(randomness);
// Draw wall background
ctx.fillStyle = color1; // Wall color
ctx.fillRect(0, 0, width, height);
const cellWidth = width / hCount;
const cellHeight = height / vCount;
const windowScaleW = 0.7;
const windowScaleH = 0.8;
const frameThickness = Math.max(2, cellWidth * 0.05);
for (let i = 0; i < vCount; i++) {
for (let j = 0; j < hCount; j++) {
const winWidth = cellWidth * windowScaleW;
const winHeight = cellHeight * windowScaleH;
const winX = (j * cellWidth) + (cellWidth - winWidth) / 2;
const winY = (i * cellHeight) + (cellHeight - winHeight) / 2;
const rX = (Math.random() - 0.5) * cellWidth * rand;
const rY = (Math.random() - 0.5) * cellHeight * rand;
// 1. Draw depth/shadow
ctx.fillStyle = darkenColor(color1, 0.2);
ctx.fillRect(winX + rX + frameThickness/2, winY + rY + frameThickness/2, winWidth, winHeight);
// 2. Draw outer frame
ctx.fillStyle = color2; // Frame color
ctx.fillRect(winX + rX, winY + rY, winWidth, winHeight);
// 3. Draw glass
const glassX = winX + rX + frameThickness;
const glassY = winY + rY + frameThickness;
const glassW = winWidth - 2 * frameThickness;
const glassH = winHeight - 2 * frameThickness;
ctx.fillStyle = color3; // Glass color
ctx.fillRect(glassX, glassY, glassW, glassH);
// 4. Draw reflection on glass
const gradient = ctx.createLinearGradient(glassX, glassY, glassX + glassW, glassY + glassH);
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.5)');
gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.0)');
ctx.fillStyle = gradient;
ctx.fillRect(glassX, glassY, glassW, glassH);
// 5. Draw muntins (crossbars)
ctx.fillStyle = color2;
const muntinSize = Math.max(1, frameThickness * 0.75);
const muntinX = glassX + glassW / 2 - muntinSize / 2;
const muntinY = glassY + glassH / 2 - muntinSize / 2;
ctx.fillRect(muntinX, glassY, muntinSize, glassH); // Vertical
ctx.fillRect(glassX, muntinY, glassW, muntinSize); // Horizontal
}
}
}
return canvas;
}
Apply Changes