2012-02-01 109 views
2

我在創建scatterview的屏幕截圖時遇到了問題。我的屏幕截圖始終包含黑框。如何在WPF中製作UIElement的屏幕截圖

這裏是我的XAML的代碼:

<s:SurfaceWindow 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:s="http://schemas.microsoft.com/surface/2008" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MakeScreenshots.SurfaceWindow1" 
    Title="MakeScreenshots" Width="1000" Height="700" 
    > 
    <s:SurfaceWindow.Resources> 
    <ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/WindowBackground.jpg"/> 
    </s:SurfaceWindow.Resources> 

    <Grid x:Name="GlobalGrid" Background="{StaticResource WindowBackground}" Width="1000" Height="700" > 

    <s:ScatterView x:Name="ScatterViewScreenShot" Margin="108,89,176,73" Width="700" Height="500"> 
     <s:ScatterView.Background> 
      <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveCaptionColorKey}}"/> 
     </s:ScatterView.Background> 
     <s:ScatterViewItem Margin="0,-26.953,-130.946,-23.047" Content="ScatterViewItem 3" HorizontalAlignment="Right" Width="125.826"/> 
     <s:ScatterViewItem Margin="0,0,-490.513,-151.256" HorizontalAlignment="Right" Width="125.77" Height="60.427" VerticalAlignment="Bottom" Content="ScatterViewItem 2"/> 
     <s:ScatterViewItem Content="ScatterViewItem 1" Margin="-331.43,0,0,-129.589" HorizontalAlignment="Left" Width="177.949" Height="67.905" VerticalAlignment="Bottom"/> 
    </s:ScatterView> 
    <Button x:Name="MakeScreenShotButton" Click="MakeScreenShotButton_Click" Content="MakeScreenShot" Margin="267,17,343,0" VerticalAlignment="Top" Height="38.96"/> 
     <Button Content="MakeScreenShotButton2" Height="39" HorizontalAlignment="Left" Margin="116,614,0,0" Name="button1" VerticalAlignment="Top" Width="301" Click="MakeScreenShotButton2_Click" /> 
     <Button Content="MakeScreenShotButton3" Click="MakeScreenShotButton3_Click" Height="39" HorizontalAlignment="Left" Margin="822,207,0,0" Name="button2" VerticalAlignment="Top" Width="147" /> 
     <Button Content="MakeScreenShotButton4" Click="MakeScreenShotButton4_Click" Height="39" HorizontalAlignment="Left" Margin="822,349,0,0" Name="button3" VerticalAlignment="Top" Width="147" /> 
     <Button Content="MakeScreenShotButton5" Click="MakeScreenShotButton5_Click" Height="39" HorizontalAlignment="Left" Margin="822,443,0,0" Name="button4" VerticalAlignment="Top" Width="147" /> 
    </Grid> 
</s:SurfaceWindow> 

這裏是C#代碼:

private void MakeScreenShotButton_Click(object sender, RoutedEventArgs e) 
    {   
     RenderTargetBitmap targetBitmap = new RenderTargetBitmap((int)ScatterViewScreenShot.ActualWidth, (int)ScatterViewScreenShot.ActualHeight, 80d, 80d, PixelFormats.Default); 

     targetBitmap.Render(ScatterViewScreenShot); 

     // add the RenderTargetBitmap to a Bitmapencoder 

     JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
     encoder.Frames.Add(BitmapFrame.Create(targetBitmap)); 

     // Encoder zum Speichern des Bildes 
     JpegBitmapEncoder encoderToSave = new JpegBitmapEncoder(); 
     encoderToSave.Frames.Add(BitmapFrame.Create(targetBitmap)); 

     // Speichern des Bildes auf der Festplatte 
     string fileName = "M:\\TestForStackOverflow.jpg"; 
     System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate); 
     encoderToSave.Save(fs); 

     encoder.QualityLevel = 40; 

     MemoryStream ms = new MemoryStream(); 
     encoder.Save(ms); 

     // Convert Image to byte[] 
     byte[] imageBytes = ms.ToArray(); 

     int anzahlBytes = imageBytes.Length; 

     string imageAsBase64String = Convert.ToBase64String(imageBytes); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(imageAsBase64String); 
    } 

    private void MakeScreenShotButton2_Click(object sender, RoutedEventArgs e) 
    { 
     // 1. Bitmap der gewünschten Größe erstellen 
     int width = (int)ScatterViewScreenShot.ActualWidth; 
     int height = (int)ScatterViewScreenShot.ActualHeight; 
     RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 100d, 100d, PixelFormats.Default); // 500 x 500 genau wie bei den Produktfotos 

     // 2. Control in Bitmap hinein rendern 
     Visual vis = (Visual)ScatterViewScreenShot; 
     rtb.Render(vis); 

     // 3. Control-Image erzeugen und dem Control-Image als Source das Bitmap übergeben 
     System.Windows.Controls.Image img = new System.Windows.Controls.Image(); 
     img.Source = rtb; 
     img.Stretch = Stretch.None; 

     // 4. Aktualisieren der Größe des Elements entsprechend des Inhaltes mittels der Methoden Measure und Arrange. 
     img.Measure(new System.Windows.Size(width, height)); 
     System.Windows.Size sizeImage = img.DesiredSize; 
     img.Arrange(new System.Windows.Rect(new System.Windows.Point(0, 0), sizeImage)); 

     // 5. Image wird mit der korrekten Größe erneut gerendert und an PngBitmapEncoder übergeben 
     RenderTargetBitmap rtb2 = new RenderTargetBitmap((int)rtb.Width, (int)rtb.Height, 60, 60, PixelFormats.Default); 
     rtb2.Render(img); 

     PngBitmapEncoder jpeg = new PngBitmapEncoder(); 
     jpeg.Frames.Add(BitmapFrame.Create(rtb2)); 


     // 6. Image in Stream schreiben 
     MemoryStream ms = new MemoryStream(); 
     jpeg.Save(ms); 

     // Convert Image to byte[] 
     byte[] imageBytes = ms.ToArray(); 

     int anzahlBytes = imageBytes.Length; 

     string imageAsBase64String = Convert.ToBase64String(imageBytes); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(imageAsBase64String); 
    } 

    private void MakeScreenShotButton3_Click(object sender, RoutedEventArgs e) 
    { 
     int width_x = 240; 
     int width_y = 400; 

     Bitmap screen = TakeScreenshot(100, 100, width_x, width_y); 

     System.Drawing.Image img = (System.Drawing.Image)screen; 
     //Image img = Image.FromFile("bla.jpg"); 
     MemoryStream ms = new MemoryStream(); 

     try 
     { 
      //Ein ImageCodecInfo-Objekt für den JPEG-Codec anlegen 
      ImageCodecInfo jpegCodec = null; 

      //Den Qualitätsarameter konfigurieren (Qualitätsfaktor in 
      //Prozent angeben) 

      EncoderParameter qualitaetsParameter = new EncoderParameter(
         System.Drawing.Imaging.Encoder.Quality, 40); 

      //Alle im System verfügbaren Codecs auflisten 
      ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders(); 

      EncoderParameters codecParameter = new EncoderParameters(1); 
      codecParameter.Param[0] = qualitaetsParameter; 

      //Den JPEG-Codec unter allen Codecs finden und dem 
      //Codec-Info-Objekt zuweisen 
      for (int i = 0; i < alleCodecs.Length; i++) 
      { 
       if (alleCodecs[i].MimeType == "image/jpeg") 
       { 
        jpegCodec = alleCodecs[i]; 
        break; 
       } 
      } 

      // Bild in Stream schreiben 
      img.Save(ms, jpegCodec, codecParameter); 
     } 
     catch (ArgumentException w) 
     { 
      throw w; 
     } 

     // Console.WriteLine(StreamToBase64(ms, System.Drawing.Imaging.ImageFormat.Jpeg)); 
     String bildBase64 = StreamToBase64(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(bildBase64); 
    } 

    private void MakeScreenShotButton4_Click(object sender, RoutedEventArgs e) 
    { 
     // save current canvas transform 
     Transform transform = ScatterViewScreenShot.LayoutTransform; 

     // get size of control 
     System.Windows.Size sizeOfControl = new System.Windows.Size(ScatterViewScreenShot.ActualWidth, ScatterViewScreenShot.ActualHeight); 
     // measure and arrange the control 
     ScatterViewScreenShot.Measure(sizeOfControl); 
     // arrange the surface 
     ScatterViewScreenShot.Arrange(new Rect(sizeOfControl)); 

     // craete and render surface and push bitmap to it 
     RenderTargetBitmap renderBitmap = new RenderTargetBitmap((Int32)sizeOfControl.Width, (Int32)sizeOfControl.Height, 96d, 96d, PixelFormats.Pbgra32); 
     // now render surface to bitmap 
     renderBitmap.Render(ScatterViewScreenShot); 

     // encode png data 
     PngBitmapEncoder pngEncoder = new PngBitmapEncoder(); 
     // puch rendered bitmap into it 
     pngEncoder.Frames.Add(BitmapFrame.Create(renderBitmap)); 

     /* Speichern des Bildes auf der Festplatte 
     string fileName = "M:\\ScreenshotClick4.jpg"; 
     System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate); 
     pngEncoder.Save(fs);*/ 

     // Encoder zum Senden des Bildes 
     JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
     encoder.Frames.Add(BitmapFrame.Create(renderBitmap)); 

     MemoryStream ms = new MemoryStream(); 
     encoder.Save(ms); 

     // Convert Image to byte[] 
     byte[] imageBytes = ms.ToArray(); 

     int anzahlBytes = imageBytes.Length; 

     string imageAsBase64String = Convert.ToBase64String(imageBytes); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(imageAsBase64String); 

    } 

    private void MakeScreenShotButton5_Click(object sender, RoutedEventArgs e) 
    { 
     int scale = 1; 

     double actualHeight = ScatterViewScreenShot.RenderSize.Height; 
     double actualWidth = ScatterViewScreenShot.RenderSize.Width; 

     double renderHeight = actualHeight * scale; 
     double renderWidth = actualWidth * scale; 

     RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); 
     VisualBrush sourceBrush = new VisualBrush(ScatterViewScreenShot); 

     DrawingVisual drawingVisual = new DrawingVisual(); 
     DrawingContext drawingContext = drawingVisual.RenderOpen(); 

     using (drawingContext) 
     { 
      drawingContext.PushTransform(new ScaleTransform(actualWidth, actualHeight)); 
      drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new System.Windows.Point(actualWidth, actualHeight))); 
     } 
     renderTarget.Render(drawingVisual); 

     JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder(); 
     jpgEncoder.QualityLevel = 40; 
     jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget)); 

     MemoryStream ms = new MemoryStream(); 
     jpgEncoder.Save(ms); 

     // Convert Image to byte[] 
     byte[] imageBytes = ms.ToArray(); 

     int anzahlBytes = imageBytes.Length; 

     string imageAsBase64String = Convert.ToBase64String(imageBytes); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(imageAsBase64String); 

    } 

    #region Hilfsmethoden 

    public string StreamToBase64(MemoryStream ms, System.Drawing.Imaging.ImageFormat format) 
    { 
     // Convert Image to byte[] 
     byte[] imageBytes = ms.ToArray(); 

     // Convert byte[] to Base64 String 
     string base64String = Convert.ToBase64String(imageBytes); 
     return base64String; 
    } 

    private Bitmap TakeScreenshot(int StartX, int StartY, int Width, int Height) 
    { 
     Bitmap Screenshot = new Bitmap(Width, Height); 
     Graphics G = Graphics.FromImage(Screenshot); 

     G.CopyFromScreen(StartX, StartY, 0, 0, new System.Drawing.Size(Width, Height), CopyPixelOperation.SourceCopy); 
     return Screenshot; 
    } 

    #endregion 


} 
} 

回答

9

下面的文章對您的問題解決方法:

以WPF「屏幕截圖」

http://www.grumpydev.com/2009/01/03/taking-wpf-screenshots/

/// 
/// Gets a JPG "screenshot" of the current UIElement 
/// 
/// UIElement to screenshot 
/// Scale to render the screenshot 
/// JPG Quality 
/// Byte array of JPG data 
public static byte[] GetJpgImage(this UIElement source, double scale, int quality) 
{ 
    double actualHeight = source.RenderSize.Height; 
    double actualWidth = source.RenderSize.Width; 

    double renderHeight = actualHeight * scale; 
    double renderWidth = actualWidth * scale; 

    RenderTargetBitmap renderTarget = new RenderTargetBitmap((int) renderWidth, (int) renderHeight, 96, 96, PixelFormats.Pbgra32); 
    VisualBrush sourceBrush = new VisualBrush(source); 

    DrawingVisual drawingVisual = new DrawingVisual(); 
    DrawingContext drawingContext = drawingVisual.RenderOpen(); 

    using (drawingContext) 
    { 
     drawingContext.PushTransform(new ScaleTransform(scale, scale)); 
     drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight))); 
    } 
    renderTarget.Render(drawingVisual); 

    JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder(); 
    jpgEncoder.QualityLevel = quality; 
    jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget)); 

    Byte[] _imageArray; 

    using (MemoryStream outputStream = new MemoryStream()) 
    { 
     jpgEncoder.Save(outputStream); 
     _imageArray = outputStream.ToArray(); 
    } 

    return _imageArray; 
} 

希望這有助於

+0

坦克爲你的答案,但這種解決方案會導致同樣的問題。試過了。我仍然得到黑色邊框的一部分散佈視圖被切斷。使用真實的點不可能製作截圖嗎? – 2012-02-01 13:17:09

+0

@DennisSchneider你可以發佈一些xaml代碼嗎? – punker76 2012-02-01 13:32:13

+0

我已經更新了我的早期文章(XAML&C#代碼) – 2012-02-01 13:54:40

3

我發現,工作得非常好一個相當簡單的方法。方法TakeScreenshot使屏幕截圖返回它作爲位圖。 MakeScreenShotButton_Click以jpeg編碼位圖,將其保存並作爲base64字符串發送給客戶端。

以下是代碼片段。首先TakeScreenshot:

private Bitmap TakeScreenshot(int StartX, int StartY, int Width, int Height) 
     { 
      // Bitmap in right size 
      Bitmap Screenshot = new Bitmap(Width, Height); 
      Graphics G = Graphics.FromImage(Screenshot); 
      // snip wanted area 
      G.CopyFromScreen(StartX, StartY, 0, 0, new System.Drawing.Size(Width, Height), CopyPixelOperation.SourceCopy); 

      // save uncompressed bitmap to disk 
      string fileName = "C:\\TestBMP.bmp"; 
      System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate); 
      Screenshot.Save(fs, System.Drawing.Imaging.ImageFormat.Bmp); 
      fs.Close(); 

      return Screenshot; 
     } 

這就是今天的MakeScreenShotButton_Click:

private void MakeScreenShotButton3_Click(object sender, RoutedEventArgs e) 
    { 
     // Start values 
     System.Windows.Point absolutPosition = ScatterViewScreenShot.TranslatePoint(new System.Windows.Point(0, 0), sw1); 
     System.Windows.Point screenPosition = this.PointToScreen(absolutPosition); 

     // Catch width and hight of scatterview 
     int widthScatterView = (int)ScatterViewScreenShot.ActualWidth; 
     int heightScatterView = (int)ScatterViewScreenShot.ActualHeight; 

     // Screenshot as bitmap TakeScreenshot(StartWert_X, StartWert_Y, BreiteBild, HöheBild) 
     Bitmap screen = TakeScreenshot((int)screenPosition.X, (int)screenPosition.Y, widthScatterView, heightScatterView); 

     MemoryStream ms = new MemoryStream(); 

     try 
     { 
      //ImageCodecInfo - Object 
      ImageCodecInfo jpegCodec = null; 

      // Quality-Parameter 
      EncoderParameter qualitaetsParameter = new EncoderParameter(
         System.Drawing.Imaging.Encoder.Quality, 40L); 

      //Show available Codes in List 
      ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders(); 

      EncoderParameters codecParameter = new EncoderParameters(1); 
      codecParameter.Param[0] = qualitaetsParameter; 

      //Find Jpeg-Codec 
      //Codec-Info-Object 
      for (int i = 0; i < alleCodecs.Length; i++) 
      { 
       if (alleCodecs[i].MimeType == "image/jpeg") 
       { 
        jpegCodec = alleCodecs[i]; 
        break; 
       } 
      } 

      // save image in stream 
      screen.Save(ms, jpegCodec, codecParameter); 
     } 
     catch (Exception k) 
     { 
      throw k; 
     } 

     // Convert image in Byte-Array 
     byte [] imageBytes = ms.ToArray(); 

     // Convert Byte-Array in Base64String --> Image as String 
     string bildBase64 = Convert.ToBase64String(imageBytes); 

     TCP_Client client = new TCP_Client("192.168.5.3", 4321); 
     client.sendeNachricht(bildBase64); 
    } 

它的工作原理沒有問題!

乾杯, 丹尼斯

+0

偉大的表現 – Andreas 2013-03-05 13:38:32

+0

這真的很好。 – Watson 2014-04-14 23:59:48