我有一个画布,用户可以使用我创建的画笔工具(在mousedown或touch上)进行绘制。 我希望绘图区域受到画布上的形状限制,例如,中文字符的形状。
形状不是简单的形状,所以使用CanvasRenderingContext2D.clip()实际上不是一个选项吗?
我的下一个解决方案是将遮罩图像作为带有drawImage的PNG绘制到画布上,然后将CanvasRenderingContext2D.globalCompositeOperation更改为“source-atop”,以便仅在遮罩图像中绘制画笔。
以下是我遇到的要求 - 在画布的最终输出中,我不想看到屏蔽图像。
我可以接受将遮蔽图像设置为非常低的alpha,这实际上是不可见的。
因此,我尝试在放置图像之前设置全局alpha,然后在画笔开始绘制时恢复它。
但是,绘制的重叠也与掩蔽图像具有相同的alpha值,但我希望它完整。
还有其他方法可以达到这个目的吗?我不知道?
答案 0 :(得分:3)
@ markE&#39的解决方案适用于一小组预定义字符,您可以在之前使用它们。
不幸的是,虽然文本是矢量绘图操作,但画布Context2d中只有两个方法是fillText
和strokeText
,它们不允许我们在Path2D对象中包含文本, clip()
方法。
因此,如果您无法执行此预处理,我认为globalCompositeOperation是clip()
的一个不错的选择。
这将涉及使用2幅画布,一幅用于用户的绘画,另一幅用于剪辑/渲染。 (这里我甚至使用第三个作为剪贴蒙版,但它也可以是带有透明度的光栅png的<img>
标签。)
source-in
的 globalCompositeOperation
模式只会绘制已绘制像素的新绘制像素。因此第一个形状(剪贴蒙版)不可见。
var ctx = canvas.getContext('2d');
// create a buffer canvas for the paintings
var paint = canvas.cloneNode(true);
var paint_ctx = paint.getContext('2d');
// create another buffer canvas for the clipping-mask
// (it could also be a raster png in an <img> tag
var clip_mask = canvas.cloneNode(true);
var clip_ctx = clip_mask.getContext('2d');
var clip = function(){
// clear the visible canvas
ctx.clearRect(0,0,canvas.width, canvas.height);
// draw the clipping mask
ctx.drawImage(clip_mask, 0,0);
// change the gCO
ctx.globalCompositeOperation = "source-in";
// draw the user paintings
ctx.drawImage(paint, 0,0);
// always reset the default gCO
ctx.globalCompositeOperation = "source-over";
// show the stroke of the clipping area
if(stroke.checked){
strokeMask();
}
};
//
// The user painting methods
//
var doPaint = function(x, y){
paint_ctx.beginPath();
paint_ctx.arc(x-3.5, y-3.5, 7, Math.PI, -Math.PI);
paint_ctx.fill();
clip();
};
canvas.onmousemove = function(evt){
var rect = this.getBoundingClientRect();
var x = evt.clientX-rect.left;
var y = evt.clientY-rect.top;
doPaint(x,y);
};
//
// the clipping mask methods
//
// init the clipping-mask
var initClip = function(){
clip_ctx.font = "150px sans-serif";
clip_ctx.textBaseline = "top";
clip_ctx.textAlign = "center";
updateClip();
};
// update the clipping-mask
var updateClip = function(){
var val = char.value;
clip_ctx.clearRect(0, 0, clip_mask.width, clip_mask.height);
var x = (clip_mask.width/2);
clip_ctx.fillText(val, x, 10);
paint_ctx.clearRect(0, 0, paint.width, paint.height);
clip();
};
// listen to the text input
char.oninput = char.onchange = function(){
var val = this.value;
// restrict to 1 character
if(val.length>1){
this.value = val[val.length-1];
}
updateClip();
};
// show the stroke of the mask
var strokeMask = function(){
ctx.font = "150px sans-serif";
ctx.textBaseline = "top";
ctx.textAlign = "center";
ctx.strokeStyle = "rgba(255,255,255,.3)";
ctx.strokeText(char.value, canvas.width/2, 10);
}
stroke.onchange = clip;
// lets go!
initClip();
&#13;
body{background-color: skyblue;}
canvas{border:1px solid;}
input{max-width:1em;}
span{font-size:.7em;}
&#13;
<input type="text" id="char" value="试"/>
<span>show the clipping-stroke</span><input type="checkbox" id="stroke" name="s"/><br>
<canvas id="canvas" width="200" height="150"></canvas>
&#13;
答案 1 :(得分:1)
如何创建&#34;隐形&#34;面具如果您想避免显示面具,可以将css背景设置为白色并用白色填充面具。这样,面具将是&#34;隐形&#34;。如果您需要透明度,那么当完成所有绘图后,您可以使用context.getImageData
使所有幸存的白色像素透明。
但是...... 合成仅影响现有和新图纸,因此问题是如果您的应用逐步增加像素,则必须进行相当多的保存+重绘以使用合成来限制像素。这是因为先前绘制的新像素在当前合成周期中将成为现有像素。
所以...... 再看看context.clip
,它将新图纸(画笔描边)限制在一个定义的剪切路径中。将复杂的形状减少到画布路径并不困难。如果您有大量字符来制作路径,请考虑使用Adobe Illustrator和Mike Swanson的插件将svg路径导出为画布路径。