实时绘制 1 像素粗的锯齿线

发布于 2024-10-09 15:45:19 字数 1016 浏览 0 评论 0原文

简要背景:我正在开发一个基于 Web 的绘图应用程序,我正在实现的工具之一是 1 像素粗铅笔。该工具允许用户在画布上绘制 1px 别名线。

为了确定用户在画布上绘图的位置,需要监视鼠标坐标。如果按住 mouse1,光标所在的像素将会改变。本质上它的工作原理就像 Photoshop 中的铅笔工具一样。

注意:Bresenham 算法不适用于这种情况。我的输入是实时提交的,所以我不会画一条从 P0 到 P1 的线,其中 P0 和 P1 之间的距离有很多像素。一般来说,P1 是 P0 的邻居。

我遇到的问题是我生成的线条没有完全干净的 1px 权重。下面是一个示例:

Line Comparison

请注意,两条线都是手绘的,因此存在一些差异。有趣的是,Photoshop 能够以更清晰的 1 像素来表示我所绘制的线条。我的线条看起来更脏的原因是这样的:

Photoshop 的线条

My line

当在我的应用程序中使用该工具绘图时,红色像素被填充。在 Photoshop 中,红色像素未被填充。这是有道理的,因为为了从例如,给定的像素到其东南邻居(东邻居或南邻居)可能会被忽略。光标恰好越过角落进入东南邻居的可能性非常小,从而避免绘制红色像素,但这通常不会发生。

所以,我剩下的问题是 Photoshop 如何能够跳过我的线条中出现的红色像素。我唯一能想到的就是等到两个像素排队后再绘制它们中的任何一个,这样我就知道是否有“角邻居”被忽略。在这种情况下,我不会绘制两个像素中的第一个,因为它相当于我图中的红色像素。如果用户绘制一个像素,将光标向南移动一个像素,然后向东移动一个像素,则存在无法绘制预期像素的风险。两个像素都应该被绘制,但算法会另有说明。

有什么想法吗? Photoshop 如何处理这个问题?

A brief background: I'm working on a web-based drawing application and one of the tools I'm implementing is a 1-pixel thick pencil. The tool allows the user to draw 1px aliased lines on the canvas.

In order to determine where the user is drawing on the canvas, mouse coordinates are monitored. If mouse1 is held down, the pixel the cursor is over will change. Essentially it works just like the pencil tool in Photoshop.

NOTE: Bresenham's algorithm will not work for this situation. My input is submitted in real-time, so I'm not drawing a line from P0 to P1 where the distance between P0 and P1 is many pixels. In general, P1 is a neighbor of P0.

The issue I'm having is that my resulting lines do not have a perfectly clean 1px weight. Here's an example:

Line comparison

Note that both of the lines are hand drawn, so there is some variance. What's interesting is that Photoshop is able to make a much cleaner 1px representation of the line that I draw. The reason why my line looks dirtier is because of this:

Photoshop's line

My line

When drawing with the tool in my application, the red pixels are filled in. In Photoshop, the red pixels are not filled in. This makes sense because in order to move from a given pixel to, say, its south-east neighbor, either the east or south neighbor will likely be passed over. There is an extremely slim chance that the cursor will pass exactly over the corner into the south-east neighbor, avoiding the drawing of the red pixel, but this usually doesn't happen.

So, the question I'm left with is how Photoshop is able to skip the red pixels that are showing up in my lines. The only thing I could think of was waiting until two pixels are queued up before drawing either of them so I would know if a "corner-neighbor" was passed over. In that case I would just not draw the first of the two pixels because it would be equivalent to a red pixel in my diagram. This runs the risk of not drawing an intended pixel if the user draws a pixel, moves the cursor one pixel south, and then one pixel east. Both of the pixels should be drawn, but the algorithm would say otherwise.

Any ideas? How might Photoshop be handling this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半寸时光 2024-10-16 15:45:19

两条线之间的区别基本上是 Photoshop 在绘制像素 n 后重新考虑绘制的 n-1 像素,如果使用以下蒙版之一给出正值,则将其擦除:

 x 1 x       x 1 x
 1 o x   or  x o 1
 x x x       x x x

 x x x       x x x
 1 o x   or  x o 1
 x 1 x       x 1 x

x= 不要介意
o= n-1 像素
1= 绘制像素 n 后标记的像素

或者写为逻辑:

假设像素 n-1 位于 a[i,j],因此,在标记像素 n 后,检查:

If ( (a[i-1,j  ]==1 && a[i  ,j-1]==1) ||
     (a[i-1,j  ]==1 && a[i  ,j+1]==1) ||
     (a[i  ,j-1]==1 && a[i+1,j  ]==1) ||
     (a[i  ,j+1]==1 && a[i+1,j  ]==1))
Then
     Unmark a[i,j];

您可能希望您的线条延迟一个像素只是为了没有显示“消失”的像素(尽管我怀疑在这种规模下它会很明显)。

替代文字

The difference between both lines is basically that Photoshop is re-considering the n-1 pixel drawn AFTER drawing the pixel n, and erasing it if it gives positive with one of the following masks:

 x 1 x       x 1 x
 1 o x   or  x o 1
 x x x       x x x

or

 x x x       x x x
 1 o x   or  x o 1
 x 1 x       x 1 x

x= Don't mind
o= The n-1 pixel
1= Marked pixel after drawing pixel n

Or written as logic:

Suppose pixel n-1 is at a[i,j], so, after marking the pixel n, check:

If ( (a[i-1,j  ]==1 && a[i  ,j-1]==1) ||
     (a[i-1,j  ]==1 && a[i  ,j+1]==1) ||
     (a[i  ,j-1]==1 && a[i+1,j  ]==1) ||
     (a[i  ,j+1]==1 && a[i+1,j  ]==1))
Then
     Unmark a[i,j];

You may want your to draw your line delayed one pixel just for not showing your "disappearing" pixels (although I doubt it'll be noticeable at that scale).

alt text
.

那请放手 2024-10-16 15:45:19

原始:看看 Bresenham 的直线算法。它可以很容易地扩展有关平滑等的内容。

编辑:关于问题的发展和讨论(特别是下面的评论),我想提取一些有趣的观点: Photoshop的铅笔工具也画得很好如果鼠标移动相对较慢,则也具有“东”和“东南”像素的类似线,从而为所有这些像素提供许多样本。一旦鼠标移动得更快,轨迹就不会为所有直接相邻的像素提供样本。结果将是所需的 1 像素粗线。总而言之,我们注意到:Photoshop 的铅笔工具背后并没有什么“魔力”;它只是一个工具。它似乎只是扫描更少的样本。有关详细信息,请参阅下面的讨论/评论。

Original: Have a look at Bresenham's line algorithm. It can easily extended concerning smoothing etc.

Edit: Regarding the development of the question and the discussions (especially the comments below), I'd like to extract some interesting points: Photoshop's pencil tool does also draw very similar lines with "east" and "south-east" pixels as well, if the mouse is moved relatively slowly thus providing many samples for all those pixels. As soon as the mouse is moved faster, the trajectory does not provide samples for all directly neighbored pixels. The result would then be the desired 1-pixel thick line. In conclusion, we note: There is no "magic" behind Photoshop's pencil tool; it just seems to scan fewer samples. For details see discussions/comments below.

此生挚爱伱 2024-10-16 15:45:19

我想你终于解决了你的问题(6 年过去了......),但我只是想说,在这种特殊情况下,你的应用程序似乎比 Photoshop 效果更好。虽然我想我知道你的目标是什么(避免那些像素聚类),但你的应用程序可以更好地实现“恒定厚度”(尽管有那些不需要的分组),而 Photoshop 制作的“香肠绳”图案可能更智能,但没有宽度恒定,因此不那么“真实”。这可能是由于对小数值(四舍五入)的不同处理以及选择要填充或跳过的像素造成的。但这又是一个老话题了。

I guess you finally solved your question (6 years have passed...), but I just wanted to say your application seems to work actually better than Photoshop in this particular case. Although I think I know what your aim was (avoiding those pixel clusterings), the "constant thickness" is better achieved with your App (despite those unwanted groupings), while Photoshop makes a "sausage rope" pattern which may be smarter, but no so width-constant and, thus, not so "real". It's likely due to a different handling of decimal values (rounding) and selecting which pixels to fill or skip. But again, this is an old topic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文