新聞中心
前言
國(guó)慶節(jié)馬上要到了,今天就教你如何從0到1使用canvas生成國(guó)慶風(fēng)微信頭像。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),安澤企業(yè)網(wǎng)站建設(shè),安澤品牌網(wǎng)站建設(shè),網(wǎng)站定制,安澤網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,安澤網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
本文包含以下內(nèi)容:
- vue3項(xiàng)目搭建,需求分析
- canvas合成圖片原理
- github自動(dòng)化部署
- 開發(fā)過程遇到的問題及解決方案
搭建項(xiàng)目,分析需求
項(xiàng)目的話就直接使用腳手架生成一個(gè) Vue3 + TS項(xiàng)目
npm create vue@latest為了方便,使用了Element PlusUI庫(kù)
npm install element-plus --save配置的話,可以查看文檔,全局導(dǎo)入、按需導(dǎo)入都可以看自己的需求
項(xiàng)目搭建完后,就可以來(lái)分析一下本次需求大概會(huì)涉及哪些功能了
- 上傳頭像
這是一個(gè)合成微信頭像的工具,那就必須得讓用戶上傳自己的微信頭像了
- 合成模版
為了方便,我們當(dāng)然還需要提供多種模版供用戶自己選擇
- 用戶自定義內(nèi)容
為了讓生成的頭像更具獨(dú)一無(wú)二性,我們還需要提供用戶自定義內(nèi)容的功能,比如:用戶輸入文字、選擇文字顏色等
- 合成頭像
本次需求的重點(diǎn)當(dāng)然是合成頭像了
- 下載合成后的頭像
用戶合成完當(dāng)然還得支持讓他下載
功能開發(fā)
上傳頭像
這部分比較簡(jiǎn)單,主要是用戶上傳自己的微信頭像后再進(jìn)行展示,UI部分就不貼了,后面有源碼。
合成模版
合成模版部分,這里主要是需要考慮各個(gè)模版所需要的合成功能有哪些
合成圖片
這里其實(shí)也不難,主要是使用canvas來(lái)繪制圖片以及文字,由于各個(gè)模版的合成邏輯不一樣,這里就不全部展示了,但整體上的合成流程是一樣
// 模版4
const drawImg4 = (ctx: any) => {
const img = new Image();
img.src = user_img.value;
const gqImg = new Image();
gqImg.src = gqList.value[template_id.value - 1].img;
img.onload = () => {
ctx.drawImage(img, 0, 0, 300, 300); // 繪制頭像
gqImg.onload = () => {
ctx.drawImage(gqImg, 0, 0, 300, 300); // 繪制國(guó)慶圖
ctx.fillStyle = textColor.value; // 設(shè)置文字顏色
ctx.font = "20px kaiti"; // 設(shè)置文字大小及字體
const textList = text.value?.split(",") ?? []; // 以中文逗號(hào)分割文字
textList.forEach((item: string, i: number) => {
drawVerticalText(ctx, item ?? "", 20 + i * 20, 186 + i * 20, {
size: 20,
}); // 繪制文字
});
};
canDownload.value = true; // 合成完成
};
};這里主要的難點(diǎn)在于canvas默認(rèn)不支持文字豎排繪制,所以這里需要特殊處理,原理其實(shí)就是遍歷文字,計(jì)算文字高度,然后再一個(gè)一個(gè)去繪制
// 文字豎排
const drawVerticalText = (
context: any,
text: string,
x: number,
y: number,
font: any
) => {
context.save();
context.font = font;
for (var i = 0; i < text.length; i++) {
context.fillText(text[i], x, y + i * font.size);
}
context.restore();
};下載圖片
這里主要是借助a標(biāo)簽的download屬性,這里在手機(jī)上有點(diǎn)坑,后面會(huì)提到...
const downloadImg = () => {
if (!canDownload.value) {
ElMessage({
message: "請(qǐng)先合成頭像~",
type: "warning",
});
return;
}
const url = canvas.value.toDataURL("image/png");
const a = document.createElement("a");
a.href = url;
a.download = "國(guó)慶頭像.png";
a.click();
};自動(dòng)化部署
這里其實(shí)之前有寫過文章,主要是使用github action來(lái)完成。
搭建完就是這樣的,我們寫完代碼只需要將代碼提交上去就能夠自動(dòng)打包部署了
對(duì)這個(gè)不了解的可以去看我之前的文章:使用GitHub Actions實(shí)現(xiàn)自動(dòng)化部署
體驗(yàn)
開發(fā)部署完就可以來(lái)體驗(yàn)一下了
PC上體驗(yàn)下來(lái),效果還可以。
問題及解決方案
開發(fā)過程中也遇到一些問題,來(lái)看看是如何解決的吧
保存圖片不清晰
canvas繪制圖片不清晰的原因主要是:
- 圖片被放大或縮小
- 圖片沒處于完整像素的位置
因?yàn)閏anvas是點(diǎn)陣圖,由一個(gè)個(gè)像素組成,當(dāng)圖像被放大時(shí),一個(gè)像素會(huì)被強(qiáng)形拉伸至一個(gè)以上,多出來(lái)的像素均勻的分部在圖像中,計(jì)算機(jī)為了使拉伸后的圖像看起來(lái)平滑,會(huì)給這些多出來(lái)的像素計(jì)算出一個(gè)過渡色,縮小圖像時(shí),多個(gè)像素合成一個(gè)像素,計(jì)算機(jī)會(huì)用這多個(gè)像素的色彩值計(jì)算出一個(gè)過渡色來(lái)填充這個(gè)像素,不管是放大還是縮小,都會(huì)造成圖像原有像素信息丟失。
所以只需要加上以下代碼就能解決
const dpr = window.devicePixelRatio || 1; // 獲取設(shè)備的devicePixelRatio
canvas.value.width = 300 * dpr; // 畫布寬高放大dpr倍,繪制后再縮小dpr倍,解決模糊問題
canvas.value.height = 300 * dpr; // 畫布寬高放大dpr倍,繪制后再縮小dpr倍,解決模糊問題
canvas.value.style.width = "300px"; // 顯示高
canvas.value.style.height = "300px"; // 顯示高
ctx.value.scale(dpr, dpr); // 按比例縮放畫布,解決模糊問題優(yōu)化完,清晰度提升還是非常明顯的
移動(dòng)端體驗(yàn)問題
手機(jī)上下載圖片會(huì)失敗,這主要是因?yàn)閎lob格式在手機(jī)上不能下載,base64格式有點(diǎn)大,那就只能上傳CDN再進(jìn)行下載了?
不需要,我們可以利用手機(jī)上的長(zhǎng)按圖片保存來(lái)實(shí)現(xiàn)
const downloadImg = () => {
if (!canDownload.value) {
ElMessage({
message: "請(qǐng)先合成頭像~",
type: "warning",
});
return;
}
const url = canvas.value.toDataURL("image/png");
if (devices.some((item) => ua.includes(item))) {
ElMessageBox.alert(
`
請(qǐng)長(zhǎng)按圖片保存
`,
"保存圖片",
{
dangerouslyUseHTMLString: true,
}
);
return;
}
const a = document.createElement("a");
a.href = url;
a.download = "國(guó)慶頭像.png";
a.click();
};
打包部署問題
打包生成的_plugin-vue_export-helper.cdc0426e.js文件訪問404,剛開始我還以為是打包路徑配置的有問題,但如果是打包路徑的問題的話也不會(huì)只有這一個(gè)文件有問題。
最終,我在vite的issues中找到了答案
簡(jiǎn)單點(diǎn)講就是Github Pages 阻止了以下劃線字符開頭的文件,所以會(huì)導(dǎo)致這個(gè)文件訪問返回404。
解決方法就是修改打包邏輯:
const INVALID_CHAR_REGEX = /[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
build: {
outDir: "dist",
assetsDir: "assets",
chunkSizeWarningLimit: 2000, // 解決包大小超過500kb的警告
rollupOptions: {
output: {
manualChunks: {
// elementPlus: ["element-plus"],
// highlightjs: ["highlight.js"],
},
chunkFileNames: "assets/[name]-[hash].js",
entryFileNames: "assets/[name]-[hash].js",
assetFileNames: "assets/[name]-[hash].[ext]",
sanitizeFileName: (name) => {
const match = DRIVE_LETTER_REGEX.exec(name);
const driveLetter = match ? match[0] : "";
return (
driveLetter +
name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, "") // 處理文件名中的非法字符
);
},
},
},
},vite.config.ts中加上以上代碼,重新提交部署就可以了。
最后
整個(gè)內(nèi)容到這里就結(jié)束了
體驗(yàn)地址:https://bettersong.github.io/nanjiu-tools/#/generate_image
網(wǎng)站名稱:國(guó)慶微信頭像DIY:輕松打造個(gè)性化頭像!
本文URL:http://fisionsoft.com.cn/article/dphddcs.html


咨詢
建站咨詢
