WPF DrawingVisual 1像素的直线 如何避免抗锯齿导致的模糊效果

本文探讨了在WPF中使用DrawingVisual画直线时遇到的模糊问题,原因是默认启用的抗锯齿效果。作者详细解析了原理并提供了修复方法,通过调整坐标确保逻辑像素与物理像素对齐,以实现清晰的1像素线宽。
摘要由CSDN通过智能技术生成

在WPF中用DrawingVisual 话直线的时候,往往会画出模糊的效果

明明宽度设置成了1,但实际画出来的偏偏有两个像素,看起来有点模糊,这对于强迫症的人可忍不了!

上代码:

namespace OneLinePiexl
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var canvas=new MyCanvas();
            grid.Children.Add(canvas);
            canvas.plot();
        }
    }

    public class MyCanvas : Canvas
    {
        private DrawingVisual _drawingVisual = new DrawingVisual();
        public MyCanvas()
        {
            this.AddVisualChild(_drawingVisual);
        }
        public Pen p = new Pen(Brushes.Black, 1.0);
        public void plot()
        {
            var dc = _drawingVisual.RenderOpen();
            dc.DrawLine(p, new Point(0, 100), new Point(100, 100));
            dc.Close();
        }
    
        protected override int VisualChildrenCount
        {
            get { return 1; }
        }
        protected override Visual GetVisualChild(int index)
        {
            if (index == 0)
                return _drawingVisual;
            throw new IndexOutOfRangeException();
        }
    }
}

现象:

放大后明显可以看出来,左边的线宽有两个像素,而且看起来比较模糊,右边的线宽只有1像素。

其实我是想得到右边的效果。

那么为什么会这样呢,明明我的两个点都是整数,而且线宽指定为1

原因是因为WPF是默认采用了抗锯齿效果。首先解释下什么是抗锯齿

 

这就是一个明显的抗锯齿效果:

上半部分使用了抗锯齿效果,下半部分则没有抗锯齿,可以看出来,使用抗锯齿其实就是将连接的像素点模糊化处理,使其看起来更像一条连续的线。而没有抗锯齿的线条看起来会比较生硬

当然这在4k屏幕中跟本看不出来,只有在渣渣显示器中,放大才会明显的感觉出来

加上抗锯齿的效果,会使得图形看起来比较圆滑。这是游戏中经常的做法

 

OK,了解了抗锯齿,回到正题,这是画曲线有抗锯齿可以理解, 那为什么我画一条直线,也抗锯齿了呢?

刚提到WPF默认使用抗锯齿,不管你画什么线,总之先抗了再说

当逻辑像素点画完后没有和物理像素对齐,那么会自动加上抗锯齿的效果、

 

假设我们的屏幕是这样的,每个格子代表一个物理像素

水平为X轴,垂直为Y轴

现在我们要画一条(2,0),(2,9) 的宽度为1的直线,我们想象的线是这样的:

但是别忘了,这是屏幕,最小单位是一个像素,不是我们理想中的样子。所以实际上画出来的是这样的:

 

这根蓝色的粗线才是我们即将画出来的线。可是还是不对,这跟线横跨了两个像素,左边半个像素,右边半个像素,组成了一个像素的宽度,在显示器中最小单位就是一个像素,所以这种画法是不可能出现的(根本做不到)

同时这钟情况也达到了之前说的:当逻辑像素点画完后没有和物理像素对齐

那么WPF会自动加上抗锯齿效果,也就是这样:

绿色的线,宽度为2像素,然后横跨了第二个和第三个像素。同时会把颜色虚化,按照原来的颜色取一个相对淡一点的颜色作为整根线的颜色。这就是抗锯齿的效果

 

 

OK,明白了为什么原理,那么如何解决?

答案就是 个Point的X,Y做修正

Public static Point[] FixPoints(Point p1,Point p2,double width)
{
Double corrector=0.5;
Bool  isViertical=(p1.X==p2.X);//是否垂直
Bool  isHorizontal=(p1.Y==p2.Y);//是否水平
Bool  isWidthOdd=width%2!=0  //宽度是否为基数
If(!isVeritical&&!isHorizontal)
{
Return Point[]{p1,p2};
}
//先修正成整数,若有小数,必然会抗锯齿
p1.X=(int)p1.X;
P1.Y=(int)p1.Y;
P2.X=(int)p2.X;
P2.Y=(int)p2.Y;
If(isVertical)
{
If(isWidthOdd)
{
P1.X=p1.x+corrector;
P2.X=p2.x+corrector;
}
Else if(isHorizontal)
{
If(isWidthOdd)
{
P1.Y=p1.y+corrector;
P2.y=p2.y+corrector;
}
}
Return new Point[]{p1,p2};
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值