Canvas创建一个透明的图像蒙版

时间:2016-01-30 04:42:24

标签: canvas html5-canvas masking

我有一个画布,用户可以使用我创建的画笔工具(在mousedown或touch上)进行绘制。 我希望绘图区域受到画布上的形状限制,例如,中文字符的形状。

形状不是简单的形状,所以使用CanvasRenderingContext2D.clip()实际上不是一个选项吗?

我的下一个解决方案是将遮罩图像作为带有drawImage的PNG绘制到画布上,然后将CanvasRenderingContext2D.globalCompositeOperation更改为“source-atop”,以便仅在遮罩图像中绘制画笔。

以下是我遇到的要求 - 在画布的最终输出中,我不想看到屏蔽图像。

我可以接受将遮蔽图像设置为非常低的alpha,这实际上是不可见的。

因此,我尝试在放置图像之前设置全局alpha,然后在画笔开始绘制时恢复它。

但是,绘制的重叠也与掩蔽图像具有相同的alpha值,但我希望它完整。

还有其他方法可以达到这个目的吗?我不知道?

2 个答案:

答案 0 :(得分:3)

@ markE&#39的解决方案适用于一小组预定义字符,您可以在之前使用它们。

不幸的是,虽然文本是矢量绘图操作,但画布Context2d中只有两个方法是fillTextstrokeText,它们不允许我们在Path2D对象中包含文本, clip()方法。

因此,如果您无法执行此预处理,我认为globalCompositeOperationclip()的一个不错的选择。 这将涉及使用2幅画布,一幅用于用户的绘画,另一幅用于剪辑/渲染。 (这里我甚至使用第三个作为剪贴蒙版,但它也可以是带有透明度的光栅png的<img>标签。)

source-in

globalCompositeOperation模式只会绘制已绘制像素的新绘制像素。因此第一个形状(剪贴蒙版)不可见。

&#13;
&#13;
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;
&#13;
&#13;

答案 1 :(得分:1)

如何创建&#34;隐形&#34;面具如果您想避免显示面具,可以将css背景设置为白色并用白色填充面具。这样,面具将是&#34;隐形&#34;。如果您需要透明度,那么当完成所有绘图后,您可以使用context.getImageData使所有幸存的白色像素透明。

但是...... 合成仅影响现有和新图纸,因此问题是如果您的应用逐步增加像素,则必须进行相当多的保存+重绘以使用合成来限制像素。这是因为先前绘制的新像素在当前合成周期中将成为现有像素。

所以...... 再看看context.clip,它将新图纸(画笔描边)限制在一个定义的剪切路径中。将复杂的形状减少到画布路径并不困难。如果您有大量字符来制作路径,请考虑使用Adobe Illustrator和Mike Swanson的插件将svg路径导出为画布路径。