JavaScript在图片上绘制文字的两种实现方案对比

作者:像素猫

时间:2026-10-31

浏览:215

本文对比了前端在图片上绘制文字的两种主流方案:基于DOM定位结合html2canvas的转换方式,以及直接使用Canvas API进行绘制的原生方式。文章详细解析了两种方案的代码实现、组件封装及使用示例,重点探讨了图片跨域导致的Canvas污染问题及其解决方案,帮助开发者根据复杂样式需求与性能要求选择合适的技术路径。

文章目录

前言

本文介绍了在前端图片上合成文字的两种实现思路,并通过具体的Demo代码展示了落地过程。提供的代码已封装为React组件,开发者可直接复制使用,无需额外配置环境。

效果展示

前言

需求背景

业务场景中,B端用户上传了图片模板,C端用户需要在该模板上生成带有个性化字体的内容,并最终支持C端用户将合成后的图片下载保存。

解决思路

梳理该需求的关键环节,主要涉及图片资源的获取、数据传输路径、图片加载、文字合成绘制以及最终图片的下载保存。

前言

其中,核心难点在于如何在图片上准确绘制文字并生成可下载的文件。

针对这一核心步骤,本文提出两种可行的技术方案:

方案一:DOM定位结合html2canvas

该方案首先将背景图片通过Image标签渲染至DOM节点,随后将需要绘制的文字单独置于另一个DOM元素中,通过CSS定位将其精确放置于图片的指定坐标。最后,利用html2canvas库将整个DOM区域快照并转换为Canvas画布,进而生成图片供用户下载。

代码实现

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; // 需要写的值
  textStyle?: React.CSSProperties; // 渲染文本的样式

  buttonValue?: string; // button值
  onClickButton?: () => void; // 点击下载前执行的函数

  loadName?: string; // 下载后的文件名称
};

const LoadCanvasImg: React.FC<LoadCanvasImgProps> = ({
  text = "我是名字",
  loadName = "load",
  buttonValue = "点击下载",
  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="保存证书"
        onClickButton={() => {}} // 点击下载前执行的函数
        ImageWidth={200}
      />
    </div>
  );
};

方案二:Canvas原生绘制

该方案直接在Canvas画布上先绘制背景图片,随后使用Canvas的文本绘制API将文字渲染到画布对应位置,最后通过Canvas接口生成图片供下载。

代码实现

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'); // 跨域的时候加上
    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轴坐标
        y={10}  // y轴坐标
        textStyle = { fontFamily: "e1kcQpNW_GBK_ry", fontSize: "22px" } // 文字样式
        fillStyle = "#000" // 文字颜色
        canvasStyle = { width: 800, height: 600 } // canvas样式
      />
    </div>
  );
};

两种方案的优缺点对比

优点缺点
定位+html2canvas对绘制复杂样式支持友好需要安装第三方依赖
canvas绘制使用简单,canvas原生支持遇到复杂样式绘制较为困难

常见坑点与解决方案

图片跨域问题

在使用Canvas绘制图片时,若图片域名与当前项目域名不一致,浏览器会触发跨域限制,导致Canvas被污染。这通常会在执行const dataURL = canvas?.toDataURL("image/png") || ""(即调用toDataURL方法)时抛出安全错误,导致图片无法生成。

解决方法:在创建Image对象加载图片前,必须设置backgroundImage.setAttribute('crossOrigin', 'Anonymous')(即设置crossOrigin属性为'Anonymous'),以允许跨域图片在Canvas中正常使用。

以上就是关于JavaScript在前端图片上绘制文字的两种实现方法与对比分析,更多相关JavaScript图片合成技术内容可参考本站往期文章。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章