中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

WPF怎么基于物理像素繪制圖形

發布時間:2022-10-21 09:55:39 來源:億速云 閱讀:109 作者:iii 欄目:開發技術

本篇內容主要講解“WPF怎么基于物理像素繪制圖形”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“WPF怎么基于物理像素繪制圖形”吧!

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,效果(右下角有放大鏡)如下:

WPF怎么基于物理像素繪制圖形

通過放大圖形,能夠很清晰地看到線條是不均勻的,在宏觀視覺效果上感覺模糊,看上去很不舒服。于是,兩個問題就產生了:

  • 為什么會出現這樣的問題?

  • 如何解決?

怎么辦?MSDN,百度,Google一起上!皇天不負苦心人,現在,謎底來到了我們的面前:

1、為什么會出現這樣的效果呢?

WPF呈現引擎的反鋸齒系統將那些沒有在物理像素系統上的線擴展到了多個像素上。這里涉及到以下三個概念:

  • 物理像素系統:與物理圖形設備相關。可以簡單地理解為一個像素點的二維矩陣;

  • 邏輯像素系統:我們在畫法方法中所使用的定位系統;

  • 反鋸齒效果:一種計算機圖形學上的算法,使得圖形邊緣更光滑;

聲明:以上三個概念的解釋是根據我個人的理解,不一定準確、嚴謹。如果您發現什么不對的地方,還望不吝指正。
為了更好地幫助您理解這個過程,這里給出一個示意圖來解釋一下:

WPF怎么基于物理像素繪制圖形

上圖中的淡藍色網格可以視為“物理像素系統”,深色的圖案是您畫出的線條。可以很明顯地看出,這條線的四條邊都不在“物理像素系統”上,因此,“反鋸齒系統”會將此線條的四條邊擴展到相應的“物理像素系統”上。于是,本文最開始的情景便出現了。

2、如何解決這個問題?

針對不同的問題上下文,WPF給出了與之相應的解決方案。據我所知,有如下幾個:

  • 1> 對于UIElement及其子類,使用SnapsToDevicePixels屬性

對于從UIElement繼承的類型,比如Control,通過將SnapsToDevicePixels設置為true可以得到清晰的圖像,該屬性的默認值為false。FrameworkElement從UIElement繼承的時候,給這個屬性賦予了一個Inherited元數據。如此一來,只要您在FrameworkElement Tree的根結點上將此屬性設置為true,那么整個FrameworkElement Tree的繪制都將變得清晰起來。

  • 2> 對于自定義畫法,使用GuidelineSet

SnapsToDevicePixels屬性對于WPF Control來說是有用的,但是對本文的問題無能為力,于是,嗯,GuidelineSet橫空出世!對于這個類,MSDN只是給出了一個用法的示例,從這個例子中我只能看到GuidelineSet可以這么用,但為什么是這樣用就沒有答案了。而且,有點離譜、神奇的是:MSDN上關于這點上一個示意圖內容上有錯。如下圖所示:

WPF怎么基于物理像素繪制圖形

圖下部的左黑框是用了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>

運行后的效果如下:

WPF怎么基于物理像素繪制圖形

另外,使用GuidelineSet的時候需要注意以下幾個細節:

  • 1、Push和pop一般情況下要成對(其實當您調用DrawingContext上的PushXXX方法后,都要考慮是否有與之對應的Pop方法調用);

  • 2、GuidelineSet只對水平或者垂直線有用;

  • 3、使用GuidelineSet后,您所繪制圖形的位置或大小可能和最初的設定有細微的差別。

到此,相信大家對“WPF怎么基于物理像素繪制圖形”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

wpf
AI

玉田县| 洞头县| 咸丰县| 遂溪县| 聂荣县| 雷波县| 金门县| 石嘴山市| 剑阁县| 四平市| 阳信县| 阿城市| 同德县| 甘南县| 凤山县| 凤山市| 建宁县| 日土县| 额济纳旗| 高唐县| 通山县| 湄潭县| 曲靖市| 额敏县| 皮山县| 三原县| 奉节县| 和平县| 伊川县| 包头市| 定襄县| 清河县| 濮阳市| 聊城市| 荆州市| 怀远县| 河西区| 会同县| 乌拉特中旗| 怀柔区| 鹰潭市|