Ana içeriğe atla

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

Yorumlar

Bu blogdaki popüler yayınlar

SharePoint 2010 - Content Query for Blog Posts

I hope this post will help many of you feel comfortable with using the Content Query Web Part. In this post I will walk you through the process of creating a content query web part and configuring it to show custom field types. I will also give details on how to use XSLT to stylize and format the data being pulled. I will be using the following scenario as an example. Say that you had a site collection with a top level publishing site. This publishing site would display a the most recent blog posts from all blog sites within its own site collection. To solve this problem we will use a Content Query Web Part and a customized ItemStyle.xsl using XSLT. Please note that the “SharePoint Server Publishing Infrastructure” needs to be enabled at the site collection to display the content query web part. Step 1: Add a Content Query Web Part to Page Navigate to the site that you want the blog posts to show up and click on edit page. Under Editing Tools in the Ribb

.Net 3.5 SP1 – Full Install Packages (Tam Kurulum)

.Net Framework 3.5 SP1 ‘i bilgisayarınıza kurmak istediğinizde normal şartlar altında Microsoft ‘un sitesinde 2.7 mb ‘lik bir dosya indirir ve kurulum işlemlerinizi bu dosya üzerinden yaparsınız. Ancak bu indirmiş oluğunuz dosya yaklaşık 220 mb ‘lik veriyi internetten indirerek kurulum yapmaktadır. İnternet çıkışına izin verilmeyen kurumlar ve kuruluşlar için bu durum bir sıkıntı oluşturmaktadır. Bu sebepten ötürü aşağıdaki link yardımı ile tam yükleme paketini indirdikten sonra hiç internet ihtiyacınız olmadan .Net 3.5 SP1 ‘i kurabilmeniz mümkün olacaktır. Link

Microsoft .Net Framework 3.0 & 3.5 Full Download

.Net ile yazılım geliştiricilerin özelliklede Framework 3.x ile geliştirenlerin başlıca sorunu kurulum dosyası hazırladıklarında .Net Framework ‘ü kurmak için internete bağlanmalarıdır. Çünkü kurulum dosyaları 2-3 MB arasıdır. Yavaş internet kullanıcılarında ve kurumsal şirketlerde projelerin çok ama çok geç kurulmasına sebep olmaktadır. Bu sebepten ötürü sizlere .Net 3.x Framework ‘lerin tam kurulabilir paketlerinin linklerini sizlere sunuyorum. Umarım yararlı olur. Microsoft .NET Framework 3.5 Setup 32-bit version (Boyut(Size): ~200MB Microsoft .NET Framework 3.0 Setup 32-bit Version (Boyut(Size): ~50MB) 64-bit Version (Boyut(Size): ~90MB) Herkese iyi çalışmalar, kolay kurumlar diliyorum. :)