日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

WPF 绘制对齐像素的清晰显示的线条

發布時間:2023/12/9 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WPF 绘制对齐像素的清晰显示的线条 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
WPF 繪制對齊像素的清晰顯示的線條 原文:WPF 繪制對齊像素的清晰顯示的線條

版權聲明:本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名呂毅(包含鏈接:http://blog.csdn.net/wpwalter/),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布。如有任何疑問,請與我聯系(walter.lv@qq.com)。 https://blog.csdn.net/WPwalter/article/details/78858762

此前有小伙伴詢問我為何他 1 像素的線條顯示發虛,然后我告訴他是“像素對齊”的問題,然而他設置了各種對齊像素的屬性依舊沒有作用。于是我對此進行了一系列試驗,對 WPF 像素對齊的各種方法進行了一次總結。此后在 StackOverflow 中,我回答了 graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow 問題。

閱讀本文,我們將了解解決 WPF 像素對齊的四種方法以及其各自的適用范圍和副作用。


為什么要做像素對齊

看線條!這是 3 像素的線條:

然而論其原因,就是因為我們屏幕太渣~哦~不,是因為繪制的線條沒有與屏幕像素對齊,具體來說是視覺對象(Visual)的位置不在整數像素上或尺寸不是整數像素。而與此同時屏幕的點距又太大以至于我們看出來繪制的線條和屏幕像素之間的差異。

然而為什么 WPF 不默認為我們對齊像素呢?這是因為要對齊像素必定帶來尺寸上的偏差;這是繪制尺寸精度和最終呈現效果之間的平衡。在 MacBook、Surface Pro 這些高檔顯示屏上,根本不用管這樣的平衡問題;但在渣渣顯示器上,微軟把這種平衡的控制交給了應用的開發者。

處理像素對齊的四種方法

方法一:布局取整 UseLayoutRounding

實際效果是:

根本就不起作用

事實上我們從 .NET Framework 源碼可以得知,UseLayoutRounding 實際只處理 UI 元素對自己子級控件的布局取整。一旦整棵布局樹種有任何一個不是整數(或者 DPI 相乘后不是整數),那么就依然沒有解決問題。

方法二:對齊設備像素 SnapsToDevicePixels

這是一個會沿著邏輯樹繼承的屬性,只要最頂層設置了這個屬性,里面的元素都會具備此特性。不過,他只處理矩形的渲染,也就是說,只對 Border Rectangle 這些類型的元素生效,其他的包括自己寫的元素基本都是不管用的。

它有一個好處,是像素對齊的情況下同時能夠保證顯示不足或超過 1 像素時,也能帶一點兒透明或者超過一點像素。

方法三:使用 DrwingContext 繪制并配合 GuidelineSet

如果自己處理繪制,則可以在 OnRender 方法中使用 DrawingContext 來繪制各種各樣的形狀。DrawingContext 有方法 PushGuidelineSet,而 PushGuidelineSet 就是用來處理對齊的。

以下是四種不同方式的對齊效果對比,其中上面一半是直接對齊(即繪制過程是緊貼著的),下面一半則是多個部分帶上一點偏移(即并不是緊貼):


▲ 看不清的可以考慮方法看

于是要想像素對齊,必須:

  • 布局或繪制時,UI 元素之間一點偏移或空隙都不能有,一點都不行
  • SnapsToDevicePixels 和 GuidelineSet 在實際對齊中有效,而 UseLayoutRounding 就是在逗你

GuidelineSet 的使用可以參考我在 StackOverflow 上的回答:graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow。

以下是我編寫的用于輔助繪制對齊線條的擴展方法:

public static class SnapDrawingExtensions {public static void DrawSnappedLinesBetweenPoints(this DrawingContext dc,Pen pen, double lineThickness, params Point[] points){var guidelineSet = new GuidelineSet();foreach (var point in points){guidelineSet.GuidelinesX.Add(point.X);guidelineSet.GuidelinesY.Add(point.Y);}var half = lineThickness / 2;points = points.Select(p => new Point(p.X + half, p.Y + half)).ToArray();dc.PushGuidelineSet(guidelineSet);for (var i = 0; i < points.Length - 1; i = i + 2){dc.DrawLine(pen, points[i], points[i + 1]);}dc.Pop();} }

注意添加到 GuidelineSet 的尺寸不需要是整數,也不需要計算對齊屏幕的位置,只需要隨便指定一個值即可,但相鄰的繪制元素的值需要在 double 級別完全相同,多一點少一點都不行

在 OnRender 中調用它繪制:

protected override void OnRender(DrawingContext dc) {// Draw four horizontal lines and one vertical line.// Notice that even the point X or Y is not an integer, the line is still snapped to device.dc.DrawSnappedLinesBetweenPoints(_pen, LineThickness,new Point(0, 0), new Point(320, 0),new Point(0, 40), new Point(320, 40),new Point(0, 80.5), new Point(320, 80.5),new Point(0, 119.7777), new Point(320, 119.7777),new Point(0, 0), new Point(0, 120)); }

方法四:RenderOptions.EdgeMode

這是純渲染級別的附加屬性,對所有 UI 元素有效。這個屬性很神奇,一旦設置,元素就再也不會出現模糊的邊緣了,一定是硬像素邊緣。不足半像素的全部刪掉,超過半像素的變為 1 個像素。

以為它可以解決問題?——Too young, too simple.

你希望能夠繪制 1 像素的線條,實際上它會讓你有時看得見 1 像素線條,有時看的是 2 像素線條,有時居然完全看不見!!!

如果你都作用對象上還有其它視覺對象,它們也會一并變成了“硬邊緣”,是可以看得見一個個像素的邊緣。

各種方法適用范圍總結

  • 如果畫粗線條粗邊框,那么 RenderOptions.EdgeMode 最適合了,因為設置起來最方便,可以設置到所有的 UI 元素上。由于邊框很粗,所以多一個少一個像素用戶也注意不到。
  • 如果是畫細邊框,那么使用 Border 配合 SnapsToDevicePixels 可以解決,無論是 0.8 像素還是 1.0 像素,1.2 像素,都能在準確地顯示其粗細的基礎之上還保證像素對齊。
  • 如果圖形比較復雜,比如繪制表格或者其它各種交叉了線條的圖形,那么使用 DrawingContext 繪制,并設置 GuidelineSet 對齊。
  • 如果窗口非常簡單,既沒有縮放,UI 元素也不多,可以考慮使用 UseLayoutRounding 碰碰運氣,萬一界面簡單到只需要整數對齊就夠了呢?
  • 特別說明,上面四種方法不足與應對所有的像素對齊情況,如果還是沒辦法對齊……節哀把……我們一起找偏方……
  • posted on 2018-09-21 22:03 NET未來之路 閱讀(...) 評論(...) 編輯 收藏

    轉載于:https://www.cnblogs.com/lonelyxmas/p/9688697.html

    總結

    以上是生活随笔為你收集整理的WPF 绘制对齐像素的清晰显示的线条的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。