You can edit the below JavaScript code to customize the image tool.
/**
* Tries to identify the font used in an image by performing OCR and comparing character shapes.
* This is a complex task and this function is a best-effort implementation. Accuracy may vary.
* It dynamically loads the Tesseract.js library for OCR, which may take some time on first run.
*
* @param {Image} originalImg The original image object to analyze.
* @param {string} [candidateFonts='Arial,Verdana,Times New Roman,Georgia,Courier New,Roboto,Open Sans,Lato,Montserrat,Lobster'] A comma-separated string of font names to test against. For Google Fonts, they must be pre-loaded on the page.
* @param {string} [ocrLanguage='eng'] The language for the Optical Character Recognition (OCR) engine.
* @param {number} [threshold=128] The brightness threshold (0-255) for converting the image to black and white for comparison.
* @returns {Promise<HTMLDivElement>} A promise that resolves to a div element containing the results.
*/
async function processImage(originalImg, candidateFonts = 'Arial,Verdana,Helvetica,Times New Roman,Georgia,Courier New,Roboto,Open Sans,Lato,Montserrat,Lobster', ocrLanguage = 'eng', threshold = 128) {
/**
* Dynamically loads a script and returns a promise that resolves when it's ready.
* @param {string} url The URL of the script to load.
* @returns {Promise<void>}
*/
const loadScript = (url) => {
return new Promise((resolve, reject) => {
// Check if Tesseract is already available
if (window.Tesseract) {
return resolve();
}
// Check if script tag already exists
let script = document.querySelector(`script[src="${url}"]`);
if (script) {
script.addEventListener('load', () => resolve());
script.addEventListener('error', () => reject(new Error(`Failed to load script: ${url}`)));
return;
}
script = document.createElement('script');
script.src = url;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
document.head.appendChild(script);
});
};
const resultDiv = document.createElement('div');
resultDiv.style.fontFamily = 'sans-serif';
resultDiv.innerHTML = '<p>Initializing font finder...</p>';
try {
resultDiv.innerHTML = '<p>Loading text recognition library (Tesseract.js)...</p>';
await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js');
} catch (error) {
console.error(error);
resultDiv.innerHTML = `<p style="color: red;">Error: Could not load the Tesseract.js library. Please check your internet connection and try again.</p>`;
return resultDiv;
}
let recognizer;
try {
recognizer = await Tesseract.create({
logger: m => {
if (m.status === 'recognizing text') {
const progress = (m.progress * 100).toFixed(0);
resultDiv.innerHTML = `<p>Recognizing text... ${progress}%</p>`;
}
}
});
await recognizer.loadLanguage(ocrLanguage);
await recognizer.initialize(ocrLanguage);
} catch (err) {
console.error("Tesseract initialization failed:", err);
resultDiv.innerHTML = `<p style="color: red;">Error: Could not initialize the text recognition engine. The language pack for '${ocrLanguage}' might be invalid or unreachable.</p>`;
return resultDiv;
}
const { data } = await recognizer.recognize(originalImg);
if (data.words.length === 0) {
resultDiv.innerHTML = '<p>No text could be recognized in the image.</p>';
await recognizer.terminate();
return resultDiv;
}
// Find a reliable word to test, preferring longer words with higher confidence
const bestWord = data.words.filter(w => w.text.length > 2).sort((a, b) => b.confidence - a.confidence)[0] || data.words.sort((a, b) => b.text.length - a.text.length)[0];
if (!bestWord || bestWord.symbols.length === 0) {
resultDiv.innerHTML = '<p>Could not find a suitable character to analyze.</p>';
await recognizer.terminate();
return resultDiv;
}
// Use the first character of this word for comparison
const charToTest = bestWord.symbols[0];
const bbox = charToTest.bbox;
const charWidth = bbox.x1 - bbox.x0;
const charHeight = bbox.y1 - bbox.y0;
// --- Create a binarized (black & white) version of the original character for comparison ---
const processingCanvas = document.createElement('canvas');
processingCanvas.width = originalImg.width;
processingCanvas.height = originalImg.height;
const pCtx = processingCanvas.getContext('2d', { willReadFrequently: true });
pCtx.drawImage(originalImg, 0, 0);
const imgData = pCtx.getImageData(0, 0, originalImg.width, originalImg.height);
for (let i = 0; i < imgData.data.length; i += 4) {
const luminance = 0.299 * imgData.data[i] + 0.587 * imgData.data[i + 1] + 0.114 * imgData.data[i + 2];
const color = luminance > threshold ? 255 : 0; // White background, black text
imgData.data[i] = color;
imgData.data[i + 1] = color;
imgData.data[i + 2] = color;
}
pCtx.putImageData(imgData, 0, 0);
const targetCanvas = document.createElement('canvas');
targetCanvas.width = charWidth;
targetCanvas.height = charHeight;
const tCtx = targetCanvas.getContext('2d', { willReadFrequently: true });
tCtx.drawImage(processingCanvas, bbox.x0, bbox.y0, charWidth, charHeight, 0, 0, charWidth, charHeight);
const targetImageData = tCtx.getImageData(0, 0, charWidth, charHeight).data;
// --- Iterate through candidate fonts and compare ---
const fonts = candidateFonts.split(',').map(f => f.trim());
let bestMatch = { font: 'None', score: Infinity };
resultDiv.innerHTML = `<p>Recognized text: "${bestWord.text}". Now testing ${fonts.length} fonts...</p>`;
for (const font of fonts) {
try {
await document.fonts.load(`${charHeight}px '${font}'`);
} catch (e) {
console.warn(`Could not load or verify font: ${font}. It may not be installed or linked.`);
continue;
}
const renderCanvas = document.createElement('canvas');
renderCanvas.width = charWidth;
renderCanvas.height = charHeight;
const rCtx = renderCanvas.getContext('2d', { willReadFrequently: true });
// Render the candidate character with a white background and black text to match the processed image
rCtx.fillStyle = 'white';
rCtx.fillRect(0, 0, charWidth, charHeight);
rCtx.fillStyle = 'black';
rCtx.font = `${charHeight}px '${font}'`;
rCtx.textBaseline = 'top';
rCtx.textAlign = 'left';
rCtx.fillText(charToTest.text, 0, 0);
const renderedImageData = rCtx.getImageData(0, 0, charWidth, charHeight).data;
// Calculate difference using Sum of Absolute Differences on pixel values
let diff = 0;
for (let i = 0; i < targetImageData.length; i += 4) {
diff += Math.abs(targetImageData[i] - renderedImageData[i]);
}
if (diff < bestMatch.score) {
bestMatch = { font, score: diff };
}
}
await recognizer.terminate();
// --- Display the final result ---
resultDiv.innerHTML = ''; // Clear status updates
if (bestMatch.font === 'None') {
resultDiv.innerHTML = '<p>Could not find a suitable match from the provided font list.</p>';
return resultDiv;
}
const title = document.createElement('h3');
title.textContent = `Best Match Found: ${bestMatch.font}`;
const sampleWrapper = document.createElement('div');
sampleWrapper.style.marginTop = '1em';
sampleWrapper.style.padding = '1em';
sampleWrapper.style.border = '1px solid #ccc';
sampleWrapper.style.borderRadius = '5px';
const sampleLabel = document.createElement('p');
sampleLabel.textContent = 'Sample text rendered in the matched font:';
sampleLabel.style.margin = '0 0 0.5em 0';
sampleLabel.style.fontSize = '0.9em';
sampleLabel.style.color = '#555';
const sampleText = document.createElement('p');
sampleText.textContent = bestWord.text;
sampleText.style.margin = '0';
sampleText.style.fontFamily = `'${bestMatch.font}', sans-serif`;
sampleText.style.fontSize = `${charHeight}px`;
sampleWrapper.appendChild(sampleLabel);
sampleWrapper.appendChild(sampleText);
resultDiv.appendChild(title);
resultDiv.appendChild(sampleWrapper);
return resultDiv;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
Image Font Finder is a tool designed to help users identify the font used in an image. It utilizes Optical Character Recognition (OCR) technology to read text within the image and then compares the recognized characters against a list of candidate fonts. This tool can be particularly useful for graphic designers, typographers, and anyone working with visual media who needs to match fonts from various sources. By providing an easy way to analyze fonts directly from images, it enhances creative workflows and aids in font selection for projects.