一、文字特效部分目錄及效果圖預(yù)覽
二、圖片處理部分都使用了下面這張
一、文字特效部分目錄及效果圖預(yù)覽
-
1.陰影文字
陰影文字效果圖.png -
2.3d拉影文字
3d拉影文字效果圖.png -
3.空心文字
空心文字效果圖.png -
4.線性漸變文字
線性漸變文字效果圖.png -
5.圖片填充文字
圖片填充文字效果圖.png 6.涂鴉及將涂鴉圖標(biāo)保存到本地
可以創(chuàng)建一個(gè)1000px*600px的畫布,使用鼠標(biāo)進(jìn)行隨意涂鴉,同時(shí)還可以點(diǎn)擊將所繪制的畫布以png圖片的形式下載到本地。
目錄1-5的html結(jié)構(gòu)都是統(tǒng)一的
<p>
<button id="btn">創(chuàng)建涂鴉</button>
</p>
<canvas id="canvas" width="1000" height="600"></canvas>
js部分我們都是先獲取點(diǎn)擊按鈕,然后給點(diǎn)擊按鈕綁定generate事件,所有的邏輯代碼都是寫在generate事件函數(shù)中
var btn = document.getElementById("btn")
btn.onclick = generate
var canvas = document.getElementById("canvas")
// 獲取繪圖環(huán)境,參數(shù)目前都是2d
var ctx = canvas.getContext('2d')
function generate() {
}
1.陰影文字
function generate() {
// 陰影顏色
ctx.shadowColor = 'gray'
// 陰影相對于文字的水平距離
ctx.shadowOffsetX = 10
// 陰影相對于文字的垂直距離
ctx.shadowOffsetY = 10
// 模糊效果
ctx.shadowBlur = 20
ctx.font = '100px Arail'
// 100和200就是我們繪制出來的圖形相對于畫布的x坐標(biāo)和y坐標(biāo)
ctx.fillText('HELLO WORLD', 100, 200)
}
2.3d拉影文字
拉影文字通過多次循環(huán)繪制文字陰影,同時(shí)通過偏移量和透明度的漸變,來實(shí)現(xiàn)3d效果
function generate() {
// 填充背景顏色
ctx.fillStyle = 'white'
// 畫矩形,第一第二個(gè)參數(shù)是畫筆起始點(diǎn)的x坐標(biāo)和y坐標(biāo)
// 第三第四個(gè)參數(shù)是寬度和高度
ctx.fillRect(0, 0, 800, 600)
ctx.font = '100px Arial'
for (var i = 0; i < 5; i++) {
ctx.fillStyle = 'gray'
ctx.fillText('HELLO WORLD', 100, 200)
ctx.shadowColor = 'rgba(0,0,0,' + (5 - i) / 5 + ')'
ctx.shadowOffsetX = i + 4
ctx.shadowOffsetY = i * 4
ctx.shadowBlur = i * 4
}
}
3.空心文字
function generate() {
ctx.font = '100px Arail'
// 設(shè)置邊線的顏色
ctx.strokeStyle = 'green'
// 設(shè)置空心文字的內(nèi)容
ctx.strokeText('HELLO WORLD',100,200)
}
4.線性漸變文字
function generate() {
ctx.font = '100px Arail'
// 首先創(chuàng)建canvas提供的線性漸變的對象
// 第一第二個(gè)參數(shù)是漸變起點(diǎn)的x坐標(biāo)和y坐標(biāo)
// 第三第四個(gè)參數(shù)是漸變終點(diǎn)的x坐標(biāo)和y坐標(biāo)
var ctxGradient = ctx.createLinearGradient(100, 200, 600, 200)
// 第一個(gè)參數(shù)0代表的起點(diǎn),1代表終點(diǎn)
// 第二個(gè)參數(shù)代表的是顏色
ctxGradient.addColorStop(0, 'red')
ctxGradient.addColorStop(.5, 'yellow')
ctxGradient.addColorStop(1, 'blue')
// 填充顏色
ctx.fillStyle = ctxGradient
// 寫入文字
ctx.fillText('HELLO WORLD', 100, 200)
}
5.圖片填充文字
function generate() {
// 在canvas中創(chuàng)建圖片對象
ctxImg = new Image()
// 設(shè)置圖片鏈接
ctxImg.src = 'https://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1596697694&t=d1cdff4144a92fd685442fbdd7cb7fc9'
// 加載圖片完成后會觸發(fā)onload回調(diào)函數(shù)
ctxImg.onload = function () {
// 抓取圖片準(zhǔn)備使用,第二個(gè)參數(shù)有四個(gè)選擇
// repeat重復(fù),repeat-x只重復(fù)x方向,repeat-y只重復(fù)y方向,no-repeat不重復(fù)
var ctxPattern = ctx.createPattern(ctxImg, 'repeat')
// 使用圖片進(jìn)行填充
ctx.fillStyle = ctxPattern
ctx.font = '100px Arail'
ctx.fillText('HELLO WORLD', 100, 200)
}
}
6.涂鴉及將涂鴉圖標(biāo)保存到本地
html結(jié)構(gòu)代碼
<p>
<button id="btn">創(chuàng)建涂鴉</button>
<button id="btn2">保存涂鴉到本體</button>
</p>
<canvas id="canvas" width="1000" height="600"></canvas>
js代碼
var btn = document.getElementById("btn")
btn.onclick = generate
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d')
function generate() {
// 先把畫布填充上顏色,明確可以進(jìn)行涂鴉的區(qū)域
ctx.fillStyle = 'skyblue'
ctx.fillRect(0, 0, 1000, 600)
// 涂鴉從鼠標(biāo)點(diǎn)擊下去開始
canvas.onmousedown = function (e) {
var x = e.clientX - canvas.offsetLeft
var y = e.clientY - canvas.offsetTop
// 告訴瀏覽器我們要重復(fù)開始一段繪制
ctx.beginPath()
// 移動開始繪制的畫筆起點(diǎn)
ctx.moveTo(x, y)
canvas.onmousemove = function (e) {
var mx = e.clientX - canvas.offsetLeft
var my = e.clientY - canvas.offsetTop
ctx.strokeStyle = 'red'
ctx.lineWidth = 5
// 移動的過程中繪點(diǎn)連線
ctx.lineTo(mx, my)
// 一定要調(diào)用下這個(gè)方法,路徑才能繪制出來
ctx.stroke()
}
canvas.onmouseup = function (e) {
canvas.onmousemove = null
}
}
}
var btn2 = document.getElementById("btn2")
btn2.onclick = handleImg
function handleImg() {
// 第一個(gè)參數(shù)是要保存的圖片格式,第二個(gè)參數(shù)是文件質(zhì)量,1為最高質(zhì)量
var imgData = canvas.toDataURL('image/png', 1)
// 拿到的數(shù)據(jù)含有base64編碼形式的圖片資源
console.log(imgData)
var a = document.createElement('a')
a.href = imgData
// h5中的a標(biāo)簽可以提供直接點(diǎn)擊下載的download屬性,屬性值就是下載的文件的默認(rèn)名稱
a.download = 'imgData'
// 模擬點(diǎn)擊a標(biāo)簽,觸發(fā)下載效果
a.click()
}
二、圖片處理部分都使用了下面這張

-
1.底片效果
底片效果.png -
2.灰度效果
灰度效果.png -
3.黑白效果
黑白效果.png -
4.模糊效果
模糊效果.png -
5.馬賽克效果
馬賽克效果.png -
6.毛玻璃效果
毛玻璃效果.png -
7.浮雕效果
浮雕效果.png -
8.水平鏡像效果
水平鏡像效果.png -
9.刮刮樂
創(chuàng)建一個(gè)灰色的畫布,點(diǎn)擊鼠標(biāo)開始繪制,漏出下面的底圖,模擬刮獎效果
刮刮樂.png
-
10.繪制餅圖裁剪圖片
繪制餅圖裁剪圖片.png
目錄1-8的html結(jié)構(gòu)代碼都是統(tǒng)一的
<p>
<button id="btn">顯示圖片</button>
<button id="btn2">處理成xx效果</button>
</p>
<canvas id="canvas" width="1000" height="600"></canvas>
js部分我們都是先獲取點(diǎn)擊按鈕btn和btn2,然后分別綁定generate事件和handleImg事件,所有的邏輯代碼都是寫在這兩個(gè)事件函數(shù)中,其中g(shù)enerate函數(shù)都是將圖片繪制到canvas畫布中
var btn = document.getElementById("btn")
btn.onclick = generate
function generate(){
var img = new Image()
img.src = '../demo1.webp'
img.onload = function (e) {
// 將圖片繪制到canvas畫布上面
// 第一個(gè)參數(shù)是圖片路徑
// 第二第三是圖片在canvas畫布中的起始x和y位置
// 第四個(gè)第五個(gè)參數(shù)是圖片的寬和高
ctx.drawImage(img, 0, 0, 1000, 600)
}
}
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d')
var btn2 = document.getElementById("btn2")
btn2.onclick = handleImg
function handleImg(){
}
1.底片效果
底片效果就是拿到每一個(gè)像素點(diǎn),把rgb的值逐個(gè)取出來,然后被255減去,重置復(fù)制色值。
這里需要學(xué)習(xí)一下創(chuàng)建本地服務(wù)器的前置知識,因?yàn)閏anvas是不允許跨域加載資源的
function handleImg() {
// 第一第二參數(shù)是拿圖片數(shù)據(jù)的起始x和y
// 第三第四參數(shù)是拿到圖片的寬和高
// 下面這行代碼的完整意思就是我們要從canvas中拿一個(gè)圖片,
// 圖片從畫布的(0,0)位置開始,寬為1000,高600
var imgData = ctx.getImageData(0, 0, 1000, 600)
console.log(imgData)
for (var i = 0; i < imgData.data.length; i += 4) {
imgData.data[i] = 255 - imgData.data[i]
imgData.data[i + 1] = 255 - imgData.data[i + 1]
imgData.data[i + 2] = 255 - imgData.data[i + 2]
// 下面這個(gè)代表著rgba里面a,我們直接給設(shè)置成不透明就可以了
imgData.data[i + 3] = 255
}
// 重新設(shè)置一下canvas畫布的對應(yīng)位置的圖片
// 第二第三個(gè)參數(shù)是設(shè)置的在畫布上的起始點(diǎn)的坐標(biāo)x和y
ctx.putImageData(imgData, 0, 0)
}
這個(gè)時(shí)候打印的話,我們會發(fā)現(xiàn)了報(bào)錯(cuò)了,報(bào)錯(cuò)信息大致就是圖片請求跨域了
因?yàn)槲覀儸F(xiàn)在的資源是在本地路徑下。
所以我們可以通過node全局安裝一下http-server,
npm i http-server -g
然后把這個(gè)項(xiàng)目的根目錄下運(yùn)行指令 http-server,就可以把項(xiàng)目變成了
服務(wù)器運(yùn)行的模式,通過對應(yīng)的端口就可以對項(xiàng)目進(jìn)行訪問了
2.灰度效果
灰度效果就是取每個(gè)像素點(diǎn)的rgb,將三個(gè)數(shù)值取平均數(shù),然后將平均數(shù)賦值給對應(yīng)的色值。
function handleImg() {
// 第一第二參數(shù)是拿圖片數(shù)據(jù)的起始x和y
// 第三第四參數(shù)是拿到圖片的寬和高
// 下面這行代碼的完整意思就是我們要從canvas中拿一個(gè)圖片,
// 圖片從畫布的(0,0)位置開始,寬為1000,高600
var imgData = ctx.getImageData(0, 0, 1000, 600)
console.log(imgData)
for (var i = 0; i < imgData.data.length; i += 4) {
var pxValue = (imgData.data[i] + imgData.data[i + 1] + imgData.data[i + 2]) / 3
imgData.data[i] = pxValue
imgData.data[i + 1] = pxValue
imgData.data[i + 2] = pxValue
}
// 重新設(shè)置一下canvas畫布的對應(yīng)位置的圖片
// 第二第三個(gè)參數(shù)是設(shè)置的在畫布上的起始點(diǎn)的坐標(biāo)x和y
ctx.putImageData(imgData, 0, 0)
}
3.黑白效果
黑白效果只有兩種顏色,所以色值轉(zhuǎn)換不是255就是0
function handleImg() {
// 第一第二參數(shù)是拿圖片數(shù)據(jù)的起始x和y
// 第三第四參數(shù)是拿到圖片的寬和高
// 下面這行代碼的完整意思就是我們要從canvas中拿一個(gè)圖片,
// 圖片從畫布的(0,0)位置開始,寬為1000,高600
var imgData = ctx.getImageData(0, 0, 1000, 600)
console.log(imgData)
for (var i = 0; i < imgData.data.length; i += 4) {
var pxValue = (imgData.data[i] + imgData.data[i + 1] + imgData.data[i + 2]) / 3 > 128 ? 255 : 0
imgData.data[i] = pxValue
imgData.data[i + 1] = pxValue
imgData.data[i + 2] = pxValue
}
// 重新設(shè)置一下canvas畫布的對應(yīng)位置的圖片
// 第二第三個(gè)參數(shù)是設(shè)置的在畫布上的起始點(diǎn)的坐標(biāo)x和y
ctx.putImageData(imgData, 0, 0)
}
4.模糊效果
根據(jù)每一個(gè)像素點(diǎn),取自身及周圍的的像素點(diǎn),求出rgb的平均值,然后賦值給對應(yīng)中心像素點(diǎn)。
我們定義了一個(gè)模板變量tmpdata,該變量存儲的是圖片的原始色值數(shù)據(jù),只會被讀取,不會被改變。
function handleImg() {
var imgData = ctx.getImageData(0, 0, 1000, 600)
// 拿到像素?cái)?shù)據(jù)
var pxData = imgData.data
// 創(chuàng)建和上面一樣的imgData的數(shù)據(jù)對象,當(dāng)做模板數(shù)據(jù)
var tmpdata = ctx.createImageData(canvas.width, canvas.height)
tmpdata.data.set(pxData)
// 循環(huán)出來畫布的每一個(gè)像素
for (var i = 0; i < canvas.width; i++) {
for (var j = 0; j < canvas.height; j++) {
// 獲取到每個(gè)像素的index值
var op = j * canvas.width + i
var totalR = 0, totalG = 0, totalB = 0
// 找到當(dāng)前像素為中心的周圍一共9個(gè)像素
// dx和dy決定了圖片的模糊程度
for (var dx = -2; dx <= 2; dx++) {
for (var dy = -2; dy <= 2; dy++) {
var x = i + dx
// 邊界處理
if (x < 0 || x >= canvas.width) {
x = 0
}
var y = j + dy
if (y < 0 || y >= canvas.height) {
y = 0
}
var p = y * canvas.width + x
totalR += tmpdata.data[p * 4 + 0]
totalG += tmpdata.data[p * 4 + 1]
totalB += tmpdata.data[p * 4 + 2]
}
}
var newR = totalR / 25
var newG = totalG / 25
var newB = totalB / 25
pxData[op * 4 + 0] = newR
pxData[op * 4 + 1] = newG
pxData[op * 4 + 2] = newB
pxData[op * 4 + 3] = 255
}
}
ctx.putImageData(imgData, 0, 0)
console.log(imgData)
}
5.馬賽克效果
馬賽克效果和模糊效果的區(qū)別:馬賽克效果是每一個(gè)固定區(qū)域,只能一次rgb的平均值,然后賦值給這個(gè)區(qū)域的每一個(gè)像素點(diǎn),最終形成的是一塊一塊的棱角分明的模糊效果。
function handleImg() {
var imgData = ctx.getImageData(0, 0, 1000, 600)
// 拿到像素?cái)?shù)據(jù)
var pxData = imgData.data
// 創(chuàng)建和上面一樣的imgData的數(shù)據(jù)對象,當(dāng)做模板數(shù)據(jù)
var tmpdata = ctx.createImageData(canvas.width, canvas.height)
tmpdata.data.set(pxData)
// 設(shè)置區(qū)塊大小
var size = 4
var totalSize = size * size
// 循環(huán)出來畫布的每一個(gè)像素
for (var i = 0; i < canvas.width; i += 4) {
for (var j = 0; j < canvas.height; j += 4) {
// 獲取到每個(gè)像素的index值
var op = j * canvas.width + i
var totalR = 0, totalG = 0, totalB = 0
// 找到當(dāng)前像素為中心的周圍一共9個(gè)像素
// dx和dy決定了圖片的模糊程度
for (var dx = 0; dx < size; dx++) {
for (var dy = 0; dy < size; dy++) {
var x = i + dx
var y = j + dy
var p = y * canvas.width + x
totalR += tmpdata.data[p * 4 + 0]
totalG += tmpdata.data[p * 4 + 1]
totalB += tmpdata.data[p * 4 + 2]
}
}
var newR = totalR / totalSize
var newG = totalG / totalSize
var newB = totalB / totalSize
// 通過遍歷賦值
for (var dx = 0; dx < size; dx++) {
for (var dy = 0; dy < size; dy++) {
var x = i + dx
var y = j + dy
var p = y * canvas.width + x
pxData[op * 4 + 0] = newR
pxData[p * 4 + 1] = newG
pxData[p * 4 + 2] = newB
}
}
}
}
ctx.putImageData(imgData, 0, 0)
}
6.毛玻璃效果
毛玻璃效果實(shí)現(xiàn)了像素點(diǎn)色值的指定范圍內(nèi)的隨機(jī)改變,圖形會一定程度上產(chǎn)生扭曲的效果。
function handleImg() {
var imgData = ctx.getImageData(0, 0, 1000, 600)
// 拿到像素?cái)?shù)據(jù)
var pxData = imgData.data
// 創(chuàng)建和上面一樣的imgData的數(shù)據(jù)對象,當(dāng)做模板數(shù)據(jù)
var tmpdata = ctx.createImageData(canvas.width, canvas.height)
tmpdata.data.set(pxData)
for (var i = 0; i < canvas.width; i++) {
for (var j = 0; j < canvas.height; j++) {
var op = j * canvas.width + i
// rand的大小決定了毛玻璃的清晰程度
var rand = Math.floor(Math.random() * 10)
var tp = (j + rand) * canvas.width + (i + rand)
pxData[op * 4] = tmpdata.data[tp * 4]
pxData[op * 4 + 1] = tmpdata.data[tp * 4 + 1]
pxData[op * 4 + 2] = tmpdata.data[tp * 4 + 2]
pxData[op * 4 + 3] = tmpdata.data[tp * 4 + 3]
}
}
ctx.putImageData(imgData, 0, 0)
}
7.浮雕效果
取到每一個(gè)像素點(diǎn)和它的后一個(gè)像素點(diǎn),然后兩者的rgb色值取差,然后加上128。
function handleImg() {
var imgData = ctx.getImageData(0, 0, 1000, 600)
// 拿到像素?cái)?shù)據(jù)
var pxData = imgData.data
// 創(chuàng)建和上面一樣的imgData的數(shù)據(jù)對象,當(dāng)做模板數(shù)據(jù)
var tmpdata = ctx.createImageData(canvas.width, canvas.height)
tmpdata.data.set(pxData)
for (var i = 0; i < canvas.width; i++) {
for (var j = 0; j < canvas.height; j++) {
var op = j * canvas.width + i
var tp = j * canvas.width + i + 1
var r = pxData[op * 4] - pxData[tp * 4] + 128
var g = pxData[op * 4 + 1] - pxData[tp * 4 + 1] + 128
var b = pxData[op * 4 + 2] - pxData[tp * 4 + 2] + 128
var newR = r < 0 ? 0 : (r > 255 ? 255 : r)
var newG = g < 0 ? 0 : (g > 255 ? 255 : g)
var newB = b < 0 ? 0 : (b > 255 ? 255 : b)
pxData[op * 4] = newR
pxData[op * 4 + 1] = newG
pxData[op * 4 + 2] = newB
}
}
ctx.putImageData(imgData, 0, 0)
}
8.水平鏡像效果
像素點(diǎn)的對稱交換,這里實(shí)現(xiàn)的是水平位置的交換,兩者canvas畫布并列,一張實(shí)現(xiàn)鏡像效果,另外一張不做處理,則可呈現(xiàn)出來水平鏡像效果。
function handleImg() {
var imgData = ctx.getImageData(0, 0, 1000, 600)
// 拿到像素?cái)?shù)據(jù)
var pxData = imgData.data
// 創(chuàng)建和上面一樣的imgData的數(shù)據(jù)對象,當(dāng)做模板數(shù)據(jù)
var tmpdata = ctx.createImageData(canvas.width, canvas.height)
tmpdata.data.set(pxData)
for (var i = 0; i < canvas.width; i++) {
for (var j = 0; j < canvas.height; j++) {
var op = j * canvas.width + i
var tp = j * canvas.width + (canvas.width - 1 - i)
pxData[op * 4] = tmpdata.data[tp * 4]
pxData[op * 4 + 1] = tmpdata.data[tp * 4 + 1]
pxData[op * 4 + 2] = tmpdata.data[tp * 4 + 2]
pxData[op * 4 + 3] = tmpdata.data[tp * 4 + 3]
}
}
ctx.putImageData(imgData, 0, 0)
}
9.刮刮樂
我們將圖片通過css設(shè)置成canvas畫布的背景,然后在背景圖上模擬出刮刮樂效果。
css代碼
#canvas {
background: url('./demo1.webp');
background-position: center center;
background-size: cover;
}
html結(jié)構(gòu)代碼
<p>
<button id="btn">開始刮一刮</button>
</p>
<canvas id="canvas" width="1000" height="600"></canvas>
js代碼
var btn = document.getElementById("btn")
btn.onclick = generate
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d')
ctx.fillStyle = 'gray'
ctx.fillRect(0, 0, 1000, 600)
function generate() {
canvas.onmousedown = function (e) {
canvas.onmousemove = function (e) {
var x = e.clientX - canvas.offsetLeft
var y = e.clientY - canvas.offsetTop
// 清除指定區(qū)域的像素
// 第一第二個(gè)參數(shù)是清除的起始點(diǎn)x坐標(biāo)和y坐標(biāo)
// 第三第四個(gè)參數(shù)是清除的區(qū)塊大小
//-20/2是為了讓清除區(qū)域以鼠標(biāo)為中心
ctx.clearRect(x-20/2, y-20/2, 20, 20)
}
canvas.onmouseup = function (e) {
canvas.onmousemove = null
}
}
}
10.繪制餅圖裁剪圖片
不需要用css進(jìn)行設(shè)置,html結(jié)構(gòu)代碼同“刮刮樂”,js代碼部分只有g(shù)enerate事件函數(shù)和“刮刮樂”不同。
function generate() {
ctx.strokeStyle = 'red'
ctx.moveTo(160, 120)
// arc方法主要就是為了繪制圓形或者弧線
// 第一第二個(gè)參數(shù)是圓心坐標(biāo)
// 第三個(gè)參數(shù)是半徑
// 第四第五個(gè)參數(shù)是弧度的開始與結(jié)束
ctx.arc(160, 120, 120, 135 * Math.PI / 180, 45 * Math.PI / 180)
ctx.lineTo(160, 120)
ctx.stroke()
// 把繪制好的形狀剪切出來
// 后面繪制的形狀和圖片都只能顯示在剪切出來的這個(gè)區(qū)域
ctx.clip()
var img = new Image()
img.src = './demo1.webp'
img.onload = function () {
ctx.drawImage(img,0,0,400,300)
}
}














