Makale Özeti

Bu yazımızda Silvelright 3.0 içerisinde dinamik bitmap yaratmak için kullanılabilecek WriteableBitmap nesnesini inceliyoruz.

Makale

Silverlight içerisinde tamamen kod ile çizim yapmanın ötesinde bazı durumlarda sıfırdan bir Bitmap oluşturmak da isteyebilirsiniz. Bazı durumlarda ise belki de elinizde var olan bir Bitmap nesnesini değiştirmek isteyebilirsiniz. Bu gibi durumlarda Silverlight 2.0 içerisinde derdimize derman olabilecek hazır bir API gelmezken artık Silverlight 3.0 içerisinde WriteableBitmap nesnesi bulunuyor. WriteableBitmap ile beraber istediğimiz Bitmap'i sıfırdan kod ile yaratabiliyoruz. Hatta bununla kalmayıp çok güzel şeyler de yapılabiliyor ama tüm bu güzel şeyleri görebilmek için biraz daha makeleyi okumaya devam etmeniz gerekecek :)

Hadi sıfırdan Bitmap yaratalım?

Sıfırdan bir Bitmap yaratmak demek aslında bir resim veya fotoğraf yaratırken her bir pikselde yer alacak renge karar vermek demektir. Bununla ilgili kullanabileceğiniz çok ilginç algoritmalar oluşturabilirsiniz. (Mandelbrot :)) Örneğin Quake1 zamanında 3D bir oyun olarak gözükse de özünde bu şekilde ekrana Bitmap'ler pompalayan bir yapıdan farklı bir mimarisi yoktu. Neyse konumuza dönelim ve bakalım biz kendi bitmapimizi nasıl yaratabileceğiz.

[XAML]

    <Grid x:Name="LayoutRoot" Background="White">

        <Image

           x:Name="imgFoto" />

    </Grid>

Yukarıdaki şekli ile basit bir Image nesnesini Silverlight uygulamamızın sahnesine yerleştiriyoruz. Bundan sonraki kodlarımızda söz konusu nesnenin içerisine farklı Bitmap'ler oluşturarak yerleştireceğiz.

[VB]

        Dim bitmap As New Imaging.WriteableBitmap(100, 100, Media.PixelFormats.Bgr32)

[C#]

            System.Windows.Media.Imaging.WriteableBitmap bitmap =

                new System.Windows.Media.Imaging.WriteableBitmap(100, 100,

                    System.Windows.Media.PixelFormats.Bgr32);

WriteableBitmap nesnesini yaratırken oluşturacağımız Bitmap'in genişlik ve yükseklik değerlerinin yanı sıra bir de Piksel formatını tanımlıyoruz. Bu aşamada iki seçenek söz konusu. Eğer Bgr32 kullanırsanız resminizde R (Red), G (Green) ve B (Blue) kanalları yer alacaktır. Eğer Pbgra32 kullanırsanız RGB'ye ek olarak bir de Alpha (şeffaflık) kanalı kullanabilirsiniz. Yani özünde eğer oluşturacağınız resmin şeffaflığı olacak ise Pbgra32, olmayacaksa Bgr32 kullanmanız uygun olacaktır.

[VB]

        bitmap.Lock()

Lock ve Unlock metodlarını Bitmap yaratma işleminin başında ve sonunda kullanacağız. Bu metodların amacı Bitmap yaratılırken veya değiştirilirken söz konusu değişikliklerin görsel olarak ekrana yansımasını engellemek. Lock işlemini de yaptığımıza göre artık yavaş yavaş çizimimizi yapmaya başlayalım.

[VB]

        For y As Integer = 0 To 99

            For x As Integer = 0 To 99

                Dim renkler(3) As Byte

                renkler(0) = x 'B (Mavi)

                renkler(1) = x 'G (Yeşil)

                renkler(2) = y 'R (Kırmızı)

                bitmap((x * 100) + y) = BitConverter.ToInt32(renkler, 0)

            Next

        Next

[C#]

            for (int y = 0; y <= 99; y++)

            {

                for (int x = 0; x <= 99; x++)

                {

                    byte[] renkler = new byte[4];

                    renkler[0] = (byte)x; //B (Mavi)

                    renkler[1] = (byte)x; //G (Yeşil)

                    renkler[2] = (byte)y; //R (Kırmızı)

                    bitmap[(x * 100) + y] = BitConverter.ToInt32(renkler, 0);

                }

            }

WriteableBitmap içerisinde herhangi bir piksele ulaşmak gerçekten çok kolay. Ulaşmak istediğiniz bir pikselin indeks numarasını doğrudan bitmap(0) şeklinde vererek söz konusu piksele ulaşabiliyorsunuz. Indeks numarası sürekli soldan sağa giderek satır bittiğinde de bir alt satıra geçerek devam ediyor. Böylece iç içe iki döngü kullanarak rahatlıkla tüm pikselleri gezebiliyoruz. Piksellere renk atama işlemini yaparken üçlü bir byte yaratıp 255 üzerinden RGB değerlerini verip sonra da Byte'ımızı Int32'ye çevirip Bitmap'imize atıyoruz. Şimdilik örneğimizde döngülerden değerler alıp kullandık ki her seferinde biraz daha farklı bir renk yaratılsın.

[VB]

        bitmap.Invalidate()

        bitmap.Unlock()

        imgFoto.Source = bitmap

Son olarak Invalidate metodu ile verdiğimiz değerlerden Bitmap'in çizilmesini ve Unlock ile de gösterilebilir olmasını sağladıktan sonra XAML içerisinde tanımladığımız Image nesnesine kaynak olarak atıyoruz.

Yarattığımız Bitmap karşımızda!
Yarattığımız Bitmap karşımızda!

Yukarıdaki görselde gördüğünüz Bitmap'i tamamen kendi kodumuz ile yaratmış olduk. Bu şekilde Bitmap yaratma proseslerini Multithread olarak çalıştırarak farklı animasyonlar yapmak da mümkün.

Başka başka?

WriteableBitmap'in bir diğer özelliği ise ekrandaki herhangi bir Silverlight elementinin görselliğini alabiliyor olması. Böylece belki de ekranda gösterdiğiniz bir Grid'in görselliğini resim olarak alabilir veya belki de oynattığınız bir videonun o anki karesini yakalayabilirsiniz. Tüm bunları WriteableBitmap ile yapmak gerçekten çok kolay.

[XAML]

<UserControl

   x:Class="SilverlightApplication26.MainPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400"

   Height="300">

    <Grid

       x:Name="LayoutRoot"

       Background="White">

        <Image

           Height="100"

           HorizontalAlignment="Left"

           VerticalAlignment="Top"

           Source="Flower.jpg"

           Width="100"

           x:Name="imgFoto" />

        <Image

           Height="100"

           HorizontalAlignment="Right"

           VerticalAlignment="Top"

           Width="100"

           x:Name="imgFoto2" />

    </Grid>

</UserControl>

Yukarıdaki gibi iki adet Image kontrolümüzün olduğu bir uygulama düşünelim. Image'lardan birinde Flower.jpg adındaki dosya gösterilirken diğeri ise boş. Biz kodumuz ile bir Image kontrolündeki görselliği alıp diğerine kaynak olarak vereceğiz.

[VB]

        Dim bitmap As New Imaging.WriteableBitmap(100, 100, PixelFormats.Pbgra32)

        bitmap.Render(imgFoto, imgFoto.RenderTransform)

        imgFoto2.Source = bitmap

[C#]

               System.Windows.Media.Imaging.WriteableBitmap bitmap =

                   new System.Windows.Media.Imaging.WriteableBitmap(100, 100, PixelFormats.Pbgra32);

                bitmap.Render(imgFoto, imgFoto.RenderTransform);

                imgFoto2.Source = bitmap;

Gördüğünüz gibi WriteableBitmap nesnemizi her zamanki gibi yarattıktan sonra tek yaptığımız Render metodunu çağırmak. Render metodu ilk olarak görselliği alacağı Silverlight elementinin adını istiyor. İkinci parametre ise söz konusu kontrole uygulanmış olan RenderTransform özellikleri. Böylece Render işlemi esnasında tam olarak doğru koordinatlar yakalanabiliyor. Sonrasında elimizdeki bitmap'i başka bir Image nesnesine kaynak olarak verebiliyoruz. Bu işlemi belirli aralıkla yaparsanız kabaca WPF'teki VisualBrush efektini elde etmeniz de mümkün.

Hepinize kolay gelsin.