Руководства

Как сжать изображение Base64 (почему Gzip обычно не помогает)

Узнайте, как уменьшать Base64 через оптимизацию изображения, почему Gzip не заменяет Data URL и как стремиться к 100 КБ в JavaScript.

Почему Base64 больше примерно на 33,3%

Base64 кодирует три байта четырьмя символами. Точная длина — 4 × ceil(n / 3), без префикса Data URL.

Три цепочки обработки

Байты→Base64 стандартны, но больше. Base64→Gzip→Base64 требует снять два слоя. Декодировать изображение→оптимизировать→Base64 сохраняет обычное изображение для img src.

Почему выигрыш Gzip исчезает после возврата к тексту

Промежуточный Gzip может быть меньше, но новый Base64 и заголовки добавляют объём. Результат — Gzip, а не JPEG, PNG или WebP, и напрямую не отображается.

Форматы изображений уже сжаты

JPEG, PNG и WebP применяют своё сжатие. Реальная экономия обычно даётся меньшим числом пикселей, качеством с потерями, удалением метаданных или сменой формата.

Правильный JavaScript в браузере

Проверьте Base64 и magic bytes, декодируйте ImageBitmap, рисуйте на ограниченной Canvas и используйте toBlob. В рабочем коде нужны лимиты, запрет анимации, проверка WebP и защита от старых задач.

Короткий пример на встроенных API

async function compressBase64Image(dataUrl, maxWidth = 1600, quality = 0.82) {
  const [header, payload] = dataUrl.split(',', 2);
  const mime = header.match(/^data:([^;]+);base64$/)?.[1];
  if (!mime || !/^image\/(png|jpeg|webp)$/.test(mime)) throw new Error('Unsupported image');

  const binary = atob(payload.replace(/\s+/g, ''));
  const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
  const bitmap = await createImageBitmap(new Blob([bytes], { type: mime }));
  try {
    const scale = Math.min(1, maxWidth / bitmap.width);
    const canvas = document.createElement('canvas');
    canvas.width = Math.max(1, Math.round(bitmap.width * scale));
    canvas.height = Math.max(1, Math.round(bitmap.height * scale));
    const context = canvas.getContext('2d');
    if (!context) throw new Error('Canvas 2D unavailable');
    context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/webp', quality));
    if (!blob) throw new Error('Encoding failed');
    const output = new Uint8Array(await blob.arrayBuffer());
    let outputBinary = '';
    for (let offset = 0; offset < output.length; offset += 0x8000) {
      outputBinary += String.fromCharCode(...output.subarray(offset, offset + 0x8000));
    }
    return `data:${blob.type};base64,${btoa(outputBinary)}`;
  } finally {
    bitmap.close();
  }
}

Как получить 100 КБ

Считайте 100 КБ как 102 400 байт. Ограниченно ищите качество JPEG/WebP; затем масштабируйте с sqrt(цель/текущее) всего несколько раундов.

Качество, размеры и формат

Качество меняет codec, масштабирование удаляет пиксели. Фото часто подходят JPEG/WebP, прозрачность — PNG/WebP. Сравнивайте реальные файлы.

Прозрачность PNG и фон JPEG

У JPEG нет alpha. Сохраняйте PNG/WebP или требуйте подтверждённый фон перед сведением.

GIF, анимированный WebP и SVG

Canvas обычно берёт один кадр. Отклоняйте GIF, WebP-анимацию и ICO; для SVG нужен отдельный текстовый оптимизатор.

Локально — приватнее, но не гарантированно безопасно

Нет загрузки и серверного хранения, но это не антивирус. Риски устройства, расширений и browser codec остаются.

Когда отказаться от Base64

Для больших изображений лучше Blob URL, отдельный кэшируемый файл или бинарная отправка Blob/FormData/ArrayBuffer.

Частые вопросы

Можно сжать Base64?

Да, но общее сжатие не даёт напрямую используемый Base64 изображения.

Работает в img src?

Только если после декодирования это изображение; Gzip надо распаковать.

Как получить 100 КБ?

Ограниченно ищите качество, затем пропорционально уменьшайте размеры.

Качество снизится?

Масштабирование и lossy-качество могут его снизить.

Почему +33%?

Три байта представлены четырьмя символами.

Есть загрузка?

Компрессор работает только в браузере.

Gzip до или после?

Используйте HTTP-сжатие вокруг документа, не внутри Data URL.

Стандарты и документация браузера