ctx.createLinearGradient

作者: 科技微讯

日期:

我有一个需求: 把图片连带它的 css 样式画到 canvas 中, 但搜索了一番, 似乎不能直接实现. 如果这个图片的 css 样式比较简单, 可以尝试 wxml-to-canvas, 但它支持的 css 样式比较少, 所以不能处理相对复杂的情况.

另一种方法是用 canvas 的 api 把图片的 css 样式逐个画出来, 下图最右边是原图, 第一二两幅分别由 css 和 canvas api 实现, 并不完全一样, 因为我偷懒, 但基本一致.

canvas css

看起来有点复杂, 其实主要是通过 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 这个颜色.

颜色沿着这条直线发生渐变, 而任何一条垂直于这条直线的直线上, 所有颜色都是一样.

linear gradient

最左边通过 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