You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, charSet = " .ـاوسمشغح", blockSize = 10, invertColorsStr = "false", customFontFamily = "Arial", textColor = "black", backgroundColor = "white") {
const chars = Array.from(charSet); // Convert string to array of characters
const invertColors = invertColorsStr.toLowerCase() === "true";
// Ensure blockSize is a positive integer
const effectiveBlockSize = Math.max(1, parseInt(blockSize, 10) || 10);
const blockWidth = effectiveBlockSize;
const blockHeight = effectiveBlockSize;
let effectiveFontFamily = customFontFamily;
// Special handling for 'Amiri' font to load it dynamically if not available
if (customFontFamily.toLowerCase() === 'amiri') {
// Check if Amiri font is already available in the document
if (!document.fonts.check(`12px Amiri`)) {
try {
// WOFF2 URL for Amiri Regular 400. This URL might change; found by inspecting Google Fonts CSS.
const amiriFont = new FontFace(
'Amiri',
'url(https://fonts.gstatic.com/s/amiri/v26/J7acnpignkdp68E.woff2)',
{ style: 'normal', weight: '400' }
);
await amiriFont.load(); // Load the font
document.fonts.add(amiriFont); // Add it to the document's font set
console.log("Amiri font loaded dynamically.");
// effectiveFontFamily is already 'Amiri'
} catch (err) {
console.error("Failed to load Amiri font:", err, ". Falling back to Arial.");
effectiveFontFamily = 'Arial'; // Fallback font
}
} else {
// Font already available, no action needed, effectiveFontFamily is 'Amiri'
// console.log("Amiri font already available in document.");
}
}
// Create a temporary canvas to draw the image and get its pixel data
const tempCanvas = document.createElement('canvas');
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
const tempCtx = tempCanvas.getContext('2d');
if (!tempCtx) {
console.error("Failed to get 2D context from temporary canvas.");
return document.createElement('canvas'); // Return empty canvas on error
}
tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let imageData;
try {
imageData = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Failed to get ImageData, possibly due to cross-origin restrictions if image is not from the same domain or CORB policy violations.", e);
// Create a canvas with an error message
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 300;
errorCanvas.height = 100;
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
errCtx.fillStyle = 'red';
errCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
errCtx.fillStyle = 'white';
errCtx.font = '12px Arial';
errCtx.textAlign = 'center';
errCtx.fillText("Error: Cannot process image.", errorCanvas.width/2, errorCanvas.height/3);
errCtx.fillText("May be a cross-origin issue.", errorCanvas.width/2, errorCanvas.height*2/3);
}
return errorCanvas;
}
const data = imageData.data;
const numCharsWide = Math.floor(imgWidth / blockWidth);
const numCharsHigh = Math.floor(imgHeight / blockHeight);
// Create the output canvas
const outputCanvas = document.createElement('canvas');
outputCanvas.width = numCharsWide * blockWidth;
outputCanvas.height = numCharsHigh * blockHeight;
const outCtx = outputCanvas.getContext('2d');
if (!outCtx) {
console.error("Failed to get 2D context from output canvas.");
return document.createElement('canvas'); // Return empty canvas on error
}
// Fill background
outCtx.fillStyle = backgroundColor;
outCtx.fillRect(0, 0, outputCanvas.width, outputCanvas.height);
// Set font properties
// Font size is based on block height, with some padding factor
const fontSize = blockHeight * 0.85;
outCtx.font = `${fontSize}px ${effectiveFontFamily}`;
outCtx.textAlign = 'center';
outCtx.textBaseline = 'middle';
outCtx.fillStyle = textColor;
if (chars.length === 0) {
console.warn("Character set is empty. Returning a blank canvas with background color.");
return outputCanvas; // Return canvas with background color if no characters
}
for (let y = 0; y < numCharsHigh; y++) {
for (let x = 0; x < numCharsWide; x++) {
let totalBrightness = 0;
let pixelCount = 0;
// Calculate average brightness for the current block in the original image
for (let j = 0; j < blockHeight; j++) {
for (let i = 0; i < blockWidth; i++) {
const pixelX = x * blockWidth + i;
const pixelY = y * blockHeight + j;
// Ensure we are within image bounds
if (pixelX < imgWidth && pixelY < imgHeight) {
const R_INDEX = (pixelY * imgWidth + pixelX) * 4;
const r = data[R_INDEX];
const g = data[R_INDEX + 1];
const b = data[R_INDEX + 2];
// Luminosity method for perceived brightness (0-255)
const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
totalBrightness += brightness;
pixelCount++;
}
}
}
const avgBrightness = pixelCount > 0 ? totalBrightness / pixelCount : 0;
let charIndex;
if (chars.length === 1) {
charIndex = 0;
} else {
// The default `charSet` is ordered from light to dark (e.g., " .ـاوسمشغح")
// Dark image part (low avgBrightness) should use a dark char (high index in this `charSet`).
// Light image part (high avgBrightness) should use a light char (low index in this `charSet`).
// So, map (255 - avgBrightness) to index range.
charIndex = ((255 - avgBrightness) / 255) * (chars.length - 1);
}
if (invertColors) {
charIndex = (chars.length - 1) - charIndex;
}
// Round to nearest integer and clamp index to be within valid bounds
charIndex = Math.round(charIndex);
charIndex = Math.max(0, Math.min(chars.length - 1, charIndex));
const charToDraw = chars[charIndex];
// Calculate drawing position for the character (center of the block)
const drawX = x * blockWidth + blockWidth / 2;
const drawY = y * blockHeight + blockHeight / 2;
outCtx.fillText(charToDraw, drawX, drawY);
}
}
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 To Arabic Character Art Converter transforms images into visually appealing character art created from Arabic characters. By converting each section of an image into ASCII-like representations, it creates a unique artistic effect that can serve various purposes such as designing posters, creating social media content, or providing a creative way to visualize photographs. Users can customize the font, colors, and character set used for the conversion, allowing for personalized artwork that blends technology with traditional art forms.