You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法修改SVG源码时,如何调整Canvas中SVG的颜色?

问题:无法修改SVG源码时,如何在Canvas中将黑色SVG转为白色显示?

我有一段无法修改源码的SVG:

<?xml version="1.0" encoding="UTF-8"?>
<svg id="shape" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <path d="M29.57,19.75l-3.5-13.59c-.12-.52-.45-.97-.89-1.23-2.03-1.25-4.19-1.28-6.22-.08-.59,.35-.96,1-.96,1.71v3.45h-4v-3.45c0-.71-.37-1.36-.96-1.71-2.04-1.19-4.19-1.16-6.22,.08-.44,.27-.76,.72-.88,1.22l-3.51,13.61h0c-.28,.7-.44,1.45-.44,2.25,0,3.31,2.69,6,6,6s6-2.69,6-6v-2h4v2c0,3.31,2.69,6,6,6s6-2.69,6-6c0-.79-.16-1.55-.44-2.25h0Zm-5.44-13.11l2.58,10.01c-.81-.41-1.73-.65-2.7-.65-1.54,0-2.94,.59-4.01,1.55l-.02-10.98c1.42-.83,2.74-.81,4.16,.08Zm-16.26-.01c1.42-.87,2.75-.89,4.14-.08v10.99c-1.06-.95-2.46-1.54-4-1.54-.98,0-1.89,.24-2.71,.65L7.86,6.63Zm.14,19.37c-2.21,0-4-1.79-4-4s1.79-4,4-4,4,1.79,4,4-1.79,4-4,4Zm6-8v-6h4v6h-4Zm10,8c-2.21,0-4-1.79-4-4s1.79-4,4-4,4,1.79,4,4-1.79,4-4,4Z"/>
</svg>

我需要将该SVG居中放置在带方形背景色的Canvas中,且要把默认黑色的SVG改为白色。当前React实现代码如下:

export const useRenderIcon = (
    previewCanvas: React.RefObject<HTMLCanvasElement>,
    selectedColor: Color,
    selectedSVG: Svg
): void => {
    useEffect(() => {
        if (previewCanvas.current) {
            const ctx = previewCanvas.current.getContext("2d");

            if (ctx) {
                previewCanvas.current.style.width = `${PREVIEW_CANVAS_SIZE}px`;
                previewCanvas.current.style.height = `${PREVIEW_CANVAS_SIZE}px`;

                // draw icon background color
                ctx.fillStyle = selectedColor.color;
                ctx.fillRect(0, 0, previewCanvas.current.width, previewCanvas.current.height);

                // draw icon svg
                const offset = previewCanvas.current.width - PREVIEW_SVG_SIZE; // calculate offset to center icon to middle of canvas

                const svgIconImage = new Image();
                svgIconImage.setAttribute("src", selectedSVG.uri);
                svgIconImage.setAttribute("width", `${PREVIEW_SVG_SIZE}`);
                // trying to make it white
                svgIconImage.style.fill = "white";
                svgIconImage.style.stroke = "white";
                svgIconImage.onload = () => {
                    // trying to make it white
                    svgIconImage.style.fill = "white";
                    svgIconImage.style.stroke = "white";
                    ctx.imageSmoothingEnabled = false;
                    ctx.drawImage(svgIconImage, offset / 2, offset / 2, PREVIEW_SVG_SIZE, PREVIEW_SVG_SIZE);
                };
            }
        }
    }, [previewCanvas, selectedColor, selectedSVG]);
};

但设置svgIconImage.style.fill = "white"和svgIconImage.style.stroke = "white"没有效果,SVG在Canvas中仍显示为黑色,请问该如何解决?


解决方案

方法一:使用Canvas全局合成模式实现颜色替换

原理是先绘制白色矩形覆盖SVG区域,再通过合成模式只保留SVG形状与白色矩形的重叠部分,最终得到白色的SVG图案。

修改后的代码:

export const useRenderIcon = (
    previewCanvas: React.RefObject<HTMLCanvasElement>,
    selectedColor: Color,
    selectedSVG: Svg
): void => {
    useEffect(() => {
        if (previewCanvas.current) {
            const ctx = previewCanvas.current.getContext("2d");
            const canvas = previewCanvas.current;

            if (ctx) {
                // 同步Canvas实际尺寸与样式尺寸,避免拉伸变形
                canvas.width = PREVIEW_CANVAS_SIZE;
                canvas.height = PREVIEW_CANVAS_SIZE;
                canvas.style.width = `${PREVIEW_CANVAS_SIZE}px`;
                canvas.style.height = `${PREVIEW_CANVAS_SIZE}px`;

                // 绘制背景色
                ctx.fillStyle = selectedColor.color;
                ctx.fillRect(0, 0, canvas.width, canvas.height);

                const offset = canvas.width - PREVIEW_SVG_SIZE;
                const svgX = offset / 2;
                const svgY = offset / 2;

                const svgIconImage = new Image();
                // 跨域SVG需设置此属性,避免后续操作报错
                svgIconImage.crossOrigin = "anonymous";
                svgIconImage.src = selectedSVG.uri;
                
                svgIconImage.onload = () => {
                    ctx.imageSmoothingEnabled = false;

                    // 1. 绘制白色矩形,覆盖SVG的位置和大小
                    ctx.fillStyle = "white";
                    ctx.fillRect(svgX, svgY, PREVIEW_SVG_SIZE, PREVIEW_SVG_SIZE);

                    // 2. 设置合成模式为destination-in,只保留白色矩形与SVG重叠的区域
                    ctx.globalCompositeOperation = "destination-in";
                    ctx.drawImage(svgIconImage, svgX, svgY, PREVIEW_SVG_SIZE, PREVIEW_SVG_SIZE);

                    // 3. 恢复默认合成模式,不影响后续绘制
                    ctx.globalCompositeOperation = "source-over";
                };
            }
        }
    }, [previewCanvas, selectedColor, selectedSVG]);
};

方法二:修改SVG的Data URI(仅适用于Data URI格式的SVG)

如果selectedSVG.uri是data:image/svg+xml开头的格式,可以直接解码并插入强制颜色的样式:

// 工具函数:修改SVG的填充和描边颜色
const modifySvgColor = (svgUri: string, color: string) => {
    const svgContent = decodeURIComponent(svgUri.split(",")[1]);
    // 在svg标签内添加全局样式,强制所有元素使用指定颜色
    const modifiedSvg = svgContent.replace(
        '<svg',
        `<svg style="fill: ${color}; stroke: ${color};"`
    );
    return `data:image/svg+xml,${encodeURIComponent(modifiedSvg)}`;
};

// 在useEffect中使用:
export const useRenderIcon = (
    previewCanvas: React.RefObject<HTMLCanvasElement>,
    selectedColor: Color,
    selectedSVG: Svg
): void => {
    useEffect(() => {
        if (previewCanvas.current) {
            const ctx = previewCanvas.current.getContext("2d");
            const canvas = previewCanvas.current;

            if (ctx) {
                canvas.width = PREVIEW_CANVAS_SIZE;
                canvas.height = PREVIEW_CANVAS_SIZE;
                canvas.style.width = `${PREVIEW_CANVAS_SIZE}px`;
                canvas.style.height = `${PREVIEW_CANVAS_SIZE}px`;

                ctx.fillStyle = selectedColor.color;
                ctx.fillRect(0, 0, canvas.width, canvas.height);

                const offset = canvas.width - PREVIEW_SVG_SIZE;
                const svgIconImage = new Image();
                svgIconImage.src = modifySvgColor(selectedSVG.uri, "white");
                
                svgIconImage.onload = () => {
                    ctx.imageSmoothingEnabled = false;
                    ctx.drawImage(svgIconImage, offset/2, offset/2, PREVIEW_SVG_SIZE, PREVIEW_SVG_SIZE);
                };
            }
        }
    }, [previewCanvas, selectedColor, selectedSVG]);
};

方法三:使用Canvas滤镜反转颜色(仅适用于纯黑色转白色)

如果SVG只有黑色内容,直接用反转滤镜即可快速转换颜色:

svgIconImage.onload = () => {
    ctx.imageSmoothingEnabled = false;
    // 应用反转滤镜,黑色转为白色
    ctx.filter = "invert(100%)";
    ctx.drawImage(svgIconImage, offset / 2, offset / 2, PREVIEW_SVG_SIZE, PREVIEW_SVG_SIZE);
    // 清除滤镜,避免影响后续绘制
    ctx.filter = "none";
};

各方法优缺点

  • 方法一:兼容性强,支持任意颜色转换,不受SVG内容限制
  • 方法二:修改直接,绘制时无需额外操作,但仅适用于Data URI格式的SVG
  • 方法三:代码最简洁,但仅适合黑白互转的场景

内容的提问来源于stack exchange,提问作者erol_smsr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:07:05