0%

修改 TikZ-cd 的渲染方式

好久不见!很久没有更新网站了,因为最近一直在忙这个问题。我跟你说我现在已经是 SVG 领域大神了

上回书说到:彼时的网站,在 添加对 TikZ 的支持并修改配置 这篇文章中,将 tikz 与 tikzcd 代码块做了区分,并替换了文字和背景颜色;之后又在 调整黑暗模式设置 里面更正了颜色配置。到现在为止都没有任何问题。

但是,在更新了 【更新】更改透明显示方式, 调整代码块配色, 添加友链 这篇文章后,由于我们修改了 --content-bg-color,这就带来了一个渲染问题:如果我们回到最开始的文章,就会发现蛇引理的交换图中, 这个映射的渲染出现问题了:

/images/2025/10/transparent-clippings-using-tikz-cd/坏.png 加载失败

这件事的来源是 tikz-cd 的绘图方式。我们想让 显示在其经过的箭头的“上面”,这是通过沿着同样的 path 先画一条 stroke-width 较大的白色线条,盖住下面箭头的一部分,再在其上画出黑色的箭头本体;类似的,要绘制 这个符号,也是先画一个填充为白色的小圆,为它清理出一小片空间的。

然而,在第三篇文章中,我们将 --content-bg-color 改成了带 alpha 通道的颜色,所以这就相当于尝试用一个半透明的东西盖住下面的东西,当然是不能完全盖住的。这也给问题带来了两个方向的难度:如果把颜色改成不透明,相比于透明背景就会很明显;如果不把颜色改成不透明,就遮不住下面的箭头。

我为这个问题困扰了很久,研究了很长时间的 SVG,一度想尝试为每个白色物体创建遮罩(mask),但后来发现 mask 直接应用在边界框长或宽为零的元素上(比如水平或竖直的 path,即使 stroke-width 不为零)会直接让它消失。在进一步走火入魔给每个元素绑上不可见元素之前,突然想到了一个完美适配当前要求的解决办法。

SVG 的 mask 的使用方式是:先通过

1
2
3
4
5
6
7
8
9
10
11
12
<svg ...>
<defs>
<mask id="myMask">
<!-- 画图指令 -->
...
</mask>
<!-- 其他定义指令 -->
</defs>

<!-- 其他指令 -->
...
</svg>

定义一个 idmyMask 的遮罩,之后再在画图指令中使用属性 mask='url(#myMask)' 对其应用。一个 mask 几乎就是一张 SVG 图片,默认的遮罩类型为 luminance,即将 mask 中的图像的明度作为被应用元素的透明度。也就是说,一个纯白色矩形作为遮罩相当于什么也不干,而一个灰色矩形作为遮罩就会将元素变为半透明。

如果我们现在有一张只在白色背景下才能正常显示的 SVG 图像,该怎么去除掉白色背景,并将文字原本的黑色替换成任何我们想要的颜色呢?

一个巧妙的想法是:先手动添加白色背景,得到一张白底黑字的“模板成图”;再将其反色制作成遮罩,应用到固定颜色的矩形上。这样一来,原来的白色就变成了被去掉的部分,而原来的黑色则变成了透出固定颜色的部分。这样做的好处是,我们根本不需要对原来的画图指令做任何改动,只需要将其放入 <mask></mask> 里即可。由于边界处的处理,出来的 SVG 里的线条会比原来粗一点点,但我选择忽略它。

所以我就直接 forkhexo-filter-tikzjax,并修改了渲染 tikzcd 代码块的部分。具体代码就不在这里放了。

/images/2025/10/transparent-clippings-using-tikz-cd/好.png 加载失败

等着 我马上就开始更 Achar 专题