WPF / C#在ValueChanged事件中更新(和处理)Bitmap / BitmapSource?

时间:2014-10-26 14:21:23

标签: c# wpf

我有一个小型的图像编辑程序,可以打开一个图像并为它做一些奇特的东西。在这种情况下,我试图调整像素的亮度。问题是没有正确的像素,它在我的滑块的ValueChanged事件中处理了Bitmap / BitmapSources。

所以基本上用户会点击一个按钮,它会打开一个带滑块的新窗口。这个新窗口会生成原始位图的副本供以后使用。

当滑块的值发生变化时,它将从原始位图创建一个具有相应亮度增加的新位图,从中创建一个新的BitmapSource,并更新图像控件的源。即使我使用'使用'声明,我仍然得到一个"内存不足"滑动这么长时间后的异常。

知道为什么会这样吗?是否有更好的解决方法可以实现相同的目标?我已经包含以下代码:

using Imagin.Slideshow;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Imagin
{
    /// <summary>
    /// Interaction logic for BrightnessWindow.xaml
    /// </summary>
    public partial class BrightnessWindow : Window
    {

        public int Increase;

        private System.Drawing.Bitmap Bitmap;
        private System.Drawing.Bitmap NewBitmap;

        private MainWindow ParentWindow;

        public BrightnessWindow(MainWindow m)
        {

            InitializeComponent();

            this.ParentWindow = m;

            this.Bitmap = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone();

        }

        private void slider1_ValueChanged(object sender, RoutedEventArgs e) 
        {

            using (System.Drawing.Bitmap b = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone(new RectangleF() { Width = (int)this.ParentWindow.Document.Bitmap.Width, Height = (int)this.ParentWindow.Document.Bitmap.Height, X = 0, Y = 0 }, this.ParentWindow.Document.Bitmap.PixelFormat))
            {
                this.ParentWindow.SetPixels(b, AdjustmentTypes.Brightness, Convert.ToInt32(this.slider1.Value));
                BitmapSource m = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                this.ParentWindow.image1.Source = m;
                this.NewBitmap = (System.Drawing.Bitmap)b.Clone();
            }

        }

        private void applyButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.NewBitmap != null)
            {
                this.ParentWindow.Document.Bitmap = this.NewBitmap;
            }
            this.Close();
        }

        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.ParentWindow.Document.Refresh();

            this.Close();
        }
    }
}

我想知道的另一件事是,是否有更好的方法来改变MainWindow的控件而不必将其作为参数传递,或者这是否是这种事情的首选方法?谢谢!

1 个答案:

答案 0 :(得分:0)

http://msdn.microsoft.com/en-us/library/1dz311e4%28v=vs.110%29.aspx

每次使用bitmap.GetHbitmap时,都会创建一个gdibitmap的新实例。根据msdn链接,“您负责调用GDI DeleteObject方法来释放GDI位图对象使用的内存。有关GDI位图的更多信息,请参阅Windows GDI文档中的位图。”

我会把那个人拉到变量上并在完成后调用deleteobject,否则你只是创建n gdibitmaps n = number of times you move the slider并且永远不要丢弃它们。

编辑:突出显示该行:

//Somewhere in the class
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

    private void slider1_ValueChanged(object sender, RoutedEventArgs e) 
    {

        using (System.Drawing.Bitmap b = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone(new RectangleF() { Width = (int)this.ParentWindow.Document.Bitmap.Width, Height = (int)this.ParentWindow.Document.Bitmap.Height, X = 0, Y = 0 }, this.ParentWindow.Document.Bitmap.PixelFormat))
        {
            this.ParentWindow.SetPixels(b, AdjustmentTypes.Brightness, Convert.ToInt32(this.slider1.Value));
            IntPtr hbitmap = b.GetHbitmap(); //create variable so we don't orphan the object
            BitmapSource m = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); //use variable
            this.ParentWindow.image1.Source = m;
            this.NewBitmap = (System.Drawing.Bitmap)b.Clone();
            DeleteObject(hbitmap); //delete gdi object
        }

    }