Silverlight 2.0 - DeepZoom Teknolojisi

Windows Presentation Foundation ile yapılmış ilk örnekleri incelerken kütüphaneler için yapılmış uygulamalar ve kullanılan teknikler bizleri oldukça şaşırtmıştı. Kütüphanelerde yer alan kitaplar çok yüksek çözünürlüklerle tarandıktan sonra kitap haline getirilerek kullanıma sunuluyordu. Fakat ufak bir detay dikkatimizi çekmekteydi. Bu da gözükecek olan resimlerin tamamı net değildi. Yalnızca yakınlaştırılan nokta netleşiyor, diğer noktalar ise bulanık kalmaya devam ediyordu. Bu yöntem sayesinde o çok büyük boyutlu resmin tamamının gösterilmesi için gerekli zaman beklenilmesi yerine kullanıcının istediği nokta netleştirilerek daha hızlı işlem yapılması sağlanmaktaydı.

Zaman ilerledikçe bu tür uygulamaları Silverlight ile de yapıldığını gördük. Fakat 1.x sürümü ile yapılan uygulamalarda çok uzun satırlarca JavaScript kodu yazılması gerektiÄŸi için geliÅŸtiricilerin tercih sıralamasında geride kalıyordu. Silverlight ‘ın 2.0 sürümüne iliÅŸkin çalışmalarda bu güzel özelliÄŸin kullanıcılar ve geliÅŸtiriciler tarafında çok beÄŸenildiÄŸinin fakat geliÅŸtirme kısmına gelindiÄŸinde zorluklarından ötürü kaçınıldığının farkına varılmıştır. Bu düşünce sonucunda ise ek yazılımlar yardımı ile geliÅŸtiricilere yardım edilmesine olanak tanınmak istenmiÅŸtir.

Bu yazımızda Silverlight 2.0 ile gelen yeni özelliklerden birisi olan DeepZoom ‘u inceliyor olacağız. DeepZoom teknolojisi internet üzerinde gösterilmesi zor olabilecek çok büyük çözünürlükteki resimleri alıp o anda ekranda görebileceÄŸiniz kadarını netleÅŸtirerek gösteriyor, teknik olarak bunu da resimleri parçalara ayırarak ve farklı çözünürlüklerde kaydederek yapıyor, böylelikle bir son kullanıcı rahatlıkla 2-3 GB’lık resimleri bile tek bir ekranda görüntüleyebiliyor. Özellikle HD FotoÄŸraflar ile birlikte bu teknolojinin daha fazla artacaktır.

DeepZoom fikrinin ortaya atılmasını saÄŸlayan proje SeaDragon projesidir. Bu proje esnasında kullanılan tekniklerin tamamına yakını DeepZoom uygulamasında da kullanılmaktadır. Peki, DeepZoom ‘u nasıl elde edebiliriz. Microsoft ‘un web sayfası yardımı ile
bu linkten
indirilmesi mümkündür. 4.4 mb ‘lik bir kurulum dosyası indikten sonra bilgisayarımıza kurulum yapıyoruz. Kurulumdan sonraki ilk ekranda karşımıza aÅŸağıdaki gibi bir ekran gelmektedir.



Kullanım ekranı Expression Blend ‘e oldukça fazla benzemektedir. Uygulamamızı oluÅŸturmaya yeni bir proje oluÅŸtur seçeneÄŸine tıkladıktan sonra karşımıza çıkacak olan ekrana tamam diyerek baÅŸlıyoruz.

Uygulamamızı nasıl oluÅŸturacağımıza deÄŸinmeden önce DeepZoom ‘un kullandığı mantığı birde görüntüsel olarak incelersek daha mantıklı olacaktır. DeepZoom büyük bir resmin küçük bir parçasını net olarak kullanıcıya sunarken diÄŸer kısımları sistemi yavaÅŸlatmamak için net olarak göstermemektedir.


Resimden de dikkat edeceğiniz üzere büyük boyutlu bir tamamı ama daha küçük bir biçimde gösterilmektedir. Kullanıcı resmi kendisine yaklaştırdıkça odak noktası dışındaki noktalarda netleşerek büyük boyuttaki resmin netliğine kavuşacaktır.

DeepZoom ‘un çalışma mantığı ile ilgili bu ufak bilgiyi de edindikten sonra uygulama geliÅŸtirmeye devam edebiliriz. Åžimdi yapmamız gereken yakınlaÅŸtırıp uzaklaÅŸtıracak olduÄŸumuz resimleri uygulamamıza eklemek olacaktır.



Resimleri çalışmamıza ekledikten sonraki görüntü aşağıdaki gibi olacaktır.



Şimdi yapacağımız işlem ise arka plan olarak bir resmi seçtikten sonra onun üzerine diğer resimleri eklemek olacaktır. Bu işlem için Compose menüsünün kullanılması gerekmektedir.



Ekranımızda Layer View yazan bölümde ekranda yer alan resimlerimizin görünüp görünmemesini gibi özelliklerini ayarlayabiliyoruz.

Bunda sonra yapacağımız işlem ise uygulamanın yayınlanabilir duruma getirilmesi olacaktır. Export menüsüne tıkladıktan sonra karşımıza çıkan ekranda gerekli olan özellikler yer almaktadır.



Export butonuna tıkladığımız zaman ise uygulamamız hazır duruma gelmiş olacaktır. Uygulamayı kullanabileceğimiz seçenekler yayınlama işleminin hemen sonrasında bizlere sunulmaktadır.



Web uygulaması ile göster dediğimizde ise karşımıza oldukça iyi bir uygulama çıkacaktır.












Eğer ki Flash animasyon tamamlanmışsa üzerinde sağa tıkladıktan sonra play seçeneğini seçtiğiniz zaman yeniden görüntüleyebilmeniz mümkündür.

Uygulamamızın çalışması tam istediÄŸimiz gibi görünüyor. Ama kafamıza takılan birkaç soru var. “Uygulamanın çalışmasını saÄŸlayan dosyanın içerisinde neler var?” , ”Hangi kodlar arka planda oluÅŸmuÅŸ?” Bu soruların cevapları için ilk olarak uygulanın oluÅŸturulduÄŸu klasöre gitmemiz gerekmektedir. DeepZoom uygulamalarını
C:\Users\Turhal\Documents\Expression\Deep Zoom Composer Projects yolundaki klâsöre oluşturmaktadır. Biz uygulamamızı bulabilmek için bu dizin içerisinden kendi projemizi bularak sonrasında
source images isimli klasörün içerisine bakarak oluşturulan proje dosyalarını ve resimleri bulabilmemiz mümkündür.



Eğer ki uygulamamızın kod tarafında bir değişiklik yapmak istersek DeepZoomProject klasörünü kullanabilir. Web tarafında kullanmamız gereken dosyalar için ise
DeepZoomProjectWeb klasörü isteklerimizi karşılamaya yetecektir.

Kod tarafında nelerin oluşturulduğuna göz atalım şimdide. İlk olarak projemizde resimleri görüntüleyebildiğimiz
Page.XAML dosyasının içerisindeki kodlara göz atıyoruz.

Açtığımız anda dikkatimizi çeken şey Silverlight 2.0 ile gelen MultiScaleImage nesnesinin kullanıldığına ve çağırılan resimlerin bu nesne ile oluşturulan alanın içerisinde gözükmesi sağlandığını görürüz.


Uygulamamızda gösterilen ekranın kod tarafında oluÅŸturulan C# kodlarına göz atarsak…

C#


using System;
using System.Collections.Generic;
using
System.Linq;
using System.Net;
using System.Windows;
using
System.Windows.Controls;
using System.Windows.Documents;
using
System.Windows.Input;
using System.Windows.Media;
using
System.Windows.Media.Animation;
using System.Windows.Shapes;


namespace DeepZoomProject
{
    public partial class Page : UserControl

   
{

        Point lastMousePos = new Point();

        double _zoom = 1;
        bool
mouseButtonPressed = false;
        bool mouseIsDragging = false;
        Point
dragOffset;
        Point currentPosition;

        public double ZoomFactor
        {

           
get { return _zoom; }
            set { _zoom = value; }
        }

        public Page()

       
{
            InitializeComponent();

            //
            // Blend yardımcı ile XAML
özellikler oluşturuluyor.
            //
            this.msi.Source = new
DeepZoomImageTileSource(new Uri("GeneratedImages/dzc_output.xml", UriKind.Relative));


            //
            // MultiScaleImage yükleniyor
            //
            this.msi.Loaded += new
RoutedEventHandler(msi_Loaded);

            //
            // MultiScaleImage yüklendikten
sonra diğer bütün resimler yüklenmeye başlıyor
            //
            this.msi.ImageOpenSucceeded
+= new RoutedEventHandler(msi_ImageOpenSucceeded);

            //
            // Klavyeden
basılan tuşları algılıyor.
            //
            this.MouseMove += delegate(object sender,
MouseEventArgs e)
            {
                if (mouseButtonPressed)
                {
                    mouseIsDragging =
true;
                }
                this.lastMousePos = e.GetPosition(this.msi);
            };

            this.MouseLeftButtonDown
+= delegate(object sender, MouseButtonEventArgs e)
            {

               
mouseButtonPressed = true;
                mouseIsDragging = false;
                dragOffset = e.GetPosition(this);

               
currentPosition = msi.ViewportOrigin;
            };

            this.msi.MouseLeave +=
delegate(object sender, MouseEventArgs e)
            {
                mouseIsDragging = false;

           
};

            this.MouseLeftButtonUp += delegate(object sender,
MouseButtonEventArgs e)
            {
                mouseButtonPressed = false;
                if (mouseIsDragging
== false)
                {
                    bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift)
== ModifierKeys.Shift;

                    ZoomFactor = 2.0;
                    if (shiftDown) ZoomFactor
= 0.5;
                    Zoom(ZoomFactor, this.lastMousePos);
                }
                mouseIsDragging =
false;
            };

            this.MouseMove += delegate(object sender, MouseEventArgs
e)
            {
                if (mouseIsDragging)
                {
                    Point newOrigin = new Point();

                   
newOrigin.X = currentPosition.X - (((e.GetPosition(msi).X - dragOffset.X) /
msi.ActualWidth) * msi.ViewportWidth);
                    newOrigin.Y = currentPosition.Y -
(((e.GetPosition(msi).Y - dragOffset.Y) / msi.ActualHeight) * msi.ViewportWidth);

                   
msi.ViewportOrigin = newOrigin;
                }
            };

            new MouseWheelHelper(this).Moved
+= delegate(object sender, MouseWheelEventArgs e)
            {
                e.Handled = true;

               
if (e.Delta > 0)
                    ZoomFactor = 1.2;
                else
                    ZoomFactor = .80;


                   
Zoom(ZoomFactor, this.lastMousePos);
            };
        }

        void msi_ImageOpenSucceeded(object
sender, RoutedEventArgs e)
        {
        }

        void msi_Loaded(object sender,
RoutedEventArgs e)
        {
            Zoom(.5, new Point(this.ActualWidth / 2, this.ActualHeight
/ 2));
        }

        public void Zoom(double zoom, Point pointToZoom)
        {

           
Point logicalPoint = this.msi.ElementToLogicalPoint(pointToZoom);
            this.msi.ZoomAboutLogicalPoint(zoom,
logicalPoint.X, logicalPoint.Y);
        }


    }
}



Şeklinde oluşturulduğunu görürüz. Yukarıdaki kod bloğunda bizleri dikkatini çeken bölüm farenin hareketi sonucunda görüntünün nasıl hareket ettiği bloktur
C#



this.MouseMove += delegate(object sender, MouseEventArgs e)
{
   
if (mouseIsDragging)
        {
           
Point newOrigin = new Point();
           
newOrigin.X = currentPosition.X - (((e.GetPosition(msi).X - dragOffset.X) /
msi.ActualWidth) * msi.ViewportWidth);
           
newOrigin.Y = currentPosition.Y - (((e.GetPosition(msi).Y - dragOffset.Y) /
msi.ActualHeight) * msi.ViewportWidth);
           
msi.ViewportOrigin = newOrigin;
       
}
};


Yukarıdaki kod bloğunda ekran üzerindeki son pozisyonu alındıktan sonra fare ile sürüklenen, yakınlaştırılan değerleri alınarak yeni değerlere atanıyor. Sonrasında ise ekran üzerindeki yeni yeri belirlenebiliyor.

Projemizde oluşturulan kod bloklarından biride Farenin sürükleme topu ile yapılmış işlemlerin nasıl algılanacağına ait sınıftır.

C#


using System;
using System.Net;
using System.Windows;

using System.Windows.Controls;
using System.Windows.Documents;
using
System.Windows.Ink;
using System.Windows.Input;
using
System.Windows.Media;
using System.Windows.Media.Animation;
using
System.Windows.Shapes;
using System.Windows.Browser;

namespace
DeepZoomProject
{
    // Courtesy of Pete Blois
    public class
MouseWheelEventArgs : EventArgs
    {
        private double delta;
        private
bool handled = false;

        public MouseWheelEventArgs(double delta)
        {

           
this.delta = delta;
        }

        public double Delta
        {
            get { return
this.delta; }
        }

        // Use handled to prevent the default browser
behavior!
        public bool Handled
        {
            get { return this.handled; }
            set
{ this.handled = value; }
        }
    }

    public class MouseWheelHelper

   
{

        public event EventHandler<MouseWheelEventArgs> Moved;
        private
static Worker worker;
        private bool isMouseOver = false;

        public
MouseWheelHelper(FrameworkElement element)
        {

            if (MouseWheelHelper.worker
== null)
            MouseWheelHelper.worker = new Worker();
            MouseWheelHelper.worker.Moved
+= this.HandleMouseWheel;
            element.MouseEnter += this.HandleMouseEnter;

           
element.MouseLeave += this.HandleMouseLeave;
            element.MouseMove += this.HandleMouseMove;

       
}

        private void HandleMouseWheel(object sender, MouseWheelEventArgs
args)
        {
            if (this.isMouseOver)
            this.Moved(this, args);
        }


       
private void HandleMouseEnter(object sender, EventArgs e)
        {
            this.isMouseOver
= true;
        }

        private void HandleMouseLeave(object sender, EventArgs
e)
        {
            this.isMouseOver = false;
        }

        private void
HandleMouseMove(object sender, EventArgs e)
        {
            this.isMouseOver = true;

       
}

        private class Worker
        {
            public event EventHandler<MouseWheelEventArgs>
Moved;
           

            public Worker()
            {

                if (HtmlPage.IsEnabled)
                {

                   
HtmlPage.Window.AttachEvent("DOMMouseScroll", this.HandleMouseWheel);

                   
HtmlPage.Window.AttachEvent("onmousewheel", this.HandleMouseWheel);

                   
HtmlPage.Document.AttachEvent("onmousewheel", this.HandleMouseWheel);
                }


            }

            private void HandleMouseWheel(object sender, HtmlEventArgs args)

           
{
                double delta = 0;

                ScriptObject eventObj = args.EventObject;


                if (eventObj.GetProperty("wheelDelta") != null)
                {
                    delta = ((double)eventObj.GetProperty("wheelDelta"))
/ 120;

                    if (HtmlPage.Window.GetProperty("opera") != null)
                    delta
= -delta;
                }
                else if (eventObj.GetProperty("detail") != null)
                {

                   
delta = -((double)eventObj.GetProperty("detail")) / 3;

                    if (HtmlPage.BrowserInformation.UserAgent.IndexOf("Macintosh")
!= -1)
                    delta = delta * 3;
                }

                if (delta != 0 && this.Moved !=
null)
                {
                    MouseWheelEventArgs wheelArgs = new MouseWheelEventArgs(delta);

                   
this.Moved(this, wheelArgs);

                    if (wheelArgs.Handled)
                    args.PreventDefault();

               
}
            }
        }
    }
}

Bu sınıfta ise farenin kaydırma topu ile yapılan hareketleri algılayarak uygulamamıza ait sınıfın içerisinde oluşturulan yakınlaştırma ve uzaklaştırma ile ilgili kod bloğunda kullanılmaktadır.

Sonuç olarak Silverlight 2.0 ‘ın yeni özelliklerinden olan DeepZoom ‘u incelemeye çalıştık. Çok büyük boyutlardaki resimleri web uygulamalarında tamamını göstermek yerine yaklaÅŸtırdıkça belirli alanlarını göstererek performansı nasıl arttırabileceÄŸimize deÄŸinmeye çalıştık.

Bir sonraki Silverlight makalemizde ise MultiScaleImage kontrolü otomatik olarak değilde kendimiz kullanarak uygulama geliştirmek istersek nasıl yapabileceğimize değinmeye çalışacağız.

Umarım yararlı olmuştur.
turhal.temizer@csharpnedir.com

Yorum Gönder

0 Yorumlar

Ad Code

Responsive Advertisement