如何在 wpf mvvm 项目中将图像加载和保存为字节数组
How to load and save image as byte array in a wpf mvvm project
我在视图中有一个图像,它绑定到视图模型中的一个字节数组。
<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));
}
}
用户通过执行此命令的按钮加载图像
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));
}
问题是,当我尝试加载图像时,转换器接收 null 作为参数。如果我从 xaml 文件中的绑定中删除转换器,它会成功加载到视图,但不能绑定到视图模型中的 属性。
这是转换器的实现
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();
}
}
}
是什么导致了空输入?
您正在使用 WinForms Image
class 而不是 WPF BitmapSource
。 BitmapSource 是 ImageSource
的子class,它是 Image 元素的 Source
属性.
的类型
您的转换器应如下所示:
public class ByteArrayToBitmapSourceConverter : 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)
{
BitmapSource bitmap = null;
if (buffer != null)
{
using (var stream = new MemoryStream(buffer))
{
bitmap = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
return bitmap;
}
public static byte[] ToByteArray(BitmapSource bitmap)
{
byte[] buffer = null;
if (bitmap != null)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
buffer = stream.ToArray();
}
}
return buffer;
}
}
然而,直接将图像文件中的帧缓冲区分配给视图模型属性会很多更简单
viewModel.InputImage = File.ReadAllBytes(op.FileName);
您根本不需要您的转换器,因为由于 built-in 类型转换,Image.Source
属性 可以直接绑定到 string
类型的源属性, Uri
和 byte[]
(除了 ImageSource
)。
所以你可以简单地写
<Image Source="{Binding InputImage}" ... />
我在视图中有一个图像,它绑定到视图模型中的一个字节数组。
<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));
}
}
用户通过执行此命令的按钮加载图像
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)); }
问题是,当我尝试加载图像时,转换器接收 null 作为参数。如果我从 xaml 文件中的绑定中删除转换器,它会成功加载到视图,但不能绑定到视图模型中的 属性。
这是转换器的实现
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();
}
}
}
是什么导致了空输入?
您正在使用 WinForms Image
class 而不是 WPF BitmapSource
。 BitmapSource 是 ImageSource
的子class,它是 Image 元素的 Source
属性.
您的转换器应如下所示:
public class ByteArrayToBitmapSourceConverter : 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)
{
BitmapSource bitmap = null;
if (buffer != null)
{
using (var stream = new MemoryStream(buffer))
{
bitmap = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
return bitmap;
}
public static byte[] ToByteArray(BitmapSource bitmap)
{
byte[] buffer = null;
if (bitmap != null)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
buffer = stream.ToArray();
}
}
return buffer;
}
}
然而,直接将图像文件中的帧缓冲区分配给视图模型属性会很多更简单
viewModel.InputImage = File.ReadAllBytes(op.FileName);
您根本不需要您的转换器,因为由于 built-in 类型转换,Image.Source
属性 可以直接绑定到 string
类型的源属性, Uri
和 byte[]
(除了 ImageSource
)。
所以你可以简单地写
<Image Source="{Binding InputImage}" ... />