Ouarzy's Blog

Ouarzy's Blog

Téléchargement de (grosses) images en Silverlight

Sans entrer dans le détail, une grosse partie de mon projet actuel est de pouvoir présenter le plus rapidement possible des images de grande taille (>15mb) à travers une interface Web en Silverlight.

Ce qui m’a amené à cette question: quelle est la façon la plus rapide de télécharger dynamiquement une image en SL? C'est la réponse que je vais tenter d'amener dans ce petit article sans prétention.

 

DL à travers l’UI

Le contrôle Image de SL est capable de prendre une source URI en XAML. Si on a une image à récupérer sur un serveur, mais dont l’adresse ne change jamais, c’est de loin l’approche la plus simple.
Si on doit donner une adresse dynamique à l’Image, on peut attribuer la source en code behind à l’aide de la classe BitmapImage qui est l’implémentation de BitmapSource:


 

Mais le problème du DL à travers l’UI, c’est qu’il est très difficile de l’intégrer directement dans une architecture propre. En effet puisqu’on souhaite finalement récupérer des images de façon dynamique, on souhaiterait plutôt avoir à faire à un service de Download, ce qui permettrait de l'inclure plus simplement dans un pattern MVVM par exemple.

 

 

DL à travers un service

 

1ère approche: utilisation d’un webClient

 

Avec les classes SL de base

 

Etant assez bas niveau, une idée logique serait d’utiliser la classe Webclient pour télécharger notre flux, et l’attribuer à un BitmapImage qu’on pourra ensuite utiliser comme source sur le contrôle Image SL.
La responsabilité du service serait donc uniquement de remplir ce Bitmap à partir d’une Uri. On peut remplir une BitmapImage à partir d’un Stream (ce qui est justement renvoyé par le WebClient) grâce à la fonction SetSource :


 

(Dans cet exemple, e.Result est le callback du WebClient)

De mon point de vue ça aurait été la meilleur approche, car on pourrait arriver à une séparation claire : la couche d’accès aux données traite un Stream, la couche métier le transforme en BitmapImage, l’UI utilise ce Bitmap pour l’afficher dans le contrôle Image.

Malheureusement, la fonction SetSource en SL5 semble être boguée pour les grosses images (>15mb). En effet l’image apparait coupée :

 

 

D’ailleurs si quelqu’un a des infos la dessus, je suis preneur, car je n’ai rien pu trouver de concluant par rapport à ce problème sur Google aprés une bonne journée de recherche.

 

 

Avec les classes SL de ImageTools

 

Qu’à cela ne tienne, puisque le SetSource du BitmapImage ne fonctionne pas, je mets la main sur une lib open source qui ré-implémente ces comportements (http://imagetools.codeplex.com/).
Assez facile à mettre en œuvre, je constate avec joie que le SetSource fonctionne cette fois-ci ! Seul problème, par rapport à la première approche où le composant Image gère directement son DL, j’ai quasiment pris un facteur 5 sur le temps d’affichage d’une image !!!

 


Comme je ne me voyais pas expliquer à mon commercial que les images s’affichent 5 fois plus lentement mais qu’on a une super archi, j’ai donc dû trouver une autre solution intermédiaire.
Cela m’a permis de confirmer une fois de plus qu’il faut éviter de réinventer la roue, et qu’on a peu de chance de réécrire un composant plus performant que celui écrit par Microsoft

 

 

2eme approche: Utilisation du BitmapImage bas niveau

 

L’approche intermédiaire consiste à utiliser un objet BitmapImage bas niveau, et à directement utiliser sa propriété UriSource pour qu'il gère son propre téléchargement d’image.
Notez cependant qu’il faudra penser à modifier la propriété CreateOptions, la valeur par défaut étant DelayCreation (du lazy loading, c’est-à-dire : création seulement quand cela sera utile, et si cela est utile…Par utile comprenez : utilisé par un objet qui cherche à l’afficher dans un arbre graphique).
L’initialisation pourra donc ressembler à ça :

 


 

Puis, pour lancer le téléchargement :


 

Vous n'aurez plus qu'à gérer ce que vous voulez faire de  votre BitmapImage dans la fonction

DownloadedBmpImageImageOpened().

 

 

Conclusion:

 

Et voilà tout ! Au final ça permet de garder quelque chose de propre avec des performances satisfaisantes. A l’heure actuelle c’est la méthode la plus rapide que j’ai trouvé, mais si vous avez d’autres propositions, ça m’intéresse.

C'est une solution assez simple, qui peut même sembler trivial, mais je me permet de la poster car j'ai mis 3 jours pour arriver à cette conclusion, et que j'aurais vraiment aimé qu'un autre blogueur me donne cette approche et cette justification dés le début.

 

En éspèrant donc que ça puisse servir à d'autres aventuriers de l'image en Silverlight...


 

 



30/10/2012
0 Poster un commentaire
Ces blogs de Informatique & Internet pourraient vous intéresser