You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, spacing = 10, dotScale = 1.0, dotColor = 'black', backgroundColor = 'white', invertLuminance = 0) {
// Ensure numeric parameters are actual numbers and provide fallback values if they are invalid.
let numSpacing = Number(spacing);
if (isNaN(numSpacing) || numSpacing <= 0) {
numSpacing = 10; // Default spacing if input is invalid
}
let numDotScale = Number(dotScale);
if (isNaN(numDotScale) || numDotScale < 0) {
numDotScale = 1.0; // Default dot scale if input is invalid
}
let numInvertLuminance = Number(invertLuminance);
// Ensure invertLuminance is strictly 0 or 1
if (numInvertLuminance !== 0 && numInvertLuminance !== 1) {
numInvertLuminance = 0; // Default to not inverted if input is invalid
}
const outputCanvas = document.createElement('canvas');
const outputCtx = outputCanvas.getContext('2d');
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
// If the image has no dimensions (e.g., not loaded or invalid), return an empty canvas.
if (imgWidth === 0 || imgHeight === 0) {
outputCanvas.width = 0;
outputCanvas.height = 0;
return outputCanvas;
}
outputCanvas.width = imgWidth;
outputCanvas.height = imgHeight;
// Fill the output canvas with the specified background color.
outputCtx.fillStyle = backgroundColor;
outputCtx.fillRect(0, 0, imgWidth, imgHeight);
// Create a temporary (off-screen) canvas to draw the original image
// and access its pixel data. This handles transparency by drawing
// the image over a white background first.
const inputCanvas = document.createElement('canvas');
inputCanvas.width = imgWidth;
inputCanvas.height = imgHeight;
const inputCtx = inputCanvas.getContext('2d');
// Fill input canvas with white. When originalImg is drawn, its_HOME transparent parts will become white.
inputCtx.fillStyle = 'white';
inputCtx.fillRect(0, 0, imgWidth, imgHeight);
inputCtx.drawImage(originalImg, 0, 0);
// Get the pixel data from the input canvas.
const imageData = inputCtx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageData.data; // This is a Uint8ClampedArray [R,G,B,A, R,G,B,A, ...]
// Calculate the maximum possible radius for a dot based on spacing and scale.
// A dotScale of 1.0 means dots can touch if an area is pure black (or white if inverted).
const maxRadiusFromScale = (numSpacing / 2) * numDotScale;
// Iterate over the image in blocks defined by numSpacing.
for (let y = 0; y < imgHeight; y += numSpacing) {
for (let x = 0; x < imgWidth; x += numSpacing) {
// Calculate the average color/brightness of the current block.
let sumRed = 0, sumGreen = 0, sumBlue = 0, pixelCountInBlock = 0;
// Iterate over pixels within the current block.
// The block extends from (x, y) to (x + numSpacing - 1, y + numSpacing - 1).
for (let blockY = 0; blockY < numSpacing; blockY++) {
for (let blockX = 0; blockX < numSpacing; blockX++) {
const currentPixelX = x + blockX;
const currentPixelY = y + blockY;
// Ensure the pixel is within the image boundaries.
if (currentPixelX < imgWidth && currentPixelY < imgHeight) {
const pixelIndex = (currentPixelY * imgWidth + currentPixelX) * 4;
sumRed += data[pixelIndex];
sumGreen += data[pixelIndex + 1];
sumBlue += data[pixelIndex + 2];
// Alpha (data[pixelIndex + 3]) is implicitly handled because the image
// was drawn on a white background on the inputCanvas.
pixelCountInBlock++;
}
}
}
// If the block had no pixels (e.g., numSpacing is 0, though guarded), skip.
if (pixelCountInBlock === 0) {
continue;
}
const avgRed = sumRed / pixelCountInBlock;
const avgGreen = sumGreen / pixelCountInBlock;
const avgBlue = sumBlue / pixelCountInBlock;
// Convert the average color to a grayscale brightness value (0.0 to 1.0).
// 0.0 = black, 1.0 = white. Uses standard luminance coefficients.
const brightness = (0.299 * avgRed + 0.587 * avgGreen + 0.114 * avgBlue) / 255;
let radiusCoefficient;
if (numInvertLuminance === 1) {
// Inverted: lighter areas get larger dots.
radiusCoefficient = brightness;
} else {
// Standard: darker areas get larger dots.
radiusCoefficient = 1 - brightness;
}
const radius = maxRadiusFromScale * radiusCoefficient;
// Draw the dot if its radius is positive.
if (radius > 0) {
const dotCenterX = x + numSpacing / 2;
const dotCenterY = y + numSpacing / 2;
outputCtx.beginPath();
// Ensure radius is not negative, though logic should prevent this with numDotScale >= 0.
outputCtx.arc(dotCenterX, dotCenterY, Math.max(0, radius), 0, 2 * Math.PI, false);
outputCtx.fillStyle = dotColor;
outputCtx.fill();
}
}
}
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Halftone Filter Application is a tool that applies a halftone effect to images, transforming them into dot-based art. Users can customize the appearance by adjusting parameters such as dot spacing, dot scale, dot color, and background color. This tool is useful for graphic designers, artists, and anyone looking to create unique visual effects for prints, illustrations, or digital art. By converting images into a series of dots based on their brightness, it provides a classic printed look that can enhance various creative projects.