<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
WPF中有一個DrawingContext類,該類提供了很多畫法方法,例如DrawLine,DrawText,DrawRectangle等。開發者使用它們可以方便地進行圖形繪製。不過,在使用DrawingContext過程中,我發現使用DawLine方法畫出的線條在某些部分有些模糊。這個問題的解決,需要一些計算機圖學方面的知識,使用的方法並不是很複雜。不過,這個方法所涉及到的一些過程有些令人費解(好吧,我沒有專門學過計算機圖學),本文是我在實踐中的一些嘗試和經驗的總結。
還是從一個例子開始吧:
從FrameworkElement繼承一個MyRectangleElement,然後重寫OnRender方法如下:
protected override void OnRender(DrawingContext drawingContext) { Pen pen = new Pen(Brushes.Black, 1); Rect rect = new Rect(20,20, 50, 60); drawingContext.DrawRectangle(null, pen, rect); }
然後在Window上呈現MyRectangleElement,效果(右下角有放大鏡)如下:
通過放大圖形,能夠很清晰地看到線條是不均勻的,在宏觀視覺效果上感覺模糊,看上去很不舒服。於是,兩個問題就產生了:
怎麼辦?MSDN,百度,Google一起上!皇天不負苦心人,現在,謎底來到了我們的面前:
WPF呈現引擎的反鋸齒系統將那些沒有在物理畫素系統上的線擴充套件到了多個畫素上。這裡涉及到以下三個概念:
宣告:以上三個概念的解釋是根據我個人的理解,不一定準確、嚴謹。如果您發現什麼不對的地方,還望不吝指正。
為了更好地幫助您理解這個過程,這裡給出一個示意圖來解釋一下:
上圖中的淡藍色網格可以視為“物理畫素系統”,深色的圖案是您畫出的線條。可以很明顯地看出,這條線的四條邊都不在“物理畫素系統”上,因此,“反鋸齒系統”會將此線條的四條邊擴充套件到相應的“物理畫素系統”上。於是,本文最開始的情景便出現了。
針對不同的問題上下文,WPF給出了與之相應的解決方案。據我所知,有如下幾個:
對於從UIElement繼承的型別,比如Control,通過將SnapsToDevicePixels設定為true可以得到清晰的影象,該屬性的預設值為false。FrameworkElement從UIElement繼承的時候,給這個屬性賦予了一個Inherited後設資料。如此一來,只要您在FrameworkElement Tree的根結點上將此屬性設定為true,那麼整個FrameworkElement Tree的繪製都將變得清晰起來。
SnapsToDevicePixels屬性對於WPF Control來說是有用的,但是對本文的問題無能為力,於是,嗯,GuidelineSet橫空出世!對於這個類,MSDN只是給出了一個用法的範例,從這個例子中我只能看到GuidelineSet可以這麼用,但為什麼是這樣用就沒有答案了。而且,有點離譜、神奇的是:MSDN上關於這點上一個示意圖內容上有錯。如下圖所示:
圖下部的左黑框是用了GuidelineSet後出現的結果,右邊才是沒有使用的結果。這兩個圖的位置應該互換一下。
我們必須回答這個問題:如果在(x1,y1) (x2,y2)處畫一條線該如何在DrawingContext上使用GuidelineSet,以保證畫法是清晰的呢?
這個問題讓我著實納悶了許久(原因本文第一段已經交代),不過,經過不斷地嘗試和思考,最終我找到了答案:
Guideline其實是圖形裝置在呈現時用來把邏輯畫素點對齊到物理畫素點的參考量。 使用它告訴圖形裝置你希望哪些邏輯畫素點被對齊到物理畫素點上。
宣告:以上概念的解釋是根據我個人的理解,不一定準確、嚴謹。如果您發現什麼不對的地方,還望不吝指正。
下面,我將使用一個簡單的範例來演示如何使用GuidelineSet,以及它所帶來的效果。在這個範例中,我們使用DrawingContext的DrawLine方法繪製一個10×10的網格,相關程式碼如下:
首先,定義畫法所用到的常數
internal static class DrawingConstants { public static readonly int Rows = 10; public static readonly int Columms = 10; public static readonly double PenThickness = 1.0; public static readonly double HalfOfPenThickness = PenThickness/2; }
然後,定義NormalDrawingElement(使用一般畫法):
class NormalDrawingElement : FrameworkElement { protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) { base.OnRender(drawingContext); double xOffset = Math.Floor(this.RenderSize.Width / DrawingConstants.Columms); double yOffset = Math.Floor(this.RenderSize.Height / DrawingConstants.Rows); double xLineWidth = Math.Floor(this.RenderSize.Width); double yLineHeight = Math.Floor(this.RenderSize.Height); DrawingContext dct = drawingContext; Pen blackPen = new Pen(Brushes.Black, DrawingConstants.PenThickness); blackPen.Freeze(); //Draw the horizontal lines Point x = new Point(0, 0); Point y = new Point(xLineWidth, 0); for (int i = 0; i <= DrawingConstants.Rows; i++) { dct.DrawLine(blackPen, x, y); x.Offset(0, yOffset); y.Offset(0, yOffset); } //Draw the vertical lines x = new Point(0, 0); y = new Point(0, yLineHeight); for (int i = 0; i <= DrawingConstants.Columms; i++) { dct.DrawLine(blackPen, x, y); x.Offset(xOffset, 0); y.Offset(xOffset, 0); } } }
定義GuidelineSetDrawingElement(使用GuidelineSet):
class GuidelineSetDrawingElement : FrameworkElement { protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) { base.OnRender(drawingContext); double xOffset = Math.Floor(this.RenderSize.Width / DrawingConstants.Columms); double yOffset = Math.Floor(this.RenderSize.Height / DrawingConstants.Rows); double xLineWidth = Math.Floor(this.RenderSize.Width); double yLineHeight = Math.Floor(this.RenderSize.Height); DrawingContext dct = drawingContext; Pen blackPen = new Pen(Brushes.Black, DrawingConstants.PenThickness); blackPen.Freeze(); //Draw the horizontal lines Point x = new Point(0, 0); Point y = new Point(xLineWidth, 0); for (int i = 0; i <= DrawingConstants.Rows; i++) { dct.PushGuidelineSet(new GuidelineSet(null, new double[] { y.Y - DrawingConstants.HalfOfPenThickness, y.Y + DrawingConstants.HalfOfPenThickness})); dct.DrawLine(blackPen, x, y); dct.Pop(); x.Offset(0, yOffset); y.Offset(0, yOffset); } //Draw the vertical lines x = new Point(0, 0); y = new Point(0, yLineHeight); for (int i = 0; i <= DrawingConstants.Columms; i++) { dct.PushGuidelineSet(new GuidelineSet(new double[] { x.X + DrawingConstants.HalfOfPenThickness, x.X - DrawingConstants.HalfOfPenThickness}, null)); dct.DrawLine(blackPen, x, y); dct.Pop(); x.Offset(xOffset, 0); y.Offset(xOffset, 0); } } }
這個畫法和上一個畫法的區別僅僅在於以下兩點:
最後,我們將這兩個Element呈現出來:
<Window x:Class="GuidelineSetDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:loc="clr-namespace:GuideLineSetDemo" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="Normal Drawing" Margin="3" HorizontalAlignment="Center"/> <loc:NormalDrawingElement Margin="10" Grid.Row="1"/> </Grid> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="Dawing with GuidelineSet" Margin="3" HorizontalAlignment="Center"/> <loc:GuidelineSetDrawingElement Margin="10" Grid.Row="1"/> </Grid> </Grid> </Window>
執行後的效果如下:
另外,使用GuidelineSet的時候需要注意以下幾個細節:
您可以從這裡下載本文最後一個範例的原始碼。
到此這篇關於WPF基於物理畫素繪製圖形的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45