You can edit the below JavaScript code to customize the image tool.
/**
* Analyzes an image to generate a fictional "internal monologue" based on its visual properties like color, brightness, and complexity.
* @param {Image} originalImg The original javascript Image object to be processed.
* @param {string} lang The language for the monologue. Supports 'en' for English and 'ru' for Russian. Defaults to 'en'.
* @returns {HTMLElement} A div element containing the original image with a text overlay of the generated monologue.
*/
async function processImage(originalImg, lang = 'en') {
// 1. Create a canvas to analyze the image data
const canvas = document.createElement('canvas');
// For performance, we can scale down the analysis canvas
const scale = Math.min(1, 200 / originalImg.width);
canvas.width = originalImg.width * scale;
canvas.height = originalImg.height * scale;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// 2. Phrase bank for generating the monologue
const phrases = {
en: {
brightness: {
dark: ["Is anyone there?", "So dark...", "Lost in the shadows.", "Where did the light go?", "A sliver of light is all that's left."],
neutral: ["Just... as it is.", "A quiet moment.", "Neither day nor night.", "Everything seems so... normal."],
bright: ["So bright.", "My eyes... it's overwhelming.", "A flash of white light.", "Is this a memory?"]
},
saturation: {
low: ["The colors... they're all gone.", "Faded, like an old photograph.", "A world in grayscale.", "Is this even real?"],
neutral: ["The colors are muted.", "A sense of calm.", "Nothing out of the ordinary."],
high: ["The colors are screaming.", "So vivid, it almost hurts.", "Overwhelming.", "Is this a dream?"]
},
color: {
red: ["Red. Passion? Anger? Blood?", "A splash of crimson.", "Everything feels so intense."],
green: ["Green... a memory of nature.", "Is this a forest? Or just a feeling?", "Growth. Or is it decay?"],
blue: ["Blue. The color of distance.", "Like the ocean, deep and cold.", "A touch of sadness, or is it peace?"],
yellow: ["Yellow. A spark of hope?", "A strange warmth.", "Sunlight, maybe."],
cyan: ["A cold, digital feeling.", "Electric blue.", "Otherworldly."],
magenta: ["Unnatural. Vibrant.", "A shock to the system."]
},
complexity: {
low: ["So simple. So empty.", "Just one thing to focus on.", "A sense of isolation.", "Quiet... too quiet."],
high: ["Too much to see at once.", "My mind is racing.", "Chaos...", "Where do I even begin to look?"]
},
start: ["Hmm...", "What is this?", "I remember...", "Let's see..."],
end: ["...I suppose.", "...is that all there is?", "...and then it was gone.", "...what does it all mean?"]
},
ru: {
brightness: {
dark: ["Здесь кто-нибудь есть?", "Так темно...", "Потерян в тенях.", "Куда исчез свет?", "Лишь проблеск света."],
neutral: ["Просто... как есть.", "Тихий момент.", "Ни день, ни ночь.", "Всё кажется таким... обычным."],
bright: ["Так ярко.", "Мои глаза... это слишком.", "Вспышка белого света.", "Это воспоминание?"]
},
saturation: {
low: ["Цвета... они все исчезли.", "Блекло, как старая фотография.", "Мир в оттенках серого.", "Это реально?"],
neutral: ["Приглушенные тона.", "Чувство спокойствия.", "Ничего необычного."],
high: ["Цвета просто кричат.", "Так живо, до боли.", "Всепоглощающе.", "Это сон?"]
},
color: {
red: ["Красный. Страсть? Гнев? Кровь?", "Багровый всплеск.", "Все кажется таким напряженным."],
green: ["Зеленый... воспоминание о природе.", "Это лес? Или просто ощущение?", "Рост. Или это увядание?"],
blue: ["Синий. Цвет дали.", "Словно океан, глубокий и холодный.", "Нотка грусти, или это умиротворение?"],
yellow: ["Желтый. Искра надежды?", "Странное тепло.", "Солнечный свет, возможно."],
cyan: ["Холодное, цифровое чувство.", "Электрический синий.", "Нездешний."],
magenta: ["Неестественно. Ярко.", "Шок для системы."]
},
complexity: {
low: ["Так просто. Так пусто.", "Можно сосредоточиться на чем-то одном.", "Чувство изоляции.", "Тихо... слишком тихо."],
high: ["Слишком много всего.", "Мысли путаются.", "Хаос...", "С чего мне вообще начать?"]
},
start: ["Хм...", "Что это?", "Я помню...", "Так, посмотрим..."],
end: ["...полагаю.", "...и это всё?", "...а потом всё исчезло.", "...что всё это значит?"]
}
};
// Select the correct language, defaulting to English
const currentLang = phrases[lang.toLowerCase()] || phrases['en'];
const getRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
// 3. Analyze the image data
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const pixelCount = data.length / 4;
let totalLuminance = 0;
let totalSaturation = 0;
let complexity = 0;
const colorCounts = { red: 0, green: 0, blue: 0, yellow: 0, cyan: 0, magenta: 0, gray: 0 };
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Luminance
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
totalLuminance += luminance;
// Saturation (HSL formula approximation) and dominant color
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const sat = (max - min) / 255;
totalSaturation += sat;
if (sat < 0.1) {
colorCounts.gray++;
} else if (r > g && r > b) {
if (g > b) colorCounts.yellow++; // Orange/Yellow
else colorCounts.red++;
} else if (g > r && g > b) {
colorCounts.green++;
} else if (b > r && b > g) {
if (g > r) colorCounts.cyan++;
else colorCounts.blue++;
}
if (r > g && b > g && Math.abs(r-b) < 30) colorCounts.magenta++;
// Complexity (simple edge detection)
if (i + 4 < data.length) {
const r2 = data[i + 4];
complexity += Math.abs(r - r2);
}
}
const avgLuminance = totalLuminance / pixelCount;
const avgSaturation = totalSaturation / pixelCount;
const avgComplexity = complexity / (pixelCount * 255);
// 4. Generate the monologue from analysis results
const monologue = new Set();
monologue.add(getRandom(currentLang.start));
// Brightness
if (avgLuminance < 0.3) monologue.add(getRandom(currentLang.brightness.dark));
else if (avgLuminance > 0.7) monologue.add(getRandom(currentLang.brightness.bright));
else { if (Math.random() > 0.6) monologue.add(getRandom(currentLang.brightness.neutral)); }
// Saturation
if (avgSaturation < 0.15) monologue.add(getRandom(currentLang.saturation.low));
else if (avgSaturation > 0.4) monologue.add(getRandom(currentLang.saturation.high));
// Dominant Color
let dominantColor = 'gray';
let maxCount = colorCounts.gray;
for (const color in colorCounts) {
if (colorCounts[color] > maxCount) {
maxCount = colorCounts[color];
dominantColor = color;
}
}
if (dominantColor !== 'gray' && currentLang.color[dominantColor] && (maxCount / pixelCount) > 0.1) {
monologue.add(getRandom(currentLang.color[dominantColor]));
}
// Complexity
if (avgComplexity > 0.05) monologue.add(getRandom(currentLang.complexity.high));
else if (avgComplexity < 0.015) monologue.add(getRandom(currentLang.complexity.low));
monologue.add(getRandom(currentLang.end));
// 5. Create and return the final HTML element
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-block';
container.style.lineHeight = '0'; // Avoide extra space below image
const imgElement = document.createElement('img');
imgElement.src = originalImg.src;
imgElement.style.maxWidth = '100%';
imgElement.style.display = 'block';
const textOverlay = document.createElement('div');
textOverlay.textContent = Array.from(monologue).join(' ');
textOverlay.style.position = 'absolute';
textOverlay.style.bottom = '0';
textOverlay.style.left = '0';
textOverlay.style.width = '100%';
textOverlay.style.boxSizing = 'border-box';
textOverlay.style.padding = '15px 20px';
textOverlay.style.lineHeight = '1.4';
textOverlay.style.textAlign = 'center';
textOverlay.style.fontFamily = "'Courier New', Courier, monospace";
textOverlay.style.fontSize = 'clamp(12px, 2vw, 18px)';
textOverlay.style.color = 'white';
textOverlay.style.textShadow = '2px 2px 5px rgba(0, 0, 0, 0.9)';
textOverlay.style.background = 'linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0))';
textOverlay.style.pointerEvents = 'none';
container.appendChild(imgElement);
container.appendChild(textOverlay);
return container;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Analysis For Internal Monologues tool analyzes images to generate a fictional internal monologue based on their visual characteristics such as color, brightness, and complexity. This tool can be used for creative writing, art critique, or simply for enjoyment, allowing users to explore artistic interpretations of images they provide. It supports both English and Russian languages for the generated text, making it versatile for a broader audience.