#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 был каким-то образом оптимизирован, поэтому было бы быстрее, чем переходить по пикселям — я кое-что узнал.