Silverlight 2 sonrasında CLR'a geçiş ve 3 ile gelen yeni özellikler çerçevesinde en sık aldığım sorulardan biri Mikrofon ve Ses kartı erişiminin olup olmadığıydı. Silverlight 4 ile beraber her iki donanıma da doğrudan erişim geliyor. Bu erişim ile çok farklı uygulamalar geliştirmek mümkün, ister görüntülü chat sistemleri, ister Silverlight içerisinde doğrudan harici bir görüntü kaynağından gelen görüntüyü proses eden barkod okuma uygulamaları olsun çok ilginç çözümler geliştirilebilir. Biz bu yazımızda Silverlight 4 Beta içerisinden kamera erişimine göz atacağız ve kamera görüntüsünden de bir kare almaya çalışacağız. Aldığınız fotoğrafı sonrasında ister sunucuya gönderebilir ister doğrudan kullanıcıya verebilirsiniz.
Kamera'ya nasıl ulaşırız?
Silverlight içerisinden sistemde bulunan tüm kameraların bir listesini alabilir ve özelliklerine göre kamera seçebilirsiniz. Hatta söz konusu kameraların tek tek hangi çözünürlüklerde ve kalitede kayıt sağlayabileceğini de bulabilirsiniz.
[VB]
Partial Public Class MainPage
Inherits UserControl
Public Sub New()
InitializeComponent()
End Sub
Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim Kameralar = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices
Dim Liste = From inc In Kameralar
From formats In inc.SupportedFormats
Select New Kamera With {.Adi = inc.FriendlyName,
.Format = formats.FramesPerSecond & "fps," &
formats.Width & "x" & formats.Height,
.Varsayilan = inc.IsDefaultDevice}
myGrid.ItemsSource = Liste
Public Class Kamera
Property Adi As String
Property Format As String
Property Varsayilan As Boolean
End Class
Yukarıdaki örnek uygulamada ekran bir DataGrid bulunuyor. Bu gride CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices ile aldığımız tüm kameraları SupportedFormats dizilerindeki sağladıkları çözünürlüklerle beraber joinleyerek aktarıyoruz. Benim test makinemde tek kamera olduğu için aşağıdaki ekran görüntüsü ile karşılaştım.
Webcam'in desteklediğini ayarlar.
Peki istediğimiz webcamden görüntüyü alıp nasıl gösterebiliriz?
İlk olarak kullanıcıdan izin almamız gerek. Eğer kullanıcı webcam erişimine izin vermez ise hiçbirşey yapamayız. Session bazında saklanan bu izni kullanıcıdan istemek için kullanacağımız metodun adı RequestDeviceAccess şeklinde.
Dim IzinVarMi = CaptureDeviceConfiguration.AllowedDeviceAccess
If Not IzinVarMi Then IzinVarMi = CaptureDeviceConfiguration.RequestDeviceAccess
Yukarıdaki ilk satırda AllowedDeviceAccess ile ilk olarak o anda iznimiz var mı yoksa yok mu konusunu kontrol ediyoruz. Eğer iznimiz varsa tekrar kullanıcıdan izin istemek saçma olur. Eğer yoksa hemen bir alt satırda RequestDeviceAccess ile iznimizi istiyoruz.
Kullanıcıdan kameraya bağlanma izni istiyoruz.
İznimizi aldıktan sonra rahatlık istediğimiz bir Device'ı seçerek cihazdan veri kaynağını alabiliriz. Sistemde farklı mikrofon ve kameralar olabileceği için bunların kompinasyonundan bir CaptureSource yaratabiliyorsunuz. Bizim örneğimizde sadece kameraya ulaşacağımız için yaratacağımız CaptureSource'un sadece VideoCaptureDevice özelliğini set edeceğiz.
Dim Cihaz = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice
Dim Kaynak As New CaptureSource
Kaynak.VideoCaptureDevice = Cihaz
Tüm bu ayarları yaptıktan sonra sıra geliyor görüntü alma işlemini başlatmaya ve alacağımız görüntüyü de bir yerlerde göstermeye. Bunun için herhangi bir kontrolü kullanabilirsiniz çünkü görüntüyü bir VideoBrush aracılığı ile alacağız ve bildiğiniz üzere VideoBrush'ları da istediğimiz herhangi bir SL kontrolünde normal renk fırçaları gibi kullanabiliyoruz.
Dim Firca As New VideoBrush
Firca.SetSource(Kaynak)
Kaynak.Start()
Dikdortgen.Fill = Firca
Yukarıdaki kodumuzda VideoBrush'ımızı yaratarak Source olarak eldeki CaptureSource'u veriyoruz. Sonrasında CaptureSource üzerinden görüntü veya ses yakalama işlemini başlatmak için Start metodunu çağırmayı unutmamak gerek. En son olarak da eldeki VideoBrush'a adı Dikdortgen olarak bir Rectangle'a basit bir şekilde aktarabiliriz.
Kamera görüntüsü karşınızda.
Yukarıda gördüğünüz üzere kamera görüntüsünü almakla kalmayıp Silverlight'taki Transformasyon ve PixelShader özelliklerini de rahatlıkla bu görüntüler üzerine uygulayabiliyoruz. Uygulamanın tam kodlarını aşağıda bulabilirsiniz.
Private Sub btnTikla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTikla.Click
If IzinVarMi Then
Golge.Fill = Firca
End If
[XAML]
<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightApplication25.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Canvas x:Name="LayoutRoot" Background="White">
<Rectangle x:Name="Dikdortgen" Height="168" Width="249" Canvas.Left="20" Canvas.Top="19">
<Rectangle.Effect>
<BlurEffect Radius="15"/>
</Rectangle.Effect>
</Rectangle>
<Button x:Name="btnTikla" Content="BAŞLAT" Height="25" Width="100" Canvas.Left="300" Canvas.Top="275" />
<Rectangle x:Name="Golge" Height="67" Canvas.Left="27.207" Canvas.Top="191" Width="249" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">
<Rectangle.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Transparent" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Rectangle.OpacityMask>
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" ScaleX="1"/>
<SkewTransform AngleY="0" AngleX="52.651"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="36.69"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Canvas>
</UserControl>
Kameradan fotoğrafı nasıl yakalarız?
Kameranın görüntüsünden fotoğraf yakalayabilmeniz için hazır bir API doğrudan CaptureSource nesnesi üzerinden sunuluyor. Ama sunulan API'ın birkaç ufak sorunu var. Birincisi eğer yukarıdaki gibi görüntüye bir PixelShader eklediyseniz veya üzerine birşeyler bindirdiyseniz maalesef bunların hiçbiri aldığınız fotoğrafta yer almayacaktır. İkincisi ile eğer CaptureSource durdurulmuş ise son gelen kareyi alma şansınız olmuyor. Gelin yine de ilk önce bu API'ye bir göz atalım sonra da istersek daha farklı bir yöntem olarak ne uygulayabiliriz ona bakarız.
Private Sub btnTikla2_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTikla2.Click
If Kaynak IsNot Nothing Then
Kaynak.AsyncCaptureImage(Sub(Foto)
Dispatcher.BeginInvoke(Sub()
imgFoto.Source = Foto
End Sub)
Yukarıdaki kod içerisinde Kaynak olarak geçen nesne bizim bir önceki örneğimizde başlattığımız CaptureSource nesnesi. Bu nesneyi UserControl içerisinde tanımlayarak farklı eventlarda kullanılabilir hale getirdikten sonra fotoğraf çekme işlemini yapacak düğmede nesnenin varlığını kontrol ederek işleme devam ediyoruz. CaptureSource üzerinden AsyncCaptureImage metodunu çağırdığınızda fotoğraf alma işlemini yaparak bir Callback'e düşüyor. Bu Callback'den geri veri döndürebilmek ve sahneye yeni koyduğumuz imgFoto adındaki Image nesnesine source aktarabilmek adına Dispatcher üzerinden UI Thread'e ulaşıyoruz. Tüm bunları lamdalarla yapınca iş epey kolayca halloluyor.
Fotoğrafımızı yakalayap sağa koyduk.
Gördüğünüz gibi aldığımız görüntü ana kaynaktan olduğu için Blur efekti vs uygulanmış değil. Oysa orta kısımda gördüğümüzün tam aynısını almak isterdi gönül. İşte böyle bir durumda doğrudan Silverlight 3 ile gelen WriteableBitmap sınıfını kullanabiliriz.
Dim Goruntu As New Imaging.WriteableBitmap(Dikdortgen, Nothing)
imgFoto.Source = Goruntu
Kodumuzda WriteableBitmap yaratırken ekranda hedef nesne olarak da Rectangle tipindeki Dikdortgen'imizi veriyoruz. Böylece Blur vs efektleri uygulanmış hali ile görüntüyü alabiliyoruz.
PixelShader efekti ile görüntüyü aldık.
Artık aldığınız bu fotoğrafları işlemek veya doğrudan sunucuya bir web servisi aracılığı ile göndermek vs tamamen size kalmış. Hepinize kolay gelsin.