Someone the other day tweeted a link to some very cool animated gifs. I love animated gifs !!
I have always wanted animated gifs in Silverlight/WPF BUT for reasons unknown they never came. They would have been perfect for A LOT of scenarios where creating storyboard animations would have been overkill.
Well turns out WinRT XAML, firmly rooted in Silverlight XAML, also doesn’t have GIF support nor will it probably ever get it. BUT it does have WinRT support and it has access to DirectX & WIC via SharpDx!!
And today on Twitter Jeremiah Morrill tweeted that WIC has support for GIF’s, this intrigued me. Can I build my own support for animated gifs in XAML using DirectX & WIC (via SharpDx) ?!
Challenge is on ……
This is the animated gif I will try to render…
Source : “Savannah Rain” (frommetoyou)
Default XAML/C# metro app project + SharpDx
I created an empty managed metro project and added the necessary SharpDx bits, basically like I have been over the last several posts.
As always this project has a effect renderer that will render to a (Direct2D or Direct3D) surface via a (SwapChainBackgroundPanel or SurfaceImageSource). Again this is what I’ve been doing in all my SharpDx posts to date so just go back to those or the samples if you’ve forgotten
Animated GIF resource
Now just add the Animated GIF as a content resource to the project. I could load it in via a URI BUT I thought it would be easier to just include it for now .
Load GIF via WIC
Ok this is where it gets interesting, SharpDx gives us access to WIC from C#. Question is does it have the GIF bits.
As I’ve said many times before SharpDx is a very thin/performant wrapper over C++ libraries (but just to clarify there will always be an overhead to using WIC via this wrapper even thou it is small). This wrapper is a metadata mapping generated api so technically the GIF bits of WIC should have come across. Lets test it out.
Lets instantiate a WIC GIFDecoder that will be used to read the animated GIF resource. The “asset” is simple the internal uri to the gif content.
Next when we animate this gif we need to know how many frames to animate. The GIF spec defines this…
Now for each frame we want to get the bitmap of that layer and store it for rendering. There is a lot going on in this code BUT in a nutshell an object is created that lets us get at the bytes of data for a particular frame in the gif. (its easy to follow just step through the code , that’s how I learnt
As it turns out for GIFS the first layer normally has the entire bitmap contents of the GIF and all the other frames above that contain delta information.. Also the ‘delta’ frames are all offseted so we need to get the offset (left,top) of those frames and store them for rendering of that frame later on..
So assuming that SharpDx’s GIF WIC works fine that’s basically all we need information wise.. We just need a way to store those frames and render them to the UI.
…. hello SpriteBatch
SpriteBatch
The best way to render a series of textures in the graphics world is via a spritebatch. Lets create a very very dirty one that will serve our purposes ..
I’m not going to go into too much detail of how this dirty spritebatch works, it’s not in the truest sense a spritebatch BUT it will do for now..
This spritebatch will keep a cache of the GIFs frames that I will render on a DirectX Surface. I’ve defined 2 lists to store the static frames ( 0 ) and the rotating frames ( 1 – 7 )
I’ve created a way to add sprites (frames) to my spritebatch via the methods
1. DrawAlways – sprites that will always get rendered on each loop of the rendering pipeline eg. frame 0 of the aimated gif
2. DrawRotating – sprites that will rotate there appearance with each loop of the rendering pipeline eg. frames 1 to 7 of the animated gif
These methods are called when we are decoding our GIF (the section prior to this outlined this process)
The sprite batch, as expected, has the ability to render itself and all it’s sprites. In my example it will render on a D2D surface and will use the much loved BitmapEffect to render the layer .
Also note that the offset(_texturesRotatedOffset) for the layer needs to be rendered for the 1-7 frames
Now if you don’t understand the above just step through the code, it will all make sense..
Does this all work ?!
Does SharpDx’s support for WIC GIF’s work for animated gifs ?!
Running the demo
Here’s some awesome gifs from a very cool site
Here’s the metro xaml/c# demo running one of those animated gifs. Note that the framerate is low because of the simultaneous video recording going on. Without it it runs buttery smooth at 65-70fps.
Sample code
Conclusion
I started out this experiment fully expecting it NOT to work… I was so surprised that it actually did . Animated gifs in a XAML managed metro app!!! Damn!!
XAML/WinRT + DirectX/WIC (via SharpDx) is turning into a killer combination of features for building pretty amazing new experiences. I’m only now getting familiar with the frameworks, I can’t wait to see what I’ll be creating a month from now!
I’m loving XAML/DirectX …
Pingback: Animated gifs in XAML/C# :) | Silverlight and other cool things …
Pingback: Windows 8 Developer Links – 2012-05-08 | Dan Rigby
Pingback: Animated gifs in XAML/C# :) :: Learning
I haven’t tried this but looks really cool. Have you tried adding it to a live tile? Would that work?
This is really cool, loving it, but I wonder will this be avaliable for loading in a live tile as well
Pingback: All my XAML/C#/SharpDx demos | Silverlight and other cool things …
can you give a simpler code adding gif animation in xaml/c# for beginner learner?
Seems a great work, but under RTM it doesn’t work. I am not familar with c# so I can’t bringing it to work. Would be great if you can provide a working example.
Cheers, Franz
Hello, I brought it to run Yeah. So I copy the standardstyle, strange a section shows errror, so commeted it out, in xaml replaced by simple , pointereventargs replaced by PointerRoutedEventArgs.
So for me as non c# guy i had problems to solve ApplicationView.GetForCurrentView().ViewStateChanged += this.ViewStateChanged; and related private void ViewStateChanged(ApplicationView sender, ApplicationViewStateChangedEventArgs e)
{
this.InvalidateVisualState(e.ViewState);
}
so I commeted it out, but this should for a c# guy solvable
For the error
return new Windows.Foundation.Rect(0, 0, surfaceImageSource.PixelWidth, surfaceImageSource.PixelHeight); I found no solution, so tried with hardcoded
return new Windows.Foundation.Rect(0, 0, 350, 350);
With this changes the sample runs at 80Frames and looks very ugly. Is there anybody to bring the code to work at a smooth look?
Franz
Heya Jose, looking really good! However, as Franz has said, there is an issue with the framerate in RTM (I think I nearly had a fit from watching it!) There is an horrendous amount of flickering.
Franz has identified the workarounds for getting the code to compile, although instead of the hardcoded 350 values for width and height, he should use the class level pixelWidth and pixelHeight fields passed to the SurfaceImageSourceTarget constructor.
The rendering has issues in both the draggable canvas and the panel. The issue appears to be a disjoint in the frame rate and the frame delay (?):
using: _spriteBatch.FrameDelay = 1 results in very little delay between frames and has no flicker. But of course, the delay being very little is an issue as frames just shoot by.
Anything greater than 1 has the flickering.
I guess it has to be in the SpriteBatch Render method. The setup works, as all frames are loaded into the collections in the SpriteBatch, and the gif auto repeats. I have played with the calls between the BeginDraw and EndDraw methods and nothing seems to sort it. Unless there is something in the SurfaceImageSourceTarget.RenderAll method; although it’ll take me a while to work out what that code does!
Any ideas?
Whoops, was meant to remove that ridiculous paragraph about the disjoint…
I have now also tried it with the latest SharpDX Windows 8 assemblies, and no luck.
Had to change the GifBitmapDecoder to the base BitmapDecoder class, and all the frames were retrieved successfully still.
Had to get the latest CommonDX library as well.
Spamming the comments, sorry…
So, I now understand how your code uses the FrameDelay 🙂
Rather than having the SurfaceImageSourceTarget’s RenderAll go to waste, I embraced it.
Instead of:
_currentFrame++;
if (_currentFrame < FrameDelay) return;
_currentFrame = 0;
I use:
_currentFrame++;
//if (_currentFrame < FrameDelay) return;
//_currentFrame = 0;
And then, just after the EndDraw call:
if (_currentFrame == FrameDelay)
{
_currentFrame = 0;
_currentTexture++;
}
This way, the same frame is rendered for each time the _currentFrame falls within the delay.
Fixed!
Fixed… sort of. Now the rendering of the gif uses a fair bit of CPU (well, for rendering a gif!!!)
As long as I dispose it, I should be all good. It can’t be any worse than playing a video in my app.
This is a lot of work when you could just use HTML5 in a WebView.
Try using an animated gif that you have downloaded to one of the local storage folders. There is no issue if the gif is online, or is included in the app (as you can use the ms-appx-web schema to open the html file).
If you can find a way, let me know.
Magnificent beat ! I wish to apprentice while you amend your website, how can i subscribe for a blog website?
The account helped me a acceptable deal. I had been tiny bit acquainted of this your broadcast provided
bright clear concept
Hey! This is my 1st comment here so I just wanted to give a quick shout out and
say I genuinely enjoy reading your posts. Can you
recommend any other blogs/websites/forums that go
over the same subjects? Thanks for your time!
Every weekend i used to pay a visit this site, as i wish for enjoyment, as this this web site conations really nice funny information too.
Hi there! I’m at work surfing around your blog from my new iphone!
Just wanted to say I love reading your blog and look forward to all your posts!
Keep up the superb work!
I read this article completely regarding the resemblance of most recent and preceding technologies, it’s remarkable article.
I’m gone to say to my little brother, that he should also pay a quick visit this blog on regular basis to take updated from newest reports.
I have been exploring for a bit for any high quality articles or blog posts in this sort of house .
Exploring in Yahoo I eventually stumbled upon this site.
Reading this information So i am happy to convey that I’ve an incredibly
good uncanny feeling I came upon just what I needed.
I such a lot without a doubt will make sure to don?t omit this site and give it a look regularly.
Link exchange is nothing else however it is just placing the other person’s website link on your page
at suitable place and other person will also do same in support of you.
Hi friends, how is all, and what you want to say concerning this piece of writing, in my view its really amazing in favor
of me.
If you are going for most excellent contents like I do,
just go to see this web site daily as it presents
feature contents, thanks
I will immediately grab your rss feed as I can’t
in finding your email subscription link or
newsletter service. Do you have any? Please allow me know in order that I may just subscribe.
Thanks.
Good day I am so excited I found your web site,
I really found you by mistake, while I was looking on Aol for something else, Anyhow I am here now and
would just like to say many thanks for a fantastic post and a all round entertaining blog
(I also love the theme/design), I don’t have time to
go through it all at the minute but I have bookmarked it and also added your RSS feeds,
so when I have time I will be back to read more,
Please do keep up the great jo.
It’s awesome for me to have a web site, which is useful designed
for my knowledge. thanks admin
Hi! I could have sworn I’ve been to this site before but after
reading through some of the post I realized it’s new to me.
Anyhow, I’m definitely happy I found it and
I’ll be book-marking and checking back often!
Hey! Do you use Twitter? I’d like to follow you if that
would be okay. I’m absolutely enjoying your blog and look
forward to new updates.
I’ve been surfing on-line greater than three hours nowadays,
yet I by no means found any fascinating article like yours.
It is pretty worth sufficient for me. Personally, if all web owners and bloggers made just right
content material as you probably did, the internet might be a lot more useful than ever before.
I like the valuable info you supply in your articles.
I will bookmark your blog and test once more here frequently.
I am relatively sure I’ll be informed many new stuff right here!
Good luck for the next!
Quality articles or reviews is the key to be a focus for the visitors to go to see the web page, that’s what
this website is providing.
I’m not sure where you’re getting your info, but great topic.
I needs to spend some time learning much more or understanding more.
Thanks for wonderful information I was looking for this information for my mission.
Greetings from California! I’m bored at work so I decided to browse your website on my iphone during lunch break.
I love the info you present here and can’t wait to take a look when I get
home. I’m surprised at how fast your blog loaded on my cell phone ..
I’m not even using WIFI, just 3G .. Anyhow, wonderful site!
I enjoy reading through a post that will make people think.
Also, thank you for allowing me to comment!
I am now not certain where you’re getting your information, however good topic.
I needs to spend some time finding out much more or understanding
more. Thank you for great info I used to be in search of this info for my
mission.
http://0daymusic.org/
For most recent information you have to go to see internet and on
world-wide-web I found this web site as a most excellent web site for newest updates.
view it https://cool-mining.com/en/mining-en/new-tt-miner-v4-0-0-download-with-kawpow-support-for-windows/
check over here Dating Accounts
сердечный сайт http://zarabotat-v-internete.biz/347-nastroyka-gugl-advords.html
take a look at the site here кардинг форум