Quantcast
Channel: 午後わてんのブログ
Viewing all articles
Browse latest Browse all 420

画像をくっきり表示させたい(ぼやけるのがイヤな)とき、EdgeModeとScalingMode、WPF

$
0
0

前回は図形に対するアンチエイリアスの切り替えだった
今回は画像に対するアンチエイリアスの切り替えというかぼやけるのを切り替え

特に設定しないと拡大や回転表示させたときにはアンチエイリアスが有効な状態で表示される、くっきり表示させたいときは
EdgeModeをAliased
ScalingModeをNearestNeighbor

MyImageなら
RenderOptions.SetEdgeMode(MyImage, EdgeMode.Aliased)
RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.NearestNeighbor)

イメージ 9


テストに使う画像は白背景に黒枠が3つ
イメージ 1
枠の太さは1ピクセル
画像の大きさは16x16ピクセル
形式はBMP


WPFのImageコントロールを使ってこの画像を表示
イメージ 2
特に何も設定しないで表示すると普通(期待通り)に表示される

3倍に拡大表示
イメージ 3
RenderTransformのScaleTransformを3にして3倍に拡大表示

ScalingModeをNearestNeighborに変更して拡大
イメージ 4
くっきりになる
ScalingModeの初期設定値はUnspecified(未定義)なんだけどイメージ 5
実際はLinearみたい

回転
ScalingModeをUnspecifiedに戻してから
10度回転
イメージ 6

ScalingModeをNearestneighborに変更
イメージ 7
くっきりになるぶんガタガタになるけど
よく見ると外側だけはなめらか

EdgeModeをAliasedに変更
イメージ 8
これで全部くっきりになる

なので、くっきり表示させたいときは
EdgeModeをAliased
ScalingModeをNearestNeighbor

写真画像の場合
イメージ 11




UseLayoutRoundingの切り替え
0.1ポイント単位で移動させると違いがわかる
イメージ 10
UseLayoutRoundingをTrueにすると
0.1ポイント単位で移動させても1ポイント(ピクセル)単位での移動になるみたい



XAMLデザイン画面
イメージ 12


VBコード

Class MainWindow
    Private MyImage As Image

    Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
        AddHandler btnEdge.Click, AddressOf btnEdge_Click
        AddHandler btnUseLayoutRounding.Click, AddressOf btnUseLayoutRounding_Click
        AddHandler btnSnapsToDevicePixels.Click, AddressOf btnSnapsToDevicePixels_Click
        AddHandler btnScalingMode.Click, AddressOf btnNearestNeighbor_Click
        AddHandler btnReset.Click, AddressOf btnReset_Click

        Dim bi As New BitmapImage(New Uri("D:\ブログ用\テスト用画像\border_round.bmp"))

        MyImage = New Image With {
            .Source = bi,
            .RenderTransform = GetRenderTransform(),
            .RenderTransformOrigin = New Point(0.5, 0.5)
        }

        Canvas.SetLeft(MyImage, 50) : Canvas.SetTop(MyImage, 50)
        MyCanvas.Children.Add(MyImage)

        Call MySetBinding()
    End Sub
    Private Function GetRenderTransform() As Transform
        Dim tg As New TransformGroup
        With tg.Children
            .Add(New ScaleTransform(1.0, 1.0))
            .Add(New SkewTransform)
            .Add(New RotateTransform)
        End With
        Return tg
    End Function

    'Binding
    Private Sub MySetBinding()
        Dim b As Binding

        b = New Binding With {
            .Source = MyImage,
            .Path = New PropertyPath(RenderOptions.EdgeModeProperty),
            .StringFormat = "EdgeMode = {0}"
        }
        tbEdge.SetBinding(TextBlock.TextProperty, b)

        b = New Binding With {
            .Source = MyImage,
            .Path = New PropertyPath(UseLayoutRoundingProperty),
            .StringFormat = "UseLayoutRounding = {0}"}
        tbUseLayout.SetBinding(TextBlock.TextProperty, b)

        b = New Binding With {
            .Source = MyImage,
            .Path = New PropertyPath(SnapsToDevicePixelsProperty),
            .StringFormat = "SnapsToDevicePixels = {0}"}
        tbSnapTo.SetBinding(TextBlock.TextProperty, b)

        b = New Binding With {
            .Source = MyImage,
            .Path = New PropertyPath(RenderOptions.BitmapScalingModeProperty),
            .StringFormat = "ScalingMode = {0}"}
        tbScalingMode.SetBinding(TextBlock.TextProperty, b)

        Dim st As ScaleTransform = GetTransform(GetType(ScaleTransform))
        b = New Binding With {.Source = st, .Path = New PropertyPath(ScaleTransform.ScaleXProperty),
            .StringFormat = "ScaleX = {0}"}
        sldScaleX.SetBinding(Slider.ValueProperty, b)
        tbScaleX.SetBinding(TextBlock.TextProperty, b)
        b = New Binding With {.Source = st, .Path = New PropertyPath(ScaleTransform.ScaleYProperty),
            .StringFormat = "ScaleY = {0}"}
        sldScaleY.SetBinding(Slider.ValueProperty, b)
        tbScaleY.SetBinding(TextBlock.TextProperty, b)

        Dim ro As RotateTransform = GetTransform(GetType(RotateTransform))
        b = New Binding With {.Source = ro, .Path = New PropertyPath(RotateTransform.AngleProperty),
            .StringFormat = "RotateAngle = {0}"}
        sldRotateAngle.SetBinding(Slider.ValueProperty, b)
        tbRotateAngle.SetBinding(TextBlock.TextProperty, b)

        b = New Binding With {.Source = MyImage, .Path = New PropertyPath(Canvas.TopProperty),
            .StringFormat = "CanvasTop = {0}"}
        sldCanvasTop.SetBinding(Slider.ValueProperty, b)
        tbCanvasTop.SetBinding(TextBlock.TextProperty, b)

    End Sub

    Private Function GetTransform(t As Type) As Transform
        Dim tg As TransformGroup = MyImage.RenderTransform
        For Each c As Transform In tg.Children
            If c.GetType = t Then
                Return c
            End If
        Next
        Return Nothing
    End Function

    'イベント

    Private Sub btnEdge_Click(sender As Object, e As RoutedEventArgs)
        If RenderOptions.GetEdgeMode(MyImage) = EdgeMode.Aliased Then
            RenderOptions.SetEdgeMode(MyImage, EdgeMode.Unspecified)
        Else
            RenderOptions.SetEdgeMode(MyImage, EdgeMode.Aliased)
        End If
    End Sub

    Private Sub btnUseLayoutRounding_Click(sender As Object, e As RoutedEventArgs)
        MyImage.UseLayoutRounding = Not MyImage.UseLayoutRounding
    End Sub

    Private Sub btnSnapsToDevicePixels_Click(sender As Object, e As RoutedEventArgs)
        MyImage.SnapsToDevicePixels = Not MyImage.SnapsToDevicePixels
    End Sub

    Private Sub btnNearestNeighbor_Click(sender As Object, e As RoutedEventArgs)
        If RenderOptions.GetBitmapScalingMode(MyImage) = BitmapScalingMode.NearestNeighbor Then
            RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.Unspecified)
        Else
            RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.NearestNeighbor)
        End If
    End Sub

    Private Sub btnReset_Click(sender As Object, e As RoutedEventArgs)
        sldRotateAngle.Value = 0
        sldScaleX.Value = 1
        sldScaleY.Value = 1
        sldCanvasTop.Value = 50
        'Canvas.SetTop(MyImage, 50)
    End Sub
End Class







前回
EdgeModeでアンチエイリアスの有無を切り替え、WPF ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/14910458.html



イメージ 14
初代Pixtack紫陽花はWindowsFormアプリ
WindowsFormは回転表示でアンチエイリアスを無効にできなかった記憶がある
真ん中下段も微妙にアンチエイリアスがかかっている

イメージ 13
2代目Pixtack紫陽花はWPFアプリ
このときはEdgeModeの存在を知らなくて
ScalingModeの切り替えのみなので
回転表示のときは外側だけアンチエイリアスがかかっている



Viewing all articles
Browse latest Browse all 420

Trending Articles