SVG 剪切区域为什么不锐利?

huangapple go评论62阅读模式
英文:

Why is the cut out of an SVG not sharp?

问题

因为我是吃饼干的专家,所以我想,为什么不成为SVG方面的专家呢?你永远不知道它将来可能会有什么用处...

所以我选择要实现的是绘制一个内部带感叹号的实心圆。我阅读了一些教程,决定只使用一个路径对象。绘制圆似乎相当容易:

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="circle" viewBox="0 0 24 24" aria-hidden="true">

      <path d="M12 0 A12 12 0 1 1 11.99 0Z" stroke="none"/>

    </symbol>
  </defs>
</svg>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>SVG Test</title>

  <style>
    .circle {
      width: 1rem;
      height: 1rem;
      fill: red;
    }
  </style>
    
</head>

<body>

  <svg class="circle"><use href="icons.svg#circle"/></svg>

</body>
</html>

如路径所示,它必须绘制到终点 (11.99|0)。这对我来说似乎有点奇怪,但如果我将其精确绘制到 (12|0),圆就不会绘制在画布上。

所以我的第一个问题是:

Q1) 为什么我不能在起始点关闭圆,而必须在某个点之前停止并用 `z` 闭合路径?

我的第二个问题涉及到 viewBox。据我所知,路径本身没有尺寸。所以这个 viewBox 从 (0|0) 开始,到 (24|24) 结束。

Q2) 如果我们为SVG指定这些值,那么这个 viewBox 的宽度和高度是否完全等同于24像素,或者我们会遇到0.00...001的偏差?

现在情况变得有点奇怪,至少对我来说是这样。我想从圆中间剪裁出感叹号。我在某处读到过,要做到这一点,你必须以与绘制内部路径相反的方向绘制圆。在我下面的示例中,我顺时针绘制了圆(顺便说一下,这要求在 11.99 处结束圆,而逆时针绘制圆则要求在 12.01 处结束路径)。内部的矩形被移除了:

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="circle-with-line" viewBox="0 0 24 24" aria-hidden="true">

      <path d="M12 0 A12 12 0 1 1 11.99 0Z M11 6 v8 h3 V6 H11Z" stroke="none"/>

    </symbol>
  </defs>
</svg>

不幸的是,这个矩形的边缘不是锐利的。我原以为从一个确切的点开始并沿着坐标轴精确地绘制线条会给我一个锐利而清晰的切口。但事实并非如此,边缘是模糊的。因此,第三个问题出现了:

Q3) 为什么剪切出来的边缘不是与显示器像素对齐的,如何修复这个问题?

正如我上面提到的,我对SVG还很陌生,初学者教程似乎没有涵盖到一些边缘情况。所以请耐心等待。

一如既往,非常感谢您的任何帮助。

英文:

Since I'm an expert in eating cookies I thought by myself, why not become en expert in SVG as well - you'll never know what it might be good for some day...

So what I've chosen to achieve is to draw a filled circle with an exclamation mark inside. I've read some tutorials and I decided to use only one path object for that. Drawing the circle seems to be quite easy:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
  &lt;defs&gt;
    &lt;symbol id=&quot;circle&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;

      &lt;path d=&quot;M12 0 A12 12 0 1 1 11.99 0Z&quot; stroke=&quot;none&quot;/&gt;

    &lt;/symbol&gt;
  &lt;/defs&gt;
&lt;/svg&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot; /&gt;
  &lt;title&gt;SVG Test&lt;/title&gt;

  &lt;style&gt;
    .circle {
      width: 1rem;
      height: 1rem;
      fill: red;
    }
  &lt;/style&gt;
    
&lt;/head&gt;

&lt;body&gt;

  &lt;svg class=&quot;circle&quot;&gt;&lt;use href=&quot;icons.svg#circle&quot;/&gt;&lt;/svg&gt;

&lt;/body&gt;
&lt;/html&gt;

As the path shows, it has to be drawn to an endpoint of (11.99|0). This seems a little odd to me, but if I draw it exactly to (12|0) the circle won't get drawn onto the canvas.
So my first question
is:

<h4>Q1) Why can't I close the circle at the starting point but have to stop some point before to close the path with z?</h4>

My second question is regarding the viewBox. As far as I know the path itself has no dimensions. So this viewBox starts at (0|0) and ends ad (24|24).

<h4>Q2) Is this viewBox width and height totally equivalent to 24px in case we give the SVG these values, or are we dealing with an off by 0.00...001?</h4>

And now it gets a little weird, at least for me. I want to crop out the exclamation mark from the middle of the circle. I've read somewhere, that to do this, you have to draw the circle in exactly the other direction as you draw the inner path. In my following example I'm drawing the circle clockwise (which btw requires to end the circle at 11.99 while in case drawing the circle counter-clockwise would require to end the path at 12.01). And the rectangle inside gets removed:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
  &lt;defs&gt;
    &lt;symbol id=&quot;circle-with-line&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;

      &lt;path d=&quot;M12 0 A12 12 0 1 1 11.99 0Z M11 6 v8 h3 V6 H11Z&quot; stroke=&quot;none&quot;/&gt;

    &lt;/symbol&gt;
  &lt;/defs&gt;
&lt;/svg&gt;

Unfortunately, this rectangle doesn't get cut out sharply. I'd expected that starting the rectangle at an exact point and drawing lines exactly along the axis should give me a sharp and crisp cut. But that's not the case, the edges are blurry. So question number three comes here:

<h4>Q3) Why is the cut out not sharp lined with the monitor pixels and how to fix this?</h4>

As I've mentioned above, I'm new to SVG and the edgcases seem not to be covered in the beginners turorials. So please be patient with me.

<b>As always, many thanks for any help</b>

答案1

得分: 3

Q1: 答案可以通过一个简单的实验找到。考虑以下两个圆形路径,起点位于本地坐标系原点。一个将终点略微向右移动,一个略微向下移动。第一个弧是在起点上方绘制的,第二个是在右侧绘制的。现在想象一下,起点和终点的距离减小到零。弧应该以哪个方向绘制?这两个变体都会退化为相同的奇点。由于没有唯一的解决方案,路径定义存在错误,因此无法绘制。

Q2: 事情变得与呈现图形的视口一样精确。描述如何从由 viewBox 描述的坐标系统转换为包含视口的坐标系统的算法在此处有记录。

Q3: 事情的精度取决于呈现图形的视口。如果在转换过程中将整数坐标转换为带有小数部分的像素值,那么只能一次显示一个像素的渲染器将采用抗锯齿等插值技术。

有限的可能性可以影响这些技术的使用方式。演示属性 shape-rendering 将设置一个提示,指定应优先考虑哪种渲染方式:清晰的边缘、平滑的曲线或渲染速度?

尽管这些是渲染器可以以自己的方式解释的提示,但通常情况下,shape-rendering: crispEdges 将导致抗锯齿(导致“模糊”边缘)被禁用。

英文:

Q1: The answer can be found with a simple experiment. Consider the following two circular paths, with the start point at the local coordinate system origin. One has the end point slightly to the right, one slightly below. The first arc is drawn above the start point, the second to the right. Now imagine the distance of the start and end point being reduced to zero. Which direction should the arc be be drawn in? Both variants degrade to the same singularity. Since there is no unique solution, the path definition is in error and thus not drawn.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

.circle {
  fill: lightgrey;
  stroke: black;
}

.mark {
  fill: none;
  stroke: blue;
}

<!-- language: lang-html -->

&lt;svg height=&quot;100vh&quot; viewBox=&quot;0 0 100 60&quot;&gt;
  &lt;g transform=&quot;translate(25,30)&quot;&gt;
    &lt;path class=&quot;circle&quot; d=&quot;M0 0 A12 12 0 1 1 0.01 0Z&quot; /&gt;
    &lt;path class=&quot;mark&quot; d=&quot;M4 0h-8M0 4v-8&quot; /&gt;
  &lt;/g&gt;
  &lt;g transform=&quot;translate(75,30)&quot;&gt;
    &lt;path class=&quot;circle&quot; d=&quot;M0 0 A12 12 0 1 1 0 0.01Z&quot; /&gt;
    &lt;path class=&quot;mark&quot; d=&quot;M4 0h-8M0 4v-8&quot; /&gt;
  &lt;/g&gt;
&lt;/svg&gt;

<!-- end snippet -->

To resolve this, most grafical editors (if they support the arc command) draw two half-circles:

d=&quot;M0,0A12 12 0 0 1 0,24 12 0 0 1 0,0 z&quot;

...or simply use a grafical primitive element:

&lt;circle r=&quot;12&quot; cx=&quot;12&quot; cy=&quot;0&quot; /&gt;

Q2: Things get as precise as the viewport that renders the grafic can be. The algorithm that describes how to go from the coordinate system described by the viewBox to the coordinate system for the containing viewport is documented here.

Q3: Things get as precise as the viewport that renders the grafic can be. If while transforming an integer coordinate gets transformed to a pixel value with a fractional part, a renderer that can only display one pixel at a time will resort to interpolating techniques like antialiasing.

There are limited possibilities to affect how these techniques are used. The presentation attribute shape-rendering will set a hint which way of rendering should be prioritized: crisp edges, smooth curves or rendering speed?

While these are hints the renderes can interpret in their own way, it is pretty standard that shape-rendering: crispEdges will result in antialiasing (the reason for the "blurry" edges) being deactivated.

答案2

得分: 0

Q3) 为什么剪切部分与监视器像素的边缘不清晰,如何解决?

这个谜团已经解开。对于像我这样第一次遇到这些问题的人,这里是答案:

只要视口的尺寸与SVG的尺寸相等,边缘就会保持锐利。在这种情况下:

&lt;style&gt;
  .circle {
    width: 24px;
    height: 24px;
  }
&lt;/style&gt;

为了演示,我使用了像素,但我更倾向于使用rem,并尝试假设1rem对应16像素的标准尺寸来匹配尺寸。

另外,视口大小的任何倍数也应该会产生锐利的边缘,比如48、72、96...

英文:

Q3) Why is the cut out not sharp lined with the monitor pixels and how to fix this?

Well, this mystery got solved. For everybody facing these problems the first time like me, here the answer:

The edges stay sharp as long as the viewport's dimensions equal the SVG dimensions. In this case:

&lt;style&gt;
  .circle {
    width: 24px;
    height: 24px;
  }
&lt;/style&gt;

For demonstration I've used px, but I will rather stay with rem and try to match the dimensions assuming 16px standard for 1rem.

Also, any multiple of the viewPort size should also result in sharp edges, means 48, 72, 96...

huangapple
  • 本文由 发表于 2023年6月26日 02:40:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76551920.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定