demo 地址
cssandjs.com/cat/
源碼地址
github.com/tinlee/1000…
背景
在以前有一個(gè)很火的養(yǎng)貓項(xiàng)目,會(huì)隨機(jī)生成各種貓的圖案,鑒于我女兒非常喜歡卡通貓,所以我想幫她也畫一批隨機(jī)的貓。
首先用 ai 生成一張貓的圖片
技術(shù)方案
其實(shí)最好的方案是使用 svg,但是我真的沒(méi)有辦法畫出來(lái)貓的全部 svg,所以我想是不是可以使用一個(gè)簡(jiǎn)單的辦法。 按照?qǐng)D片上的信息來(lái)說(shuō),分成 3 個(gè)部分
一個(gè)完整的圖片樣式,通過(guò)背景,花紋,邊框三部分組成。
那么我們只要實(shí)現(xiàn)了這幾部分,然后疊加上去就可以了。
例如一條沒(méi)有花紋的尾巴,那么只需要
一張背景圖片改變顏色,然后加上邊框,即可自動(dòng)生成。
所以我們先把貓的所有需要渲染的部分,進(jìn)行切割,拆成底色和邊框兩部分。
具體實(shí)現(xiàn)
加載圖片
export function createImage(src: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = src;
img.onload = () => {
resolve(img);
};
img.onerror = (e) => {
reject(e);
};
});
}
加載圖片需要保證圖片已經(jīng)加載成功,所以封裝一個(gè) promise,在圖片資源加載完成后返回圖片信息。
圖片著色
export function fillColor(
imgUrl: string,
color: string
): Promise<HTMLImageElement | null> {
return createImage(imgUrl).then((img) => {
if (!img) {
return null;
}
const canvas: HTMLCanvasElement = document.createElement(
"canvas"
) as HTMLCanvasElement;
const context: CanvasRenderingContext2D = canvas.getContext(
"2d"
) as CanvasRenderingContext2D;
canvas.width = img.width;
canvas.height = img.height;
context.fillStyle = color;
context.fillRect(0, 0, img.width, img.height);
context.globalCompositeOperation = "destination-in";
context.drawImage(img, 0, 0, img.width, img.height);
context.globalCompositeOperation = "source-over";
const finnalImage = canvas.toDataURL();
return createImage(finnalImage);
});
}
這里最關(guān)鍵的代碼在于context.globalCompositeOperation = "destination-in"
,它的作用在于講目標(biāo)圖形與源圖形合并,并保留源圖形。 整體代碼的過(guò)程為先繪制一個(gè)矩形填充整體區(qū)域即背景,然后設(shè)定為 destination-in 模式,繪制圖片,此時(shí)經(jīng)過(guò)疊加,會(huì)保留圖片繪制區(qū)域內(nèi)的背景。
在繪制完成后將globalCompositeOperation
修改為默認(rèn)的source-over
,并將圖片通過(guò)toDataURL
轉(zhuǎn)成轉(zhuǎn)成 base64 供繪制使用
繪制圖片
繪制邊框比較簡(jiǎn)單,直接使用 context.drawImage 即可,將著色后的背景圖及邊框依次繪制,即可得到一個(gè)改變顏色圖片。
顏色選擇 hsl
如果隨機(jī)一個(gè) rgb 顏色,可能存在顏色過(guò)亮或者過(guò)暗的情況。 我們更希望以一種顏色比較柔和的方式呈現(xiàn),所以不適用 rgb 顏色,改為 hsl 顏色。 hsl 是將 rgb 顏色變?yōu)樽鴺?biāo)顯示的一種顏色表現(xiàn)方式。 可以看到,亮度(light ness)越低的地方,顏色越暗,越高的地方,顏色越亮。 飽和度(saturation)越靠外的地方,顏色越鮮艷,所以我們可以設(shè)定一定的范圍取值,用來(lái)約束顏色的色彩范圍。
export function getColor() {
return (
"hsl(" +
360 * Math.random() +
"," +
// (25 + 70 * Math.random()) +
100 * Math.random() +
"%," +
// (70 + 10 * Math.random()) +
100 * Math.random() +
"%)"
);
}
此時(shí)獲取到顏色色值更符合我們的審美。
花紋生成
花紋,我們可以直接使用如上述描述的方式,通過(guò)圖片的形式生成,在頭部我也嘗試使用了一種隨機(jī)的圓形用來(lái)模擬貓的臉部。靈感來(lái)源于起司貓。
可以看到基本的圖形就是兩個(gè)圓形的疊加,所以我用了兩個(gè)圓來(lái)模擬各種情況
// 圓形
context.beginPath();
if (side !== 3) {
const randomHeight = Math.floor(Math.random() * 120);
if (side === 0) {
// 左半邊
context.arc(40, 0, 240, 0, 2 * Math.PI);
} else if (side === 1) {
// 右半邊
context.arc(460, 0, 240, 0, 2 * Math.PI);
} else if (side === 2) {
// 全部
context.arc(40, 0, 240 + randomHeight, 0, 2 * Math.PI);
context.arc(460, 0, 240 + randomHeight, 0, 2 * Math.PI);
}
}
這里用半圓,兩個(gè)圓,沒(méi)有圓來(lái)模擬三種情況。
end 最終效果
作者:天元reborn
鏈接:https://juejin.cn/post/7378330155384700928
來(lái)源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
該文章在 2024/6/11 9:08:15 編輯過(guò)