2011-05-14 4 views
18

웹 URL에서로드하는 과정에서 점진적 JPEG를 표시하는 방법은 무엇입니까? WPF의 이미지 컨트롤에 Google Maps 이미지를 표시하려고하지만 이미지가 점진적으로 JPG로 유지되도록하고 싶습니다.어떻게 프로그레시브 JPEG를 WPF로 표시 할 수 있습니까?

WPF에서 프로그레시브 JPG를로드하는 방법은 무엇입니까?

Image imgMap; 
BitmapImage mapLoader = new BitmapImage(); 

mapLoader.BeginInit(); 
mapLoader.UriSource = new Uri(URL); 
mapLoader.EndInit(); 

imgMap.Source = mapLoader; 

현재이 작업을 수행하고 있습니다. 이미지가 완전히로드 된 후에 만 ​​이미지가 표시됩니다. 나는 그것을 점진적으로 보여주고 싶다.

답변

12

매우 기본적인 샘플입니다. 확실히 거기에 최적화 할 수있는 여지가 있으며, 많은 요청을 처리 할 수있는 별도의 클래스를 수행 할 수 있지만 적어도 작동하는 것은 필요하며 사용자는이를 위해 모양을 지정할 수 있습니다. 또한이 샘플은 진행 상황을보고 할 때마다 이미지를 생성하므로주의해야합니다. 커다란 오버 헤드를 피하기 위해 약 5 % 정도의 이미지를 만듭니다.

XAML :

<Window x:Class="ScrollViewerTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <StackPanel> 
    <TextBlock Text="{Binding Path=Progress, StringFormat=Progress: {0}}" /> 
    <Image Source="{Binding Path=Image}" /> 
    </StackPanel> 
</Window> 

코드 숨김

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 

    #region Public Properties 

    private int _progress; 
    public int Progress 
    { 
    get { return _progress; } 
    set 
    { 
     if (_progress != value) 
     { 
     _progress = value; 

     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs("Progress")); 
     } 
    } 
    } 

    private BitmapImage image; 
    public BitmapImage Image 
    { 
    get { return image; } 
    set 
    { 
     if (image != value) 
     { 
     image = value; 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs("Image")); 
     } 
    } 
    } 

    #endregion 

    BackgroundWorker worker = new BackgroundWorker(); 

    public MainWindow() 
    { 
    InitializeComponent(); 

    worker.DoWork += backgroundWorker1_DoWork; 
    worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); 
    worker.WorkerReportsProgress = true; 
    worker.RunWorkerAsync(@"http://Tools.CentralShooters.co.nz/Images/ProgressiveSample1.jpg"); 
    } 

    // This function is based on code from 
    // http://devtoolshed.com/content/c-download-file-progress-bar 
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
    // the URL to download the file from 
    string sUrlToReadFileFrom = e.Argument as string; 

    // first, we need to get the exact size (in bytes) of the file we are downloading 
    Uri url = new Uri(sUrlToReadFileFrom); 
    System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); 
    System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); 
    response.Close(); 
    // gets the size of the file in bytes 
    Int64 iSize = response.ContentLength; 

    // keeps track of the total bytes downloaded so we can update the progress bar 
    Int64 iRunningByteTotal = 0; 

    // use the webclient object to download the file 
    using (System.Net.WebClient client = new System.Net.WebClient()) 
    { 
     // open the file at the remote URL for reading 
     using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom))) 
     { 
     using (Stream streamLocal = new MemoryStream((int)iSize)) 
     { 
      // loop the stream and get the file into the byte buffer 
      int iByteSize = 0; 
      byte[] byteBuffer = new byte[iSize]; 
      while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0) 
      { 
      // write the bytes to the file system at the file path specified 
      streamLocal.Write(byteBuffer, 0, iByteSize); 
      iRunningByteTotal += iByteSize; 

      // calculate the progress out of a base "100" 
      double dIndex = (double)(iRunningByteTotal); 
      double dTotal = (double)byteBuffer.Length; 
      double dProgressPercentage = (dIndex/dTotal); 
      int iProgressPercentage = (int)(dProgressPercentage * 100); 

      // update the progress bar, and we pass our MemoryStream, 
      // so we can use it in the progress changed event handler 
      worker.ReportProgress(iProgressPercentage, streamLocal); 
      } 

      // clean up the file stream 
      streamLocal.Close(); 
     } 

     // close the connection to the remote server 
     streamRemote.Close(); 
     } 
    } 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
    Dispatcher.BeginInvoke(
     System.Windows.Threading.DispatcherPriority.Normal, 
     new Action(delegate() 
     { 
      MemoryStream stream = e.UserState as MemoryStream; 

      BitmapImage bi = new BitmapImage(); 
      bi.BeginInit(); 
      bi.StreamSource = new MemoryStream(stream.ToArray()); 
      bi.EndInit(); 

      this.Progress = e.ProgressPercentage; 
      this.Image = bi; 
     } 
     )); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 
+0

@TFD Google 프로그레시브 JPeG를 제안합니다. 그것이 무엇인지에 대한 많은 자원이 있습니다. 그러나 정말로 그들을 다루는 방법은 아닙니다. 특히 .net에서 .net을 쓰는 것은 쉬운 일이 아닙니다. – Mel

+4

나는 Progressive 일을 정말로 건너 뛰는 동안, 나는 약간 자신을 방어하려고 노력할 것이다. 기본 문제는 다운로드가 완료되었을 때만 이미지가 나타나고, OP는 이미지의 일부를 보여주고 자 할 때 donwloading하는 것이다. 내 샘플 코드가 그것을 않습니다. 그것의 문제에 대한 해결책이며, 당신이 위에서 읽을 수있는 욕구에 대한 대답입니다 : '진보적으로 보여주고 싶습니다.' _question_에 대한 답변이 없어도 문제는 해결됩니다. 최종 사용자는 다운로드 이미지의 진행 상황을 볼 수 있습니다. 어쩌면 나는 OP가 내 대답을 받아 들일 자격이 될 수는 없지만, 나는 그 중 하나를받을 자격이 없다. – Ben

+0

@BoltClock 나는 진보적 인 JPG가 무엇인지 안다. 진행률 막대는 무엇입니까? 이 샘플 코드는 "진행률 : {0}"을 사용하여 이미지와 퍼센트 완료 카운터를 보여줍니다. 해당 부분 스트림을 사용할 수있는 경우 이미지가 표시됩니다. 그것이 OP가 원했던 것입니까? 유일한 실수는 프로그레시브 JPG 샘플에 연결하지 않는 것이 었습니다. URL을 큰 프로그레시브로 변경하면 제대로 작동하는 것을 볼 수 있습니다. 제발 -1 기술적으로 정확한 게시물을하지 마십시오 – TFD

1

이 이미지 컨트롤의 단점으로 보인다. 어쩌면 당신은 Image로부터 상속받은 StreamImage를 생성하고, 생성자에서 스트림을 취하고, 스트림에서 백그라운드의 바이트를 읽고, 충분한 시간을 계산하고, 지금까지 읽은 바이트로 내부 "퍼지 이미지"를 생성하고 반복적으로 모든 바이트를 가질 때까지. 프로그레시브 JPEG의 바이트를 보내는 방법을 이해해야합니다. 간단하다고 생각하지 않습니다.

+0

@Patrick_Szalapski 이해가 안됩니다. 귀하의 의견은 어디에서오고 있습니다. WPF 이미지는 점진적 jpg를 완벽하게 지원합니다. 단점이 없습니다. 그냥 작동합니다[email protected]의 대답 – TFD

+1

@TFD를 참조하십시오. 그래도 부분 이미지를 매 5 %마다 다시 렌더링합니다. 전체 지원은로드 될 때 한 번에 렌더링을 렌더링합니다. – Rup

+0

맞아요. @ Ben의 모든 코드가 컨트롤에 구워진 맞춤 컨트롤이라고 생각했습니다. 외부에서 해당 코드를 관리하는 경우 특수 컨트롤이 필요하지 않습니다. –

관련 문제