I have a function to capture the screenshot of a WPF control:
public System.Drawing.Bitmap CaptureScreenshot()
{
Point p = this.PointToScreen(new Point(0, 0));
System.Drawing.Rectangle rc = new System.Drawing.Rectangle((int)p.X, (int)p.Y, (int)this.ActualWidth, (int)this.ActualHeight);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rc.Width, rc.Height);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(rc.Location, System.Drawing.Point.Empty, rc.Size);
}
return bitmap;
}
This is working fine in Win7. However, in Win8, if this function is called from a context menu, the captured screenshot also shows the context menu. It is not waiting for my context menu to disappear before it's taking the screenshot.
Why it's working in Win7 but not Win8? How do I wait until context menu disappears before taking the screenshot? I tried several things like DoEvents or UpdateLayout() but they don't seem to help.
UPDATE:
Following pushpraj's comment, I got it working using RenderTargetBitmap:
var bitmap = new RenderTargetBitmap((int)grid.ActualWidth, (int)grid.ActualHeight, 96, 96, PixelFormats.Default);
bitmap.Render(grid);
Clipboard.SetImage(bitmap);
It seems to be working except one issue. My control has a light background, which turns into full black when I paste the clipboard. If I save the bitmap to a file directly, I don't have this problem. What's wrong?
UPDATE 2:
Okay, for the background problem using RenderTargetBitmap, I found a fix at here.
Related
as you can read from the title i want to be able to draw some images on the screen, move them in some direction and video capture the movement with a good fps rate.
I want to specify that i do not want to record the desktop nor some portion of it but the content of the actual window in which the images are moving(so the window can also be minimized). Also if possible i want to be able to set a custom size for my view where everything will happen.
Where i should start from?
I have already tried with WPF but as the UI is single threaded i am not able to take a screenshot of the view while something is moving on it.
What library you would suggest me?
Are there similar open-source projects i can learn from?
Any suggestion i welcomed!
Here's some code I recently wrote to do this, it cycles through a number of frames and renders a control (in this case, a Canvas) into PNGs:
private void Export(int frame)
{
// force the control to update after any changes you've just made
theCanvas.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
// render the control into a bitmap
RenderTargetBitmap bitmap = new RenderTargetBitmap(1920, 1080, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(theCanvas);
// save the bitmap out as a PNG
using (var stream = File.Create($"Animation/Frame_{frame.ToString("D3")}.png"))
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
}
You can then use ffmpeg to pack those PNGs into the movie file format of your choice.
I have WPF window in which my Direct3D engine render. WPF Window I start from my engine, which I develop on C++/CLI.
I have 2 displays and when I move window between them, part of the window became white and not update until I am not stop dragging it (like on screen shot).
Does somebody know how to fix this issue?
It will be hard to post code here as it is a lot of code, but I will try:
I use managed C++ and unmanaged in one project:
So, I add .Net dll`s to have access to the WPF window:
Window^ wnd = gcnew Window();
wnd->Width = 1280;
wnd->Height = 720;
wnd->Show();
WindowInteropHelper^ helper = gcnew WindowInteropHelper(wnd);
HWND WPFHwnd = (HWND)helper->Handle.ToPointer();
HINSTANCE hinstance = (HINSTANCE)Marshal::GetHINSTANCE(this->GetType()->Module).ToPointer();
engine->SetHisnstanceHWND(WPFHwnd, hinstance);
engine->InitializeSystem(wnd->ActualWidth, wnd->ActualHeight);
engine - this is unmanaged class which incapsulates all work with rendering.
Further it is a stardard d3d rendering loop. Nothing special.
It render OK, but when I resizing or move window, it draw a part of it like this (with white). When I stop resizing or moving - all OK again.
My question is: is it possible to get rid of this effect or not?
UPDATE:
I hooked the wndProc if the WPF window and try to use UpdateLayout() when size changing, but this has no effect. Seems window is not react on any intervention.
Well, it sounds like your engine is receiving WM_ERASEBKGND and it clears the window. After you release the window, it sends WM_PAINT and everything is clear again. That's what I believe might be happening.
In order to test this theory, you can handle that message and return true. Put that to your engine message handling routine:
case WM_ERASEBKGND:
{
PAINTSTRUCT pss;
BeginPaint(hWnd,&pss);
EndPaint(hWnd,&pss);
return true;
}
You can use WinSpy++ to check out what messages are delivered to underneath window. If you want to see why the background is whited out, you can do it through ProcessMonitor and see what API calls are being issued. You're probably interested in API calls that include the color white.
In Application window there is scroll view ,on taking the print out of the window whole scroll view didn't come ,only the window size print is coming ,I can take the print of scroll view only but is there any way to take the printout of whole scrollview with the window?
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
// printDialog.PrintVisual(canvas, "Scrollview Description");
printDialog.PrintVisual(this, this.Title);
}
I didnot get any answer for this question even after editing it, well I look into google several time and after multiple failed attempt finally I got a solution , problem in my code was that ,i used webbrowser control inside scroll view , after reading one solution i remove the scrollview and put code for taking print out of browser control and it works, this is the code i use
mshtml.IHTMLDocument2 doc = webbrwsr.Document as mshtml.IHTMLDocument2;
doc.execCommand("Print", true, null);
for this i have to include one .NET reference Microsoft.mshtml
hope this solution will work for any one else facing the same problem.
I'm trying to understand why my images are not snappy, so I built a sample to test WPF performance. I used a timer to calculate how long my "display images" event handler executed, and used a stop watch to measure how long it took the images to appear on the screen. The bottom line: when displaying 100, 1600, 2500 and 3600 images, WPF took 2, 9, 12 and 16 seconds after my code had finished to display the images on the screen. So I feel helpless: It seems I can't improve my code to make the images appear faster - I need to do something with WPF!
So my question is: What do I need to do differently to make the images display faster?
The test setup is simple:
The window contains a Grid. After the "test" button is clicked, row and column definitions are added.Then an Image is added to each cell of the grid as follows:
var image = new Image();
image.BeginInit();
image.Name = ImageNameFromCell(theRow, theColumn);
image.Stretch = Stretch.None;
image.HorizontalAlignment = HorizontalAlignment.Center;
image.VerticalAlignment = VerticalAlignment.Center;
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.LowQuality);
image.EndInit();
theGrid.Children.Add(image);
Finally, the Source of each image is set to a bitmap:a gray-scale image already scaled down to the estimated screen size. The bitmap is generated as follows:
var smallerBitmapImage = new BitmapImage();
smallerBitmapImage.BeginInit();
smallerBitmapImage.DecodePixelWidth = (int)(theImageWidth);
smallerBitmapImage.UriSource = theUri;
smallerBitmapImage.CacheOption = BitmapCacheOption.None;
smallerBitmapImage.EndInit();
//BitmapFrame bitmapFrame = BitmapFrame.Create(this.FullPath);
var convertedBitmap = new FormatConvertedBitmap();
convertedBitmap.BeginInit();
convertedBitmap.Source = smallerBitmapImage;
convertedBitmap.DestinationFormat = PixelFormats.Gray16;
convertedBitmap.EndInit();
convertedBitmap.Freeze();
So, I'm at my wits end. The images appear with a noticeable delay, and it seems to be out of my control. What can I do?
What appears to have made the difference is setting the image's cache option to OnLoad
smallerBitmapImage.CacheOption = BitmapCacheOption.OnLoad;
This moved the work to my event handler, so now I can use pre-fetching to do this at the background.
Do you actually see all those images at the same time? If not you can use some ItemsControl with a virtualizing panel so only images in view are displayed. (Speaking of panels, your current setup could also be replaced with an ItemsControl which uses a UniformGrid as panel)
You could also try to write a better decoder, which probably is a wasted effort.
I need to capture the entire screen with a transparent WPF window as the topmost window.
I tried 2 approaches:
using System.Windows.Drawing.Graphics.CopyFromScreen
using WINAPI GetDesktopWindow
Both methods yield the same result. I get the entire screen EXCEPT my topmost transparent WPF window.
The WPF window w is created with:
w.AllowsTransparency = true;
w.WindowStyle = System.Windows.WindowStyle.None;
w.Background = new SolidColorBrush( Color.FromArgb( 1, 0, 0, 0 ) );
w.Topmost = true;
plus some content of course. The window covers the entire screen surface.
Apparently, the WPF window draws on a surface that is not included in GetDesktopWindow.
Can anybody pls shed some light on this and share some ideas how to truly get the entire screen surface?
Just found the solution:
As far as I can tell there is no solution for the Graphics.CopyFromScreen approach because you'd need to OR CopyPixelOperation.CaptureBlt with CopyPixelOperation.SourceCopy but you can't. The usual M$ inconsistency madness...
However, the WINAPI approach works since you can combine SRCCOPY and CAPTUREBLT when using BitBlt. Without CAPTUREBLT transparent and layered windows will not be included.