belun.app Блог
EN

Как декодировать строку Base64 обратно в картинку

Что на самом деле лежит внутри Base64-строки изображения, как вернуть её в PNG или JPG и о какой прибавке к весу обычно молчат.

Цветные пиксели на экране монитора — декодированное из Base64 изображение крупным планом

Открываете JSON-ответ, исходник письма или чужой CSS, а там стена из букв и цифр на три тысячи символов, начинается с iVBORw0KGgo. Это картинка. Просто вы её пока не видите.

Инструмент Base64 в изображение превращает эту стену обратно в то, на что можно посмотреть и что можно сохранить.

Что это за строка

Base64 переписывает произвольные байты 64 печатными символами, чтобы двоичные данные пережили путешествие там, где допустим только текст. Тело письма. Поле JSON. Атрибут в HTML. Каждые 3 байта исходного файла превращаются в 4 символа — отсюда и берётся прибавка примерно в 33%.

Формат выдают первые символы, потому что сигнатура файла всегда оказывается в одном и том же месте:

  • iVBORw0KGgo — это PNG
  • /9j/ — JPEG
  • R0lGOD — GIF
  • UklGR — WebP
  • PHN2Zw или PD94bWw — SVG (это XML, поэтому начало читается глазами)

Знание этих четырёх префиксов сэкономило мне больше времени на отладке, чем хочется признавать. Когда коллега клянётся, что API отдаёт JPEG, а строка начинается с iVBOR, спор закончен.

Как декодировать

Вставьте строку в поле. Можно отдать целиком data:image/png;base64,..., можно только полезную нагрузку после запятой — сработает и то и другое. Если вы скопировали значение из стилей вместе с обёрткой url("..."), она тоже отрежется.

Появится превью, а рядом — формат, размер файла и разрешение в пикселях. Дальше выбираете, что скачать: исходные байты или перекодировку в PNG либо JPG.

Одна деталь про JPG, на которой спотыкаются. В JPEG нет альфа-канала. Если перевести PNG-логотип с прозрачным фоном напрямую в JPG, прозрачные пиксели обязаны стать чем-то, и наивный ответ — чёрным. Инструмент подкладывает белый фон перед кодированием, обычно этого и хотят. Но если прозрачность нужна по-настоящему, оставайтесь на PNG.

Почему формат определяется по байтам, а не по подписи

MIME-тип в data URI — это просто надпись, которую кто-то напечатал. Она бывает неверной, а в сгенерированном коде неверна довольно часто. Поэтому декодер читает настоящую сигнатуру из декодированных байтов и сообщает, что перед вами на самом деле. JPEG, подписанный как image/png, всё равно раскодируется и корректно отрисуется.

Когда Base64-картинка — плохая идея

Встроить изображение прямо в разметку кажется аккуратным: меньше HTTP-запросов, не надо выкладывать отдельный файл. Для иконки в 400 байт нормально. После пары килобайт начинаются издержки:

  • Те самые 33% оплачиваются при каждой загрузке страницы, а встроенный data URI лежит внутри HTML или CSS и не кэшируется отдельно от них
  • Браузер не может отложить загрузку картинки, которая уже находится в разметке
  • Base64 сжимается gzip заметно хуже исходного бинарника
  • Фотография на 200 КБ становится строкой на 267 КБ, и теперь ваш CSS тяжелее на эти 267 КБ для каждого посетителя

Правило, которого держусь: меньше 2 КБ — встраивайте, больше — отдавайте настоящим файлом.

Приватность

Строка не покидает браузер. Декодирование, определение формата, превью и перекодировка выполняются на вашей машине. Это важно, когда на картинке внутренняя схема, подписанный документ или неопубликованная работа клиента.

Есть строка, которую не получается прочитать? Вставьте её в декодер и посмотрите, что это.

Попробуйте инструмент

Base64 в изображение →