Чиним генерацию WEBP на PHP
На днях добавил к блогу поддержку формата WEBP. Работать начало всё сразу, но без костылей не обошлось.
Каналы передачи данных становятся всё шире, скорости растут, а дух оптимизатора все никак не унимается. WEBP обещает выигрыш до 30% на размер файла по сравнению с JPG при примерно одинаковом количестве деталей. Проверено, так и есть.
Реализация WEBP на этом блоге
Сегодня, из всех браузеров, полноценно поддерживают WEBP только Chromium-подобные браузеры. Не очень-то и обширно, но радует, что крупные игроки один за одним сообщают о внедрении технологии в ближайшее время. Тем не менее, реализуя поддержку WEBP уже сегодня, мы получаем ощутимый прирост скорости загрузки. А по данным comss.ru, мы покрываем более 60% всех пользователей.
Браузер | Покрытие, % | webp | Примечание |
---|---|---|---|
Chromium | 61,29 | да | все Chromium-подобные браузеры (Chrome, Yandex-браузер, новая Opera и.т.д) |
Firefox | 12,38 | нет | говорят, поддержку уже добавили в тестовую версию |
Edge | 4,03 | нет | поддержку грозятся внести не только в Edge, но ещё и в Windows |
Как же быть с браузерами, не поддерживающими WEBP? Умные головы придумали тег <picture>, а в нём теги <source> с указанием типа изображения и пути к файлу. Браузеры сами решают, какое изображение они будут показывать. Например, Chrome выбирает WEBP. Современные браузеры корректно обработают эту конструкцию, а старые пропустят неизвестные теги. Особое внимание нужно обратить на атрибут type, в нем указывается mime-тип изображения.
<picture> <source type="image/webp" srcset="/images/coolimg.webp"/> <source type="image/jpeg" srcset="/images/coolimg.jpg"/> <img src="/images/coolimg.jpg"/> </picture>
Я был приятно удивлен, обнаружив поддержку WEBP в библиотеке php-gd. На стороне сервера за сохранение изображений отвечают следующие функции:
imagejpeg($imageObject, $jpgDestination, $quality); //в JPG imagewebp($imageObject, $webpDestination, $quality); //в WEBP
PHP ломает WEBP
Как и положено, у этого блога есть 2 сервера. На тесте стоит php 5.6.36, на проме php 5.6.37. Внеся все необходимые правки, я протестировал сайт на домашнем компьютере и обновил пром. Я был удивлен, изображения на проме не отображались, вообще, хотя на тестовом сервере работали без проблем.
В консоли хрома ошибок не было, более того Хром рапортовал о нормальной загрузке изображений.
Я скачал сгенерированный WEBP-файл с блога и... файл отлично открылся в ACDSee. Сравнивая файлы прома и теста, я обнаружил несоответствие размеров для сгенерированных WEBP-файлов на сервере и на домашнем компьютере. Размер файлов отличался всего лишь в 1 байт.
Вот эти 2 файла:
Скачать изображение с тестаjcup_gen.webp
157 КБ Скачать изображение с прома
jcup_ru.webp
157 КБ
Сдул пыль с HEX-редактора и полез смотреть, чего там не хватает. Оказалось, что промовкий PHP не дописывает 1 байт в конец файла, файл оказывается не валидным и Chrome не может его отобразить. Обновление пакетов php5.6 и php5.6-gd на проме не дало, ровным счётом, никаких результатов.
Немного поисследовав структуру WEBP, я пришел к выводу, что все живые файлы всегда заканчиваются байтом x00, кроме того WEBP продолжает нормально работать, если добавить любое количество x00 в конец. Можете проверить сами, всё отлично работает:
Скачать webp с огромным кол-ом x00 в концеru_with_many_x00.webp
157.1 КБ
Так и появился на свет очередной костыль. Сразу после генерации изображения, дописываем x00 в конец файла.
//x00 webp generation fix $fpr=fopen($webpDestination, "a+"); fwrite($fpr, chr(0x00)); fclose($fpr);