Razan Paul Blog

Explaining thoughts and findings is a great way to learn

November 2009 - Posts

A simple snapshot taker application in WPF

The simple application is implemented using media player in WPF. You can also use this code to make preview of video in WPF. Here MediaPlayer is used to play video instead of MediaElement. There is nothing ground breaking here. The overall idea is: as we are playing video in content control which is a visual and we know, we can make image from any visual, so we are just making image from the video content control. The simple snapshot taker application looks like the following:

snapshotTaker

Here an openfiledialog is used to open video file. If you select non-video file, the application will give you the message “invalid file”. Process.Start(filename) starts a viewer by specifying a file name. It is similar to typing the information in the run dialog box of the Windows Start menu. The used c# code for this is in the following:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Windows;
   6: using System.Windows.Media;
   7: using System.Windows.Controls;
   8: using System.Windows.Media.Imaging;
   9: using System.Windows.Shapes;
  10: using System.IO;
  11:  
  12: namespace SnapShotUsingMediaPlayer
  13: {
  14:     public class MediaPlayerControl : ContentControl
  15:     {      
  16:         MediaPlayer _MediaPlayer;
  17:         private Uri _Source = null;
  18:         public Uri Source
  19:         {
  20:             get { return _Source; }
  21:             set
  22:             {
  23:                 _Source = value;
  24:                 Play(value);
  25:             }
  26:         }
  27:  
  28:         public void Play(Uri source)
  29:         {
  30:             if (_MediaPlayer == null)
  31:             {
  32:                 _MediaPlayer = new MediaPlayer();
  33:  
  34:             }
  35:             _MediaPlayer.MediaFailed += new EventHandler<ExceptionEventArgs>(_MediaPlayer_MediaFailed);           
  36:             _MediaPlayer.MediaOpened += new EventHandler(_MediaPlayer_MediaOpened);
  37:             _MediaPlayer.Open(source);     
  38:         }
  39:  
  40:         void _MediaPlayer_MediaOpened(object sender, EventArgs e)
  41:         {
  42:             System.Threading.Thread.Sleep(1000);
  43:             VideoDrawing videoDrawing = new VideoDrawing();
  44:             videoDrawing.Player = _MediaPlayer;
  45:             videoDrawing.Rect = new Rect(0, 0, _MediaPlayer.NaturalVideoWidth, _MediaPlayer.NaturalVideoHeight);
  46:             Rectangle rectangle = new Rectangle();
  47:             rectangle.Height = this.Height;
  48:             rectangle.Width = this.Width;
  49:             Brush brush = new DrawingBrush(videoDrawing);
  50:             rectangle.Fill = brush;
  51:             this.Content = rectangle;
  52:             _MediaPlayer.Play();           
  53:         }
  54:  
  55:         void _MediaPlayer_MediaFailed(object sender, ExceptionEventArgs e)
  56:         {
  57:             MessageBox.Show("Invalid File");
  58:         }
  59:  
  60:         public string Takesnapshot()
  61:         {            
  62:             RenderTargetBitmap renderBitmap = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);
  63:             renderBitmap.Render(this);
  64:             string filename = "Temp" + ".gif";
  65:             FileStream fs = new FileStream(filename, FileMode.Create);
  66:             BitmapEncoder encoder = new GifBitmapEncoder();
  67:             encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
  68:             encoder.Save(fs);
  69:             fs.Close();
  70:             return filename;
  71:         }
  72:     }
  73: }

VideoDrawing draws video to the specified rectangle. Here we have used fixed size rectangle with size 300*300 to show the video from VideoDrawing. We have made drawing brush from video drwaing and used this video drwaing to fill the rectangle. As we have not made VideoDrawing freeze, so it will change its content with time when media player is playing. RenderTargetBitmap Class is used to convert the video container element into a bitmap. Then GifBitmapEncoder is used to encode the bitmap into gif format and then the gif file is saved as temp.gif.

The used XAML for this is in the following:

   1: <Window x:Class="SnapShotUsingMediaPlayer.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:         xmlns:local ="clr-namespace:SnapShotUsingMediaPlayer"
   5:     Title="Window1" Height="500" Width="500">
   6:     <StackPanel>
   7:         <Button FontSize="20"  Margin="0,5,0,0"  HorizontalAlignment="Center" Width="Auto" Name="btnOpenFile" Click="btnOpenFile_Click"  Content="Open Video File"/>
   8:         <Border BorderThickness="2" Margin="0,10,0,0" Height="300" Width="300" BorderBrush="Black">
   9:             <local:MediaPlayerControl x:Name="player" Background="Black"  Width="300" Height="300"  />
  10:             </Border>
  11:         <StackPanel Margin="0,5,0,0"  Orientation="Horizontal" Width="Auto" HorizontalAlignment="Center" VerticalAlignment="Center" >
  12:             <Button FontSize="20" Name="btnTakeSnapShot" Click="btnTakeSnapShot_Click"  Content="Take SnapShot"/>
  13:         </StackPanel>
  14:     </StackPanel>
  15: </Window>

You can download the sample code from here. Hope this will save some of your time.

Internationalization in the web service method of Asp.net

Asp.net internationalization facilitates to adapt an asp.net web site to different languages and regional differences. If we use browser’s language/ culture for internationalization, we only need to set the following line in web.config under system.web : <globalization culture="auto" uiCulture="auto" enableClientBasedCulture="true"/>.

If we use user-preferred language/ culture for internationalization, we have to do more work. As we know, to support Internationalization in an asp.net page, we can override InitializeCulture method. In the override InitializeCulture method, we can change both the Culture and UI culture. However, in the web service method call of asp.net, asp.net does not provide any functionality to override this method or this type of functionality. Another point is we can change the both culture and UI culture when the web service method is invoked but it does not have an effect on the internationalization.

As we know, on every web service call or asp.net page request, BeginRequest event of global.asax is fired before any specific processing. If we change the Culture and UIculture of current thread in the BeginRequest event of global.asax, it affects the Internationalization both in web service method and asp.net page and we can get the desired result. We can write the following code to implement so in global.asax:

   1: void Application_BeginRequest(Object Sender, EventArgs e)
   2:   {
   3:       string culture= string.Empty;
   4:       if (HttpContext.Current.Request.Cookies["language"] != null)
   5:       {
   6:           culture = Request.Cookies.Get("language").Value.ToString();
   7:       }
   8:       else
   9:       {
  10:           culture = "en-US";
  11:       }
  12:       System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture);
  13:       System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(culture);
  14:   }

Changing the CurrentCulture of current thread based on the cookie value will change the number formats, date format according to user-selected culture. As we know, a new resource file is created for each language/culture that the website supports. Then culture wise strings are retrieved by name. Changing the CurrentUICulture of current thread based on the cookie value will select proper resource file according to user-selected culture.

Now the question is how we can get the current culture to set in the BeginRequest event of global.asax. A cookie is a small text that associated with every http request for a particular domain. We can set cookie from both the server side and client side. In the client side, we can keep the culture setting in cookie using JavaScript code and retrieve it from the request object in the BeginRequest event of global.asax. Moreover, When BeginRequest method is invoked, the session object is not initialized that time for this request. Therefore, we cannot keep the culture setting in the session. In client side, you can set the cookie using the following Jquery code: $.cookie('language', prefLanguage). In server side, you can use the following code to set the cookie:

   1: System.Web.HttpCookie aCookie = new System.Web.HttpCookie("language");
   2: aCookie.Value = prefLanguage.ToString();
   3: System.Web.HttpContext.Current.Response.Cookies.Add(aCookie);  

Hope this will save some of your time.

More Posts