Как конвертировать Base64 в WebP
- Вставьте Base64 или полный URI
data:image/webp;base64,.... Подойдёт и код, в котором он есть, например CSSurl()или тег<img>. - Убедитесь, что в строке статуса написано Определено WebP, затем посмотрите превью и размеры над ним. Анимированный WebP в превью проигрывается.
- Нажмите Скачать файл. Расширение уже выставлено в
webp.
Три вида WebP
WebP – это контейнер RIFF, в котором сразу после метки WEBP идёт чанк одного из трёх типов. Метка стоит на фиксированном смещении, поэтому и тип оказывается на фиксированном месте в Base64:
| Base64 начинается с | Чанк | Что это |
|---|---|---|
UklGR…XRUJQVlA4I | VP8 | с потерями, без прозрачности |
UklGR…XRUJQVlA4T | VP8L | без потерь, может быть с прозрачностью |
UklGR…XRUJQVlA4W | VP8X | расширенный: с потерями и альфа-каналом, анимация, ICC-профиль или EXIF |
Шесть символов между UklGR и XRUJQ кодируют размер файла и меняются от файла к файлу. XRUJQ (из WEBP) всегда стоит на позициях 12–16, а VlA4 (из VP8) – на 17–20. Тип выдаёт 21-й символ: I, T или W.
Тип стоит проверить, прежде чем передавать файл дальше. WebP без потерь вполне заменяет PNG. WebP с потерями уже лишился деталей, так что конвертация в PNG даст большой файл, а качество не вернёт. Расширенный файл может содержать несколько кадров; при конвертации в статичный формат останется только первый.
Проверить тип WebP в коде
Та же проверка на Python читает метку чанка, а для расширенных файлов – байт флагов:
import base64
def webp_kind(b64: str) -> str:
data = base64.b64decode(b64.split(",", 1)[-1])
if data[:4] != b"RIFF" or data[8:12] != b"WEBP":
return "not WebP"
chunk = data[12:16]
if chunk == b"VP8 ":
return "lossy"
if chunk == b"VP8L":
return "lossless"
flags = data[20]
parts = ["extended"]
if flags & 0x10:
parts.append("alpha")
if flags & 0x02:
parts.append("animated")
return ", ".join(parts)
Для файлов WebP, записанных Pillow, функция возвращает lossy, lossless, extended, alpha для изображения с потерями и прозрачностью и extended, animated для анимации. См. также статью Base64 в Python.
RIFF не всегда означает WebP
UklGR означает только «RIFF». Аудио WAV и видео AVI начинаются так же и отличаются меткой в байтах 8–11. Декодер проверяет эту метку, поэтому для вставленного сюда WAV он сообщит «Похоже на WAV, а не на WebP» и предложит кнопку для сохранения в .wav. Воспроизвести его можно на странице Base64 в аудио.
Где встречается WebP в Base64
- Экспорт из canvas через
toDataURL("image/webp", quality). Проверяйте результат: браузеры без кодировщика WebP молча возвращают PNG. - API изображений и CDN, которые отдают WebP, если клиент его принимает. В поле с именем
thumbnail_jpgможет лежать WebP, если картинку запрашивал браузер. - Встроенные заглушки и иконки в HTML и CSS, где WebP даёт строку короче, чем PNG или JPEG.
- Стикеры в мессенджерах: часто это WebP, иногда анимированный.
Если старая программа не принимает сохранённый файл, сравните SHA-256, показанный здесь, с хешем файла, который она получила. Если они совпадают, программа просто не читает WebP, и выход – копия в PNG или JPEG.
Вопросы и ответы
Мой WebP в Base64 – с потерями или без?
Посмотрите на 21-й символ строки. I после VlA4 означает изображение VP8 с потерями, T – VP8L без потерь, а W – расширенный формат, который используют изображения с потерями и прозрачностью или анимация.
Можно сохранить декодированный WebP как PNG или JPG?
Переименованием – нет: байты останутся WebP. Скачайте .webp, откройте WebP в Base64, выберите в Конвертировать в PNG или JPEG и декодируйте новую строку на странице Base64 в PNG.
Почему canvas.toDataURL('image/webp') вернул PNG?
Браузеры, которые не умеют кодировать WebP, в первую очередь Safari, молча возвращают data URI с PNG. Вставьте результат сюда: если инструмент пишет PNG, так и случилось.
Почему превью не работает на старом Mac или iPhone?
Safari 14 и 15 показывают WebP только на macOS 11 Big Sur и новее, а Safari до 14-й версии не показывает вовсе. Там превью сообщит, что браузер не может показать изображение, но Скачать файл всё равно сохранит корректный .webp.