Comment télécharger une image du Web montrant la progression du téléchargement en c # à l’aide de winforms

Je télécharge une image à partir d’une URL de manière asynchrone à l’aide de WebRequest de cette façon:

public void Download(ssortingng url) { byte[] buffer = new byte[0x1000]; WebRequest request = HttpWebRequest.Create(url); request.Method = "GET"; request.ContentType = "image/gif"; request.BeginGetResponse(result => { WebRequest webRequest = result.AsyncState as WebRequest; WebResponse response = webRequest.EndGetResponse(result); ReadState readState = new ReadState() { Response = response.GetResponseStream(), AccumulatedResponse = new MemoryStream(), Buffer = buffer, }; readState.Response.BeginRead(buffer, 0, readState.Buffer.Length, ReadCallback, readState); }, request); } public void ReadCallback(IAsyncResult result) { ReadState readState = result.AsyncState as ReadState; int bytesRead = readState.Response.EndRead(result); if(bytesRead > 0) { readState.AccumulatedResponse.BeginWrite(readState.Buffer, 0, bytesRead, writeResult => { readState.AccumulatedResponse.EndWrite(writeResult); readState.Response.BeginRead(readState.Buffer, 0, readState.Buffer.Length, ReadCallback, readState); }, null); } else { readState.AccumulatedResponse.Flush(); readState.Response.Close(); pictureBox1.Image = Image.FromStream(readState.AccumulatedResponse); } } public class ReadState { public Stream Response { get; set; } public Stream AccumulatedResponse { get; set; } public byte[] Buffer { get; set; } } 

et cela fonctionne bien, mais je voudrais montrer la progression du téléchargement comme le font les navigateurs, et pas seulement quand il se termine.

Si je fais

 pictureBox1.Image = Image.FromStream(readState.AccumulatedResponse); 

avant qu’il ne soit terminé, j’obtiens une exception: l’image n’est pas valide, même si elle contient des données. Est-il possible d’afficher des données partielles?

JPEG possède un mode de codage spécial appelé “JPEG progressif” dans lequel les données sont compressées en plusieurs passes de plus en plus détaillées. Windows 7 a un support intégré pour cela.

Je voudrais montrer l’avancement du téléchargement comme le font les navigateurs, et pas seulement quand il se termine.

Vous avez deux options:

  1. Utilisez WebClient.DownloadDataAsync . Cela déclenchera des événements de progression via DownloadProgressChanged et fournira une notification finale du moment où les données sont disponibles via l’événement DownloadDataCompleted . À ce stade, vous pouvez atsortingbuer l’image au PictureBox .

  2. Si vous téléchargez une image pour l’afficher éventuellement dans un contrôle PictureBox il sera peut-être même plus simple d’utiliser PictureBox.LoadAsync . Cela aussi fournira des mises à jour de progression via son événement LoadProgressChanged et enfin LoadCompleted à la fin.

Vous avez un problème avec le contrôle PictureBox, pas avec le téléchargement partiel.

Un hack consiste à utiliser WebBrowserControl, car IE est capable d’afficher des images partielles.

Lorsque vous commencez la demande, vérifiez la propriété WebResponse.ContentLength , qui devrait vous donner le nombre total d’octets à attendre. Suivez ensuite le nombre total d’octets lus dans votre méthode ReadCallback. Le rest devrait être évident. 🙂

[modifier] Oups, j’ai relu la question, et ce n’était pas tout à fait ce que tu voulais. Je laisse encore cette question en place, au cas où quelqu’un en tirerait profit.

Je ne pense pas que vous y parveniez à l’aide des méthodes intégrées du framework .NET, car ils vont d’abord lire la totalité de l’image, puis l’afficher. Vous devrez trouver une autre bibliothèque prenant en charge l’affichage d’images partiellement téléchargées ou écrire vous-même un parsingur.

Vous pouvez probablement le faire, cependant, cela nécessitera des connaissances supplémentaires sur la structure des fichiers gif. Wotsit.org a plusieurs liens vers des documents de structure gif, pour vous aider à démarrer.

L’approche générale consisterait à prendre le total de vos données accumulées et à partir de la fin, rechercher en arrière jusqu’à ce que vous trouviez la fin d’un terminateur de bloc. Les données entre ce dernier bloc valide et la fin du stream ne sont que partiellement complètes et doivent être considérées comme des données indésirables. Vous souhaitez le supprimer et append un bloc de fin de fichier au stream. Ensuite, vous devriez pouvoir charger ce stream édité dans un PictureBox.

Il existe un événement que vous pouvez utiliser sur une demande de téléchargement Web asynchrone, appelé périodiquement et permettant de mettre à jour directement un contrôle ProgressBar. Voici un exemple d’utilisation de cet événement:

  delegate void SetProgressDelegate(int percentComplete); ///  /// A thread-safe method for updating the file download progress bar. ///  ///  ///  void SetDownloadProgress(int percentComplete) { if (this.InvokeRequired) { SetProgressDelegate d = new SetProgressDelegate(SetDownloadProgress); this.Invoke(d, new object[] { percentComplete }); } else { this.progressFileDownload.Value = percentComplete; } } ///  /// Event handler to update the progress bar during file download. ///  ///  ///  void web_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { SetDownloadProgress(e.ProgressPercentage); } 

Et voici comment j’ai connecté l’événement et commencé le téléchargement:

  WebClient web = new WebClient(); web.DownloadFileCompleted += new AsyncCompletedEventHandler(web_DownloadFileCompleted); web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(web_DownloadProgressChanged); web.DownloadFileAsync(sourceUri, destinationFileName); 

Votre solution lit le fichier directement dans la mémoire, tandis que la mienne l’enregistre dans un fichier sur disque. Cette solution peut donc ne pas fonctionner pour vous. Si l’affichage d’une indication de progression est important pour vous, cette méthode fonctionne et vous pouvez toujours télécharger dans un fichier temporaire, puis charger ce fichier dans le contrôle d’image une fois terminé.