文章目录
前言
本节将综合运用图像处理、离屏 canvas 以及剪辑区域等技术实现墨镜效果。
示例

主线程代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>4-18-综合运用图像处理、离屏canvas以及剪辑区域等技术的墨镜效果演示</title>
<style>
#canvas {
background: rgba(0, 0, 0, 0.4);
}
</style>
</head>
<body>
<div id="controls">墨镜滤镜<input type="checkbox" id="sunglassCheckbox" /></div>
<canvas id="canvas" width="800" height="600"> canvas not supports </canvas>
<script>
const canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
sunglassCheckbox = document.getElementById('sunglassCheckbox'),
offscreenCanvas = document.createElement('canvas'),
offscreenContext = offscreenCanvas.getContext('2d'),
sunglassFilter = new Worker('./sunglassFilter.js'),
LENS_RADIUS = canvas.width / 5
const image = new Image()
offscreenCanvas.width = canvas.width
offscreenCanvas.height = canvas.height
// Functions......
function drawOriginalImage() {
context.drawImage(image, 0, 0, canvas.width, canvas.height)
}
// 绘制镜片
function drawLenses(leftLensLocation, rightLensLocation) {
context.save()
context.beginPath()
context.arc(leftLensLocation.x, leftLensLocation.y, LENS_RADIUS, 0, Math.PI * 2, false)
context.stroke()
moveTo(rightLensLocation.x, rightLensLocation.y)
context.arc(rightLensLocation.x, rightLensLocation.y, LENS_RADIUS, 0, Math.PI * 2, false)
context.stroke()
context.clip()
context.drawImage(offscreenCanvas, 0, 0, canvas.width, canvas.height)
context.restore()
}
// 绘制镜线
function drawWire(center) {
context.beginPath()
context.moveTo(center.x - LENS_RADIUS / 4, center.y - LENS_RADIUS / 2)
context.quadraticCurveTo(
center.x,
center.y - LENS_RADIUS + 20,
center.x + LENS_RADIUS / 4,
center.y - LENS_RADIUS / 2
)
context.stroke()
}
function putSunglassesOn() {
const imagedata = context.getImageData(0, 0, canvas.width, canvas.height),
center = {
x: canvas.width / 2,
y: canvas.height / 2,
},
leftLensLocation = {
x: center.x - LENS_RADIUS - 10,
y: center.y,
},
rightLensLocation = {
x: center.x + LENS_RADIUS + 10,
y: center.y,
}
sunglassFilter.postMessage(imagedata)
sunglassFilter.onmessage = (e) => {
offscreenContext.putImageData(e.data, 0, 0)
drawLenses(leftLensLocation, rightLensLocation)
drawWire(center)
}
}
// Event handlers......
sunglassCheckbox.onchange = () => {
if (sunglassCheckbox.checked) {
putSunglassesOn()
} else {
drawOriginalImage()
}
}
// Initialization......
image.src = './waterfall.png'
image.onload = () => {
drawOriginalImage()
}
</script>
</body>
</html>
Worker线程代码:
javascript
self.onmessage = function (e) {
const imagedata = e.data,
data = imagedata.data,
width = imagedata.width,
length = data.length
for (let i = 0; i < length; ++i) {
if ((i + 1) % 4 != 0) {
if ((i + 4) % (width * 4) == 0) {
data[i] = data[i - 4]
data[i + 1] = data[i - 3]
data[i + 2] = data[i - 2]
data[i + 3] = data[i - 1]
} else {
data[i] = 2 * data[i] - data[i + 4] - 0.5 * data[i + 4]
}
}
}
self.postMessage(imagedata)
}