2010-11-12 128 views
20

我正在从一个程序下载图像从一个URL到一个bitmapimage并显示它。接下来,我尝试使用jpegbitmapencoder将bitmapimage保存到硬盘上。该文件已成功创建,但实际的jpeg图像为空或1个黑色像素。保存BitmapImage到文件

public Guid SavePhoto(string istrImagePath) 
{ 
    ImagePath = istrImagePath; 

    BitmapImage objImage = new BitmapImage(
     new Uri(istrImagePath, UriKind.RelativeOrAbsolute)); 
    PictureDisplayed.Source = objImage; 
    savedCreationObject = objImage; 

    Guid photoID = System.Guid.NewGuid(); 
    string photolocation = photoID.ToString() + ".jpg"; //file name 
    FileStream filestream = new FileStream(photolocation, FileMode.Create); 
    JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
    encoder.Frames.Add(BitmapFrame.Create(objImage)); 
    encoder.Save(filestream); 

    return photoID; 
} 

这是保存并显示照片的功能。照片显示正确,但保存时会再次显示空白jpeg或1个黑色像素。

+0

只需使用encoder.Frames.Add(BitmapFrame.Create(新的WriteableBitmap(objImage))); – Andreas 2016-06-09 13:16:55

回答

28

当您从Uri创建BitmapImage时,需要时间来下载图像。

如果您检查以下属性,该值将可能是TRUE

objImage.IsDownloading 

因此,你多少附加一个监听器DownloadCompleted事件处理程序,将所有处理该事件处理程序。

objImage.DownloadCompleted += objImage_DownloadCompleted; 

如果该处理程序看起来像:

private void objImage_DownloadCompleted(object sender, EventArgs e) 
{ 
    JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
    Guid photoID = System.Guid.NewGuid(); 
    String photolocation = photoID.ToString() + ".jpg"; //file name 

    encoder.Frames.Add(BitmapFrame.Create((BitmapImage)sender)); 

    using (var filestream = new FileStream(photolocation, FileMode.Create)) 
    encoder.Save(filestream); 
} 

你可能也想添加一个事件处理程序的DownloadFailed,以便适当地处理任何错误情况。

编辑基于Ben的评论

加全样本类:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
    InitializeComponent(); 

    SavePhoto("http://www.google.ca/intl/en_com/images/srpr/logo1w.png"); 
    } 

    public void SavePhoto(string istrImagePath) 
    { 
    BitmapImage objImage = new BitmapImage(new Uri(istrImagePath, UriKind.RelativeOrAbsolute)); 

    objImage.DownloadCompleted += objImage_DownloadCompleted; 
    } 

    private void objImage_DownloadCompleted(object sender, EventArgs e) 
    { 
    JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
    Guid photoID = System.Guid.NewGuid(); 
    String photolocation = photoID.ToString() + ".jpg"; //file name 

    encoder.Frames.Add(BitmapFrame.Create((BitmapImage)sender)); 

    using (var filestream = new FileStream(photolocation, FileMode.Create)) 
     encoder.Save(filestream); 
    } 
} 
+0

我测试了你的代码,同样的问题仍然存在。保存的jpeg为空或具有1个黑色像素。 – 2010-11-12 04:07:30

+0

@Ben - 代码运行...更新的答案将用于测试我的答案的完整示例代码;那对你有用吗?应下载9KB Google徽标并将其保存到磁盘。 – 2010-11-12 04:11:20

+0

感谢您的代码完美工作,并且在我的代码中工作。你指出的问题是该照片没有完全从Uri下载。再次,谢谢。 – 2010-11-12 04:37:41

4

扩大克里斯·巴克斯特的解决方案,这种转换器使用本地版本,如果它存在,否则它下载并保存文件。

using System; 
using System.Globalization; 
using System.IO; 
using System.Windows.Data; 
using System.Windows.Media.Imaging; 

namespace MyNamespace 
{ 
    public sealed class UriToCachedImageConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      var url = value as string; 
      if (url == null) 
       return null; 

      var webUri = new Uri(url, UriKind.Absolute); 
      var filename = Path.GetFileName(webUri.AbsolutePath); 

      var localFilePath = Path.Combine("C:\\MyImagesFolder\\", filename); 

      if (File.Exists(localFilePath)) 
      { 
       return BitmapFrame.Create(new Uri(localFilePath, UriKind.Absolute)); 
      } 

      var image = new BitmapImage(); 
      image.BeginInit(); 
      image.CacheOption = BitmapCacheOption.OnLoad; 
      image.UriSource = webUri; 
      image.EndInit(); 

      SaveImage(image, localFilePath); 

      return image; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 

     public void SaveImage(BitmapImage image, string localFilePath) 
     { 
      image.DownloadCompleted += (sender, args) => 
      { 
       var encoder = new PngBitmapEncoder(); 
       encoder.Frames.Add(BitmapFrame.Create((BitmapImage) sender)); 
       using (var filestream = new FileStream(localFilePath, FileMode.Create)) 
       { 
        encoder.Save(filestream); 
       } 
      }; 
     } 
    } 
} 

并确保您可以在XAML

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:u="clr-namespace:MyNamespace"   
      d:DesignHeight="500" 
      d:DesignWidth="420"> 
    <UserControl.Resources> 
     <ResourceDictionary> 
      <u:UriToCachedImageConverter x:Key="UrlToCachedImageConverter" /> 
     </ResourceDictionary> 
    </UserControl.Resources>    
</UserControl> 

中访问转换器和使用该转换器的图像

<Image Source="{Binding URL, Mode=OneWay, Converter={StaticResource UrlToCachedImageConverter}, IsAsync=true}"/>