【问题标题】:SVG - How to apply a gradient transform matrix to a linear gradient brush?SVG - 如何将渐变变换矩阵应用于线性渐变画笔?
【发布时间】:2025-11-14 17:20:01
【问题描述】:

我正在用 c++ 语言编写一个 SVG 查看器应用程序。实际上,我在几个 SVG 文件中遇到了一个我无法弄清楚的转换问题。

考虑以下 SVG 文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg9686" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="90mm" width="145mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 145 90" xmlns:dc="http://purl.org/dc/elements/1.1/">
 <defs id="defs9680">
  <linearGradient id="linearGradient6593-0" gradientUnits="userSpaceOnUse" x1="74.658" y1="-398.92" x2="75.519" y2="-485.7" gradientTransform="matrix(1.0069 0 0 1.19 1.4571 709.77)">
   <stop id="stop6595" stop-color="#be245a" offset="0"/>
   <stop id="stop6600" stop-color="#e46e6f" offset=".48408"/>
   <stop id="stop6597" stop-color="#f1a769" offset="1"/>
  </linearGradient>
 </defs>
 <g id="layer1" transform="translate(-7.631 -139.36)">
  <rect id="rect3690-4-2-09-4-2-8-0" height="90" width="145" y="139.36" x="7.631" fill="url(#linearGradient6593-0)"/>
 </g>
</svg>

这基本上是一个用渐变笔刷填充的矩形,从橙色到洋红色。矩形大小为 90x145,在应用所有变换后位于坐标 [0, 0]。

如果我理解理论,要正确绘制矩形,我应该处理以下步骤:

  1. 在本地文档坐标系中计算由 x1、y1、x2 和 y2 值给出的渐变画笔边界框。这应该通过将给定的梯度变换矩阵应用于从 x1、y1、x2 和 y2 计算的点来完成
  2. 由于渐变单元被声明为“使用中的用户空间”,因此根据线性渐变标记值和变换后的边界框计算画笔
  3. 将矩形坐标转换为填充,也放入文档坐标系中
  4. 使用之前创建的画笔,在变换后的坐标处绘制矩形

应用上述过程,我预计会达到以下结果:

但我得到了这个结果:

如果我手动更改上述源文件中的所有值,以删除所有转换并应用文档坐标中的所有值,线性渐变将正确填充到我的矩形中。因此,如果有人可以向我解释,我将非常感激

  1. 我在流程中做错了什么?
  2. 我应该如何计算线性梯度值?
  3. 我应该如何将梯度矩阵应用于给定的值? (即我希望将矩阵应用于值应该在文档系统坐标中转换它们,因此转换后的值应该大致给出 x1 = 0、y1 = 0、x2 = 90 和 y2 = 145 作为结果,但事实并非如此)

注意欢迎以数学形式进行演示

【问题讨论】:

    标签: svg matrix gradient transformation linear-gradients


    【解决方案1】:

    首先,我认为对渐变使用术语“边界框”没有帮助。四个值 x1, x2, y1, y2 描述了一个向量,梯度停止点匹配到该向量上,并且梯度法线垂直于该向量(在应用任何变换之前)。 “盒子”与渐变属性没有任何意义。

    梯度向量可以可视化为线元素

    <line x1="74.658" y1="-398.92" x2="75.519" y2="-485.7" />
    

    第一步是申请gradientTransform="matrix(1.0069 0 0 1.19 1.4571 709.77)"。结果线将被绘制为

    <line x1="76.6302" y1="235.055" x2="77.4972" y2="131.787" />
    

    (由于变换没有引入倾斜,梯度法线仍然垂直于那条线。)

    此时,渐变应用到矩形在其局部坐标系中

    <rect width="145" height="90" x="7.631" y="139.36"/>
    <line x1="76.6302" y1="235.055" x2="77.4972" y2="131.787" />
    

    只有在那之后,最终的transform="translate(-7.631 -139.36)" 才会同时应用于矩形和向量:

    <rect width="145" height="90" x="7.631" y="139.36"/>
    <line x1="70" y1="95.7" x2="69.87" y2="-7.57" />
    

    请注意,如果直接将变换应用于矩形而不是封闭组,这甚至会成立。将变换应用于元素始终是最后执行的操作。

    我认为你出错的地方是在对矩形应用变换后将 userSpaceOnUse 解释为 final 坐标系。但它是什么,是coordinate system

    在引用渐变元素的时候就位,

    因此进一步转换之前。

    【讨论】:

    • 感谢您的详细回答,它帮助我找到了我的错误。
    • 如何使用Matrix4(c++语言)将计算出来的线信息(与渐变相关)添加到矩形中?
    最近更新 更多