Всем привет.
У меня тут возникла задачка на проекте, а я ее решал.
Что-то решил, к чему-то пришел, а потом подумал, что могу об этом рассказать всем.
В тексте ниже я поделюсь опытом запрозрачнивания JPG в браузере.
Мысль про поддержку прозрачности в JPG-файле очень заразна. Я почти уверен, что она посещала хоть раз каждого веб-разработчика. Разные люди, разные идеи — разные решения. Вот список того, что придумали до меня:
Всё это хорошо, но, признайтесь, своё велосипед всегда ближе. Тем более, когда в голове крутится принцип работы, и всё, что нужно — это просто взять и написать код.
Пусть рассматриваемое изображение имеет только одну градацию прозрачности. Тогда, для ее кодирования, мы можем использовать произвольный цвет, не встречающийся более в картинке. Приём очень старый, но действующий.
Картинку с прозрачностью, замененную на такой цвет, мы можем сохранить в JPG и отдавать затем браузеру. Браузер же будет отображать ее, произведя обратные операции с использованием Сanvas.
Ребята из Mozilla примерно так и сделали, разве что в JPG не сохраняли, а просто гнали видео.
Если посмотреть на то, что у них получилось, видно, что границы у картинки шумят. Это происходит потому, что для отсечения они используют значения в RGB-представлении. Я предлагаю использовать для этого HSV. В этом случае мы можем прямо проассоциировать наш кодовый цвет со значением H в этой системе, фильтровать его с некоторым разбросом, а в самых спорных случаях дополнительно использовать значения S и V.
Величину отклонения фильтруемых точек от H определим в передаваемых параметрах: корректный порог лучше всего определять экспериментально для различных уровней JPG-компрессии. Чем уровень компрессии выше, тем шум на сжатой картинке будет больше, в том числе и в H-координате. Шум может привести к возникновению фальшивых прозрачных точек, которые испортят нам весь результат.
На самом деле, такие точки возникнут в любом случае, просто их будет больше или меньше. Для того, чтобы это скорректировать, я использовал дополнительный фильтр при выводе. Для каждой точки-кандидата-на-прозрачность рассматривается ее окрестность из 8 соседних точек. Если прозрачностью обладает менее половины соседей, принимается решение о фальшивом срабатывании, и точке присваивается средний цвет соседей и их усредненная прозрачность.
Такова общая схема работы. Она проста и примитивна, и, наверное, имело бы смысл сделать отсечение и фильтрацию изощреннее, но тут возникает следующий вопрос.
Поточечный обход изображения никогда не был особо быстрым, а векторных операций с аппаратным ускорением для canvas пока не создали. Переход в HSV, фильтрация (даже такая примитивная) — всё это расходует ресурсы. Когда я прототипировал всё это на локалхосте в настольном браузере, производительность казалась приемлемой. Картинка считалась полсекунды. А затем я открыл браузер на смартфоне и понял, что даже в таком, упрощенном виде, код выполняется очень медленно.
Знаете, я смотрел в код несколько часов и понял, что не знаю, как существенно поднять производительность. Если у вас появятся идеи, напишите их в комментариях.
Вот тут я положу ссылки на то, что у меня получилось:
Идея казалась красивой, а реализация — простой, но мобильные устройства испортили праздник. Наверное, мне будет проще отдать несколько мегабайт прозрачных PNG, чем полминуты ждать обсчёта сотни килобайт JPG.
То, что получилось, мне не нравится. Но, возможно, вы сочтете этот эксперимент интересным. Если мой код покажется кому-то полезным, пишите, я выложу его на гитхаб.
У меня тут возникла задачка на проекте, а я ее решал.
Что-то решил, к чему-то пришел, а потом подумал, что могу об этом рассказать всем.
В тексте ниже я поделюсь опытом запрозрачнивания JPG в браузере.
Мысль про поддержку прозрачности в JPG-файле очень заразна. Я почти уверен, что она посещала хоть раз каждого веб-разработчика. Разные люди, разные идеи — разные решения. Вот список того, что придумали до меня:
Всё это хорошо, но, признайтесь, своё велосипед всегда ближе. Тем более, когда в голове крутится принцип работы, и всё, что нужно — это просто взять и написать код.
Принцип работы
Пусть рассматриваемое изображение имеет только одну градацию прозрачности. Тогда, для ее кодирования, мы можем использовать произвольный цвет, не встречающийся более в картинке. Приём очень старый, но действующий.
Картинку с прозрачностью, замененную на такой цвет, мы можем сохранить в JPG и отдавать затем браузеру. Браузер же будет отображать ее, произведя обратные операции с использованием Сanvas.
Ребята из Mozilla примерно так и сделали, разве что в JPG не сохраняли, а просто гнали видео.
На самом деле не всё так просто.
Если посмотреть на то, что у них получилось, видно, что границы у картинки шумят. Это происходит потому, что для отсечения они используют значения в RGB-представлении. Я предлагаю использовать для этого HSV. В этом случае мы можем прямо проассоциировать наш кодовый цвет со значением H в этой системе, фильтровать его с некоторым разбросом, а в самых спорных случаях дополнительно использовать значения S и V.
Величину отклонения фильтруемых точек от H определим в передаваемых параметрах: корректный порог лучше всего определять экспериментально для различных уровней JPG-компрессии. Чем уровень компрессии выше, тем шум на сжатой картинке будет больше, в том числе и в H-координате. Шум может привести к возникновению фальшивых прозрачных точек, которые испортят нам весь результат.
На самом деле, такие точки возникнут в любом случае, просто их будет больше или меньше. Для того, чтобы это скорректировать, я использовал дополнительный фильтр при выводе. Для каждой точки-кандидата-на-прозрачность рассматривается ее окрестность из 8 соседних точек. Если прозрачностью обладает менее половины соседей, принимается решение о фальшивом срабатывании, и точке присваивается средний цвет соседей и их усредненная прозрачность.
Такова общая схема работы. Она проста и примитивна, и, наверное, имело бы смысл сделать отсечение и фильтрацию изощреннее, но тут возникает следующий вопрос.
Производительность
Поточечный обход изображения никогда не был особо быстрым, а векторных операций с аппаратным ускорением для canvas пока не создали. Переход в HSV, фильтрация (даже такая примитивная) — всё это расходует ресурсы. Когда я прототипировал всё это на локалхосте в настольном браузере, производительность казалась приемлемой. Картинка считалась полсекунды. А затем я открыл браузер на смартфоне и понял, что даже в таком, упрощенном виде, код выполняется очень медленно.
Знаете, я смотрел в код несколько часов и понял, что не знаю, как существенно поднять производительность. Если у вас появятся идеи, напишите их в комментариях.
Вот тут я положу ссылки на то, что у меня получилось:
- разные картинки, в консоли выводится время рендеринга (осторожно, фон!)
- то, ради чего всё это затевалось (будет грузиться 8-15 секунд)
- код
Резюме
Идея казалась красивой, а реализация — простой, но мобильные устройства испортили праздник. Наверное, мне будет проще отдать несколько мегабайт прозрачных PNG, чем полминуты ждать обсчёта сотни килобайт JPG.
То, что получилось, мне не нравится. Но, возможно, вы сочтете этот эксперимент интересным. Если мой код покажется кому-то полезным, пишите, я выложу его на гитхаб.