/**
* Função auxiliar para extrair a cor média de um contexto 2D
*/
function getAverageColor(ctx, width, height) {
// Pega os dados dos pixels (R, G, B, Alpha)
// Para performance, poderíamos ler apenas uma amostra, mas aqui leremos tudo
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
let r = 0, g = 0, b = 0;
let count = 0;
// Loop pulando de 10 em 10 pixels para ser MUITO rápido
// i += 4 * 10 (4 canais: r,g,b,a)
for (let i = 0; i < data.length; i += 40) {
r += data[i];
g += data[i + 1];
b += data[i + 2];
count++;
}
// Calcula a média
r = Math.floor(r / count);
g = Math.floor(g / count);
b = Math.floor(b / count);
// Converte para Hexadecimal (#RRGGBB)
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
export async function compressImage(file, quality = 0.8, maxWidth = 1200) {
return new Promise((resolve, reject) => {
if (!file.type.match(/image.*/)) {
reject(new Error("O arquivo não é uma imagem."));
return;
}
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (event) => {
const img = new Image();
img.src = event.target.result;
img.onload = () => {
// --- Captura dados originais ---
const originalWidth = img.naturalWidth;
const originalHeight = img.naturalHeight;
// --- Lógica de Redimensionamento ---
let width = originalWidth;
let height = originalHeight;
if (width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Desenha a imagem redimensionada no canvas
ctx.drawImage(img, 0, 0, width, height);
// --- Extração de Cor ---
// Analisa os pixels da imagem já desenhada
const dominantColor = getAverageColor(ctx, width, height);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error("Erro ao processar."));
return;
}
const newName = file.name.replace(/\.[^/.]+$/, "") + ".webp";
const newFile = new File([blob], newName, {
type: "image/webp",
lastModified: Date.now(),
});
// Retorna um objeto rico com todos os metadados
resolve({
file: newFile,
meta: {
originalSize: file.size,
compressedSize: newFile.size,
originalWidth: originalWidth,
originalHeight: originalHeight,
finalWidth: width,
finalHeight: height,
dominantColor: dominantColor // Ex: #ff0000
}
});
},
'image/webp',
quality
);
};
img.onerror = (err) => reject(err);
};
reader.onerror = (err) => reject(err);
});
}
|