Что я хочу
Сжимать загружаемые изображения в браузере до размера ≤ целевого КБ (например, 100 КБ), сохраняя при этом достойное визуальное качество.
Ожидаемое поведение
Когда я устанавливаю целевой размер = 100 КБ, размер загруженного файла должен быть ≤ 100 КБ.
Фактическое поведение
Результат остается значительно большим (например, 300–600 КБ). Снижение качества JPEG до 0,05 иногда помогает, но для некоторых изображений этого недостаточно. Выходные файлы в формате PNG остаются большими.
Шаги по воспроизведению
- Откройте страницу (пример: https://mbtokbconverter.org/ или вставьте локальную демонстрацию).
- Загрузите большой PNG или фотографию с высоким разрешением (~2–5 МБ).
- Установите целевой размер: 100 КБ → нажмите Сжать.
- Наблюдайте за размером выходного файла.
- Браузер: Chrome / Firefox (последняя стабильная версия)
- ОС: Windows 10/macOS
- Код выполняется на стороне клиента (без сервера)
Соответствующий код (упрощенный)
Код: Выделить всё
Compress
Download
Код: Выделить всё
function readFileAsDataURL(file){
return new Promise((resolve,reject)=>{
const fr = new FileReader();
fr.onload = () => resolve(fr.result);
fr.onerror = () => reject(fr.error);
fr.readAsDataURL(file);
});
}
function createImage(url){
return new Promise((resolve,reject)=>{
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('Image load error'));
img.src = url;
});
}
function canvasToBlob(canvas, type, quality){
return new Promise(resolve => canvas.toBlob(resolve, type, quality));
}
async function compressImage(file, targetKB, maxWidth){
const targetBytes = targetKB * 1024;
const dataUrl = await readFileAsDataURL(file);
const img = await createImage(dataUrl);
let w = img.width, h = img.height;
if(maxWidth > 0 && maxWidth < w){
h = Math.round(h * (maxWidth / w));
w = maxWidth;
}
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
canvas.getContext('2d').drawImage(img, 0, 0, w, h);
// binary-search on quality
let low = 0.05, high = 0.95, bestBlob = null;
for(let i = 0; i < 10; i++){
const q = (low + high) / 2;
const blob = await canvasToBlob(canvas, 'image/jpeg', q);
if(!blob) break;
if(blob.size
Подробнее здесь: [url]https://stackoverflow.com/questions/79824623/mb-%e2%86%92-kb-image-compressor-using-canvas-and-js-final-file-remains-larger-than-tar[/url]
Мобильная версия