Как поместить перекрывающиеся изображения на холст html5?

#javascript #html #canvas

#javascript #HTML #холст

Вопрос:

Я хочу сделать классную визуализацию, в которой я бы перекрывал множество полупрозрачных изображений на моем холсте. Для этого я решил использовать context.putImageData() , потому что эти изображения хранятся в виде массивов. Проблема в том, что этот метод игнорирует фактический фон холста с уже нарисованными изображениями и вычисляет прозрачность по отношению к белому фону.

Вот фрагмент, показывающий текущее поведение:

 <!DOCTYPE html>
<html>

<body>
<canvas id='cvs' width='100' height='100'></canvas>
</body>
<script>
const size = 50
const context = document.getElementById('cvs').getContext('2d');

const redSquare = context.createImageData(size, size);

for (let i=0; i<size*size*4; i=i 4) {
    redSquare.data[i] = 255;
    redSquare.data[i   3] = 255; // 1.0 opacity rbga(1, 0, 0, 1)
}

context.putImageData(redSquare, 10, 10);

const trasparentBlackSquare = context.createImageData(size, size);

for (let i=0; i<size*size*4; i=i 4) {
    trasparentBlackSquare.data[i   3] = 100; // 0.4 opacity rbga(0, 0, 0, 0.4)
}

context.putImageData(trasparentBlackSquare, 30, 30);

</script>

</html>
  

И результат выглядит так: текущее поведение.

Однако я бы хотел, чтобы это выглядело так: ожидаемое поведение

Я сгенерировал это изображение с двумя различными перекрывающимися холстами, что не подходит для моей проблемы.

Пожалуйста, дайте мне знать, если есть какие-либо обходные пути для решения этой проблемы.

Комментарии:

1. Вы хотите наложить изображения, которые создаются как «обычные» изображения, например .jpg или .png, или вы хотите наложить фигуры, такие как вы показали? (Я предполагаю, что это было просто демонстрацией, но я не совсем уверен).

2. @A Haworth Да, моя цель — визуализировать реальные изображения, которые хранятся в виде тензоров. Извините за слишком простой демонстрационный пример.

Ответ №1:

Если вы записываете изображение в холст «workspace», вы можете просмотреть данные изображения для этого, изменив непрозрачность, так же, как вы сделали для черного квадрата. Затем запишите его обратно в workspace canvas. Затем вы можете записать это на свой основной холст, используя drawImage.

Вот что я попробовал на своем сервере, очевидно, вам нужно ввести подходящий img src, чтобы избежать проблем с CORS. А также сделайте элементы img и workspace видимыми: скрытыми — я оставил их видимыми, чтобы показать, что происходит.

 <!DOCTYPE html>
<html>

<body>
img
<img id="img" src="https://rgspaces.org.uk/wp-content/uploads/may-morning-in-lockdown-100x100.jpg"/>
cvs
<canvas id='cvs' width='100' height='100'></canvas>
workspace
<canvas id='workspace' width='100' height='100' style="visibility:visible;"></canvas>
</body>
<script>
window.onload=init;
function init() {
  const size = 50
  const cvs = document.getElementById('cvs')
  const context = cvs.getContext('2d');
  const workspace= document.getElementById('workspace')
  const workspacectx=workspace.getContext('2d');
  const img=document.getElementById('img');

  context.fillStyle = 'rgb(255,0,0,1)';
  context.fillRect(10, 10, size, size);

  workspacectx.drawImage(img,20,20,size,size);

  imgdata=workspacectx.getImageData(20, 20, size, size);
  for (var i=0;i<size*size*4;i =4) {
    imgdata.data[i 3]=150;//if it already has an opacity 0 you would leave it
  }
  workspacectx.putImageData(imgdata,20,20);
  context.drawImage(workspace,20,20);
}
</script>

</html>
  

Комментарии:

1. Спасибо, я реализовал это для своего использования, и оно работает так, как ожидалось! Однако я смог добиться значительного увеличения производительности (62 миллисекунды против 205 миллисекунд), вручную рисуя каждый пиксель. Мое решение работает, когда у вас есть только 2 уровня альфа-изображения, и ваше решение, похоже, преодолевает это ограничение. Еще раз спасибо за ваше предложение!

2. Это интересно, я бы предположил, что drawImage был каким-то образом оптимизирован, поэтому было бы быстрее, чем переходить по пикселям — я кое-что узнал.