You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, blockSize = 10, charSetString = "N,J,g,r,y,:,~, ", invertColors = 0, fontSize = 10) {
// Validate and sanitize parameters
blockSize = Math.max(1, Math.floor(blockSize));
fontSize = Math.max(1, fontSize);
let chars = charSetString.split(',');
// Fallback for empty or malformed charSetString
// If charSetString is "" -> chars is [""] -> chars.length is 1, chars[0].length is 0. This triggers fallback.
// If charSetString is " " -> chars is [" "] -> chars.length is 1, chars[0].length is 1. Not fallback. Correct.
if (chars.length === 0 || (chars.length === 1 && chars[0].length === 0 && chars[0] !== ' ')) {
chars = ["N", "J", "g", "r", "y", ":", "~", " "]; // Default Wingdings characters from dark to light
}
// Create a canvas to draw the image and get its pixel data
const canvas = document.createElement('canvas');
// Add willReadFrequently hint for potential performance optimization by the browser
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Use naturalWidth/Height for intrinsic image dimensions, fallback to width/height
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
// If the image has no dimensions, return an empty element
if (canvas.width === 0 || canvas.height === 0) {
const emptyOutputElement = document.createElement('pre');
emptyOutputElement.textContent = "";
return emptyOutputElement;
}
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]
// Create the output <pre> element
const outputElement = document.createElement('pre');
// Specify Wingdings font and fallbacks
outputElement.style.fontFamily = 'Wingdings, "Wingdings 2", "Wingdings 3", Webdings, Symbol, "Apple Symbols"';
outputElement.style.fontSize = fontSize + 'px';
// Set line height equal to font size for somewhat square character cells
// Adjust if characters appear too cramped or too spaced vertically.
outputElement.style.lineHeight = fontSize + 'px';
outputElement.style.letterSpacing = '0px'; // No extra space between characters
outputElement.style.margin = '0';
outputElement.style.padding = '0';
// outputElement.style.whiteSpace = 'pre'; // This is the default for <pre> elements
// outputElement.style.display = 'inline-block'; // Optional: makes element size to content
const outputLines = [];
// Iterate over the image in blocks
for (let y = 0; y < canvas.height; y += blockSize) {
const lineChars = [];
for (let x = 0; x < canvas.width; x += blockSize) {
let totalBrightness = 0;
let pixelCount = 0;
// Calculate average brightness for the current block
for (let blockY = 0; blockY < blockSize; blockY++) {
for (let blockX = 0; blockX < blockSize; blockX++) {
const currentPixelY = y + blockY;
const currentPixelX = x + blockX;
// Ensure a_val pixel is within image bounds
if (currentPixelX < canvas.width && currentPixelY < canvas.height) {
const pixelIndex = (currentPixelY * canvas.width + currentPixelX) * 4;
let r = data[pixelIndex];
let g = data[pixelIndex + 1];
let b = data[pixelIndex + 2];
const alpha = data[pixelIndex + 3] / 255.0; // Normalize alpha to 0-1
// Blend transparent/semi-transparent pixels with a white background
// This makes transparent areas of the image map to lighter characters
r = r * alpha + 255 * (1 - alpha);
g = g * alpha + 255 * (1 - alpha);
b = b * alpha + 255 * (1 - alpha);
// Standard grayscale conversion formula
const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
totalBrightness += brightness;
pixelCount++;
}
}
}
let averageBrightness;
if (pixelCount === 0) {
// This case occurs if blockSize is larger than remaining image dimensions
// or for empty blocks (should not happen if loops are correct).
// Default to white brightness (or black if inverted).
averageBrightness = invertColors === 1 ? 0 : 255;
} else {
averageBrightness = totalBrightness / pixelCount;
}
let normalizedBrightness = averageBrightness / 255; // Normalize to 0 (black) - 1 (white)
if (invertColors === 1) {
normalizedBrightness = 1 - normalizedBrightness;
}
// Clamp brightness to [0, 1] to prevent floating point inaccuracies
normalizedBrightness = Math.max(0, Math.min(1, normalizedBrightness));
// Map brightness to a character index
// Chars are ordered dark to light. Low brightness -> low index.
let charIndex = Math.floor(normalizedBrightness * chars.length);
// Ensure charIndex is within bounds (esp. for normalizedBrightness = 1.0)
charIndex = Math.min(charIndex, chars.length - 1);
// Use selected character, or a space if the character is undefined/empty string
lineChars.push(chars[charIndex] || " ");
}
outputLines.push(lineChars.join(''));
}
outputElement.textContent = outputLines.join('\n');
return outputElement;
}
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 Wingdings Character Art Converter transforms standard images into a unique form of art using Wingdings characters. Users can upload an image, specify settings such as block size and character sets, and the tool will convert the image into a grid of symbols representing average brightness levels. This can be particularly useful for creating ASCII-style representations of images for creative projects, social media sharing, or just for fun. The output can serve as a decorative addition to text-based content or as a distinct artistic expression.