Home > OS >  How to upload and save image as byte array in a wpf mvvm projct
How to upload and save image as byte array in a wpf mvvm projct

Time:05-24

So I have an Image in the View which is bound to byte array in the ViewModel.

 <Image 
        Source="{ Binding InputImage, Converter={StaticResource imageConvertor}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
        Panel.ZIndex="1"
        x:Name="UploadImage"
        Grid.Column="0"
        Grid.Row="0"
        Stretch="Uniform"
        Margin="5"
        />


private byte[] inputImage;

    public byte[] InputImage
    {
        get { return inputImage; }
        set 
        { 
            inputImage = value; 
            OnPropertyChanged(nameof(InputImage));
        }
    }

The user uploads an image from their fails via button which executes this command

OpenFileDialog op = new OpenFileDialog();
        op.Title = "Select a picture";
        op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|"  
          "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|"  
          "Portable Network Graphic (*.png)|*.png";
        if (op.ShowDialog() == true)
        {
            UploadImage.Source = new BitmapImage(new Uri(op.FileName));
        }

The problems is that when I try to upload an image the the converter receives null as parameter. If I remove the converter from the binding in the xaml file it gets uploaded successfully to the view but it cannot be bound to the property in the ViewModel.

This is the implementation of the converter

 public class ByteArrayToBitmapImageConverter : IValueConverter
{
    public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return null;
        }
        else
            return ToImage(value as byte[]);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return null;
        }
        else
            return ToBinary(value as Image);

    }

    public static Image ToImage(Byte[] binary)
    {
        Image image = null;
        if (binary == null || binary.Length < 100) return image;

        using (MemoryStream ms = new MemoryStream(binary))
        {
            image = Image.FromStream(ms);
        }
        return image;
    }

  public static Byte[] ToBinary(Image image)
    {
        if (image == null) return null;
        using (MemoryStream memoryStream = new MemoryStream())
        {
            image.Save(memoryStream, ImageFormat.Png);
            return memoryStream.ToArray();
        }
    }

}

What causes the null inputs

CodePudding user response:

You are using the WinForms Image class instead of the WPF BitmapSource. BitmapSource is a subclass of ImageSource, which is the type of the Image element's Source property.

Your converter should look like this:

public class ByteArrayToBitmapImageConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ToBitmapSource(value as byte[]);
    }

    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ToByteArray(value as BitmapSource);
    }

    public static BitmapSource ToBitmapSource(byte[] buffer)
    {
        if (buffer == null)
        {
            return null;
        }

        using (var stream = new MemoryStream(buffer))
        {
            return BitmapFrame.Create(
                stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }
    }

    public static byte[] ToByteArray(BitmapSource bitmap)
    {
        if (bitmap == null)
        {
            return null;
        }

        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));

        using (var stream = new MemoryStream())
        {
            encoder.Save(stream);
            return stream.ToArray();
        }
    }
}

It would however be a lot simpler to directly assign the frame buffer from the image file to the view model property like

viewModel.InputImage = File.ReadAllBytes(op.FileName);

You would not need your converter at all, because due to built-in type conversion, the Image.Source property can directly be bound to source properties of type string, Uri and byte[] (besides ImageSource).

  • Related