HTML5 Canvas |Заменить цвет |Удалить цвет - PullRequest
0 голосов
/ 09 октября 2018

Какой самый быстрый способ создать копию этого изображения без зеленого цвета или сделать зеленый цвет прозрачным или удалить зеленый цвет из 100X100 пикселей вверху слева

В этом случае мне нужно проверять значение каждого пикселя?Этот процесс слишком медленный, например: для 100X100px требуется 40000 циклов для проверки всех значений rgba

enter image description here

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Если вы проверите каждое значение пикселя и удалите зеленый, у вас останется уродливое изображение с отверстиями.Более простой способ сделать это с лучшими результатами - это заранее планировать.Это производится с холстом.Когда вы рисуете изображение, вы можете сохранить каждый круг в массиве, а затем перерисовать все после исключения зеленых кружков.

В следующем примере щелкните цвет, чтобы выбрать его, или нажмите D убрать зеленые кружочки.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width = 300,
  cx = cw / 2;
var ch = canvas.height = 180,
  cy = ch / 2;

var color = "blue";


var drawing = false;


var points= [];

class Point{
  constructor(color,x,y){
    this.color = color;
    this.x = x;
    this.y = y
  }
  draw(){
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x,this.y,5,0,2*Math.PI);
    
    ctx.fill()
  }
  
}

canvas.addEventListener('mousedown', function(evt) {
  drawing = true;
  

}, false);

canvas.addEventListener('mouseup', function(evt) {
  drawing = false;

}, false);

canvas.addEventListener("mouseout", function(evt) {
  drawing = false;
}, false);

canvas.addEventListener("mousemove", function(evt) {
  if (drawing) {
    ctx.clearRect(0, 0, cw, ch);
    m = oMousePos(canvas, evt);
    var point = new Point(color,m.x,m.y);
    //point.draw();
    points.push(point);
    
    points.forEach((p) =>{
      p.draw()
    })
  }
}, false);

function oMousePos(canvas, evt) {
  var ClientRect = canvas.getBoundingClientRect();
  return { 
    x: Math.round(evt.clientX - ClientRect.left),
    y: Math.round(evt.clientY - ClientRect.top)
  }
}

colors.addEventListener("click", (e)=>{
  if(e.target.tagName == "SPAN"){color = e.target.id;
  }else if(e.target.id == "deleteGreen"){
    ctx.clearRect(0,0,cw,ch);
    points.forEach( p => {
      if(p.color !== "green"){p.draw()}
    })
  }
})
body {
  background-color: #eee;
}

#app {
  display: block;
  margin: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 300px;
  height: 300px;
}

canvas {
  background: #fff;
  border-radius: 3px;
  box-shadow: 0px 0px 15px 3px #ccc;
  cursor: pointer;
}

#colors {
  display: flex;
  margin-top: 1em;
  justify-content: space-between;
}

#colors span, #deleteGreen {
  display: block;
  width: 50px;
  height: 50px;
  border: 1px solid #d9d9d9;
}

#green {
  background-color: green;
}

#gold {
  background-color: gold;
}

#tomato {
  background-color: tomato;
}

#blue {
  background-color: blue;
}

#deleteGreen {
  text-align: center;
  line-height: 50px;
}
<div id="app">
<canvas id="canvas">:( </canvas>
  <div id="colors" >
    <span id="green"></span>
    <span id="gold"></span>
    <span id="tomato"></span>
    <span id="blue"></span>
    <div id="deleteGreen">D</div>
  </div> 

</div>
0 голосов
/ 09 октября 2018

В браузерах, которые поддерживают это, вы можете использовать фильтры svg, чтобы сделать это:

Вот другой Q / A , который показывает интересный способ сделать это дляфиксированный цвет.

Здесь я сделал простую вспомогательную функцию, которая настроит для нас требуемый tableValues с небольшим допуском, и я удалил <feFill>, чтобы выбранный цвет стал прозрачным (<feFill>испортил бы холст в Chrome).Если вы хотите заменить цвет, вы все равно можете добиться этого с помощью параметров компоновки холста (прокомментированный код ниже фрагмента).

const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = e => {
  canvas.width = img.width;
  canvas.height = img.height;
  // update our filter
  updateChroma([76, 237, 0], 8);
// if you wish to replace the color, uncomment followings
//  ctx.fillStyle = "your_replaceColor";
//  ctx.fillRect(0,0,img.width,img.height);
  ctx.filter = 'url(#chroma)';
  ctx.drawImage(img, 0, 0);
  ctx.filter = 'none';
//  ctx.globalCompositeOperation = 'destination-in';
//  ctx.drawImage(img, 0,0);
};
img.src = "https://i.stack.imgur.com/hZm8o.png";

function updateChroma(rgb, tolerance) {
  const sels = ['R', 'G', 'B'];
  rgb.forEach((value, ind) => {
    const fe = document.querySelector('#chroma feFunc' + sels[ind]);
    let vals = '';
    if (!value) {
      vals = '0'
    } else {
      for (let i = 0; i < 256; i++) {
        vals += (Math.abs(value - i) <= tolerance) ? '1 ' : '0 ';
      }
    }
    fe.setAttribute('tableValues', vals);
  });
}
canvas {
  background: ivory
}
<svg width="0" height="0" style="position:absolute;visibility:hidden">
<filter id="chroma" color-interpolation-filters="sRGB"x="0" y="0" height="100%" width="100%">
  <feComponentTransfer>
    <feFuncR type="discrete"/>
    <feFuncG type="discrete"/>
    <feFuncB type="discrete"/>
  </feComponentTransfer>
  <feColorMatrix type="matrix" values="1 0 0 0 0 
                                       0 1 0 0 0
                                       0 0 1 0 0 
                                       1 1 1 1 -1" result="selected"/>
  <feComposite in="SourceGraphic" in2="selected" operator="out"/>
  </filter>
</svg>

<canvas id="canvas"></canvas>

Я не проводил обширные тесты на многих устройствах, но там, где аппаратное ускорение включено, это может работать лучше, чем любой пиксельный цикл, так каквсе должно быть сделано на графическом процессоре.


Но поддержка браузера все еще не так уж велика ...
Так что вам, возможно, придется в любом случае откатиться на пиксельные манипулы.

Здесь, в зависимости отна том, что вы делаете для цветности, вы можете пожертвовать немного качеством ради скорости.

Например, на видео вы можете выполнить цветность на холсте уменьшенного размера, а затем нарисовать его обратно с помощьюкомпозитинг на основной, выиграв несколько итераций за кадры.См. предыдущий Q / A для примера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...