在html5中,当您使用putImageData()绘制到画布时,如果您绘制的某些像素是透明的(或半透明),那么如何保持画布中的旧像素不受影响?
例如:
var imgData = context.createImageData(30,30);
for(var i=0; i<imgData.data.length; i+=4)
{
imgData.data[i]=255;
imgData.data[i+1]=0;
imgData.data[i+2]=0;
imgData.data[i+3]=255;
if((i/4)%30 > 15)imgData.data[i+3] = 0;
}
context.putImageData(imgData,0,0);
30x30 rect的右半部分是透明的。 如果在画布上绘制某些内容,则会删除右半部分后面的像素(或变为透明)。我该如何保留它们?
答案 0 :(得分:6)
您可以使用getImageData创建半透明叠加层:
以下是示例代码和演示:http://jsfiddle.net/m1erickson/CM7uY/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
// draw an image on the canvas
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stack1/landscape1.jpg";
function start(){
canvas.width=img.width;
canvas.height=img.height;
context.drawImage(img,0,0);
// overlay a red gradient
drawSemiTransparentOverlay(canvas.width/2,canvas.height)
}
function drawSemiTransparentOverlay(w,h){
// create a temporary canvas to hold the gradient overlay
var canvas2=document.createElement("canvas");
canvas2.width=w;
canvas2.height=h
var ctx2=canvas2.getContext("2d");
// make gradient using ImageData
var imgData = ctx2.getImageData(0,0,w,h);
var data=imgData.data;
for(var y=0; y<h; y++) {
for(var x=0; x<w; x++) {
var n=((w*y)+x)*4;
data[n]=255;
data[n+1]=0;
data[n+2]=0;
data[n+3]=255;
if(x>w/2){
data[n+3]=255*(1-((x-w/2)/(w/2)));
}
}
}
// put the modified pixels on the temporary canvas
ctx2.putImageData(imgData,0,0);
// draw the temporary gradient canvas on the visible canvas
context.drawImage(canvas2,0,0);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=200 height=200></canvas>
</body>
</html>
或者,您可以使用线性渐变检查以更直接地发挥效果。
答案 1 :(得分:2)
如您所知,您的陈述
if((i/4)%30 > 15)imgData.data[i+3] = 0;
将使图像右半部分的像素变为透明,以便可以通过画布在该像素位置看到画布后面页面上的任何其他对象。但是,您仍然使用context.putImageData
覆盖画布本身的像素,这将取代之前的所有像素。您添加的透明度不会导致前一个像素显示,因为putImageData
的结果不是画布中前一个像素顶部的第二组像素,而是替换现有像素。
我建议您不要使用createImageData
来开始代码,而getImageData
将以一组空白数据开头,而是var imgData = context.getImageData(30,30);
for(var i=0; i<imgData.data.length; i+=4)
{
if((i/4)%30 > 15) continue;
imgData.data[i]=255;
imgData.data[i+1]=0;
imgData.data[i+2]=0;
imgData.data[i+3]=255;
}
context.putImageData(imgData,0,0);
,它会为您提供要使用的现有数据的副本。然后,您可以使用条件语句来避免覆盖要保留的图像部分。这也将使您的功能更有效。
{{1}}
答案 2 :(得分:0)
我想复制一个CRISP,未经修改的画布版本。我最终想出了这个适用的解决方案。
https://jsfiddle.net/4Le454ak/1/
复制部分在此代码中:
var imageData = canvas.toDataURL(0, 0, w, h);
var tmp = document.createElement('img');
tmp.style.display = 'none'
tmp.src = imageData;
document.body.appendChild(tmp);
ctx.drawImage(tmp, 30, 30);
发生了什么:
答案 3 :(得分:0)
使我绊倒的可能有用的东西……我对此有疑问,因为我假设putImageData()
和drawImage()
可以以相同的方式工作,但看起来却没有。 putImageData()
将使用其自己的透明数据覆盖现有像素,而drawImage()
将使它们保持不变。
查看此内容时,我浏览了CanvasRenderingContext2D.globalCompositeOperation的文档(应该更仔细地阅读),发现source-over
是默认设置,但没有意识到这不适用于{{1 }}
然后绘制到临时画布中并使用putImageData()
将临时画布添加到主上下文是我需要的解决方案,因此为此感到高兴。