You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, paletteSize = 8, quality = 10, quantizationShift = 4) {
// Validate parameters
paletteSize = Math.max(1, Math.floor(paletteSize));
quality = Math.max(1, Math.floor(quality));
quantizationShift = Math.max(1, Math.min(7, Math.floor(quantizationShift))); // 1 to 7 shifts (128 to 2 levels)
const canvas = document.createElement('canvas');
const scaledWidth = Math.max(1, Math.floor(originalImg.naturalWidth / quality));
const scaledHeight = Math.max(1, Math.floor(originalImg.naturalHeight / quality));
canvas.width = scaledWidth;
canvas.height = scaledHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0, scaledWidth, scaledHeight);
let imageData;
try {
imageData = ctx.getImageData(0, 0, scaledWidth, scaledHeight).data;
} catch (e) {
console.error("Error getting imageData (cross-origin issues?):", e);
const errorDiv = document.createElement('div');
errorDiv.textContent = 'Could not process image. This may be due to cross-origin restrictions if the image is not hosted on the same domain.';
errorDiv.style.cssText = "color: red; padding: 10px; border: 1px solid red; background-color: #ffeeee;";
return errorDiv;
}
const colorCounts = {}; // Stores { key: { sumR, sumG, sumB, count } }
for (let i = 0; i < imageData.length; i += 4) {
const r = imageData[i];
const g = imageData[i + 1];
const b = imageData[i + 2];
const a = imageData[i + 3];
if (a < 128) { // Skip transparent or mostly transparent pixels
continue;
}
// Quantize colors by shifting bits
const qr = r >> quantizationShift;
const qg = g >> quantizationShift;
const qb = b >> quantizationShift;
const colorKey = `${qr}_${qg}_${qb}`;
if (!colorCounts[colorKey]) {
colorCounts[colorKey] = { sumR: 0, sumG: 0, sumB: 0, count: 0 };
}
colorCounts[colorKey].sumR += r;
colorCounts[colorKey].sumG += g;
colorCounts[colorKey].sumB += b;
colorCounts[colorKey].count++;
}
const sortedColorBins = Object.entries(colorCounts)
.sort(([, binA], [, binB]) => binB.count - binA.count)
.slice(0, paletteSize);
const dominantColors = sortedColorBins.map(([, binData]) => ({
r: Math.round(binData.sumR / binData.count),
g: Math.round(binData.sumG / binData.count),
b: Math.round(binData.sumB / binData.count),
}));
// Helper functions
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}
function getContrastingTextColor(r, g, b) {
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return luminance > 0.5 ? 'black' : 'white';
}
// Create display element
const paletteContainer = document.createElement('div');
paletteContainer.style.cssText = "display: flex; flex-wrap: wrap; gap: 10px; padding: 10px; border: 1px solid #ccc; font-family: Arial, sans-serif; background-color: #f9f9f9;";
if (dominantColors.length === 0) {
const noColorsMsg = document.createElement('div');
noColorsMsg.textContent = 'No dominant colors found. Image might be too small, transparent, or quality/quantization settings too aggressive.';
noColorsMsg.style.cssText = "padding: 10px; color: #555;";
paletteContainer.appendChild(noColorsMsg);
return paletteContainer;
}
dominantColors.forEach(color => {
const { r, g, b } = color;
const bgColor = `rgb(${r},${g},${b})`;
const hexValue = rgbToHex(r, g, b);
const textColor = getContrastingTextColor(r, g, b);
const swatch = document.createElement('div');
swatch.style.cssText = `
width: 100px;
height: 120px;
background-color: ${bgColor};
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
padding: 8px;
box-sizing: border-box;
text-align: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
`;
const rgbText = document.createElement('span');
rgbText.textContent = `RGB: ${r},${g},${b}`;
rgbText.style.cssText = `color: ${textColor}; font-size: 10px; margin-bottom: 2px; word-break: break-all; background-color: rgba(0,0,0,0.1); padding: 1px 3px; border-radius: 2px;`;
const hexText = document.createElement('span');
hexText.textContent = `HEX: ${hexValue}`;
hexText.style.cssText = `color: ${textColor}; font-size: 10px; word-break: break-all; background-color: rgba(0,0,0,0.1); padding: 1px 3px; border-radius: 2px;`;
swatch.appendChild(rgbText);
swatch.appendChild(hexText);
paletteContainer.appendChild(swatch);
});
return paletteContainer;
}
Apply Changes