HTML5画布图像上的插入阴影

时间:2016-05-22 18:34:53

标签: javascript css html5 canvas

之前我见过这个问题,但给出的答案是通过路径绘制的画布图像,但我正在绘制图像。

是否可以创建inset-shadow

context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 10;
context.shadowColor = 'rgba(30,30,30, 0.4)';

var imgOne = new Image();
imgOne.onload = function() {
    context.drawImage(imgOne, 0, 0);
};
imgOne.src = "./public/circle.png";

所以我画了圆圈图片。我现在在圈子的外面有一个小阴影,我怎么能得到这个inset而不是offset

5 个答案:

答案 0 :(得分:4)

成分链

使用一系列复合+绘制操作来获取嵌入阴影。

注意:解决方案需要在创建时对canvas元素进行独占访问,因此要么在屏幕外的画布上执行此操作,要么绘制回main,或者如果可能的话,计划在生成此图形后绘制辅助图形。

所需的步骤:

  • 绘制原始图像
  • 使用xor合成
  • 反转使用实体填充画布的Alpha通道
  • 定义阴影并在
  • 中绘制自己
  • 停用阴影并绘制原始图像(destination-atop

Result



var ctx = c.getContext("2d"), img = new Image;
img.onload = function() {

  // draw in image to main canvas
  ctx.drawImage(this, 0, 0);

  // invert alpha channel
  ctx.globalCompositeOperation = "xor";
  ctx.fillRect(0, 0, c.width, c.height);

  // draw itself again using drop-shadow filter
  ctx.shadowBlur = 7*2;  // use double of what is in CSS filter (Chrome x4)
  ctx.shadowOffsetX = ctx.shadowOffsetY = 5;
  ctx.shadowColor = "#000";
  ctx.drawImage(c, 0, 0);

  // draw original image with background mixed on top
  ctx.globalCompositeOperation = "destination-atop";
  ctx.shadowColor = "transparent";                  // remove shadow !
  ctx.drawImage(this, 0, 0);
}
img.src = "http://i.imgur.com/Qrfga2b.png";

<canvas id=c height=300></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

画布将遮挡图像从不透明变为透明的位置,因此,正如K3N在其正确答案中所示,您可以将图像从里面翻出来(不透明变为透明,反之亦然),因此阴影会在圆圈内绘制。

如果您知道圆的中心点和半径,则可以使用描边路径创建插入圆阴影。这是一个例子:

&#13;
&#13;
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

context.beginPath();
context.arc(cw/2,ch/2,75,0,Math.PI*2);
context.fillStyle='lightcyan';
context.fill();

context.globalCompositeOperation='source-atop';

context.shadowOffsetX = 500;
context.shadowOffsetY = 0;
context.shadowBlur = 15;
context.shadowColor = 'rgba(30,30,30,1)';

context.beginPath();
context.arc(cw/2-500,ch/2,75,0,Math.PI*2);
context.stroke();
context.stroke();
context.stroke();

context.globalCompositeOperation='source-over';
&#13;
<canvas id="canvas" width=300 height=300></canvas>
&#13;
&#13;
&#13;

如果您的路径不规则或难以用数学方法定义,您还可以使用边缘路径检测算法。一种常见的边缘路径算法是Marching Squares。 Stackoverflow的K3N编写了一个很好的Marching Squares algorithm

答案 2 :(得分:2)

受markE回答的启发,我根据png而非矢量图形制作了自己的版本。

此外,我可以选择阴影的真实Alpha(因为我认为默认阴影强度太柔和了)

enter image description here

|exampleKey|Version|otherProperty|
|"test"    |1      |"random data"|
|"test"    |2      |"more random"|
|"test2"   |3      |"random data"|
|"test2"   |4      |"more random"|
|exampleKey|Version|otherProperty|
|"test"    |1      |"random data"|
|"test"    |2      |"more random"|
|"test2"   |1      |"random data"|
|"test2"   |2      |"more random"|

jsfiddle在这里:https://jsfiddle.net/jrekw5og/141/

答案 3 :(得分:1)

受到K3N答案的启发,我已经针对这种情况创建了Inset.js

Inset.js

只需要设置ctx.shadowInset = true;

例如:http://codepen.io/patlillis/pen/ryoWey

var ctx = canvas.getContext('2d');
var img = new Image;
img.onload = function() {
  ctx.shadowInset = true;
  ctx.shadowBlur = 25;
  ctx.shadowColor = "#000";
  ctx.drawImage(this, 0, 0);
}
img.src = "http://i.imgur.com/Qrfga2b.png";

Inset circle

答案 4 :(得分:0)

const width = 100 * devicePixelRatio;
const height = 100 * devicePixelRatio;

// original canvas
const c = document.getElementById('canvas');
c.width = 300 * devicePixelRatio;
c.height = 300 * devicePixelRatio;
c.style.width = '300px';
c.style.height = '300px';
const cctx = c.getContext('2d');
cctx.fillStyle = 'rgb(20,205,75)';
cctx.arc(150 * devicePixelRatio, 150 * devicePixelRatio, 50 * devicePixelRatio, 0, Math.PI * 2);
cctx.fill();

// temporary canvas
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.style.width = `${width / devicePixelRatio}px`;
canvas.style.height = `${height / devicePixelRatio}px`;
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');

// original object on temporary canvas
ctx.arc(50 * devicePixelRatio, 50 * devicePixelRatio, 50 * devicePixelRatio, 0, Math.PI * 2);
ctx.fill();

// shadow cutting
ctx.globalCompositeOperation = 'xor';
ctx.arc(50 * devicePixelRatio, 50 * devicePixelRatio, 50 * devicePixelRatio, 0, Math.PI * 2);
ctx.fill();

// shadow props
ctx.shadowBlur = 50;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = -25;
ctx.shadowColor = '#000';
ctx.arc(50 * devicePixelRatio, 50 * devicePixelRatio, 50 * devicePixelRatio, 0, Math.PI * 2);
ctx.fill();

// shadow color
ctx.globalCompositeOperation = 'source-in';
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// object cutting
ctx.globalCompositeOperation = 'destination-in';
ctx.arc(50 * devicePixelRatio, 50 * devicePixelRatio, 50 * devicePixelRatio, 0, Math.PI * 2);
ctx.fill();

// shadow opacity
cctx.globalAlpha = .4

// inserting shadow into original canvas
cctx.drawImage(canvas, 200, 200);

Colored shadow /w opacity