Совсем недавно при разработке одного из проектов столкнулся с необходимостью на стороне клиента перекрасить изображение. А именно: заменить один цвет на другой.
(!) В русскоязычном интернете решение найдено не было, поэтому ниже привожу подсказку зарубежных коллег.
Может возникнуть вопрос: почему нельзя просто загрузить отдельное изображение с другим цветом?
Ответ прост: нагрузка на сервер должна быть максимально низкой. Вы можете возвращать клиенту два вида изображений (с оригинальным цветом и замененным), но это требует больше трафика и запросов к серверу (два против одного).
Более рациональным может быть трата сравнительно небольших ресурсов на стороне пользователя (который этого даже не заметит) на замену цвета, но в итоге производительность сервера повысится.
Примеров применения может быть масса и, если у вас возникла подобная проблема, добро пожаловать. Решение под катом.
Реализация основывается на canvas. Да, это означает, что пользователи IE8 и более ранних не увидят изменений. Но, согласитесь: вы используете border-radius и другие CSS3-свойства из-за удобства, «забивая» на поддержку старых монстров. И это никому не мешает.
Если ещё кто-то по доброй воле использует Windows XP, то вряд ли он пользуется вместе с ним IE8. Это самоубийство. Однако это тема другой статьи.
Итак, метод основывается на canvas. Вот его алгоритм:
- Взять необходимо изображение
- Поместить его на холст canvas
- Сравнить цвет каждого пикселя холста с тем, о которого необходимо избавиться
- Заменить совпавшие цвета на необходимые
- Вернуть готовое изображение
Для удобства мы принимаем и возвращаем изображение в base64. Но этот участок функции можно легко модифицировать.
Функция:
function changeColorURI(data, oldColor, newColor)
{
var img, cnv, cnt, imgData;
img = document.createElement('img');
img.src = data;
cnv = document.createElement('canvas');
cnv.width = img.width;
cnv.height = img.height;
ctx = cnv.getContext('2d');
ctx.drawImage(img, 0, 0);
imgData = ctx.getImageData(0, 0, cnv.width, cnv.height)
data = imgData.data;
for(var x = 0, len = data.length; x < len; x += 4)
{
if((data[x] == oldColor[0]) && (data[x + 1] == oldColor[1]) && (data[x + 2] == oldColor[2]))
{
data[x] = newColor[0];
data[x + 1] = newColor[1];
data[x + 2] = newColor[2];
}
}
ctx.putImageData(imgData, 0, 0);
return cnv.toDataURL();
}
На вход поступает закодированное изображение (переменная data), заменяемый цвет в виде массива, состоящего из 3х цветов модели RGB (переменная oldColor), заменяющий цвет также в виде массива (переменная newColor).
Функцию можно доработать, передавая цвета в HEX-формате и переводить в RGB средствами JavaScript.
Важно!
Не стоит пользоваться функцией, если необходимо заменять одновременно 3 и более изображений в особенности, если они больших размеров. В таких случая задержка будет весьма заметной для пользователя, а в худшем случае можно и вовсе «повесить» браузер.
Функцию хорошо применять, если у вас есть спрайт с несколькими иконками одного цвета, которые необходимо одновременно перекрасить.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: