首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >截图质量

截图质量
EN

Stack Overflow用户
提问于 2020-11-19 07:59:39
回答 1查看 40关注 0票数 1

在我之前的一个问题中,我问过如何才能截取ScrollViewer中所有内容的屏幕截图,而不仅仅是ViewPort中可见的内容。经过多次尝试,我给自己找到了一个答案,但不幸的是,这个答案提出了另一个问题。

看看下面的示例代码:

ItemViewModel.vb (我的TreeViewItems的一个简单视图模型):

代码语言:javascript
复制
Public Class ItemViewModel
    Public Property Text As String
    Public Property Items As New ObservableCollection(Of ItemViewModel)
End Class

ViewModel.vb (我的主窗口的视图模型,在构造函数中创建一些项):

代码语言:javascript
复制
Public Class ViewModel
    Public Property Items As New ObservableCollection(Of ItemViewModel)

    Private Const levels As Integer = 3

    Public Sub New()
        Dim item1 As ItemViewModel
        Dim item2 As ItemViewModel
        Dim item3 As ItemViewModel

        For index1 As Integer = 1 To levels
            item1 = New ItemViewModel With {.Text = String.Format("Node {0} - {1}", index1, Guid.NewGuid.ToString)}
            Me.Items.Add(item1)

            For index2 As Integer = 1 To levels
                item2 = New ItemViewModel With {.Text = String.Format("Node {0}.{1} - {2}", index1, index2, Guid.NewGuid.ToString)}
                item1.Items.Add(item2)

                For index3 As Integer = 1 To levels
                    item3 = New ItemViewModel With {.Text = String.Format("Node {0}.{1}.{2} - {3}", index1, index2, index3, Guid.NewGuid.ToString)}
                    item2.Items.Add(item3)
                Next index3
            Next index2
        Next index1
    End Sub

End Class

MainWindow.xaml (主窗口本身,显示一个TreeView):

代码语言:javascript
复制
<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ScreenshotTest"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="200" Width="300" KeyDown="Window_KeyDown">

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>

    <TreeView x:Name="Tree" ItemsSource="{Binding Items}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:ItemViewModel}" ItemsSource="{Binding Items}">
                <Border BorderThickness="1" BorderBrush="Black" Margin="1">
                    <TextBlock Text="{Binding Text}" Margin="2" />
                </Border>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsExpanded" Value="True" />
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>
</Window>

MainWindow.xaml.vb (主窗口的代码隐藏,这里是“有用”代码所在的位置):

代码语言:javascript
复制
Class MainWindow

    Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs)
        Dim panel As StackPanel

        If e.Key <> Key.P Then
            Exit Sub
        End If

        panel = GetFirstChildOfType(Of StackPanel)(Me.Tree)
        panel.Background = Brushes.White
        panel.UpdateLayout()

        Me.CaptureScreen(panel, "C:\Temp\Screenshot.png")
    End Sub

    Private Shared Function GetFirstChildOfType(Of T As DependencyObject)(obj As DependencyObject) As T
        Dim result As T
        Dim child As DependencyObject

        If (obj Is Nothing) Then
            Return Nothing
        End If

        If (VisualTreeHelper.GetChildrenCount(obj) = 0) Then
            Return Nothing
        End If

        For index As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj)
            child = VisualTreeHelper.GetChild(obj, index)
            result = TryCast(child, T)

            If (result Is Nothing) Then
                result = GetFirstChildOfType(Of T)(child)
            End If

            If (result IsNot Nothing) Then
                Return result
            End If
        Next index

        Return Nothing
    End Function

    Private Sub CaptureScreen(source As UIElement, filename As String)
        Dim height As Double
        Dim renderHeight As Double
        Dim width As Double
        Dim renderWidth As Double
        Dim renderTarget As RenderTargetBitmap
        Dim vb As VisualBrush
        Dim dv As DrawingVisual
        Dim encoder As PngBitmapEncoder

        Try
            height = source.RenderSize.Height
            renderHeight = height
            width = source.RenderSize.Width
            renderWidth = width

            renderTarget = New RenderTargetBitmap(Convert.ToInt32(renderWidth), Convert.ToInt32(renderHeight), 96, 96, PixelFormats.Pbgra32)
            vb = New VisualBrush(source)

            dv = New DrawingVisual

            Using dc As DrawingContext = dv.RenderOpen
                dc.DrawRectangle(vb, Nothing, New Rect(New Point(0, 0), New Point(width, height)))
            End Using

            renderTarget.Render(dv)

            encoder = New PngBitmapEncoder
            encoder.Frames.Add(BitmapFrame.Create(renderTarget))

            Using fs As IO.FileStream = New IO.FileStream(filename, IO.FileMode.Create, IO.FileAccess.Write)
                encoder.Save(fs)
            End Using
        Catch ex As Exception
            Stop
        End Try
    End Sub

End Class

如果你运行这个程序,你会看到一个包含几个项目的TreeView,如果你按下P,TreeView内容的屏幕截图就会被截取并保存为"C:\Temp\Screenshot.png“。

到目前为止,屏幕截图看起来和屏幕上看到的大致相同(质量方面)。例如,如果您在IrfanView中查看创建的png文件( 100%大小),则所有内容都是可读的。

但是如果我创建越来越多的项目(将levels常量增加到5,然后增加到7),图片质量会变得更差,当levels=7时,用户无法读取屏幕截图上的任何内容。

有没有人知道这里发生了什么,我怎么解决这个问题?我对C#中的答案也很满意。

这里有几个屏幕截图来直观地说明我的问题:

屏幕上的主窗口

levels=3的屏幕截图

levels=5的屏幕截图

levels=7的屏幕截图

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-11-19 10:05:22

我不是那么精通WPF,但创建一个VisualBrush来绘制项目似乎是错误的。因此,不用使用VisualBrushDrawingVisual编写代码,只需使用renderTarget.Render(source)即可。

代码语言:javascript
复制
Private Sub CaptureScreen(source As UIElement, filename As String)
  Dim height As Double
  Dim renderHeight As Double
  Dim width As Double
  Dim renderWidth As Double
  Dim renderTarget As RenderTargetBitmap
  Dim vb As VisualBrush
  Dim dv As DrawingVisual
  Dim encoder As PngBitmapEncoder

  Try
    height = source.RenderSize.Height
    Debug.Print(height.ToString)
    renderHeight = height
    width = source.RenderSize.Width
    renderWidth = width

    renderTarget = New RenderTargetBitmap(Convert.ToInt32(renderWidth), Convert.ToInt32(renderHeight), 96, 96, PixelFormats.Pbgra32)
    renderTarget.Render(source)

    encoder = New PngBitmapEncoder
    encoder.Frames.Add(BitmapFrame.Create(renderTarget))

    Using fs As IO.FileStream = New IO.FileStream(filename, IO.FileMode.Create, IO.FileAccess.Write)
      encoder.Save(fs)
    End Using
  Catch ex As Exception
    Stop
  End Try
End Sub

这对我来说似乎很有效。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64903293

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档