Sain mõni päev tagasi kirja ühelt inimeselt, kes oli näinud minu MIX esitlust ning saanud sellest innustust teha mõned Deep Zoom albumid ja nüüd soovis viia albumid järgmisele tasemele lisades piltide juurde ka selgitavat teksti. Ja tõsi ta on, siia ajaveebi jõuavad ka tellitud teemad… nii, et tellige aga… kui mul vähegi aega ja huvi on, siis genereerin postituse
Projekti ettevalmistamine
Kõigepealt loome Deep Zoom albumi kasutades rakendust Deep Zoom Composer ning paneme piltidele külge kirjeldused ehk tagid. Seda saab teha Compose sammul valides sammu ning sisestades kirjelduse tag kastikesse.
Järgnevalt tuleb see album eksportida Silverlight projektina, kusjuures eksportimisel on oluline pildid eksportida kollektsiooni (Collection), mitte kompositsioonina (Composition). Teise variandiga ekrporditakse vaid üks pilt, esimesega aga kõik pildid eraldi ning seega jääb meil ligipääs igale pildile ning tema metadatale.
Avades selle Silverlight projekti näeme sellist pilti. Sellest projektipuust huvitavad meid sel korral failid Page.xaml, Page.xaml.cs ning Metadata.xml, kus asuvad need meie kirjutatud kirjeldused.
Kõigepealt vaatame Page.xaml faili ning lisame sinna tekstikasti, kus piltide kirjeldusi näidata.
Lõpptulemus võiks olla näiteks selline ja siin element MultiScaleImage x:Name=”msi” on Deep Zoom album.
<UserControl x:Class="DeepZoomProject.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="Auto" Height="Auto" > <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="0.95*"/> <RowDefinition Height="0.05*"/> </Grid.RowDefinitions> <Border Grid.Row="0" BorderBrush="#FF727272"
BorderThickness="1,1,1,1"> <MultiScaleImage x:Name="msi"/> </Border> <TextBlock x:Name="taginfo" Text="Siia tuleb pildi info."
Grid.Row="1" TextWrapping="Wrap"
HorizontalAlignment="Stretch"
FontWeight="Bold"
FontFamily="Portable User Interface"/> </Grid> </UserControl>
See, et sinna loodud tekstikasti näidataks iga pildi tag väärtust koosneb kolmest sammust:
- Kõigepealt on meil vaja teada, milline pilt fookuses on.
- Siis on vaja laadida Metadata.xml fail, sest seal on kirjas iga piltide metainfo.
- Kui me teame, milline pilt on fookuses ja Metadata.xml fail on ka laetud, siis otsime sealt LINQ abil õige tag väärtuse välja.
Milline pilt on fookuses?
Miskipärast on nii, et Silverlight koordinaadid ja DeepZoom rakenduse koordinaadid ei kattu ja seepärast on hetkel fookuses oleva pildi leidmine üks arvutamine ja teisendamine. Samas ratast me leiutama ei pea, sest veebist leiab mitmeid ja mitmeid erinevaid viise kuidas seda arvutada.
Üks arvutusviis on järgnev:
Võttes argumendiks Deep Zoom pildi (MultiScaleImage) ning hiire asukoha, käime läbi kõik alampildid (MultiScaleSubImage) ning kontrollime, kas hiire asukoht kattub mõne pildi (ViewPort) asukohaga. Enne kui me seda teha saame, peame teisendama näidatava deep zoom ruudu (ViewPort) koordinaadid vastavateks koordinaatideks DeepZoom pildi peal ning need koordinaadid omakorda teisendame koordinaatideks Silverlight rakenduse suhtes. Need viimased koordinaadid on samas mõõtkavas, kui hiire koordinaadid ja seega saame kontrollida, kas hiire koordinaadid asuvad ühe Deep Zoom pildi peal. Koordinaatide võrdluseks loome ühe ristküliku, mille koordinaadid vastavad pildi koordinaatidele.
using System.Xml.Linq; using System.IO; using System.Text; using System.Xml;
//Lisada viide järgmistele teekidele:
System.XML;
System.XML.Linq;
System.Linq;
//Põhineb: //http://jimlynn.wordpress.com/2008/10/28/silverlight-deep-zoom-collections-and-hit-testing/
bool GetImageTag(MultiScaleImage aMsi, Point p){ bool gotHit = false; for (int i = 0; i < aMsi.SubImages.Count; i++) { MultiScaleSubImage subimage = aMsi.SubImages[i];
// DeepZoom pildid on jagatud ruutudeks
// järgnev on hetkel kontrollitava ruudu vasaku ülemise nurga koordinaat. // Seda hetkel näidatava pildi suhtes,
// mitte Silverlight rakenduse suhtes,
// ega ka mitte terve Deep Zoom pildi suhtes. Point topLeft = subimage.ViewportOrigin;
//Võttes arvesse zoom taset, //arvutame, kus on selle ruudu vasak ülemine nurk DeepZoom pildi suhtes.
topLeft.X = -(topLeft.X / subimage.ViewportWidth);
topLeft.Y = -(topLeft.Y / subimage.ViewportWidth);
// Tekitatava ruudu kõrgus double width = 1 / subimage.ViewportWidth;
// Tekitatava ruudu laius double height = width / subimage.AspectRatio; // Tekitatava ruudu ülejäänud kaks koordinaati Point bottomright = new Point(topLeft.X + width, topLeft.Y + height); // Meil on olemas ruudu koordinaadid Deep Zoom pildi suhtes,
// teisendame need Silverlight koordinaatideks topLeft = aMsi.LogicalToElementPoint(topLeft);
bottomright = aMsi.LogicalToElementPoint(bottomright); // Kontrollime, kas hiire koordinaadid (p) on meie loodud ruudu sees Rect r = new Rect(topLeft, bottomright); if (r.Contains(p)) { gotHit = true;
// Otsime varem laetud Metadata.xml failist (muutuja metadata) // õige pildi tag väärtuse ning seame selle tekstikasti väärtuseks. List<string> tags = (from image in metadata.Descendants("Image") where int.Parse(image.Element("ZOrder").Value) == i + 1 select image.Element("Tag").Value).ToList(); this.taginfo.Text = tags.First().ToString(); } } return gotHit; }
Laeme Metadata.xml-i
Selleks, et me saaks XML failist infot otsida, tuleb see fail kõigepealt rakendusse laadida:
bool metadataLoaded = false; XDocument metadata = new XDocument(); private void LoadMetadataXML() { WebClient webclient = new WebClient(); webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(MetadataLoaded); webclient.DownloadStringAsync(new Uri("GeneratedImages/Metadata.xml", UriKind.RelativeOrAbsolute)); }
Kui fail on laetud, loeme tema sees oleva XML-i muutujasse metadata.
private void MetadataLoaded(object sender, DownloadStringCompletedEventArgs e) { if (e.Error == null) { string xmlData = e.Result; MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(xmlData)); XmlReader reader = XmlReader.Create(ms); metadata = XDocument.Load(reader); metadataLoaded = true; } }
XML-i laeme kohe rakenduse laadimisel:
void Page_Loaded(object sender, RoutedEventArgs e) { LoadMetadataXML(); }
Nüüd ei olegi muud üle jäänud, kui hiire liigutamisel see meie GetImageTag meetod välja kutsuda:
this.MouseMove += delegate(object sender, MouseEventArgs e) { GetImageTag(msi, e.GetPosition(this.msi)); if (mouseButtonPressed) { mouseIsDragging = true; } this.lastMousePos = e.GetPosition(this.msi); };
Ja ongi valmis, nüüd on meil teada ka lisainfo piltide kohta. Muidugi võiks seda infot kuvada kuidagi palju peenemalt, aga ma mõtlen, et kood võiks siin näidetes võimalikult lihtsaks jääda


