gpt4 book ai didi

c# - 图像编辑异常(exception)

转载 作者:行者123 更新时间:2023-12-03 10:34:25 27 4
gpt4 key购买 nike

我正在使用 MVVM 处理 WPF 应用程序。在 imageSlider 中加载和编辑图像会给我错误和异常。

加载图片:Insufficient memory to handle图片编辑:Sharing violation
View 模型:

public class ImageList : INotifyPropertyChanged
{
#region Fields
private ObservableCollection<ImageItem> images = new ObservableCollection<ImageItem>();
private int selectedIndex;
private ImageItem currentImage;

#endregion Fields

#region Properties

public ObservableCollection<ImageItem> Images
{
get { return images; }
set { images = value; }
}

public int SelectedIndex
{
get { return selectedIndex; }
set
{
if(value < Images.Count && value > -1)
{
selectedIndex = value; OnPropertyChanged();
CurrentImage = Images[selectedIndex];
}
}
}

public ImageItem CurrentImage
{
get { return currentImage; }
set { currentImage = value; OnPropertyChanged(); }
}

#endregion Properties

#region Public Methods

public void Next()
{
SelectedIndex ++;
}

public void Back()
{
SelectedIndex--;
}

#endregion Public Methods

#region Methods

public void AddNewImage()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.gif, *.png, *.bmp, *.tif) | *.jpg; *.jpeg; *.jpe; *.gif; *.png, *.bmp, *.tif";
dlg.ShowDialog();

if(dlg.FileName != "")
{
Images.Add(new ImageItem() { URI = new Uri(dlg.FileName) });
SelectedIndex = Images.Count - 1;
}
}

#endregion Methods

#region Constructors

public ImageList()
{
_canExecute = true;
}

#endregion Constructors

#region Commands

private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
}
}

private bool _canExecute;

private ICommand nextCommand;

public ICommand NextCommand
{
get
{
if (nextCommand == null)
{
nextCommand = new CommandHandler(()=> OnNextCommand(), true);
}
return nextCommand;
}
set { nextCommand = value; }
}

private void OnNextCommand()
{
Next();
}
private ICommand backCommand;

public ICommand BackCommand
{
get
{
if(backCommand == null)
{
backCommand = new CommandHandler(() => OnBackCommand(), true);
}
return backCommand;
}
set { backCommand = value; }
}

private void OnBackCommand()
{
Back();
}

private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
}
}

private ICommand _EditImageCommand;
public ICommand EditImageCommand
{
get
{
return _EditImageCommand ?? (_EditImageCommand = new CommandHandler(obj => EditImage(obj), _canExecute));
}
}

#endregion Commands

public void EditImage(object obj)
{
string ss = ((ImageItem)obj).URI.AbsolutePath;
Process proc = Process.Start(ss);
if (proc != null)
{
proc.EnableRaisingEvents = true;
ProcessStartInfo startInfo = new ProcessStartInfo();
//startInfo.Verb = "edit";
startInfo.FileName = ("mspaint.exe");
proc.StartInfo = startInfo;

}
}


#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

#endregion INotifyPropertyChanged

}`

模型:
 public class ImageItem
{
public Uri URI { get; set; }

private BitmapSource _Source;

public BitmapSource Source
{
get
{
try
{
if (_Source == null) _Source = new BitmapImage(URI);//lazy loading

}
catch (Exception)
{
_Source = null;
}
return _Source;
}
}

public void Save(string filename)
{
var img = BitmapFrame.Create(Source);
var encoder = new JpegBitmapEncoder();

encoder.Frames.Add(img);
using (var saveStream = System.IO.File.OpenWrite(filename))
encoder.Save(saveStream);

}


}

XAML
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
</Grid.ColumnDefinitions>

<Button Content="&lt;" Command="{Binding BackCommand}" Width="25" Grid.Row="0" Grid.Column="0"/>
<Button DockPanel.Dock="Right" Content="&gt;" Command="{Binding NextCommand}" Width="25" Grid.Row="0" Grid.Column="2"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay}" Grid.Row="0" Grid.Column="1">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit Image" Command="{Binding EditImageCommand, Source={StaticResource SliderViewModel}}" CommandParameter="{Binding CurrentImage}"></MenuItem>
</ContextMenu>
</Image.ContextMenu>
</Image>
<Button Content="Add" Command="{Binding ClickCommand}" Height="30" Width="50" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4"></Button>
<!--<Image Source="{Binding CurrentImage.Source, Mode=OneWay}" Grid.Row="2" Grid.Column="1"/>-->
</Grid>
</DockPanel>

上面的代码适用于 imageSlider(Next 和 Back)。但在编辑过程中,它会在 mspaint 中打开当我保存它时,我会抛出 Sharing violation error .在 SO here 中发布了一些厌倦的解决方案和 here .尝试这些时,我可以编辑图像并保存而不会出现任何错误。但是当使用 Slider 控件(Next 和 Back)并加载较重的图像时,它经常抛出我 Insufficient memory to handle异常(exception)。

所以现在我需要消除这两个问题。请帮忙。

最佳答案

您需要为编辑者和查看者做一些不同的事情

您的模型需要更新为 ViewModel,因为它会发生变化(您可以使用模型来构建 ViewModel,但是在这种情况下,模型中的功能非常少,您不妨使用 FIleInfo 类作为模型)

public class ImageEditor: IDisposable,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private List<FileInfo> images = new List<FileInfo>();

private FileInfo _ImageFile;
public static readonly PropertyChangedEventArgs FilenameProperty = new PropertyChangedEventArgs(nameof(ImageFile));

public FileInfo ImageFile
{
get { return _ImageFile; }
set
{
_ImageFile = value;
Strokes.Clear();
PropertyChanged?.Invoke(this, ImageFrameProperty);
}
}

private int selectedIndex;
public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs(nameof(SelectedIndex));
public int SelectedIndex
{
get { return selectedIndex; }
private set
{
if (value < images.Count && value > -1)
{
selectedIndex = value;
PropertyChanged?.Invoke(this, SelectedIndexProperty);
ImageFile = images[selectedIndex];
Load();
}
}
}

MemoryStream mem;
private BitmapSource _ImageFrame;
public static readonly PropertyChangedEventArgs ImageFrameProperty = new PropertyChangedEventArgs(nameof(ImageFrame));
public BitmapSource ImageFrame
{
get { return _ImageFrame; }
set
{
_ImageFrame = value;
PropertyChanged?.Invoke(this, ImageFrameProperty);
}
}

public StrokeCollection Strokes { get; } = new StrokeCollection();

public void Open(FileInfo file)
{
images.Add(file);
SelectedIndex = images.Count - 1;
}
public void Next()
{
SelectedIndex++;
}

public void Back()
{
SelectedIndex--;
}

public void Load()
{
ImageFile.Refresh();
if (ImageFile.Exists)
{
if (mem != null)
{
mem.Dispose();
}
using (var stream = ImageFile.OpenRead())
{
mem = new MemoryStream();
stream.CopyTo(mem);
}
ImageFrame = BitmapFrame.Create(mem);
}
}
public void Dispose()
{
if (mem != null)
{
mem.Dispose();
}
ImageFrame = null;
}

public void Save()
{

DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{

drawingContext.DrawImage(ImageFrame, new Rect(0, 0, ImageFrame.Width, ImageFrame.Height));
foreach (var item in Strokes)
{
item.Draw(drawingContext);
}
drawingContext.Close();
Strokes.Clear();
var width = ImageFrame.Width;
var height = ImageFrame.Height;
var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);

ImageFrame = bitmap;

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

using (var stream = ImageFile.OpenWrite())
{
encoder.Save(stream);
}
}
}
}

注意:由于我们使用的是没有 using 语句的内存流,因此使用 IDisposable 接口(interface)进行清理对​​我们来说是个好主意

这样做是创建一个内存驻留位图,然后将其用作框架,这将删除您使用带有 URI 的普通位图获得的文件上的 openRead 锁定

接下来我们有编辑器本身
<Window x:Class="ImageDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImageDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Closing="Window_Closing" >
<Window.DataContext>
<local:ImageEditor x:Name="editor" />

</Window.DataContext>

<DockPanel>
<Menu DockPanel.Dock="Top" >
<MenuItem Header="File" >
<MenuItem Command="ApplicationCommands.Open" />
<MenuItem Command="ApplicationCommands.Save" />
</MenuItem>
<MenuItem Command="ApplicationCommands.Undo" />
<ComboBox SelectedValue="{Binding DefaultDrawingAttributes.Color, ElementName=inkCanvas}">
<Color>White</Color>
<Color>Black</Color>
<Color>Yellow</Color>
<Color>Red</Color>
<Color>Cyan</Color>
<Color>SpringGreen</Color>
<ComboBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="15" Height="15">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding Mode=OneWay}" />
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Menu>
<Button Content="&lt;" Click="Back_Click"/>
<Button Content="&gt;" DockPanel.Dock="Right" Click="Next_Click"/>
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
<Image Source="{Binding ImageFrame}" Stretch="None"/>
<InkCanvas x:Name="inkCanvas" Background="Transparent" Strokes="{Binding Strokes}" >
<InkCanvas.DefaultDrawingAttributes>
<DrawingAttributes x:Name="DrawSetting" />
</InkCanvas.DefaultDrawingAttributes>
</InkCanvas>
</Grid>
</DockPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, execSave, hasChanged));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, execOpen));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, execUndo, hasChanged));
}

private void execOpen(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();

if(dlg.ShowDialog() ?? false)
{
editor.Open(new System.IO.FileInfo(dlg.FileName));
}
e.Handled = true;
}

private void hasChanged(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = editor.Strokes.Count > 0;
e.Handled = true;
}

private void execUndo(object sender, ExecutedRoutedEventArgs e)
{
editor.Strokes.Remove(editor.Strokes.Last());
e.Handled = true;
}

private void execSave(object sender, ExecutedRoutedEventArgs e)
{
editor.Save();
e.Handled = true;
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
editor.Dispose();
}

private void Next_Click(object sender, RoutedEventArgs e)
{
editor.Next();
}
private void Back_Click(object sender, RoutedEventArgs e)
{
editor.Back();
}
}

请注意,如果您正在对图像进行任何缩放/拉伸(stretch),那么您需要在渲染它们之前反转对 Stroke 的操作,否则编辑将与屏幕而不是图像相关

关于c# - 图像编辑异常(exception),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38652086/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com