图像编辑例外 [英] Image edit exceptions

查看:138
本文介绍了图像编辑例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在MVVM WPF应用程序的工作。载入和编辑在imageSlider一个图像给我的错误和异常

I'm working in WPF application with MVVM. Loading and Editing a image in imageSlider gives me error and exceptions.

加载图像:内存不足,无法处理
编辑图片:共享冲突

视图模型:

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 打开,当我保​​存它抛出我共享冲突错误。累了几个解决方案张贴在SO 这里和的here 。当尝试这些我可以能够编辑图像并保存没有任何错误。但是,使用滑块控件(Next和Back)时,当它加载较重的图像,经常会抛出我内存不足,无法处理例外。

The code above works fine with the imageSlider(Next and Back). But during edit it opens in mspaint and when i save it throws me Sharing violation error. Tired few solutions posted in SO here and here . When trying these i can able to edit the image and save without any error. But when using the Slider control (Next and Back) and when it loads heavier images, frequently it throws me Insufficient memory to handle exception.

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

So now i need to eliminate both these issues. Kindly help.

推荐答案

您需要为编辑给观众不同的方式来做事情有点

You need to do things a little differently for an editor to a viewer

你的模型需要更新到一个视图模型,因为它会改变(你可以用模型来构建视图模型,但是在这种情况下,有示范这么少的功能,你还不如用FileInfo类的模型)

your Model needs to be updated to a ViewModel as it will be changing ( you can use the model to build the ViewModel, however in this case there is so little functionality in the Model that you might as well use the FIleInfo class as your model)

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语句那么它​​的一个好主意,我们清理

note: as we are using a memory stream with out the using statement then its a good idea to us the IDisposable interface for clean up

这是什么做的是创造一个常驻内存位图,然后使用,作为一个框架,这消除了打开读取锁定上,你用一个URI

what this is doing is creating a memory resident bitmap then using that as a Frame, this removes the openRead lock on on the file that you get with a normal bitmap with a URI

接下来我们有编辑器本身

next we have the Editor itself

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

请注意,如果你正在做的任何缩放/拉伸的图像,然后你需要使它们或之前扭转对笔画的操作或修改将在相对于屏幕没有图像

Note if you are doing any scaling/stretching on the image then you need to reverse the operation on the Strokes before rendering them or or the edits will be in relation to the screen not the image

这篇关于图像编辑例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆