如何在从网址加载时显示渐进式JPEG?我试图在WPF中的图像控件中显示Google地图图像,但我想保持图像的优势是渐进式JPG。
如何在WPF中加载渐进式JPG?
Image imgMap;
BitmapImage mapLoader = new BitmapImage();
mapLoader.BeginInit();
mapLoader.UriSource = new Uri(URL);
mapLoader.EndInit();
imgMap.Source = mapLoader;
目前,我这样做了。它只会在完全加载后显示图像。我想逐步展示它。
答案 0 :(得分: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;
}
答案 1 :(得分:1)
这似乎是Image控件的一个缺点。也许你可以创建一个继承自Image的StreamImage,在构造函数中获取一个流,从流中读取背景中的字节,在它有足够的时候计算出来,构造一个内部“模糊图像”,其中包含到目前为止读取的字节并呈现迭代地直到它具有所有字节。您必须了解渐进式JPEG的字节是如何发送的 - 我不认为这很简单。