我有一个需求:把图片连带它的 css 样式画到 canvas 中,但搜索了一番,似乎不能直接实现. 如果这个图片的 css 样式比较简单,可以尝试 wxml-to-canvas,但它支持的 css 样式比较少,所以不能处理相对复杂的情况。
另一种方法是用 canvas 的 api 把图片的 css 样式逐个画出来,下图最右边是原图,第一二两幅分别由 css 和 canvas api 实现,并不完全一样,因为我偷懒,但基本一致。
看起来有点复杂,其实主要是通过 ctx.createLinearGradient()
创建线性渐变的阴影,再把这个阴影 fill 到画布中实现. ctx.createLinearGradient()
接收两个座标点作为参数,该方法返回 CanvasGradient 对象。
两个座标点连成一条虚构的直线,接着使用 CanvasGradient 对象在这条直线上添加渐变颜色:
const gradient = ctx.createLinearGradient(0,0,100,100);
gradient.addColorStop(0.1,"grey");
gradient.addColorStop(0.5,"transparent");
假设这条直线的长度是 x,这段代码的意思是在距离 (0,0) 这个点 0.1x 的位置设置 grey 这个颜色,从这个位置开始渐变,渐变至 transparent 这个颜色,渐变的距离是从 0.1x 到 0.5x,由于没有其他渐变颜色,所以从 0.5x 到 x 这段距离保持为 transparent 这个颜色。
颜色沿着这条直线发生渐变,而任何一条垂直于这条直线的直线上,所有颜色都是一样。
最左边通过 css 实现的图片,其中的多个渐变阴影并不垂直或平行于图片的两边,这种情况下,这条虚构的直线也不应该垂直于图片的两边,所以在确定 ctx.createLinearGradient()
的参数时需要进行简单的三角形边角计算。
可以观察到处理后的图片其色彩饱和度及对比度都发生了变化,这是通过 ctx.filter 实现,但小程序似乎不支持 ctx.filter(). ctx.filter 和 css 的 filter 类似。
通过以下 api,canvas 还能实现类似于 css 的 box-shadow 的效果:
ctx.shadowColor = "rgba(0,0,0,0.2)";
ctx.shadowBlur = 20;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 5;