You can edit the below JavaScript code to customize the image tool.
/**
* Converts an image to a hatching art style.
* Darker areas of the image receive more layers of cross-hatching.
*
* @param {HTMLImageElement} originalImg The original image element to process.
* @param {string} lineColor The color of the hatching lines (e.g., '#000000', 'black').
* @param {string} backgroundColor The background color of the output image.
* @param {number} density Controls the spacing of the hatching lines. Smaller values create denser lines. Must be > 0.
* @param {number} threshold1 Brightness threshold (0-255) for the darkest areas, which get the most hatching layers.
* @param {number} threshold2 Brightness threshold (0-255) for the mid-tones.
* @param {number} threshold3 Brightness threshold (0-255) for the lighter areas.
* @returns {HTMLCanvasElement} A canvas element displaying the hatching art.
*/
function processImage(originalImg, lineColor = '#000000', backgroundColor = '#ffffff', density = 8, threshold1 = 64, threshold2 = 128, threshold3 = 192) {
/**
* Helper function to parse any valid CSS color string into an [r, g, b] array.
* It works by drawing the color onto a 1x1 canvas and reading the pixel data.
* @param {string} color - The CSS color string.
* @returns {Array<number>} An array containing the [r, g, b] values.
*/
const parseColor = (color) => {
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 1;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.fillStyle = color;
ctx.fillRect(0, 0, 1, 1);
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
return [r, g, b];
};
const width = originalImg.width;
const height = originalImg.height;
// Create a temporary canvas to get the image's pixel data
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
tempCtx.drawImage(originalImg, 0, 0);
const originalImageData = tempCtx.getImageData(0, 0, width, height);
const originalData = originalImageData.data;
// Create the output canvas
const outCanvas = document.createElement('canvas');
outCanvas.width = width;
outCanvas.height = height;
const outCtx = outCanvas.getContext('2d');
// Fill the background
outCtx.fillStyle = backgroundColor;
outCtx.fillRect(0, 0, width, height);
// Get the output imageData to manipulate pixels directly
const outImageData = outCtx.getImageData(0, 0, width, height);
const outData = outImageData.data;
const [lineR, lineG, lineB] = parseColor(lineColor);
// Ensure parameters are numbers as they might be passed as strings
const numDensity = Number(density);
const numThreshold1 = Number(threshold1);
const numThreshold2 = Number(threshold2);
const numThreshold3 = Number(threshold3);
// A density of 0 or less would cause errors.
if (numDensity <= 0) {
console.error("Density must be a positive number.");
return outCanvas; // Return canvas as is
}
// Loop through each pixel of the original image
for (let i = 0; i < originalData.length; i += 4) {
const r = originalData[i];
const g = originalData[i + 1];
const b = originalData[i + 2];
// Calculate brightness (luminance) using a standard formula
const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
// Calculate x and y coordinates from the flat pixel array index
const pixelIndex = i / 4;
const x = pixelIndex % width;
const y = Math.floor(pixelIndex / width);
let isLinePixel = false;
// Apply hatching layers based on brightness thresholds.
// The logic is additive: darker areas match more conditions and thus get more line layers,
// creating a cross-hatching effect. The `%` expressions create patterned lines.
// Layer 1: Affects all areas under threshold3. Creates sparse diagonal lines.
if (brightness < numThreshold3) {
const d = numDensity * 2;
// (x - y) % d creates lines at a 45-degree angle.
// The `+ d` ensures the modulo result is always positive.
if (((x - y) % d + d) % d === 0) {
isLinePixel = true;
}
}
// Layer 2: Affects areas under threshold2. Adds denser diagonal lines in the opposite direction.
if (brightness < numThreshold2) {
// (x + y) % d creates lines at a -45-degree (or 135-degree) angle.
if (((x + y) % numDensity + numDensity) % numDensity === 0) {
isLinePixel = true;
}
}
// Layer 3: Affects only the darkest areas under threshold1. Adds a grid (horizontal and vertical lines).
if (brightness < numThreshold1) {
if ((x % numDensity === 0) || (y % numDensity === 0)) {
isLinePixel = true;
}
}
// If the pixel is determined to be part of a line, color it.
if (isLinePixel) {
outData[i] = lineR;
outData[i + 1] = lineG;
outData[i + 2] = lineB;
outData[i + 3] = 255; // Set alpha to fully opaque
}
}
// Put the modified pixel data back onto the output canvas
outCtx.putImageData(outImageData, 0, 0);
return outCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image To Hatching Art Converter transforms standard images into a unique hatching art style. Users can customize the appearance by adjusting the color of the hatching lines, the background color, and the density of the hatching patterns. This tool uses brightness thresholds to determine how many layers of hatching are applied, creating a textured effect where darker areas receive more layers. Ideal for artists, graphic designers, and hobbyists, this converter can be used to create stylized artworks, illustrations, or visually appealing graphics for various projects.