Каков наилучший способ изменить цвет/оттенок изображения на холсте?

Я попытался найти ответ в Google, но так и не смог найти простой ответ или почему ответ работает. Поэтому я хотел бы знать, какой код можно использовать для изменения цвета изображения на холсте? Например, скажем, я хочу изменить что-то на #ff0000. Если пиксель равен #000000, он должен оставаться таким. Если пиксель использовал #ffffff, он должен стать #ff0000. Вот мой конструктор текстовых объектов:

Text = function(x, y, str, s, c){
        var img = new Image();
        img.src = "font.png";
        var alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ".", "!", "?"]
        this.text = str.toLowerCase();
        this.x = x;
        this.y = y;
        this.type = "text";
        this.rows = 1;
        this.height = this.rows * 10;
        this.width = this.text.length * 8;
        this.draw = function(){
            for (var i = 0; i < this.text.length; i++)
            {
                scene.ctx.drawImage(img, (alphabet.indexOf(this.text[i]) % 16) * 8, Library.newMath.roundZero(alphabet.indexOf(this.text[i]) / 16) * 10, 8, 10, this.x + i * 8 + (scene.xOffset * !this.fixed), this.y + 0 + (scene.yOffset * !this.fixed), 8, 10);
            }           
        }
        Shape.prototype.constructor.call(this, x, y);
    }

person Howzieky    schedule 14.10.2015    source источник
comment
Я предполагаю, что font.png — это таблица спрайтов, содержащая буквы az плюс некоторые знаки препинания. Я также предполагаю, что каждый символ повторяется на листе спрайтов разными цветами. Если это так, то scene.ctx.drawImage вырезает указанный символ указанного цвета из этого спрайт-листа и рисует его на сцене. Таким образом, код на самом деле не меняет цвета, он просто выбирает другую, уже окрашенную букву из таблицы спрайтов.   -  person markE    schedule 15.10.2015
comment
Но подробнее о вашем вопросе... Если изображение части, которое вы хотите перекрасить, имеет один сплошной цвет, проверьте context.globalCompositeOperation='source-atop'. Если часть изображения, которую вы хотите перекрасить, имеет градиенты или затенение, проверьте context.getImageData (stackoverflow.com/questions/23830471/).   -  person markE    schedule 15.10.2015
comment
@markE как насчет заполнения цветного прямоугольника, а затем использования gCO = "hue" ?   -  person Kaiido    schedule 15.10.2015
comment
@Kaiido, конечно, хорошая мысль! Когда браузер поддерживает композицию оттенков (а большинство поддерживает ее сейчас), это более эффективный метод.   -  person markE    schedule 15.10.2015
comment
Да, это одно изображение с разными персонажами, но все они белые. Я хочу иметь возможность использовать параметр 'c' (должно быть что-то вроде #0000FF) и подкрашивать символы, которые я извлекаю из font.png.   -  person Howzieky    schedule 15.10.2015


Ответы (1)


markE дал вам все ключи для достижения того, чего вы хотите an-image-on-canvas/33163140#comment-54085984">в комментариях, но здесь это применимо к вашему случаю:

Вы заявили, что ваше изображение состоит только из одного сплошного цвета, белого.
(здесь я буду считать, что прозрачный не имеет цвета, но в других контекстах он есть)
Чтобы изменить этот цвет, вы можете использовать параметр ctx.globalCompositeOperation('source-atop'), который будет рисовать новые формы «только там, где они перекрываются с существующим содержимым холста». Это означает, что вы можете сначала нарисовать свою форму буквы, затем заполнить ее прямоугольником, и будет нарисована только цветная форма буквы.

var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
  canvas.width = this.width;
  canvas.height = this.height;
  ctx.fillStyle = 'red';
  ctx.drawImage(this, 0, 0);
  ctx.globalCompositeOperation = 'source-atop';
  ctx.fillRect(0, 0, canvas.width, canvas.height)
    // reset to default
  ctx.globalCompositeOperation = 'source-over';
}
img.src = "http://i.stack.imgur.com/9RQXh.png";
<canvas id="canvas"></canvas>

Или вы можете сделать это по-другому: сначала нарисуйте цветной прямоугольник, установите globalCompositeOperation на "destination-atop", а затем нарисуйте свою букву.

var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
  canvas.width = this.width;
  canvas.height = this.height;
  ctx.fillStyle = 'red';
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.globalCompositeOperation = 'destination-atop';
  ctx.drawImage(this, 0, 0);
  // reset to default
  ctx.globalCompositeOperation = 'source-over';
}
img.src = "http://i.stack.imgur.com/9RQXh.png";
<canvas id="canvas"></canvas>

Теперь, чтобы реализовать это в своем коде, вы можете сохранить набор цветных букв в вашем объекте Text и нарисовать его вместо исходного изображения:

Text = function(x, y, str, s, c){
    var img = new Image();
    // save a pointer to our object so we can use it in the onload event
    var that = this;
    // here implement the coloring part
    img.onload = function(){
      that.img = document.createElement('canvas');
      that.img.width = this.width;
      that.img.height = this.height;
      var ctx = that.img.getContext('2d');
      // set the color to the wanted one
      ctx.fillStyle = c;
      ctx.fillRect(0, 0, canvas.width, canvas.height)
      ctx.globalCompositeOperation = 'destination-atop';
      ctx.drawImage(this, 0, 0);
      }
    img.src = "font.png";
    var alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ".", "!", "?"]
    this.text = str.toLowerCase();
    this.x = x;
    this.y = y;
    this.type = "text";
    this.rows = 1;
    this.height = this.rows * 10;
    this.width = this.text.length * 8;
    this.draw = function(){
        for (var i = 0; i < this.text.length; i++)
        {
            // here use the canvas we created
            scene.ctx.drawImage(this.img, (alphabet.indexOf(this.text[i]) % 16) * 8, Library.newMath.roundZero(alphabet.indexOf(this.text[i]) / 16) * 10, 8, 10, this.x + i * 8 + (scene.xOffset * !this.fixed), this.y + 0 + (scene.yOffset * !this.fixed), 8, 10);
        }           
    }
    Shape.prototype.constructor.call(this, x, y);
}
person Kaiido    schedule 16.10.2015