如何在 WPF 中的边框上创建斜角?

发布于 2024-10-31 09:27:56 字数 575 浏览 3 评论 0原文

我正在尝试在装饰器的子类中进行简单的绘图,类似于他们在这里所做的...

如何在 wpf 中绘制带有方角的边框?

...除了使用单像素边框厚度而不是他们在那里使用两个。然而,无论我做什么,WPF 都决定它需要进行“平滑”(例如,它不是渲染单像素线,而是渲染一条两像素线,每个“一半”大约为 50% 的不透明度。)换句话说,它试图对绘图进行抗锯齿处理。我不想要抗锯齿绘图。我想说的是,如果我从 0,0 到 10,0 画一条线,我会得到一条单像素宽的线,长度正好为 10 个像素,无需平滑。

现在我知道 WPF 可以做到这一点,但我认为这就是他们引入 SnapsToDevicePixels 和 UseLayoutRounding 的具体原因,我在 XAML 中将这两者设置为“True”。我还确保我使用的数字是实际整数而不是小数,但我仍然没有得到我所希望的漂亮、清晰、一像素宽的线条。

帮助!!!

标记

I'm trying to do simple drawing in a subclass of a decorator, similar to what they're doing here...

How can I draw a border with squared corners in wpf?

...except with a single-pixel border thickness instead of the two they're using there. However, no matter what I do, WPF decides it needs to do its 'smoothing' (e.g. instead of rendering a single-pixel line, it renders a two-pixel line with each 'half' about 50% of the opacity.) In other words, it's trying to anti-alias the drawing. I do not want anti-aliased drawing. I want to say if I draw a line from 0,0 to 10,0 that I get a single-pixel-wide line that's exactly 10 pixels long without smoothing.

Now I know WPF does that, but I thought that's specifically why they introduced SnapsToDevicePixels and UseLayoutRounding, both of which I've set to 'True' in the XAML. I'm also making sure that the numbers I'm using are actual integers and not fractional numbers, but still I'm not getting the nice, crisp, one-pixel-wide lines I'm hoping for.

Help!!!

Mark

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

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

发布评论

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

评论(2

爱殇璃 2024-11-07 09:27:56

啊啊啊……明白了! WPF 认为从 0,0 到 10,0 的线确实位于该逻辑线上,而不是像 GDI 中那样是像素行。为了更好地解释,请考虑 WPF 中的坐标代表在一张方格纸上绘制的线条,而像素是这些线条组成的正方形(假设为 96 DPI。如果它们不同,您需要进行相应调整.)

所以...为了让绘图引用像素位置,我们需要将绘图从线条本身移动到像素的中心(方格纸上的正方形),因此我们将所有绘图移动 0.5, 0.5 (再次假设 DPI 为 96)

因此,如果它是 96 DPI 设置,只需将其添加到 OnRender 方法中就可以了...

drawingContext.PushTransform(new TranslateTransform(.5, .5));

希望这对其他人有帮助!

中号

Aaaaah.... got it! WPF considers a line from 0,0 to 10,0 to literally be on that logical line, not the row of pixels as it is in GDI. To better explain, think of the coordinates in WPF being representative of the lines drawn on a piece of graph paper whereas the pixels are the squares those lines make up (assuming 96 DPI that is. You'd need to adjust accordingly if they are different.)

So... to get the drawing to refer to the pixel locations, we need to shift the drawing from the lines themselves to be the center of the pixels (squares on graph paper) so we shift all drawing by 0.5, 0.5 (again, assuming a DPI of 96)

So if it is a 96 DPI setting, simply adding this in the OnRender method worked like a charm...

drawingContext.PushTransform(new TranslateTransform(.5, .5));

Hope this helps others!

M

蓝眼泪 2024-11-07 09:27:56

看一下这篇文章:精确地在物理设备像素上绘制线条

UPD

链接中的一些有价值的引言:

线条之所以显得模糊,是因为我们的点位于中心
线的点而不是边缘。画笔宽度为 1 时,边缘为
精确地在两个像素之间绘制。

第一种方法是将每个点舍入为整数值(捕捉到
逻辑像素)并给它一个笔宽度一半的偏移量。这
确保线的边缘与逻辑像素对齐。

幸运的是,milcore 的开发者(MIL 代表媒体
集成层,即 WPF 渲染引擎)为我们提供了一种方法
引导渲染引擎将逻辑坐标精确地对齐在
物理设备像素。为了实现这一目标,我们需要创建一个
指南集

protected override void OnRender(DrawingContext drawingContext)
{
    Pen pen = new Pen(Brushes.Black, 1);
    Rect rect = new Rect(20,20, 50, 60);

    double halfPenWidth = pen.Thickness / 2;

    // Create a guidelines set
    GuidelineSet guidelines = new GuidelineSet();
    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);

    drawingContext.PushGuidelineSet(guidelines);
    drawingContext.DrawRectangle(null, pen, rect);
    drawingContext.Pop();
}

Have a look at this article: Draw lines exactly on physical device pixels

UPD

Some valuable quotes from the link:

The reason why the lines appear blurry, is that our points are center
points of the lines not edges. With a pen width of 1 the edges are
drawn excactly between two pixels.

A first approach is to round each point to an integer value (snap to a
logical pixel) an give it an offset of half the pen width. This
ensures, that the edges of the line align with logical pixels.

Fortunately the developers of the milcore (MIL stands for media
integration layer, that's WPFs rendering engine) give us a way to
guide the rendering engine to align a logical coordinate excatly on a
physical device pixels. To achieve this, we need to create a
GuidelineSet

protected override void OnRender(DrawingContext drawingContext)
{
    Pen pen = new Pen(Brushes.Black, 1);
    Rect rect = new Rect(20,20, 50, 60);

    double halfPenWidth = pen.Thickness / 2;

    // Create a guidelines set
    GuidelineSet guidelines = new GuidelineSet();
    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);

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