开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
前言
自己尝试写的一个马赛克效果,
在图片上拖动鼠标给经过的地方打上马赛克
效果如下:
一,源码
<canvas width="800px" height="400px"></canvas>
<button>清除马赛克</button>
const canvas = document.querySelector('canvas')
const button = document.querySelector('button')
if(canvas.getContext){
const context = canvas.getContext('2d')
var oldImageData = null
//1 插入图片到画布
let img = new Image()
img.src = '../img/test2.png'
img.onload = ()=>{
context.drawImage(img, 0, 0, 800, 400);
oldImageData = context.getImageData(0, 0, 800, 400);
}
let flag = false
let size = 20
//2获取xy
canvas.onmousedown = (e)=>{
flag = true
const x = e.clientX - canvas.offsetLeft
const y = e.clientY - canvas.offsetTop
draw(size,x,y)
}
canvas.onmousemove = (e)=>{
if(!flag) return
const x = e.clientX - canvas.offsetLeft
const y = e.clientY - canvas.offsetTop
draw(size,x,y)
}
canvas.onmouseup = (e)=>{
flag = false
}
//马赛克
function draw(size,x,y){
let imageData = context.getImageData(0, 0, 800, 400);
//3,随机像素点 = x 加上 [0,size)的随机数
let color = getPXInfo(imageData,
x + Math.floor(Math.random()*size),
y + Math.floor(Math.random()*size))
//4,更改矩形颜色,xy位置加上0-size,来变更矩形rgba为color
for(let a=0; a<size; a++) {
for(let b=0; b<size; b++){
setPXInfo(imageData,x+a,y+b,color)
}
}
context.putImageData(imageData, 0, 0)
}
button.onclick = ()=>{
let imageData = context.getImageData(0, 0, 800, 400);
for(let i=0; i<oldImageData.data.length; i++){
imageData.data[i] = oldImageData.data[i]
}
context.putImageData(imageData, 0, 0);
}
//封装好获取的单像素方法
function getPXInfo(imageData,x,y){
let data = imageData.data
let w = imageData.width
let h = imageData.height
let color = []
//(y*w+x)*4 y多少行*宽+x列前面多少个*4(4代表rgba) 得到坐标最终索引获取color
color[0] = data[(y*w+x)*4]//R -> 0~255
color[1] = data[(y*w+x)*4+1]//G -> 0~255
color[2] = data[(y*w+x)*4+2]//B -> 0~255
color[3] = data[(y*w+x)*4+3]//A -> 0~255
return color
}
function setPXInfo(imageData,x,y,color) {
let data = imageData.data
let w = imageData.width
let h = imageData.height
data[(y*w+x)*4] = color[0]
data[(y*w+x)*4+1] = color[1]
data[(y*w+x)*4+2] = color[2]
data[(y*w+x)*4+3] = color[3]
}
}
}
二,解析代码
- 马赛克实现思路
- 获取鼠标xy坐标,并且设置一个size矩形范围
- x+size,y+size 就是一个矩形啦, 从这个矩形中随机抽取一个像素点
- 将抽取的像素点,改为整个矩形的颜色
- canvas中一个像素点是由rgba组成,值 为0-255
- 由于我的图片太大,我就设置固定了
相关api
插入图片: ctx.drawImage(image图片对象,x,y,width,height);xy为起始坐标,
获取像素:const myImageData = ctx.getImageData(sx,sy,sw,sh) 包含画布场景数据的ImageData对象
返回值:width
height
data:数组包含每一个像素点
100width * 100height 是一万个像素点,但是data中会显示长度4万个
原因就是一个像素点由RGBA组成,RGBA都是(0~255 黑->白 0~255透明到不透明)
写入像素:ctx.putImageData(myImageData,dx,dy)方法对场景进行像素数据的写入
dx,dy左上角绘制坐标。
myImageData要插入的像素数据,