2010-11-12 6 views
20

Je travaille sur un programme qui télécharge des images d'une URL vers un fichier bitmap et l'affiche. Ensuite, j'essaie de sauvegarder l'image bitmap sur le disque dur en utilisant jpegbitmapencoder. Le fichier est créé avec succès mais l'image jpeg réelle est vide ou 1 pixel noir.Enregistrer BitmapImage dans le fichier

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; 
} 

Cette fonction enregistre et affiche la photo. La photo est affichée correctement mais à nouveau quand elle est enregistrée je reçois un jpeg vide ou 1 pixel noir. Lorsque vous créez votre image bitmap à partir d'un Uri, le temps est nécessaire pour télécharger l'image.

+0

utiliser juste encoder.Frames.Add (BitmapFrame.Create (new WriteableBitmap (objImage))); – Andreas

Répondre

28

Si vous vérifiez la propriété suivante, la valeur sera probablement vrai

objImage.IsDownloading 

En tant que tel, vous attachez beaucoup un écouteur au gestionnaire d'événements DownloadCompleted et déplacer tous les traitements que EventHandler.

objImage.DownloadCompleted += objImage_DownloadCompleted; 

Si ce gestionnaire ressemblera à quelque chose comme:

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); 
} 

Vous voudrez probablement aussi ajouter un autre pour EventHandler DownloadFailed afin de gérer correctement les cas d'erreur.

Modifier

Ajouté classe de l'échantillon complet basé sur le commentaire de 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

J'ai testé votre code et le même problème se produit toujours. le jpeg enregistré est vide ou a 1 pixel noir. –

+0

@Ben - Le code s'exécute ... la réponse mise à jour sera l'échantillon complet du code que j'ai utilisé pour tester ma réponse; est-ce que ça marche pour toi? Devrait télécharger le logo Google 9KB et l'enregistrer sur le disque. –

+0

Merci votre code fonctionne parfaitement et cela fonctionne dans mon code aussi bien. Le problème que vous avez signalé était que la photo n'avait pas été complètement téléchargée de l'Uri. Merci encore. –

4

L'expansion sur la solution de Chris Baxter, ce convertisseur utilise la version locale si elle existe, sinon il télécharge et enregistre le fichier .

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); 
       } 
      }; 
     } 
    } 
} 

Et assurez-vous que vous pouvez accéder au convertisseur de votre 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> 

Et utiliser le convertisseur sur une image

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