Cet article a fait l'objet d'une traduction automatique.
Code malveillant
En prenant complètement Silverlight Zoom niveau pour le suivant
Jeff Prosise
Contenu
Correction Panorama logique de composer
Accès Sub-Images et métadonnées
Dynamique Deep Zoom : Insertion image pixels au moment de l'exécution
DeepZoomTools.dll
Une fois que Silverlight Deep Zoom a été introduite dans le monde à MIX 2008, la grande nouvelle entourent rendue persistante pour semaines.Un outgrowth du projet Seadragon àMicrosoft Live LabsDeep Zoom est une adaptation de Silverlight d'une technologie de présentation de grandes quantités de données images aux utilisateurs de manière très efficace de la bande passante.Adaptations sister qui ciblent Windows Mobile et AJAX sont disponibles et servent à augmenter la portée de la plate-forme.
Si vous n'avez pas lu Deep Zoom avant, supprimez ce que vous faites et visitez le site Deep Zoom canonique à memorabilia.hardrock.com.Utilisez la souris pour effectuer un panoramique autour de la scène et la roulette de la souris pour effectuer un zoom avant et arrière.Grâce à Deep Zoom, vous ne devez télécharger gigaoctets (ou téraoctets) d'imagerie pour parcourir memorabilia grande collection de Coffee Hard Rock.Deep Zoom télécharge uniquement les pixels que nécessaires à la résolution dont il a besoin et dans Silverlight, la complexité de Deep Zoom est masquée derrière un contrôle remarquable nommé MultiScaleImage.Une fois qu'une scène Deep Zoom est composée (généralement avec Deep Zoom Composer, que vous pouvez télécharger gratuitement à partir de go.microsoft.com/fwlink/?LinkId=148861), présentation de la scène dans un navigateur requiert peu plus de déclarer un contrôle MultiScaleImage et pointez sur la propriété du contrôle source sortie de Deep Zoom Composer.Prise en charge interactive de panoramique et zoom nécessite un peu code de gestion de la souris qui interagit avec le contrôle, mais ces jours que Deep Zoom Composer même fournira que pour vous.
Malgré la facilité avec laquelle une application Deep Zoom base peut être créée, vous êtes manquant sortie sur la richesse de Deep Zoom la valeur true si vous allez non plus que Deep Zoom Composer permet d'accéder.Saviez-vous que, par exemple, que vous pouvez manipuler par programme les images dans une scène Deep Zoom, que vous pouvez créer des métadonnées et associer à chaque image, ou que les images Deep Zoom peuvent provenir d'une base de données ou être composé à la volée ?Certaines des remarquables réellement Deep Zoom applications existent reposent sur une fonctionnalité peu connue de Deep Zoom qui ajoute une nouvelle dimension à la plate-forme.
Si vous souhaitez prendre Silverlight Deep Zoom au niveau supérieur, Voici trois méthodes pour ce faire il vous suffit.
Correction Panorama logique de composer
Premières choses premier : Si vous souhaitez optimiser l'utilisation de Deep Zoom, la première chose à connaître est ne pas d'approuver le code de gestion de la souris émis par Deep Zoom Composer.Le code qui ont autour de la scène en réponse aux événements MouseMove "perd" la souris si vous effectuer un panoramique trop rapidement.Essayez-le.Prendre n'importe quelle application Deep Zoom créée par Deep Zoom Composer et positionnez le curseur sur un point identifiable ou pixels dans la scène.Puis déplacez la souris rapidement et inversement haut et vers le bas plusieurs fois.Notez que lorsque vous arrêtez la scène springs à la position de curseur, le curseur n'est plus situé au point qu'il était lorsque vous avez démarré.Plus les plus rapides vous déplacez, plue la différence.Il n'est pas un séparateur, mais essayez de la même expérience sur le site Hard Rock Memorabilia et vous trouverez que la scène fiable s'aligne sur la position du curseur d'origine quel comment dur vous tentez de duperie il.
la figure 1 montre comment modifier code de Deep Zoom Composer pour résoudre le problème.Déclarez d'abord deux nouveaux champs nommés lastViewportOrigin et lastMousePosition dans la classe page page.XAML.cs.(Lorsque vous travaillez dessus, supprimez les champs nommés dragOffset et currentPosition, car ils ne sont pas nécessaires.) Puis réécrivez les gestionnaires MouseLeftButtonDown et MouseMove comme indiqué.Vous trouverez que la scène s'aligne retour précisément la position du curseur d'origine lorsque vous arrêtez la souris et si vous êtes comme fastidious que je suis sur ces éléments, vous pourrez en veille pendant la nuit encore une fois.
La figure 1 résolution le code de panoramique de Deep Zoom Composer
Point lastViewportOrigin;
Point lastMousePosition;
...
this.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
{
mouseButtonPressed = true;
mouseIsDragging = false;
lastViewportOrigin = msi.ViewportOrigin;
lastMousePosition = e.GetPosition(msi);
};
this.MouseMove += delegate(object sender, MouseEventArgs e)
{
if (mouseIsDragging)
{
Point pos = e.GetPosition(msi);
Point origin = lastViewportOrigin;
origin.X += (lastMousePosition.X - pos.X) /
msi.ActualWidth * msi.ViewportWidth;
origin.Y += (lastMousePosition.Y - pos.Y) /
msi.ActualWidth * msi.ViewportWidth;
msi.ViewportOrigin = lastViewportOrigin = origin;
lastMousePosition = pos;
}
};
Accès Sub-Images et métadonnées
Vous avez peut-être remarqué que lorsque vous exportez un projet à partir de Deep Zoom Composer, vous êtes proposé le choix de l'exportation comme une composition ou sous la forme d'une collection de la dernière option est fourni avec un des avantages très souhaitable : plutôt que de l'exportation d'une scène Deep Zoom contenant toutes les images que vous avez ajouté lumped ensemble dans une image monolithique, elle exporte une scène contenant sub-images adressables individuellement. Les sub-images exposés via la propriété du contrôle MultiScaleImage sous-images et car ils sont adressables individuellement des objets, les sub-images peuvent être manipulés, animé et fumigated (que je!) pour ajouter étinceler et de l'interactivité à des applications Deep Zoom.
Chaque élément dans la collection sous-images est une instance de MultiScaleSubImage, qui dérive de DependencyObject et comprend les propriétés AspectRatio, opacité, ZIndex, ViewportOrigin égale à et ViewportWidth. Le second deux associent pour déterminer une image sous Taille et position dans une scène Deep Zoom. Sachez que lorsqu'un contrôle MultiScaleImage charge, sa propriété sous-images est vide. Votre première permet d'itérer sur les sub-images est lorsque le contrôle déclenche son événement ImageOpenSucceeded.
Une utilisation de la propriété sous-images consiste à tester des images individuelles pour afficher les métadonnées, titres, descriptions et ainsi de suite, en réponse aux clics ou mouseovers. Une autre utilisation pour qu'il consiste à Réorganiser par programme les images dans une scène Deep Zoom. L'application DeepZoomTravelDemo illustrée figure 2 montre comment effectuer les deux. Lorsque vous positionnez la souris sur une des images dans la scène, un panneau informations partiellement transparent apparaît à droite contenant une image de titre et description. Et lorsque vous cliquez sur le bouton Lecture aléatoire dans le coin supérieur gauche, les images elles-mêmes réorganiser dans un ordre aléatoire.
La figure 2 DeepZoomTravelDemo
Les neuf images de DeepZoomTravelDemo sont photos que vous alignée sur certaines de mes voyages étranger. Je les importer dans Deep Zoom Composer, en les organisant dans une grille et exporté la scène (veillant à sélectionner «Exporter en tant que collection»). Puis j'importé la sortie de Deep Zoom Composer dans un projet Silverlight et ajouté Zoom et panoramique logique, comme dans la section précédente. Pour conserver la taille téléchargement gérable (13 Mo par rapport à 170 Mo), j'ai supprimé les bas à deux couches de la pyramide d'images que éditeur générée avant que j'ai téléchargé l'application vers MSDN Code Gallery. La version que vous téléchargez fonctionne parfaitement, mais quand vous effectuez un zoom avant, les images granuleuse beaucoup plus rapide que dans la version d'origine.
Affichage des métadonnées d'image comme DeepZoomTravelDemo présente deux défis au développeur. Tout d'abord, où stockez-vous les métadonnées, et comment vous associez-le images dans la scène ? La deuxième, comment vous corréler les éléments dans sous-images collection le contrôle MultiScaleImage avec des images dans la scène depuis la classe MultiScaleSubImage ne fournit aucune information concernant les deux ?
La première tâche, stocker les métadonnées, est réalisé en tapant une chaîne de texte dans la zone Étiquette affichée dans le coin inférieur droit de Deep Zoom Composer quand une image est sélectionnée. Je l'utilisé pour stocker chaque image titre et description, séparés par des signes. Compositeur écrit les balises dans le fichier Metadata.xml créé lorsque vous exportez le projet. Chaque image dans la scène est représentée par un élément <Image> Metadata.xml et chaque élément <Image> contient un sous-élément nommé <Tag> qui contient la balise correspondante. figure 3 illustre l'élément <image> écrit dans Metadata.xml pour l'image dans le coin supérieur gauche de la scène. Balise de compositeur modification d'interface est quelque peu maladroite car la zone étiquette est trop petite, mais vous pouvez toujours modifier le fichier Metadata.xml manuellement comme de le chaque image avec un titre et une description de la balise.
Figure 3 un élément <image> dans Metadata.xml
<Image>
<FileName>
C:\Users\Jeff\Documents\Expression\Deep Zoom Composer
Projects\DeepZoomTravelDemo\source images\great wall of china.jpg
</FileName>
<x>0</x>
<y>0</y>
<Width>0.316957210776545</Width>
<Height>0.313807531380753</Height>
<ZOrder>1</ZOrder>
<Tag>
Great Wall of China+The Great Wall of China near Badaling, about an hour
north of Beijing. This portion of the Great Wall has been restored and
offers outstanding views of the surrounding mountains.
</Tag>
</Image>
Il serait pratique si la classe MultiScaleSubImage possède une propriété de balise qui a été initialisée automatiquement avec le contenu de l'élément <tag> ; mais le contraire, afin que vous ayez à improvise. Tout d'abord, vous pouvez écrire un peu de code qui télécharge Metadata.xml et traite les balises à partir de celui-ci. Ensuite, vous pouvez utiliser les éléments <zorder> dans Metadata.xml pour corréler <image> éléments avec des images dans la scène Deep Zoom. Si la scène contient des neuf images (et sous-images collection du contrôle MultiScaleImage contient donc neuf objets MultiScaleSubImage), sous-images [0] correspond à l'image dont <ZOrder> est 1, sous-images [1] correspond à l'image dont <ZOrder> est 2 et ainsi de suite.
DeepZoomTravelDemo utilise cette corrélation pour stocker les titres des images et des descriptions. Au démarrage, le constructeur de page utilise un objet WebClient pour lancer un téléchargement asynchrone de Metadata.xml dossier ClientBin du serveur (voir figure 4 ). Une fois le téléchargement terminé, la méthode WebClient_OpenReadCompleted analyse le code téléchargé XML avec XmlReader et initialise le champ nommé _Metadata avec un tableau d'objets SubImageInfo contenant des informations sur les images dans la scène, y compris titres et descriptions. La classe est indiquée ici :
public class SubImageInfo
{
public string Caption { get; set; }
public string Description { get; set; }
public int Index { get; set; }
}
La figure 4 téléchargement Metadata.xml et la corrélation des métadonnées avec Sub-Images
private SubImageInfo[] _Metadata;
...
public Page()
{
InitializeComponent();
// Register mousewheel event handler
HtmlPage.Window.AttachEvent("DOMMouseScroll ", OnMouseWheelTurned);
HtmlPage.Window.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
HtmlPage.Document.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
// Fetch Metadata.xml from the server
WebClient wc = new WebClient();
wc.OpenReadCompleted += new
OpenReadCompletedEventHandler(WebClient_OpenReadCompleted);
wc.OpenReadAsync(new Uri( "Metadata.xml ", UriKind.Relative));
}
private void WebClient_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show( "Unable to load XML metadata ");
return;
}
// Create a collection of SubImageInfo objects from Metadata.xml
List<SubImageInfo> images = new List<SubImageInfo>();
try
{
XmlReader reader = XmlReader.Create(e.Result);
SubImageInfo info = null;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "Image ")
info = new SubImageInfo();
else if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "ZOrder ")
info.Index = reader.ReadElementContentAsInt();
else if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "Tag ")
{
string[] substrings =
reader.ReadElementContentAsString().Split('+');
info.Caption = substrings[0];
if (substrings.Length > 1)
info.Description = substrings[1];
else
info.Description = String.Empty;
}
else if (reader.NodeType == XmlNodeType.EndElement &&
reader.Name == "Image ")
images.Add(info);
}
}
catch (XmlException)
{
MessageBox.Show( "Error parsing XML metadata ");
}
// Populate the _Metadata array with ordered data
_Metadata = new SubImageInfo[images.Count];
foreach (SubImageInfo image in images)
_Metadata[image.Index - 1] = image;
}
Les valeurs <zorder> lues Metadata.xml sont utilisées pour trier les objets SubImageInfo dans le tableau _Metadata, s'assurer que l'ordre des éléments dans le tableau _Metadata est identique à afin des éléments de collection sous-images de MultiScaleImage. En d'autres termes, _Metadata [0] contient le titre et la description de sous-images [0], [1] _Metadata le titre et la description de sous-images [1] et ainsi de suite. Incidemment, j'ai utilisé XmlReader plutôt que LINQ to XML pour éviter d'augmenter la taille de fichier XAP de l'en introduisant un assembly supplémentaire requis par LINQ to XML (System.Xml.Linq.dll).
Maintenant que _Metadata est initialisé avec les objets SubImageInfo contenant des titres et descriptions, l'étape suivante consiste à écrire le code pour afficher les titres et les descriptions. Cela se produit dans la figure 5 . Le Gestionnaire MouseMove qui ont la scène Deep Zoom si le bouton gauche de la souris est enfoncé se comporte différemment si le bouton gauche de la souris est relâché : il tests d'atteinte la scène pour déterminer si le curseur est actuellement sur une des sub-images. Test d'atteinte est effectué par la méthode d'assistance nommée GetSubImageIndex, retourne -1 si le curseur n'est pas sur un sub-image ou un index d'image basé sur 0 s'il s'agit. Cet index identifie à la fois un sub-image dans MutliScaleImage.SubImages et un objet SubImageInfo dans _Metadata. Quelques lignes de code copie le titre et description de l'objet SubImageInfo sur une paire de TextBlocks et plus d'une ligne de code déclencheurs une animation qui affiche le panneau informations sur si elle n'est pas déjà affichée. Notez que GetSubImageIndex vérifie sub-images pour les accès dans l'ordre inverse sub-image finale dans sous-images collection le contrôle MultiScaleimage étant plus élevée dans l'ordre de plan, le sub-image suivant à la dernière seconde est plus élevée dans l'ordre de plan, etc..
La figure 5 test atteint les Sub-Images
private int _LastIndex = -1;
...
private void MSI_MouseMove(object sender, MouseEventArgs e)
{
if (_Dragging)
{
// If the left mouse button is down, pan the Deep Zoom scene
...
}
else
{
// If the left mouse button isn't down, update the infobar
if (_Metadata != null)
{
int index = GetSubImageIndex(e.GetPosition(MSI));
if (index != _LastIndex)
{
_LastIndex = index;
if (index != -1)
{
Caption.Text = _Metadata[index].Caption;
Description.Text = _Metadata[index].Description;
FadeIn.Begin();
}
else
{
FadeOut.Begin();
}
}
}
}
}
private int GetSubImageIndex(Point point)
{
// Hit-test each sub-image in the MultiScaleImage control to determine
// whether "point " lies within a sub-image
for (int i = MSI.SubImages.Count - 1; i >= 0; i--)
{
MultiScaleSubImage image = MSI.SubImages[i];
double width = MSI.ActualWidth /
(MSI.ViewportWidth * image.ViewportWidth);
double height = MSI.ActualWidth /
(MSI.ViewportWidth * image.ViewportWidth * image.AspectRatio);
Point pos = MSI.LogicalToElementPoint(new Point(
-image.ViewportOrigin.X / image.ViewportWidth,
-image.ViewportOrigin.Y / image.ViewportWidth)
);
Rect rect = new Rect(pos.X, pos.Y, width, height);
if (rect.Contains(point))
{
// Return the image index
return i;
}
}
// No corresponding sub-image
return -1;
}
En outre pour prise en charge mouseovers, DeepZoomTravelDemo vous permet de réorganiser les images dans la scène. Si vous ne l'avez pas encore fait, essayez de cliquer sur le bouton Lecture aléatoire dans le coin supérieur gauche de la scène. (En fait, cliquez dessus plusieurs fois ; les images considère un ordre différent chaque fois.) La réorganisation est effectuée par la méthode de lecture aléatoire dans la figure 6 , qui crée un tableau contenant toutes les images ViewportOrigins, réorganise le tableau à l'aide un générateur de nombres aléatoires, puis crée une table de montage et une série de PointAnimations pour atteindre les sub-images les positions des contenus dans le tableau réorganisé. La clé ici est que la propriété du contrôle MultiScaleimage sous-images expose sub-images à votre code et vous pouvez modifier ViewportOrigin égale à propriété un sub-d'une image pour changer sa position dans la scène.
La figure 6 mélange les Sub-Images
private void Shuffle()
{
// Create a randomly ordered list of sub-image viewport origins
List<Point> origins = new List<Point>();
foreach (MultiScaleSubImage image in MSI.SubImages)
origins.Add(image.ViewportOrigin);
Random rand = new Random();
int count = origins.Count;
for (int i = 0; i < count; i++)
{
Point origin = origins[i];
origins.RemoveAt(i);
origins.Insert(rand.Next(count), origin);
}
// Create a Storyboard and animations for shuffling
Storyboard sb = new Storyboard();
for (int i = 0; i < count; i++)
{
PointAnimation animation = new PointAnimation();
animation.Duration = TimeSpan.FromMilliseconds(250);
animation.To = origins[i];
Storyboard.SetTarget(animation, MSI.SubImages[i]);
Storyboard.SetTargetProperty(animation,
new PropertyPath( "ViewportOrigin "));
sb.Children.Add(animation);
}
// Run the animations
sb.Begin();
}
Comme je solution étude cette colonne, j'ai trouvé plusieurs entrées de blog qui a fourni des informations utiles.Un était Jaime Rodriquez"Utilisation des collections dans Deep Zoom." Une autre a"Deep Zoom Composer, filtrage par étiquette, exemple", qui a été écrit par un membre de l'équipe de Expression Blend et présente une technique de filtrage des images Deep Zoom basée sur les balises d'images.Mise en œuvre mouseovers, réorganiser les images dans une scène et le filtrage en fonction de balise sont des données mais quelques-unes des fonctionnalités rendues possibles par la capacité à adresser sub-images individuels dans un Deep Zoom scène et associer métadonnées avec les images.
Création dynamique Deep Zoom très paire
J'ai été fascinated en fractales depuis que j'ai découvert les quelques 20 ans.J'ai écrit mon premier visionneuse Mandelbrot au début des années 1990, si mémoire me dessert correctement.Mon étagère de livres informatiques oldie-mais-goodie contient toujours une copie initial d'un livre intitulé compression d'image Fractal par Barnsley et Hurd utilisé dans un projet de recherche sur compression des données dans le milieu-années 90.Et l'une de mes livres préférés de tous les temps est chaos par James Gleick (pingouin, 2008).
Création interactif et visuellement attrayant Mandelbrot visionneuse pour les navigateurs est quelque chose souhaitée faire depuis le premier jour que je disposition yeux sur Silverlight.Dynamique Deep Zoom rendue possible.L'inconvénient, est bien sûr, que les images sont générées sur le serveur et téléchargés vers le client de début à la latence indésirable et augmentation également de la charge sur le serveur.
Silverlight 2 ne comprend pas une API pour générer des bitmaps sur le client, mais vous pouvez générer quand même à l'aideCodeur PNG Silverlight de Joe Stegman. Minh Nguyen utilisé pour Explorateur Mandelbrot, que vous pouvez lire tous les concernant dans son article blog de builds"Minh t.Mandelbrot Explorer 1.0 de Nguyen dans Silverlight 2.0 avec le code source." 3 Silverlight, qui sera en version bêta au moment où que vous lisez ceci, possède un bitmap API, mais le problème reste que Deep Zoom souhaite extraire les images du serveur.Il est incertaine au moment si la version suivante de Deep Zoom disposera d'un article côté client, mais si tel est le cas, vous pouvez bien sûr que vous allez réviser MandelbrotDemo 3 Silverlight travailler entièrement sur le client.
Dynamique Deep Zoom : Insertion image pixels au moment de l'exécution
Fonctionnalité d'exportation de Deep Zoom Composer génère toutes les données requises par un contrôle MultiScaleImage.Ces données incluent un fichier XML (dzc_output.xml) qui fait référence aux autres fichiers XML, qui à son tour référencent images individuelles dans la scène.Sortie du compositeur inclut également des centaines (parfois des milliers) de mosaïques d'image générés à partir de ces images.Les fragments forment une pyramide d'images, avec chaque niveau de la pyramide contenant une version en mosaïque de l'image d'origine et chaque niveau représentant une résolution différente.Le niveau en haut de la pyramide, par exemple, peut contenir une seule mosaïque avec un rendu de 256 x 256 de l'image.Le niveau suivant vers le bas contient quatre 256 x 256 mosaïques qui, rassembler formulaire une version 512 x 512 de l'image.Le niveau suivant vers le bas contiendrait seize 256 x 256 mosaïques représentant différentes parties d'un 1 024 x 1, 024 image et ainsi de suite.Deep Zoom Composer génère autant de niveaux que nécessaire pour décrire l'image d'origine dans sa résolution native.Tel qu'un utilisateur effectue un zoom avant et panoramiques dans une scène Deep Zoom, le contrôle MultiScaleImage est constamment déclencher HTTP demandes au serveur pour extraire des mosaïques d'image à la résolution.Il effectue également certains cool mélange de travail pour faciliter la transition d'un niveau à un autre.
Ce que vous probablement ne réaliser sur le contrôle MultiScaleImage est qu'il ne nécessite Deep Zoom Composer.Éditeur est simplement un outil permettant de rapidement et facilement créer des projets Deep Zoom qui incorporent des scènes générés à partir des images statiques.Comme alternative à fournir MultiScaleImage contenu statique, peuvent générer un contenu au moment de l'exécution en réponse aux demandes de MultiScaleImage et télécharger ce contenu sur le client.
Pourquoi jamais devez-vous générer contenu Deep Zoom au moment de l'exécution ?Les développeurs qui me demander comment faire tout le temps. "Est-il possible de fournir des données image Deep Zoom dynamiquement?» La raison est qu'il permet à un tout nouveau genre d'applications Deep Zoom que mosaïques d'image extraction de bases de données et qui génèrent des mosaïques d'image à la volée.
Un exemple vous souhaitez ?Consultez leProfondeur projet terreet un exemple de terre long au travaildeepearth.soulsolutions.com.au/. Terre Deep est appelé un contrôle de mappage alimenté par la combinaison de la plate-forme Microsoft Silverlight 2 et le contrôle DeepZoom (MultiScaleImage).En d'autres termes, il est un contrôle vous pouvez placer dans une application Silverlight pour exposer la grande quantité de données géographiques disponibles à partir de Microsoft Virtual Earth via un front end Deep Zoom.Vous pouvez démarrer dans l'espace outer et zoom complètement vers le bas à votre jardin avant.Et le zoom est étonnamment lisse, grâce au travail effectué en arrière-plan en MultiScaleImage et le runtime Deep Zoom.
Terre profondeur n'est pas piloté par un ensemble de fichiers XML et de sortie mosaïques image Deep Zoom Composer ; il fournit mosaïques d'image vers le contrôle MultiScaleImage dynamiquement et il extrait mosaïques d'image de Virtual Earth.Les utilisateurs de terre Deep désignent comme «dynamique Deep Zoom».
L'application décrite dans la figure 7 illustre les notions de base de dynamique Deep Zoom.MandelbrotDemo fournit une fenêtre Deep Zoom dans l'ensemble de Mandelbrot, probablement la fractale plus célèbre au monde.L'ensemble de Mandelbrot est infiniment complexe, ce qui signifie que pouvoir effectuer un zoom indéfiniment et le niveau de détail ne diminue jamais.Visionneuses de Mandelbrot sont courantes dans le monde de logiciel, mais peu sont aussi simple que celui qui utilise Deep Zoom.Essayez ; exécutez MandelbrotDemo et un zoom avant sur des régions swirling sur le bord de Mandelbrot définir (à la limite entre les couleurs en noirs et claires).Vous ne pouvez pas agrandir indéfiniment parce que même une scène Deep Zoom dynamique a une largeur déterminée et une hauteur, mais les dimensions de la scène peuvent être très, très volumineuse (de 232 pixels par côté).
deux vues de le Mandlebrot
La première étape dans l'implémentation Deep Zoom dynamique consiste à dériver de classe MultiScaleTileSource de Silverlight qui se trouve dans l'espace de noms System.Windows.Media. de System.Windows.dll et substituer la méthode GetTileLayers.Chaque fois que le contrôle MultiScaleImage a besoin d'une mosaïque, elle appelle GetTileLayers.Votre travail consiste à créer une mosaïque d'image et retourner au contrôle MultiScaleImage en ajoutant l'interface IList passé dans la liste des paramètres des GetTileLayers.Autres paramètres entrée GetTileLayers spécifient le niveau de zoom (littéralement, le niveau de la pyramide d'images à partir de laquelle les mosaïques sont demandés) et la position X et Y dans ce niveau de la pyramide de la mosaïque est demandée.Tout comme valeurs X, Y et Z sont suffisantes pour identifier un point dans l'espace de coordonnées 3D, une valeur de X, une valeur de Y et un niveau identifient une mosaïque d'image dans une pyramide d'images Deep Zoom.
figure 8 montre la classe dérivée de MultiScaleTileSource proposée dans MandelbrotDemo.La substitution GetTileLayers does peu plus de soumettre des requêtes HTTP de la mosaïque d'image sur le serveur.Le point de terminaison de la demande est un gestionnaire HTTP nommé MandelbrotImageGenerator.ashx.Avant d'examiner le Gestionnaire, cependant, nous allons voir comment MandelbrotTileSource est associée à un contrôle MultiScaleImage.
La figure 8 MultiScaleTileSource Derivative
public class MandelbrotTileSource : MultiScaleTileSource
{
private int _width; // Tile width
private int _height; // Tile height
public MandelbrotTileSource(int imageWidth, int imageHeight,
int tileWidth, int tileHeight) :
base(imageWidth, imageHeight, tileWidth, tileHeight, 0)
{
_width = tileWidth;
_height = tileHeight;
}
protected override void GetTileLayers(int level, int posx, int posy,
IList<object> sources)
{
string source = string.Format(
"http://localhost:50216/MandelbrotImageGenerator.ashx? " +
"level={0}&x={1}&y={2}&width={3}&height={4} ",
level, posx, posy, _width, _height);
sources.Add(new Uri(source, UriKind.Absolute));
}
}
figure 9 illustre un extrait de fichier page.XAML.cs de MandelbrotDemo — en particulier, le XAML code-behind du constructeur de classe. L'instruction clée est celle qui crée un objet MandelbrotTileSource et assigne une référence à celui-ci à la propriété source du contrôle MultiScaleImage. Pour statique Deep Zoom, vous définissez source à l'URI de dzc_output.xml. Pour dynamique Deep Zoom, vous pointer vers un objet MultiScaleTileSource à la place. L'objet MandelbrotTileSource créé ici indique que l'image pris en charge mesures 230 pixels de chaque côté et est divisé en fragments 128 x 128 pixels.
La figure 9 enregistrement un cœur Zoom mosaïque source
public Page()
{
InitializeComponent();
// Point MultiScaleImage control to dynamic tile source
MSI.Source = new MandelbrotTileSource((int)Math.Pow(2, 30),
(int)Math.Pow(2, 30), 128, 128);
// Register mousewheel event handler
HtmlPage.Window.AttachEvent( "DOMMouseScroll ", OnMouseWheelTurned);
HtmlPage.Window.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
HtmlPage.Document.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
}
Le travail de génération de la mosaïque d'image est effectué par MandelbrotImageGenerator.ashx revenir sur le serveur (voir figure 10 ). Après avoir récupéré les paramètres d'entrée de la chaîne de requête, il crée une bitmap représentant la mosaïque demandée et écrit les bits d'image dans la réponse HTTP. DrawMandelbrotTile ne la génération de pixel. Lorsqu'elle est appelée, elle convertit la valeur X de Y-niveau identifiant la mosaïque d'image a été demandée en coordonnées dans le plan complexe (un plan de mathématique dans lequel les nombres réels sont représentées graphiquement ainsi que les numéros de l'axe et imaginaires X — numéros qui incorporent la racine carrée de -1, sont représentées graphiquement le long de l'axe Y). Il parcourt ensuite tous les points dans le plan complexe qui correspondent aux pixels de la mosaïque d'image, vérification de chaque point pour déterminer si elle appartient à la Mandelbrot défini et en assignant le pixel correspondant une couleur représentant sa relation à la Mandelbrot défini (plus dans un instant).
Gestionnaire HTTP de la figure 10 pour génération complètement Zoom mosaïques d'image
public class MandelbrotImageGenerator : IHttpHandler
{
private const int _max = 128; // Maximum number of iterations
private const double _escape = 4; // Escape value squared
public void ProcessRequest(HttpContext context)
{
// Grab input parameters
int level = Int32.Parse(context.Request[ "level "]);
int x = Int32.Parse(context.Request[ "x "]);
int y = Int32.Parse(context.Request[ "y "]);
int width = Int32.Parse(context.Request[ "width "]);
int height = Int32.Parse(context.Request[ "height "]);
// Generate the bitmap
Bitmap bitmap = DrawMandelbrotTile(level, x, y, width, height);
// Set the response's content type to image/jpeg
context.Response.ContentType = "image/jpeg ";
// Write the image to the HTTP response
bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
// Clean up and return
bitmap.Dispose ();
}
public bool IsReusable
{
get { return true; }
}
private Bitmap DrawMandelbrotTile(int level, int posx, int posy,
int width, int height)
{
// Create a bitmap to represent the requested tile
Bitmap tile = new Bitmap(width, height);
// Compute the number of tiles in each direction at this level
int cx = Math.Max(1, (int)Math.Pow(2, level) / width);
int cy = Math.Max(1, (int)Math.Pow(2, level) / height);
// Compute starting values for real and imaginary components
// (from -2.0 - 1.5i to 1.0 + 1.5i)
double r0 = -2.0 + (3.0 * posx / cx);
double i0 = -1.5 + (3.0 * posy / cy);
// Compute increments for real and imaginary components
double dr = (3.0 / cx) / (width - 1);
double di = (3.0 / cy) / (height - 1);
// Iterate by row and column checking each pixel for
// inclusion in the Mandelbrot set
for (int x = 0; x < width; x++)
{
double cr = r0 + (x * dr);
for (int y = 0; y < height; y++)
{
double ci = i0 + (y * di);
double zr = cr;
double zi = ci;
int count = 0;
while (count < _max)
{
double zr2 = zr * zr;
double zi2 = zi * zi;
if (zr2 + zi2 > _escape)
{
tile.SetPixel(x, y,
ColorMapper.GetColor(count, _max));
break;
}
zi = ci + (2.0 * zr * zi);
zr = cr + zr2 - zi2;
count++;
}
if (count == _max)
tile.SetPixel(x, y, Color.Black);
}
}
// Return the bitmap
return tile;
}
}
Malheureusement, il n'existe pratiquement aucune documentation sur MultiScaleTileSource classe Silverlight. Moins vous pensez que je suis genius pour identifier tout cette sortie (toute personne qui connaît me va atteste que je ne suis pas), laissez-moi vous donner crédit où crédit arrive à échéance. Comme je wrestled avec la signification des paramètres d'entrée et comment mapper Deep Zoom X-Y-valeurs au niveau au plan complexe, j'ai trouvé un excellent billet par Mike Ormond, Deep Zoom, MultiScaleTileSource et l'ensemble de Mandelbrot. Son poste fourni idées clées en dynamique Deep Zoom et également référencé billet de blog une autre, L'ensemble de Mandelbrot, qui décrit une approche efficace pour calculer l'ensemble de Mandelbrot. Mon travail a été contient probablement par travail d'autres avaient avant de me.
Une remarque finale sur mon implémentation : presque toutes les applications qui rend l'ensemble de Mandelbrot utilise un modèle autre couleur. J'ai choisi un modèle qui affecte les pixels représentant les coordonnées qui appartiennent à la Mandelbrot noir et pixels représentant les coordonnées en dehors de la Mandelbrot valeur RVB. Plus une coordonnée trouve à partir de l'ensemble de Mandelbrot, la «fontaine» ou bluer la couleur ; il se trouve le plus proche à l'ensemble de Mandelbrot, la couleur de la «hotter». Distance de l'ensemble de Mandelbrot est déterminée par comment rapidement le point d'échappement à l'infini. Dans le code ici, ceci est le nombre d'itérations nécessaire de DrawMandelbrotTile while pour déterminer que le point n'est pas partie de l'ensemble de Mandelbrot. Les moins les itérations, plus le point se trouve de l'ensemble de points qui composent l'ensemble de Mandelbrot. J'ai pris en compte le code qui génère une valeur de couleur RVB à partir du nombre d'itérations dans une classe distincte nommée ColorMapper ( figure 11 ). Si vous souhaitez expérimenter les jeux de couleurs différent, modifiez simplement la méthode GetColor. Vous pouvez voir les résultats du rendu d'échelle de gris en procédant comme suit :
int val = (count * 255) / max;
return Color.FromArgb(val, val, val);
La figure 11 ColorMapper classe
public class ColorMapper
{
public static Color GetColor(int count, int max)
{
int h = max >> 1; // Divide max by 2
int q = max >> 2; // Divide max by 4
int r = (count * 255) / max;
int g = ((count % h) * 255) / h;
int b = ((count % q) * 255) / q;
return Color.FromArgb(r, g, b);
}
}
DeepZoomTools.dll
Un tidbit final des informations concernant Deep Zoom que vous pouvez trouver utiles implique un assembly nommé DeepZoomTools.dll.Deep Zoom Composer utilise cet assembly pour générer des images présentées en mosaïque et les métadonnées à partir de l'arrière-plan que vous créez.En théorie, vous pouvez l'utiliser pour créer des outils de composition de votre propre.Je dis «en théorie» car il est peu précieux existent en termes de documentation.En savoir plus sur DeepZoomTools.dll sur leConception et Expression Blendblog.Et résoudre un message électronique si vous proposez quelques utilisations uniques, creative pour Deep Zoom mais ne pas tout à fait sûr comment faire faire ce que vous voulez faire.
Envoyez vos questions et commentaires à Jeff àwicked@microsoft.com.
Jeff Prosise est à l'élaboration de MSDN Magazine et l'auteur de plusieurs livres, notamment Programming Microsoft .NET (Microsoft Press, 2002).Il est également co-fondateur de Wintellect (www.Wintellect.com), une société de conseil et de formation confirmer qui se spécialise dans Microsoft .NET.Faire un commentaire sur cette colonne ?Contactez Jeff àwicked@microsoft.com.