Ресайз картинок в браузере. Все может стать еще хуже
Знакомьтесь, это Маня. Маню поразил страшный недуг и теперь она нуждается в вашей помощи. Маня росла обычной девочкой, жизнерадостным счастливым ребенком. Но чуть больше года назад врачи поставили ей страшный диагноз — алиазинг. И она стала выглядеть вот так.
Как выяснилось, виной тому стала жадность и алчность производителей браузеров, которые решили сэкономить на алгоритмах ресайза изображений и применить самые низкокачественные фильтры. Тогда Маню удалось спасти — она прошла курс последовательных не кратных двум уменьшений, что снизило алиазинг и вернуло её былую резкость. Но теперь ей снова угрожает опасность.
Что изменилось за этот год? Хорошие новости в том, что появился стандарт, призванный управлять качеством растеризации изображений на канвасе. Новости еще лучше: этот стандарт реализован в браузере: мобильном Сафари с версии 9.3 и десктопном с версии 9.1. И судя по получающимся результатам, значению high
соответствует метод сверток с бикубическим или очень похожим фильтром. Т.е. результат действительно очень хорош. Казалось бы, можно обернуть код, вымученный в предыдущей статье, в if ('imageSmoothingQuality' in context)
и ждать появления этого же свойства в остальных браузерах. Но что-то пошло не так.
Что-то пошло не так и на маню напала другая напасть — Маня стала мыльной. Оказалось, что Гугл тоже готовит для Машеньки сюрприз, реализовав нужное свойство и пока что спрятав его за флагом chrome://flags/#enable-experimental-canvas-features
. Вот только реализовано оно не добросовестно, а чем попало. Вместо правильных, четких, православных сверток, в нем для значения high
используется техника, применяющаяся в играх: с помощью суперсэмплинга для изображения создаются mip-уровни, а потом ближайший по размеру уровень ресайзится все тем же дешевым методом с фиксированным количеством исходных точек.
Почему этот метод работает в играх? По двум причинам. Первая: в динамичной игре у вас нет времени рассматривать каждую текстуру по-отдельности, мыльная она или не очень. Гораздо больше на восприятие влияет общая картинка и спецэффекты, чем такие мелочи. Вторая: очень жесткие временные ограничения, для которых очень кстати приходится постоянная сложность этого метода относительно размеров конечного изображения (разрешения экрана в случае игр).
Почему этот метод не годится для ресайза в приложениях для работы с графикой? Да потому что это вообще не метод ресайза, алло. Это аппликация из двух решений, ни одно из которых не способно удовлетворить требования к качеству —, а уж вдвоем и подавно. Оно не обладает ни математическим обоснованием, ни стабильностью результата относительно входных параметров. Например, картинка, отресайженая до 244 пикселей в ширину может получиться ничего так, а отресайженая до 243 вся будет в мыле. Тем более это не приемлемо для специально созданного по этому случаю свойства imageSmoothingQuality
. Уж если я ставлю high
, то наверное я имею в виду, что мне нужно именно хорошее качество. Зачем вообще реализовывать новое свойство, если оно дает результат хуже, чем можно добиться, повозившись с существующим решением? Вот, например, справа Маня отресайженая последовательными не кратными двум уменьшениями. Абсолютно здоровый и счастливый ребенок.
Если вы вдруг не испытываете сочувствия и симпатии к маленьким детям, то вот вам Манечкин друг, мандрил Пупуся. Его постигла та же беда. Слева направо:
- заблюреная картинка после ресайза в Хроме с
imageSmoothingQuality = 'high'
- качественная картинки из Сафари
- более-менее качественная картинка после ресайза в Хроме методом последовательных уменьшений без
imageSmoothingQuality
Как тут можно помочь? Ну например, пойти поставить звездочку в созданном для этого баг-репотре. Не уверен, насколько это эффективно, но ничего другого придумать не могу.
Что же будет, если эта фича перекочует в стабильную версию Хрома? Вместо простой проверки на наличие фичи, придется либо городить проверку по юзер-агенту, либо отключать эту функциональность для всех пользователей, даже в Сафари. В голову пришла правильная идея: нужно пойти и прямо сейчас поставить дополнительную проверку на то, что в юзерагенте нет слова Хром. Если Хром исправится и в стабильной версии не будет этого позорища, можно будет включить. Зато если кто-то из клиентов скачает код сейчас, при выходе бажного Хрома Маня не пострадает.
Для получения использовались изображения раз и два, тестовый стенд, а также виджет для последовательных уменьшений.