c# - Enregistrer BitmapImage dans un fichier



save (2)

Développant la solution de Chris Baxter, ce convertisseur utilise la version locale si elle existe, sinon la 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 dans 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}"/>

Je travaille sur un programme qui télécharge des images depuis 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.

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

C'est la fonction qui enregistre et affiche la photo. La photo est affichée correctement, mais encore une fois quand elle est enregistrée, je reçois un JPEG ou 1 pixel noir.


Lorsque vous créez votre BitmapImage à partir d'un Uri, le temps est nécessaire pour télécharger l'image.

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

objImage.IsDownloading

En tant que tel, vous attachez beaucoup d'écouteur au gestionnaire d'événements DownloadCompleted et déplacez tous les traitements vers ce gestionnaire d'événements.

objImage.DownloadCompleted += objImage_DownloadCompleted;

Où 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 également ajouter un autre EventHandler pour DownloadFailed afin de gérer de manière appropriée tous les cas d'erreur.

modifier

Ajout de la classe d'échantillon complète basée 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);
  } 
}




bitmapimage