Save video from WPF animation / storyboard - c#

I have a really complex Storyboard which works perfectly when run on a "live" window but I have trouble manually animating this storyboard to get a frame-by-frame animation which I can save to individual PNG files. All of the generated images are 1st animation frame.
I have see this, this, this and ultimately this. There is also this MSDN sample but all of them talk about animating a single DependencyProperty. What I need is the ability to step through frame by frame having a complex Storyboard, not just one DP.
I have searched everywhere without any luck. Also my experiments have all failed. Any help is appreciated. Here is a bit of non-functional code.
storyboard.Begin(grid, true);
//storyboard.Pause();
//var clock = storyboard.CreateClock();
//clock.Controller.Pause();
var secs = Enumerable.Range(0, totalFrames).Select(t => (((double)t) / FPS));
grid.Measure(new Size(480, 340));
grid.Arrange(new Rect(grid.DesiredSize));
foreach (var sec in secs)
{
//clock.Controller.SeekAlignedToLastTick(TimeSpan.FromSeconds(sec), TimeSeekOrigin.BeginTime);
storyboard.SeekAlignedToLastTick(TimeSpan.FromSeconds(sec), TimeSeekOrigin.BeginTime);
grid.InvalidateVisual();
grid.UpdateLayout();
var filename = Path.Combine(tempFolder, string.Format("image{0}.png", sec));
var rtb = new RenderTargetBitmap((int) grid.ActualWidth, (int) grid.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(grid);
var png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
using (var stream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite))
{
png.Save(stream);
}
}

#wpfwannabe: thanks a lot for the insight.
I used your code and it worked out, although with a minor modification as shown below:
rootStoryBoard.SeekAlignedToLastTick(Program.AnimPlots.canvs, TargetTmspn, System.Windows.Media.Animation.TimeSeekOrigin.BeginTime);
In the above line of code: Program.AnimPlots.canvs is the area of snapshot, in your case it is grid and TargetTmspn is the object of type TimeSpan.
Hope this helps someone :)

Here's another approach that you may find useful. If you've exhausted all options for animating your XAML Storyboard frame-by-frame then another option you could explore would be to create your Storyboard in code instead, here's an example: Animation in codebehind for loop, using RenderTransform
The benefit of that is then you'd have total programmatic control over your Storyboard to step through the individual key frames one-by-one, where you could then save an image after each frame.
I did something conceptually similar in jQuery a while back. Basically I wrote a line drawing signature app that saved coordinate data points. I could then reload the data points back into the algorithm and reproduce the animation. http://kodekreachor.com/prototypes/
I know it's a very different technology but it's the idea of being able to completely control the sequential animation from code that should be the take-away and hopefully serve as some inspiration for you.

Related

C# move cursor on screen based on where text appears on desktop

So I have searched and can't seem to find the right resources or tools for what I am wanting to do so I thought I'd ask for some help. Below is what I am wanting to do.
I am making a .Net core application that will simulate some key strokes and that is all working fine, but I want to also move the mouse based on where certain text appears on the screen, however, I will not have control over the application where the text appears, so I will need to somehow either be streaming the desktop view and using something to analyze it, or constantly taking a screen shot every 10 seconds or so and analyzing that screen shot if the text is there and then move the mouse to that position of text and simulate a left click.
I am not really confident in the screenshot approach as I am not sure how I'd get the mouse coordinates, so I have a feeling I will need to feed a desktop stream into something in order to get the image I am analyzing and then overlay my own transparent overlay on top of that in order to move the cursor to appropriate position.
I hope this makes sense and any libraries or whatever that is recommended to do this is appreciated. I know how to move the cursor on the screen and left click, just haven't found on google the right library for analyzing a desktop screen in real time and getting coordinates based on searching conditions.
Thank you everyone.
So I figured out what I needed to do. Trying to match the text with and OCR proved to be impossible as the text was layered into an image where they actively tried to prevent detection, this is because its a video game and they don't want automation I guess. So what I did was determine I will always know what the button is going to look like, so I took a screen shot of the button and now I take screenshots of the game every 10 seconds and then search that image for my button template image. If the image has a match, then I generate coordinates and send mouse there and click it. Below is the code I used and you will need the libraries from AForge to use this code.
Bitmap sourceImage = (Bitmap)Bitmap.FromFile(#"C:\testjpg.jpg");
Bitmap template = (Bitmap)Bitmap.FromFile(#"C:\buttonjpg.jpg");
// create template matching algorithm's instance
//Resize value
var resizePercent = 0.4;
//Resizing images to increase process time. Please note this will result in skewed coordinates.
//You must divide the coordinates by your resizePercent to get native coordinates taken from screen shots.
sourceImage = new ResizeBicubic((int)(sourceImage.Width * resizePercent), (int)(sourceImage.Height * resizePercent)).Apply(sourceImage);
template = new ResizeBicubic((int)(template.Width * resizePercent), (int)(template.Height * resizePercent)).Apply(template);
// (set similarity threshold to 0.951f = 95.1%)
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.951f);
// find all matchings with specified above similarity
TemplateMatch[] matchings = tm.ProcessImage(sourceImage, template);
// highlight found matchings
BitmapData data = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadWrite, sourceImage.PixelFormat);
foreach (TemplateMatch m in matchings)
{
Drawing.Rectangle(data, m.Rectangle, Color.White);
Console.WriteLine(m.Rectangle.Location.ToString());
var x = m.Rectangle.Location.X;
var y = m.Rectangle.Location.Y;
//Fixing the coordinates to reflex the origins of the original screenshot, not the resized one.
var xResized = (int)(x / resizePercent);
var yResized = (int)(y / resizePercent);
// do something else with matching
}
sourceImage.UnlockBits(data);
I did notice my coordinates were off usually around ~4.5%-8% from dead center(the button still gets clicked, but I want a perfect center click), so for me I am calculating a range of coordinates, which in this range are not very many to ensure the button I want to click is clicked and not missed and just having program click all the potential coordinates.
So I hope this helps someone!
Kind Regards,
Aaron
Depending on the application there are a number of approaches you might want to try.
For example, using Application Insights and UI Automation, you might be able to capture the text directly.
If you have the exe file, then you might be able to decompile it with something like dotPeek and then use Visual Studio's Live debugging feature to access the text.
You might be able to inspect the heap of the running process via a tool like HeapMemView.
Optical Character Recognition might be an option worth considering. In that case Tesseract is an open source OCR engine worth considering. This can be used in conjunction with screenshots to extract text.

show 1 million locations with markers on a map based on OpenStreetMap from C# VS2013 WPF

I would like to show 1 million locations on a map based on OpenStreetMap.
I work on C# VS2013 and GMAP.NET WPF. But, when I added markers for each location, the map cannot be shown up because the marker is a bitmap image.
And 1 million markers consume too much memory on my laptop (with 8 GB mem).
The code is:
public void add_marker(List<Tuple<double, double>> latLongList, ref GMapControl myMap)
{
System.Windows.Media.Imaging.BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(#"C:\djx_2014_6_3\my_projects\test_gmap_dot_net\GMap_WPF\try1\try_gmap_wpf\try_gmap_wpf\images\map_marker.png", UriKind.Absolute);
bitmapImage.DecodePixelHeight = 5;
bitmapImage.DecodePixelWidth = 5;
bitmapImage.EndInit();
foreach(var v in latLongList)
{
GMap.NET.PointLatLng point = new GMap.NET.PointLatLng(v.Item1, v.Item2);
GMapMarker marker = new GMapMarker(point);
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = bitmapImage;
marker.Shape = image;
marker.ZIndex = 5;
myMap.Markers.Add(marker);
}
}
I do not want to use the image as markers but I cannot find out how to use default marker in openStreetMap.
Any help would be appreciated.
WPF wasn't designed to be used for things like this. First of all you're creating a Bitmap for each tag, which is a user control and comes with some pretty heavy overhead for GUI hit-testing and binding etc. Secondly, WPF renders with DirectX, which means at some point all that data has to be set up with vertex buffers and uploaded into the graphics card. If you use data binding or try to create separate UI elements then this is going to take a lot of initial set-up time and memory, as you have already discovered. And if you try to draw them yourself (e.g. by creating your own user control and overriding OnRender) then it can be even worse, since all that work is now being done every frame (apart from buffered stuff which still incurs the initial setup anyway so you're back to square one).
If I had to do this myself I would start by organizing the data set with an appropriate 2D structure such as a k-d tree, an R*-tree or even a basic quad-tree. This will allow you to quickly determine at any given moment which markers are in the view frustum.
Next, I would add the appropriate bindings to scrollbars etc so that I could monitor exactly where the current view frustum was, and then each frame I would update the list of visible tags based on that. So long as you don't have more than a few thousand objects comes into view at once you should be ok, otherwise you'll have to stagger the updates over multiple frames with a queue.
If that doesn't suit your needs then you really have only two options left: 1) generate the raw bitmap data yourself manually, or 2) use a more suitable technology.

PixelShading in C#

I hope I do not make my first mistake with my first post.
I am writing a library for several graphical effects and filters (for example Sobel or Gauß mask).
Because of the low Speed, doing this on the CPU, I wrote some shaders with the Shazzam tool.
My concret Problem is, that I am not able to use this shader in C#.
In the Internet I found only advice how to apply a pixelshader as a effect in XAML directly to a element, which is not usable for my application, because this makes it impossible to apply several shaders on one Image, which is needed, for example the Canny Edge Detector.
To illustarte this issue a Little pseudo-code, which should Show, what I expect from the method.
PixelShader somePixelShader = new PixelShader(pixelshader.ps);
somePixelShader.Input = Bitmap;
somePixelShader.Height = 200;
somePixelShader.Width = 800;
somePixelShader.Execute();
Bitmap = somePixelShader.Result;
As you see, everything should be done in C#.
Perhaps you can help me with my issue.
You can make a copy of the current effect output as a bitmap with RenderTargetBitmap, then submit this outputted image as the new input for the next effect, rinse, repeat.
Update : after a small (and inconclusive) test, this will not work : Can't render pixel shader to RenderTargetBitmap! Please help!
Check out these white papers for step-by-step instructions + examples on how to compile and use a pixel shader in WPF or SL.
You may also want to check out the WPF Pixel Shader Effects Library here.

Trackview or timeline in Naudio

How can I use trackview or timeline in Naudio in C#?
Here is my code and it's not working.
I want to see my line going as track is playing.
NAudio.Wave.WaveStream pcm = NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(new NAudio.Wave.Mp3FileReader(open.FileName));
customWaveViewer2.WaveStream = pcm;
stream = new NAudio.Wave.BlockAlignReductionStream(pcm);
trackView1.NowTime = stream.CurrentTime;
Unfortunately, TrackView and TimeLine are not completed controls, and you would be better off writing your own custom control to place a vertical line at a position that represents the now playing time.
You would probably be best using a timer to invalidate your custom wave viewer, and in the Paint method, drawing a vertical line that represents the current play time.

Overlaying Notification Icon with text

After some help here, I've got WPF using the windows.forms notifyIcon class (It's not a major app so not worried about purity). And I was wondering if its possible to overlay some text on the icom?
Basically I need it to visually show how many entries is in my gridview. And run this on everytime the SizeChanged event. This is what I have come up with so far, but not sure how to go on from here.
Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/ReturnJourneyPreparation;component/Resources/favicon.ico")).Stream;
System.Drawing.Icon notIcon = new Icon(iconStream);
System.Drawing.Image canvas = new Bitmap(notIcon.Width, notIcon.Height);
Graphics artist = Graphics.FromImage(canvas);
artist.DrawString(_Messages.Count().ToString(), new Font("Arial", 4), System.Drawing.Brushes.Black, (float)(notIcon.Width), (float)(notIcon.Height));
(PS. I can't use Philipp Sumi's NotifyIcon module)
Thanks, Psy
It looks like you're trying to add a watermark on top of your image/icon. For more information check out the following site: http://www.c-sharpcorner.com/UploadFile/scottlysle/WatermarkCS05072007024947AM/WatermarkCS.aspx
You'll be able to add custom text on top of the original icon graphic. This is a great solution if you're not updating often--but if it's something that will be run many times in a short period of time (I'm thinking progress bar here) you'll be adding unneeded lag to your program.

Categories