JavaScript在圖片繪制文字兩種方法的實(shí)現(xiàn)與對(duì)比
序言
本文實(shí)現(xiàn)了在圖片上繪制文字的兩種思路,并通過(guò)demo的方式,去具體實(shí)現(xiàn),實(shí)現(xiàn)代碼為組件形式,支持即粘即貼即用。
效果展示

需求簡(jiǎn)介
遇到一個(gè)這樣的需求,產(chǎn)品要求根據(jù)B端用戶上傳的圖片模板,在C端繪制上個(gè)性字體且展示,最后也支持C端用戶下載繪制后的圖片。
解決思路
我們先梳理一下這個(gè)需求的一些關(guān)鍵的點(diǎn),即圖片來(lái)源、圖片傳遞路徑、獲取圖片、圖片繪制文字、下載圖片

那最關(guān)鍵的步驟就是圖片繪制
我這里想到了兩種方案:
方案一:定位+html2canvas
將圖片用Image渲染出來(lái)并放在一個(gè)DOM中,然后將文字再單獨(dú)寫(xiě)一個(gè)DOM,通過(guò)定位的形式將其定位到對(duì)應(yīng)的位置,最后通過(guò)html2canvas,將整個(gè)DOM繪制成一個(gè)canvas,轉(zhuǎn)成圖片下載下來(lái)。
代碼實(shí)現(xiàn)
import React from "react";
import html2Canvas from "html2canvas";
import { Button, Image } from "antd-mobile";
type LoadCanvasImgProps = {
containerStyle?: React.CSSProperties; // 最外層父組件的樣式
backgroundImageSrc?: string; // 背景圖
ImageWidth?: string | number;
text?: string; // 需要寫(xiě)的值
textStyle?: React.CSSProperties; // 渲染文本的樣式
buttonValue?: string; // button值
onClickButton?: () => void; // 點(diǎn)擊下載前執(zhí)行的函數(shù)
loadName?: string; // 下載后的文件名稱
};
const LoadCanvasImg: React.FC<LoadCanvasImgProps> = ({
text = "我是名字",
loadName = "load",
buttonValue = "點(diǎn)擊下載",
backgroundImageSrc = "",
textStyle = { position: "absolute", top: "0px", left: "0px" },
containerStyle,
ImageWidth = 100,
onClickButton,
}) => {
const onHtml2Canvas = async () => {
try {
const loadBody = document.getElementById("loadBody") as HTMLElement;
const canvas = await html2Canvas(loadBody, {
useCORS: true,
allowTaint: false,
});
downloadCanvasImg(canvas);
onClickButton && onClickButton();
} catch (error) {
console.error("Error generating canvas image:", error);
}
};
// 下載canvas
const downloadCanvasImg = (canvas: HTMLCanvasElement) => {
const dataURL = canvas.toDataURL("image/png") || "";
const downloadLink = document.createElement("a");
downloadLink.href = dataURL;
downloadLink.download = `${loadName}.png`;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
};
return (
<div className="loadCanvasImg" style={containerStyle}>
<div id="loadBody">
<div style={textStyle}>{text}</div>
<Image src={backgroundImageSrc} width={ImageWidth} alt="Background" />
</div>
<Button onClick={onHtml2Canvas} color="primary">
{buttonValue}
</Button>
</div>
);
};
export default LoadCanvasImg;使用方式
import React from "react";
import LoadCanvasImg from "..."; // 這里的路徑是你的組件路徑
const Demo1 = () => {
return (
<div>
<LoadCanvasImg
backgroundImageSrc={""} // 圖片的url
text={"我是名字"} // 需要繪制的值
containerStyle={{ position: "relative" }}
textStyle={{
position: "absolute",
top: "10px",
left: "100px",
fontSize: "20px",
}}
buttonValue="保存證書(shū)"
onClickButton={() => {}} // 點(diǎn)擊下載前執(zhí)行的函數(shù)
ImageWidth={200}
/>
</div>
);
};
方案二:canvas繪制
先用canvas繪制圖片,再用canvas繪制字體,最后轉(zhuǎn)成圖片下載下來(lái)。
代碼實(shí)現(xiàn)
import React, { useEffect, useRef } from "react";
import { Button } from "antd-mobile";
interface CanvasFontSizeProps {
text?: string; // 要繪制的文字
backgroundImageSrc?: string; // 圖片的url鏈接
x?: number; // 圖片的x軸定位
y?: number; // 圖片的y軸定位
textStyle?: React.CSSProperties; // 繪制的文字樣式
fillStyle?: string | CanvasGradient | CanvasPattern; // canvas繪制文字的樣式
canvasStyle?: React.CSSProperties; // canvas的樣式
}
const CanvasFontSize: React.FC<CanvasFontSizeProps> = ({
text = "姓名",
backgroundImageSrc = "",
x = 100,
y = 100,
textStyle = { fontFamily: "e1kcQpNW_GBK_ry", fontSize: "22px" },
fillStyle = "#000",
canvasStyle = { width: 800, height: 600 },
}) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const downloadCanvasImage = () => {
const canvas = canvasRef.current;
const dataURL = canvas?.toDataURL("image/png") || "";
const downloadLink = document.createElement("a");
downloadLink.href = dataURL;
downloadLink.download = "canvas_image.png";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
};
useEffect(() => {
const canvas = canvasRef.current as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
const backgroundImage = new Image();
backgroundImage.setAttribute('crossOrigin', 'Anonymous'); // 跨域的時(shí)候加上
backgroundImage.src = backgroundImageSrc;
backgroundImage.onload = () => {
ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
ctx.font = `${textStyle.fontSize} ${textStyle.fontFamily}`;
ctx.fillStyle = fillStyle;
ctx.fillText(text, x, y);
};
}, [text, x, y, backgroundImageSrc, textStyle, fillStyle]);
return (
<div>
<canvas ref={canvasRef} style={canvasStyle} />
<Button onClick={downloadCanvasImage} color="primary">
下載鏈接
</Button>
</div>
);
};
export default CanvasFontSize;
使用方式
import React from "react";
import CanvasFontSize from "..."; // 這里的路徑是你的組件路徑
const Demo1 = () => {
return (
<div>
<CanvasFontSize
backgroundImageSrc={""} // 圖片的url
text={"我是名字"} // 需要繪制的值
x={10} // x軸坐標(biāo)
y={10} // y軸坐標(biāo)
textStyle = { fontFamily: "e1kcQpNW_GBK_ry", fontSize: "22px" } // 文字樣式
fillStyle = "#000" // 文字顏色
canvasStyle = { width: 800, height: 600 } // canvas樣式
/>
</div>
);
};
兩種思路的優(yōu)缺點(diǎn)對(duì)比
| 優(yōu)點(diǎn) | 缺點(diǎn) | |
|---|---|---|
| 定位+html2canvas | 對(duì)繪制復(fù)雜樣式支持友好 | 需要安裝第三方依賴 |
| canvas繪制 | 使用簡(jiǎn)單,canvas原生支持 | 遇到復(fù)雜樣式繪制較為困難 |
遇到的一些坑
圖片跨域
使用canvas畫(huà)圖片的時(shí)候,當(dāng)圖片域名與項(xiàng)目域名不一致的時(shí)候,瀏覽器會(huì)報(bào)跨域錯(cuò)誤,或執(zhí)行到const dataURL = canvas?.toDataURL("image/png") || ""這一步報(bào)錯(cuò);
解決辦法:在使用 Image對(duì)象時(shí)添加上backgroundImage.setAttribute('crossOrigin', 'Anonymous')。
到此這篇關(guān)于JavaScript在圖片繪制文字兩種方法的實(shí)現(xiàn)與對(duì)比的文章就介紹到這了,更多相關(guān)JavaScript圖片繪制文字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
動(dòng)態(tài)加載js、css的簡(jiǎn)單實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇?jiǎng)討B(tài)加載js、css的簡(jiǎn)單實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05
d3.js入門教程之?dāng)?shù)據(jù)綁定詳解
這篇文章主要介紹了關(guān)于d3.js數(shù)據(jù)綁定的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)只d3.js具有一定的參考價(jià)值,需要的朋友下面來(lái)一起看看吧。2017-04-04
JavaScript數(shù)字精度丟失問(wèn)題的解決方案
JavaScript使用64位浮點(diǎn)數(shù)表示數(shù)字(基于IEEE 754標(biāo)準(zhǔn)),這導(dǎo)致某些十進(jìn)制數(shù)字在計(jì)算過(guò)程中出現(xiàn)精度丟失,所以本文給大家介紹了JavaScript數(shù)字精度丟失問(wèn)題的解決方案,需要的朋友可以參考下2024-10-10
ie8下修改input的type屬性報(bào)錯(cuò)的解決方法
當(dāng)用戶勾選顯示明文復(fù)選框時(shí),要以明文顯示用戶輸入的密碼,去掉勾選時(shí)要變回密文,問(wèn)題是ie8中是不允許修改input的type屬性2014-09-09
使用plupload自定義參數(shù)實(shí)現(xiàn)多文件上傳
這篇文章主要介紹了使用plupload自定義參數(shù)實(shí)現(xiàn)多文件上傳的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Js實(shí)現(xiàn)雙擊鼠標(biāo)自動(dòng)滾動(dòng)屏幕的示例代碼
這篇文章主要介紹了Js實(shí)現(xiàn)雙擊鼠標(biāo)自動(dòng)滾動(dòng)屏幕的示例代碼。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12

