2009-04-27 37 views
8

Tôi tải một hình ảnh từ một URL không đồng bộ sử dụng WebRequest theo cách này:Cách tải xuống hình ảnh từ web cho biết tiến trình tải xuống trong C# bằng cách sử dụng winforms?

public void Download(string 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; } 
} 

và nó hoạt động ok, nhưng tôi muốn thể hiện sự tiến bộ của tải như các trình duyệt làm, và không hiển thị chỉ khi nó kết thúc.

Nếu tôi làm

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

trước khi nó kết thúc tôi nhận được một ngoại lệ mà hình ảnh không hợp lệ, mặc dù nó có một số dữ liệu. Có cách nào để hiển thị dữ liệu một phần không?

+1

Nếu hình ảnh không hợp lệ, bạn sẽ không may mắn khi điều khiển PictureBox có liên quan. Theo tiến độ ... kiểm tra ContentLength của Response để biết tệp lớn như thế nào. –

Trả lời

5

JPEG có một chế độ mã hóa đặc biệt gọi là "Progressive JPEG", trong đó dữ liệu được nén trong nhiều đèo chi tiết dần dần cao hơn. Windows 7 có built-in support cho việc này.

+2

thông báo anh ta được mã hóa cứng trong hình ảnh/gif để có thể không giúp được –

+2

Windows 7 cũng hỗ trợ GIF: http://msdn.microsoft.com/en-us/library/dd408863(VS.85).aspx# _pnggifprogressivedecoding –

+0

thông tin thêm tại đây: http://en.wikipedia.org/wiki/Interlace_(bitmaps) – scottm

3

Khi bạn bắt đầu yêu cầu, kiểm tra WebResponse.ContentLength bất động sản, mà nên cung cấp cho bạn biết tổng số byte mong đợi. Sau đó theo dõi tổng số byte được đọc trong phương thức ReadCallback của bạn. Phần còn lại phải rõ ràng. :)

[sửa] Rất tiếc, tôi đọc lại câu hỏi, và đó không phải là khá những gì bạn muốn. Tôi vẫn còn bỏ mặc dù vậy, trong trường hợp ai đó có thể hưởng lợi từ nó.

2

Tôi không nghĩ rằng bạn sẽ quản lý rằng việc sử dụng các phương pháp tích hợp của .NET framework, kể từ lần đầu tiên họ sẽ đọc những hình ảnh đầy đủ và sau đó hiển thị nó. Bạn sẽ cần tìm một số thư viện khác hỗ trợ hiển thị hình ảnh được tải xuống một phần hoặc tự viết một trình phân tích cú pháp.

4

Tôi muốn hiển thị tiến trình tải xuống dưới dạng trình duyệt và không chỉ hiển thị khi quá trình này kết thúc.

Bạn có hai lựa chọn:

  1. Sử dụng WebClient.DownloadDataAsync. Điều này sẽ tăng sự kiện tiến độ qua số DownloadProgressChanged và cung cấp thông báo cuối cùng khi dữ liệu có sẵn qua sự kiện DownloadDataCompleted. Tại thời điểm đó, bạn có thể gán hình ảnh cho, ví dụ: PictureBox.

  2. Nếu bạn đang tải xuống hình ảnh để cuối cùng hiển thị trong điều khiển PictureBox thì thậm chí có thể dễ dàng hơn khi đi với PictureBox.LoadAsync. Điều này cũng sẽ cung cấp cập nhật tiến độ thông qua sự kiện LoadProgressChanged và cuối cùng là hoàn thành LoadCompleted.

4

Bạn gặp sự cố với điều khiển PictureBox, không phải với tải xuống một phần.

Một Hack là sử dụng WebBrowserControl, như IE có thể hiển thị hình ảnh một phần.

2

Bạn có lẽ có thể làm được điều này, tuy nhiên, nó sẽ yêu cầu một số bổ sung kiến ​​thức về cấu trúc của các file gif. Wotsit.org có một số liên kết đến tài liệu cấu trúc gif, để giúp bạn bắt đầu.

Cách tiếp cận chung sẽ là lấy tổng dữ liệu được tích lũy của bạn và từ cuối, tìm kiếm lại cho đến khi bạn tìm thấy kết thúc của một trình kết thúc khối. Dữ liệu giữa khối hợp lệ cuối cùng này và cuối luồng chỉ hoàn toàn một phần và phải được coi là dữ liệu rác. Bạn muốn xóa nó và thêm một khối theo sau vào luồng. Sau đó, bạn sẽ có thể tải luồng đã chỉnh sửa này vào một PictureBox.

1

Có sự kiện bạn có thể sử dụng trên yêu cầu tải xuống web không đồng bộ được gọi định kỳ và cho phép bạn cập nhật trực tiếp điều khiển ProgressBar. Dưới đây là một ví dụ về cách tôi đã sử dụng sự kiện này:

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

Và dưới đây là cách tôi dây lên sự kiện này và bắt đầu tải về:

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

giải pháp của bạn đọc các tập tin trực tiếp vào bộ nhớ, trong khi tôi lưu nó vào một tập tin trên đĩa, do đó, giải pháp này có thể hoặc có thể không làm việc cho bạn. Nếu hiển thị chỉ báo tiến trình quan trọng đối với bạn, phương pháp này hoạt động và bạn luôn có thể tải xuống tệp tạm thời, sau đó tải tệp đó vào điều khiển hình ảnh sau khi hoàn thành.

Các vấn đề liên quan