Cómo hacer una captura de pantalla de UIElement en WPF
Tengo un problema al crear una captura de pantalla de una vista de dispersión. Mi captura de pantalla siempre contiene un marco negro.
Aquí está mi código 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>
Y aquí está el código 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
}
}