You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Converts an image into emoji pixel art where each "pixel" of the original
* image is represented by a colored emoji square (e.g., 🟥, 🟩, 🟦).
* The resulting art is returned in a <pre> element for easy copying and pasting.
*
* @param {HTMLImageElement} originalImg The original image object to convert.
* @param {number} pixelSize The size of the image area (in pixels) that each emoji will represent. A smaller number yields a more detailed, larger result. Defaults to 10.
* @returns {HTMLPreElement} A styled <pre> element containing the generated emoji art.
*/
function processImage(originalImg, pixelSize = 10) {
// 1. Sanitize the pixelSize parameter.
const safePixelSize = Math.max(1, parseInt(pixelSize, 10) || 10);
// 2. Define the palette of emojis and their representative RGB colors.
// These RGB values are approximations of how these emojis render on average across platforms.
const emojiPalette = [
{ emoji: '🟥', color: [221, 46, 68] }, // Red
{ emoji: '🟧', color: [244, 144, 12] }, // Orange
{ emoji: '🟨', color: [253, 203, 88] }, // Yellow
{ emoji: '🟩', color: [120, 177, 89] }, // Green
{ emoji: '🟦', color: [85, 172, 238] }, // Blue
{ emoji: '🟪', color: [170, 125, 186] }, // Purple
{ emoji: '🟫', color: [153, 90, 76] }, // Brown
{ emoji: '⬛', color: [47, 55, 67] }, // Black
{ emoji: '⬜', color: [225, 228, 232] } // White
];
/**
* Finds the closest emoji from the palette for a given RGB color using Euclidean distance.
* @param {number} r The red channel value (0-255).
* @param {number} g The green channel value (0-255).
* @param {number} b The blue channel value (0-255).
* @returns {string} The emoji character that is the closest color match.
*/
function findClosestEmoji(r, g, b) {
let closestEmoji = '?';
let minDistance = Infinity;
for (const item of emojiPalette) {
const [pr, pg, pb] = item.color;
// Using squared Euclidean distance is faster since we only need to compare, not know the actual distance.
const distance = Math.pow(r - pr, 2) + Math.pow(g - pg, 2) + Math.pow(b - pb, 2);
if (distance < minDistance) {
minDistance = distance;
closestEmoji = item.emoji;
}
}
return closestEmoji;
}
// 3. Create a canvas to extract pixel data from the image.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// 4. Downscale the image for efficient color sampling.
// Drawing the large image onto a small canvas effectively averages the colors of the corresponding blocks.
const outputWidth = Math.max(1, Math.floor(originalImg.width / safePixelSize));
const outputHeight = Math.max(1, Math.floor(originalImg.height / safePixelSize));
canvas.width = outputWidth;
canvas.height = outputHeight;
ctx.drawImage(originalImg, 0, 0, outputWidth, outputHeight);
// 5. Get the pixel data from the downscaled canvas.
const imageData = ctx.getImageData(0, 0, outputWidth, outputHeight);
const data = imageData.data;
// 6. Build the string of emojis row by row.
let emojiArt = '';
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// The alpha channel (data[i + 3]) is ignored in this implementation.
emojiArt += findClosestEmoji(r, g, b);
// Check if we've reached the end of a row in the output grid to add a newline.
const pixelIndex = i / 4;
if ((pixelIndex + 1) % outputWidth === 0) {
emojiArt += '\n';
}
}
// 7. Create the final <pre> element to display the emoji art.
const preElement = document.createElement('pre');
preElement.textContent = emojiArt.trim();
// Apply styles to make the emoji art look like a cohesive image.
preElement.style.fontFamily = 'monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
preElement.style.lineHeight = '0.9';
preElement.style.letterSpacing = '-0.1em';
preElement.style.fontSize = `${safePixelSize * 1.1}px`;
preElement.style.backgroundColor = '#f0f0f0';
preElement.style.padding = '1em';
preElement.style.border = '1px solid #ccc';
preElement.style.borderRadius = '4px';
preElement.style.overflow = 'auto';
preElement.style.textAlign = 'center';
preElement.style.margin = '0';
preElement.style.userSelect = 'all';
return preElement;
}
Apply Changes